51单片机串口通信原理、相关寄存器配置与简单串口收发程序代码

2023-05-16

目录

1. 串口通信原理

2. 51单片机串口通信

 2.1 串口简要模式图

 2.2 相关寄存器

(1)PCON、SCON、SBUF

(2)IE、IPH、IP

(3)配置T1定时器

2.3 波特率和系统时钟和TH1和TL1计算

 3.串口通信简单收发使用代码

 3.1 在STC-isp使用端口助手,从单片机发送字节

 3.2 通过端口助手利用主机输入数据在中断中控制LED

 3.3 利用中断把主机发送来数据发送回主机


1. 串口通信原理

        串口通信是通信设备间在一条传输线上串行逐个比特的发送数据的通信方式。串行通信又可分为同步异步两种通信方式。同步通信是在同一时钟信号控制下进行收发信号,异步通信中需要双方规定一致发送和接收频率

        数据传输的方向可分为单工只能向一个方向传输)半双工(不同时间在一根线上向不同方向传输)全双工(可同时向不同方向传输)。

图1.常见串行通信接口接口 

        UART是一种采用异步串行通信的通用异步收发器,在发送时将并行数据转换成串行数据,接收端则将串行数据转换成并行数据。此外UART一般需要两根数据,一根端口发送,一根端口接收。

 图2.硬件连接

        图3.一般协议层数据格式 

         常见串口通信速率为(9600、19200、38400、57600、115200)bps。

        UART串口物理层常用电平标准(51单片机使用TTL电平,由下不要直接将DB接口引线接到单片机会烧毁(15v > 5v)):

  • TTL电平:+5V 表示1,0V表示0
  • RS232电平(常用于DB 接口):-3~-15V表示1,+3~+15V表示0
  • RS485电平:两线压差+2~+6V表示1,-2~-6V表示0(差分信号)

2. 51单片机串口通信

图2.1.CPU线路图 

图2.2.USB转TTL 

  STC89C52rc有1个UART,有四种工作模式:(常用方式1)

 2.1 串口简要模式图

 图2.3 串口简要模式图

 图2.4 中断结构局部图

         SBUF为串口数据缓存寄存器,物理上是两个独立的寄存器,但占用相同的地址。写操作时,写入的是发送寄存器,读操作时,读出的是接收寄存器。SMOD控制控制是否加倍速(置1相当于加倍)

 2.2 相关寄存器

(1)PCON、SCON、SBUF

        STC89C52RC及同系列单片机串行口设两个控制寄存器,串行控制寄存器SCON和 波特率选择特殊功能寄存器PCON

 PCON(不可位寻址):

SCON(可位寻址):


TI/RI为中断标志位,一般是当要发生中断事情发送才标志中断,所以一般初始化置0

由上,当我们 想要简单的在模式1下向主机发送数据:

SCON(SM0=0,SM1=1,SM2=0,REN=0/1,TB8=0,RB8=0,T1=0,R1=0)=> 0x40

且因为需要分频,需要波特率加倍,不然速率太低。

PCON(SM0D=1,SMOD0=0)  =>  PCON | 0x80

SBUF串行口缓冲寄存器:

        虽然地址相同,但SBUF是2个缓冲器,写SBUF的操作完成待发送数据的加载,读SBUF的操作可获得已接收到的数据。两个操作分别对应两个不同的寄存器,1个是只写寄存器,1个是只读寄存器

        软件操作上,我们可以只操作SBUF,要发送时,将要发送数据赋值给SBUF,同时注意在停止位发送后将TI复位。

(2)IE、IPH、IP

        与串行口中断相关的寄存器有IE和IPH、IP。

        串行口中断允许位ES位于中断允许寄存器IE中;串行口中断优先级控制位PS/PSH位于中断优先级控制寄存器IP/IPH中

IE(可位寻址):

 IP与PH(不可位寻址):

 为了简单,可以仅考虑两个优先级,只操作PS=0/1

当我们不需要中断操作,也可以不设置中断EA、ES

(3)配置T1定时器

        串行通信模式1的波特率是可变的,可变的波特由定时器/计数器T1独立波特率发生器
