串口通信是单片机最常用的一种通信技术,通常用于单片机与计算机之间以及单片机和单片机之间的通信。通信按照基本类型可以分为并行通信和串行通信。
其中单片机中就存在一个UART模块用于通信,要正确地使用它,当然还得把对应的特殊功能寄存器配置好。
51单片机地UART串口的结构由串行口控制寄存器SCON、发送和接收电路三部分构成。首先是串口控制寄存器SCON
SCON寄存器的配置与之前配置定时器有些类似,
在硬件串口模块中,有一个专门的波特率发生器用来控制发送和接收数据的速度。对于STC89单片机来说,这个波特率发生器只能由定时器T1或定时器T2产生,而不能由定时器T0产生,使用定时器T1的模式2,也就是自动重装载模式,定时器的重载值计算公式为:
TH1 = TL1 = 256 -晶振值/12/2/16/波特率
其中12是说一个机械周期等于12个时钟周期,256是8位定时器的溢出值,串口通信接收数据的时候的采取方式是把信号采集16次,其中第7、8、9次取出来,而不是取中间值,保证最终数据的正确性。
然后串口通信的发送和接收电路在物理上有两个名字相同的SBUF寄存器,它们的地址都是0x99,但一个用来作为发送缓冲,一个用来作为接收缓冲。
编写串口通信的基本步骤如下:
需要注意的是在使用T1做波特率发生器的时候,不要再使能T1中断了。
还有关于ASCII码的相关知识,在学习C语言的时候已经学过了。
下面是通过单片机串口调试助手发送的数据,开发板上的数码管上显示出来的代码。
- #include <reg52.h>
- sbit ADDR3 = P1^3;
- sbit ENLED = P1^4;
- unsigned char code LedChar[] = { //数码管显示字符转换表
- 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
- 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
- };
- unsigned char LedBuff[7] = { //数码管+独立LED显示缓冲区
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
- };
- unsigned char T0RH = 0; //T0重载值的高字节
- unsigned char T0RL = 0; //T0重载值的低字节
- unsigned char RxdByte = 0; //串口接收到的字节
- void ConfigTimer0(unsigned int ms);
- void ConfigUART(unsigned int baud);
- void main()
- {
- EA = 1; //使能总中断
- ENLED = 0; //选择数码管和独立LED
- ADDR3 = 1;
- ConfigTimer0(1); //配置T0定时1ms
- ConfigUART(9600); //配置波特率为9600
-
- while (1)
- { //将接收字节在数码管上以十六进制形式显示出来
- LedBuff[0] = LedChar[RxdByte & 0x0F];
- LedBuff[1] = LedChar[RxdByte >> 4];
- }
- }
- /* 配置并启动T0,ms-T0定时时间 */
- void ConfigTimer0(unsigned int ms)
- {
- unsigned long tmp; //临时变量
-
- tmp = 11059200 / 12; //定时器计数频率
- tmp = (tmp * ms) / 1000; //计算所需的计数值
- tmp = 65536 - tmp; //计算定时器重载值
- tmp = tmp + 18; //补偿中断响应延时造成的误差
- T0RH = (unsigned char)(tmp>>8); //定时器重载值拆分为高低字节
- T0RL = (unsigned char)tmp;
- TMOD &= 0xF0; //清零T0的控制位
- TMOD |= 0x01; //配置T0为模式1
- TH0 = T0RH; //加载T0重载值
- TL0 = T0RL;
- ET0 = 1; //使能T0中断
- TR0 = 1; //启动T0
- }
- /* 串口配置函数,baud-通信波特率 */
- void ConfigUART(unsigned int baud)
- {
- SCON = 0x50; //配置串口为模式1
- TMOD &= 0x0F; //清零T1的控制位
- TMOD |= 0x20; //配置T1为模式2
- TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值
- TL1 = TH1; //初值等于重载值
- ET1 = 0; //禁止T1中断
- ES = 1; //使能串口中断
- TR1 = 1; //启动T1
- }
- /* 按键扫描函数,需在定时中断中调用 */
- void LedScan()
- {
- static unsigned char i = 0; //动态扫描索引
-
- P0 = 0xFF; //关闭所有段选位,显示消隐
- P1 = (P1 & 0xF8) | i; //位选索引值赋值到P1口低3位
- P0 = LedBuff[i]; //缓冲区中索引位置的数据送到P0口
- if (i < 6) //索引递增循环,遍历整个缓冲区
- i++;
- else
- i = 0;
- }
- /* T0中断服务函数,完成LED扫描 */
- void InterruptTimer0() interrupt 1
- {
- TH0 = T0RH; //重新加载重载值
- TL0 = T0RL;
- LedScan(); //LED扫描显示
- }
- /* UART中断服务函数 */
- void InterruptUART() interrupt 4
- {
- if (RI) //接收到字节
- {
- RI = 0; //手动清零接收中断标志位
- RxdByte = SBUF; //接收到的数据保存到接收字节变量中
- SBUF = RxdByte; //接收到的数据又直接发回,叫作-"echo",
- //用以提示用户输入的信息是否已正确接收
- }
- if (TI) //字节发送完毕
- {
- TI = 0; //手动清零发送中断标志位
- }
- }
复制代码
|