这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 高校专区» 坤创E-Geek/天科大新电社» 第十一届蓝桥杯信息技术人才大赛-单片机竞赛备赛分享十——串口通信基础知识讲解(二

共5条 1/1 1 跳转至

第十一届蓝桥杯信息技术人才大赛-单片机竞赛备赛分享十——串口通信基础知识讲解(二)

工程师
2020-03-16 19:26:48 打赏

哈喽哈喽大家好,我是阿飞的小蝴蝶,大家可以叫我阿飞或者小飞,我又回来啦!

我们接着上节的内容来给讲一下51单片机串口的使用方法,好的,直接开始我们今天的内容。


串行口的结构:

image.png

这里有两个物理上独立的接收、发送寄存器SBUF,它们占用同一内存(99H)。

在程序逻辑上,SBUF只有一个,既代表发送寄存器,又代表接收寄存器,具有同一单元地址,但在物理结构上,则有两个完全独立的SBUF,一个发送寄存器SBUF和一个接收寄存器SBUF。如果CPU写SBUF,数据会被存入发送寄存器准备发送;如果CPU读SBUF,则读入的数据一定来自接收寄存器SBUF。(a=SBUF;SBUF=a;)。

接下来讲一下与串口有关的寄存器:

首先是SCON寄存器:

image.png

这里我简单说一声每一位的功能:

SM0:当PCON寄存器中SMOD0位为1时,该为用于帧错误检测。为0时,该位与SM1一起控制串口通信的工作方式。(这里一般用于控制工作方式)

SM0、SM1控制串口通信工作方式:

image.png

这里的SYSclk是晶振频率,方式0和方式2是比波特率固定的,具体大家可以自己算一下。方式1和方式3通过配置定时器1来改变波特率,SMOD是PCON寄存器中可以配置的,配置为1时可以将波特率提升1倍,后边会再介绍。

我们一般使用方式1,发送/接收8位数据,波特率可变。

SM2:多机通信控制位,主要用在方式2和方式3,为0时双机通信,为1时多机通信。

REN:串行接收允许位,REN=0时禁止接收,REN=1时允许接收

TB8/TR8:在方式2和方式3时分别用于存放发送/接收的第9位数据。

TI:发送中断请求标志位,数据发送结束时,标志位被自动置1并向CPU请求中断,需通过程序置0。

RI:接收中断请求标志位,数据接收结束时,标志位被自动置1并向CPU请求中断,需通过程序置0。

接下来是PCON寄存器:

image.png

SMOD:波特率选择位:SMOD=1时,工作方式1、2、3中波特率加倍。

最后还是我们熟悉的IE寄存器:

image.png

这里与串口有关的为:

EA:CPU总中断允许控制位,前边多次介绍过的,不多说了

ES:串行口中断允许位,ES=1,允许串行口中断;ES=0,禁止串行口中断。

我们配置好串口工作模式、打开串口中断后,CPU接收到串口的中断请求时就会相应串口中断执行串口中断服务函数。

波特率计算:

当串口工作在方式1时,波特率由定时器1的溢出率决定,此时定时器1通常选用定时器初值自动重装的工作模式(工作模式2,TMOD=0x20;)此时仅用低8位来计数,溢出以后8位的存放的数据会放入低8位中重新计时,无需再通过程序重放初值

因此,波特率=(2^SMOD/32)*(单片机时钟频率/(256-X)),X是初值。

在实际应用中,通常是选确定波特率,再根据波特率算出TI的定时初值,因此:X=256-(2^SMOD/32)*(单片机时钟频率/波特率)

我举个栗子:波特率为9600时,T1存放的初值(晶振频率为11.0592MHZ)。

SMOD=0,(2^SMOD/32)=1/32,(单片机时钟频率/波特率)=((11.0592MHZ/12)/9600)=96。X=253,因此T1存放初值为253(TH1=0xfd;TL1=0xfd;)。


再使用串口前,我们要把上边讲到的寄存器进行配置,设定好工作方式。

1、设置T1工作方式(编程TMOD寄存器);

2、计算T1的初值,装载TH1、TL1;

3、启动T1(编程TCON中的TR1位);

4、确定串行口控制(编程SCON寄存器);

5、如需串口在中断方式工作时,要进行中断设置编程IE寄存器


好的,现在用代码来对串口进行初始化:

void uart_init()

{

TMOD = 0x20; //T1工作模式2 8位自动重装

TH1 = 0xfd;
TL1 = 0xfd; //比特率9600
TR1 = 1; //启动T1定时器
SM0 = 0;
SM1 = 1; //串口工作方式1 10位异步
REN = 1; //串口允许接收
EA = 1; //开总中断
ES = 1; //串口中断打开

}

下边用一个例子来带大家了解一下:

串口收发数据,设置波特率为9600,把接收到的数据用P1端口的LED灯以二进制的形式显示(灭为0,亮为1),在把接收到的数据加1并发出。

#include  #define u8 unsigned char #define u16 unsigned int u8 num; //用于存放接收/发送数据 void delay(u16 z) { u16 x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } void UART_init() { TMOD = 0x20; //T1工作模式2 8位自动重装 TH1 = 0xfd; TL1 = 0xfd; //比特率9600 TR1 = 1; //启动T1定时器 SM0 = 0; SM1 = 1; //串口工作方式1 10位异步 REN = 1; //串口允许接收 EA = 1; //开总中断 ES = 1; //串口中断打开 } void main() { UART_init(); //串口初始化 while(1); } void UART() interrupt 4 { if(RI) //检测是否接收完成 { num = SBUF; //采集接收到的数据 P1 = SBUF; num++; //把接收的数据加1并发送 RI = 0; SBUF = num; while(!TI); //等待发送完成 TI = 0; } }


当我们使用串口发送字符串时,可以直接添加头文件“#include ”,这个就是我们学习C语言时常用到了,我们可以直接调用其中的“printf”、“putchar”等函数来通过串口发送数据,这里要注意的是:在发送前要通过程序来把“TI”置1,因为在这些函数开头就会通过“while(!TI);”来判断数据是否发送完成。

/*************************************************

void putchar (unsigned char sbyte)

{

while(!TI); //等待数据发送完成

//如果没有置1,程序会卡在这里

SBUF = sbyte;

}

*************************************************/


好的,现在用程序来实现一下:

#include  #define u8 unsigned char #define u16 unsigned int u8 num; //用于存放接收/发送数据 void Delay(u16 n) { u8 j; while(n--) for(j=113;j>0;j--); } void UART_init() { TMOD = 0x20; //T1工作模式2 8位自动重装 TH1 = 0xfd; TL1 = 0xfd; //比特率9600 TR1 = 1; //启动T1定时器 SM0 = 0; SM1 = 1; //串口工作方式1 10位异步 }//这里没有使用中断和接收功能,可以不配置 void main() { UART_init(); //串口初始化 while(1) { TI = 1; printf("欢迎大家使用串口通信!\n"); while(!TI); //等待发送完成 TI = 0; Delay(1000); //每隔1S发送一次 } }


调试串口时,可以使用“STC-ISP(V6.85)”(其它版本应该也可以)

}~KMUCB}}%H%NSQBRFM1L]R.png


好的,本节内容就先到这里啦,这节没有小练习啦,我会找个时间来更新一篇“备赛番外篇”来带大家使用一些串口(保证是大家都想看到的哦~)






工程师
2020-03-16 21:56:55 打赏
2楼

多谢分享哦


工程师
2020-03-19 16:15:38 打赏
3楼

感谢分享


工程师
2020-03-19 16:16:14 打赏
4楼

感谢分享,楼主辛苦了


菜鸟
2020-04-10 11:03:49 打赏
5楼

感谢楼主,,,实属有大收获


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]