生 ,因此我们需要配置T1定时器,常选用定时器计数器T1的工作方式2(8位自动重装) 作为波特率的溢出率。

        对于TMOD,T1模式控制为前四位:(x,x,1,0)=> (TMOD & 0x0f) | 0x02

        对于TCNO模式1控制位:

                不需要计时器发送中断,只需要它的溢出:ET1 = 0;

                允许T1开始计时:TR1 = 1;

 (4)使用STC-ISP配置寄存器

  本系列单片机没有AUXR,系统时钟为11.0592MHZ(因为串口通信要求较精准,如果使用12mhz与板子晶振频率不符传输错误率较大,此外通信两端波特率也要一致

2.3 波特率和系统时钟和TH1和TL1计算

建议使用STC-ISP设置TH1和TL1

对于串口模式1,定时器1使用模式2(8位自动重装)。利用公式逆着推从溢出率推出波特率。

  1. 当TL1 = 0xf4
  2. (ff +1)- f4 = 12          //计数12次溢出
  3. 1 /(11.0592MHZ/12)= 1.0850694444444us    //定时器12分频下计数一次的时间
  4. 12*1.0850694444444us  = 13.0208333333328us
  5. 溢出率:1/13.0208333333328us = 0.07680000000000314572800000012885
  6.  波特率 = 2^1/32 * 溢出率 = 0.00480000000000019660800000000805HZ 约等于4800MHZ
  7. 误差 = (0.00480000000000019660800000000805-0.0048)/0.0048 约等于0

 3.串口通信简单收发使用代码

3.1 在STC-isp使用端口助手,从单片机发送字节

#include <REGX52.H>
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON  = 0x40;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF4;			//设置定时初始值
	TH1 = 0xF4;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
    
    //中断加不加都行,因为我们不需要中断操作
    //EA =1;
	//ES =1;
}

//发送一个字节数据经过SBUF缓存并到达主机
void UART_SendByte(unsigned char byte) {
	SBUF = byte;
    //当发送完成,TI位硬件自动置1
	while(TI == 0);
	TI = 0;
}

int main()
{
	UartInit();
	UART_SendByte(0x66);
	while(1)
	{

	}		
	
}

 3.2 通过端口助手利用主机输入数据在中断中控制LED

#include <REGX52.H>
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON  = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF4;			//设置定时初始值
	TH1 = 0xF4;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
    
    //我们尝试利用发送中断,所以需要中断操作,即电脑发送数据来,申请中断来接受数据和其他操作
    EA =1;
	ES =1;
    //为了简便,不配置优先级,选用默认优先级
}


int main()
{
	UartInit();
	while(1)
	{

	}		
	
}

void UART_Routine() interrupt 4 {
    //主机发送数据到SBUF后,RI会置1
    //单片机发送也会触发中断,为TI且占用同一中断,所以判断RI
    if(RI == 1)
    {
        //中断后响应的操作
        //利用主机发送给SBUF中数控制LED,如发送1就是除了LED1,其他都点亮
        P2 = SBUF;
        //RI必须软件复位
        RI = 0;
    }
    
}

 3.3 利用中断把主机发送来数据发送回主机

中断逻辑在注释中解释

#include <REGX52.H>
void UartInit(void)		//4800bps@11.0592MHz
{
	PCON |= 0x80;		//使能波特率倍速位SMOD
	SCON  = 0x50;		//8位数据,可变波特率
	TMOD &= 0x0F;		//设置定时器模式
	TMOD |= 0x20;		//设置定时器模式
	TL1 = 0xF4;			//设置定时初始值
	TH1 = 0xF4;			//设置定时重载值
	ET1 = 0;			//禁止定时器中断
	TR1 = 1;			//定时器1开始计时
    
    //我们尝试利用发送中断,所以需要中断操作,即电脑发送数据来,申请中断来接受数据和其他操作
    EA =1;
	ES =1;
    //为了简便,不配置优先级,选用默认优先级
}

//发送一个字节数据经过SBUF缓存并到达主机
void UART_SendByte(unsigned char byte) {
	SBUF = byte;
    //当发送完成,TI位硬件自动置1
	while(TI == 0);
	TI = 0;
}

int main()
{
	UartInit();
	while(1)
	{

	}		
	
}

void UART_Routine() interrupt 4 {
    //主机发送数据到SBUF后,RI会置1
    //单片机发送也会触发中断,为TI且占用同一中断,所以判断RI
    if(RI == 1)
    {
        //中断后响应的操作
        //此时SBUF内容为主机发来的数据,通过UART_SendByte函数发送回到主机
        //因为该中断由接受端发起,发送操作已经中断,所以现在不会有接收操作与发送操作冲突
        UART_SendByte(SBUF);
        //RI必须软件复位
        RI = 0;
    }
    
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

51单片机串口通信原理、相关寄存器配置与简单串口收发程序代码 的相关文章

  • Linux网络编程 | TCP详解

    文章目录 前言一 TCP是什么二 TCP粘包问题三 TCP怎么保证可靠性四 TCP三次握手 xff0c 四次挥手五 TCP状态转移图总结 前言 总结TCP相关问题 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一
  • Linux网络编程 | UDP编程

    文章目录 前言一 UDP是什么二 UDP 数据报服务特点二 UDP 编程流程1 服务器2 客户端3 输出结果 总结 前言 浅谈UDP 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 UDP是什么 UDP是一种不可
  • Linux网络编程 | HTTP、Web服务器

    提示 xff1a 写完文章后 xff0c 目录可以自动生成 xff0c 如何生成可参考右边的帮助文档 文章目录 前言一 http协议二 请求报文三 应答报文四 实现简单的Web服务器1 代码如下2 输出结果 xff1a 总结 前言 介绍ht
  • Multipath多路径冗余全解

    一 什么是multipath 普通的电脑主机都是一个硬盘挂接到一个总线上 xff0c 这里是一对一的关系 而到了有光纤组成的SAN环境 xff0c 由于主机和存储通过了光纤交换机连接 xff0c 这样的话 xff0c 就构成了多对多的关系
  • Linux网络编程 | I/O复用之select

    文章目录 前言一 select二 API接口 xff1a 三 使用步骤1 服务器端2 客户端 总结 前言 select的原理以及使用 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 select select系统
  • Linux网络编程 | I/O复用之poll

    文章目录 前言一 poll二 API接口三 使用步骤1 服务器端2 客户端 总结 前言 poll的原理以及使用 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 poll poll 系统调用和 select 类似
  • Linux网络编程 | I/O复用之epoll(LT模式)

    文章目录 前言一 epoll二 常用API xff1a 三 使用步骤1 服务器端 xff08 LT模式 xff09 2 客户端 总结 前言 epoll原理以及使用 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一
  • Linux网络编程 | I/O复用之epoll(ET模式)

    文章目录 前言一 epoll的LT模式与ET模式二 使用步骤1 服务器端 xff08 ET xff09 2 客户端 总结 前言 epoll xff08 ET模式 xff09 以及使用方法 提示 xff1a 以下是本篇文章正文内容 xff0c
  • Linux网络编程 | Libevent库

    文章目录 前言一 libevent二 Libevent模型1 模型图2 结构图 三 支持事件类型四 使用libevent完成TCP服务器端1 服务器端 总结 前言 简单介绍libevent库以及使用 提示 xff1a 以下是本篇文章正文内容
  • Linux基础 | 守护进程

    文章目录 前言一 守护进程是什么 xff1f 二 编程流程三 使用步骤1 后台运行 xff0c 每隔五秒输出一次时间2 输出结果 总结 前言 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 守护进程是什么 xff
  • C++ | shared_ptr与weak_ptr

    文章目录 前言一 shared ptr与weak ptr是什么 xff1f 1 shared ptr的内存模型2 weak ptr的内存模型 二 仿写系统的shared ptr与weak ptr1 mdeletor2 Ref con3 sh
  • C++ | lambda表达式

    文章目录 前言一 lambda是什么二 使用步骤总结 前言 简单介绍lambda表达式以及使用方法 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 lambda是什么 lambda表达式是C 43 43 11最重
  • Linux基础 | 内存管理

    96 文章目录 前言一 准备工作1 存储器结构2 进程运行原理3 内存扩充技术 二 内存管理1 连续分配管理方式a 单一连续分配b 固定分区分配c 动态分区分配d 动态分区的分配策略 2 非连续分配管理方式 三 虚拟内存管理1 虚拟内存概念
  • C++ | C++中二维数组创建与初始化

    文章目录 前言一 使用步骤1 创建数组2 初始化 总结 前言 刷题时碰到需要用vector创建二维数组的情况 xff0c 简单记录一下 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 使用步骤 1 创建数组 代码
  • group by与partition by用法

    本文采用Oracle数据库测试 xff0c 前4个查询为一组 xff0c 后2个查询为一组 xff0c 每组前面的查询是为了推出最后的查询 创建表 xff0c 为了简化处理 xff0c 字段类型都采用varchar create table
  • 算法 | 二分查找及其变种

    文章目录 前言一 二分查找二 数组完全有序且不重复1 第一题2 第二题 三 数组完全有序且重复1 第一题2 第二题 四 数组部分有序且不重复1 第一题2 第二题 五 数组部分有序且重复1 第一题2 第二题3 第三题 六 二维数组总结 前言
  • C++ | 四种类型转换

    文章目录 前言一 类型转化的四种方式二 每个类型转换的使用以及注意事项1 const cast2 static cast3 reinterpret cast4 dynamic cast 总结 前言 简单记录一下C 43 43 中常用的四种类
  • C++ | sort()函数使用详解

    文章目录 前言一 sort 是什么 xff1f 二 使用步骤1 对二维数组进行排序2 针对其它内置类型与结构体或者类 总结 前言 提示 xff1a 这里可以添加本文要记录的大概内容 xff1a 力扣347题 xff1a 给你一个整数数组 n
  • C++ | 菱形继承与虚继承

    文章目录 前言一 菱形继承是什么 xff1f 二 没有虚继承的情况1 具体代码2 结构图 二 有虚继承的情况1 具体代码2 结构图 总结 前言 简单介绍一下C 43 43 中的菱形继承 提示 xff1a 以下是本篇文章正文内容 xff0c
  • C++ | 不用额外空间反转句子

    描述 给定一个字符串 xff0c 逐个翻转字符串中的每个单词 说明 单词的构成 xff1a 无空格字母构成一个单词 样例 给出s 61 the sky is blue xff0c 返回 34 blue is sky the 34 span

随机推荐