(C51学习五)单片机与PC通过串口通信【转】

时间:2024-03-06 21:54:56

转自:

1.开发步骤

2.串口模块

3.SBUF是什么

4.串口相应寄存器

5.给定波特率求定时值

6.代码实现


1.开发步骤

1.设置串口中断寄存器

2.求出给定波特率对应的T1定时器初始值(因为传统的C51是用T1定时器产生波特率的)

3.写程序


2.串口模块

什么是串口?串口就是COM口,串口是串行发送数据的,是一位位地发送数据位,常见的是9针串口。但在一般的C51学习版和开发版上都有集成CH340转换芯片,

使得用usb口就可以代替串口,所以用一般的学习板进行开发,只要插上usb线就可以进行串口测试。


3.SBUF是什么

SBUF是一个寄存器,作为一个缓冲区,当单片机准备接收数据时,会先把数据放到SBUF中,然后再接收。发送也是,当单片机准备发送数据时,会先把数据放到

SBUF中,再发送出去


SCON串口控制寄存器(主要用方式1)

SM1,SM0:

 

SM0 SM1 工作方式 功能 波特率
0 0 方式0 8位同步移位寄存器 晶振频率 / 12
0 1 方式1 10位UART 可变
1 0 方式2 11位UART 晶振频率/32或晶振频率/64
1 1 方式3 11位UART 可变

SM2:----多机通信控制位(可以先不理)

多机通信是工作在方式2和方式3的,所以SM2主要用于方式2和方式3,多级通信时,SM2=1,当SM2=1时,只有当接收到的数据帧第9位(RB8)为1时,

单片机才把前八位数据放入自己的SBUF中,否则,将丢弃数据帧。当SM2=0时,不论RB8的值是什么,都会把串口收到的数据放到SBUF中。


REN:-----允许接收位

REN用于控制是否允许接收数据,REN=1时,允许接收数据,REN=0时,拒绝接收数据


TB8:-------是要发送的第9位数据位

在方式2和方式3中,TB8是要作为数据帧第9位被发送出去的,在多机通信中,可用于判断当前数据帧的数据是地址还是数据,TB8=0为数据,TB8=1为地址


RB8:-------接收到的第9位数据位

当单片机已经接收一帧数据帧时,会把数据帧中的第9位放到 RB8中。方式0不使用RB8,在方式2和方式3中,RB8为接收到的数据帧的第9位数据位。


TI:-----发送中断标志位

方式0中,不用管他。其他方式下,当发送数据完毕,硬件会将其置1,当 TI 被置1,会向CPU发送中断请求。我们记得要在中断服务程序中把 IT 置回0.


RI:-----接收中断标志位

当接受完一帧数据时,RI  由硬件置1,当RI 被置1,会向CPU请求中断。同样要在中断服务程序中把 RI 置回0。

 


PCON功率控制寄存器

这个寄存器只有一个位SMOD,在方式1,2.,3时,波特率都与SMOD有关,当SMOD=1时,波特率会增加一倍。复位时,SMOD变回0



5.给定波特率求定时值

串口中断要有定时器T1参加,因为C51是用定时器1来产生波特率的。

因此就需要给 定时器T1 设置初值。


首先,我们要选择一个合适的波特率,波特率关乎数据发送的快慢,一般我们选择9600b/s好了,你选2400也没问题。

一般我们会选择定时器的方式2(这里不是说上面的方式2,而是最大计数为256且自动重载定时器初值的方式)

使用这种方式是因为它能自动重载定时器初值,不用在中断服务程序中人工重设,可以减少误差。


6.代码实现:

测试前提:首先要在PC机(电脑)上下载个串口助手,用于接收51单片机的数据。


C51发送数据到电脑:

 

  1. #include <reg51.h>  
  2.   
  3. typedef   unsigned char  uint8;  
  4. typedef   unsigned int   uint16;  
  5.   
  6. uint8 Buf[]="hello world!\n";  
  7.   
  8. void delay(uint16 n)  
  9. {  
  10.     while (n--);  
  11. }  
  12.   
  13. /*波特率为9600*/  
  14. void UART_init(void)  
  15. {  
  16.     SCON = 0x50;        //串口方式1  
  17.   
  18.     TMOD = 0x20;        // 定时器使用方式2自动重载  
  19.     TH1 = 0xFD;    //9600波特率对应的预设数,定时器方式2下,TH1=TL1  
  20.     TL1 = 0xFD;  
  21.   
  22.     TR1 = 1;//开启定时器,开始产生波特率  
  23. }  
  24.   
  25. /*发送一个字符*/  
  26. void UART_send_byte(uint8 dat)  
  27. {  
  28.     SBUF = dat;       //把数据放到SBUF中  
  29.     while (TI == 0);//未发送完毕就等待  
  30.     TI = 0;    //发送完毕后,要把TI重新置0  
  31. }  
  32.   
  33. /*发送一个字符串*/  
  34. void UART_send_string(uint8 *buf)  
  35. {  
  36.     while (*buf != \'\0\')  
  37.     {  
  38.         UART_send_byte(*buf++);  
  39.     }  
  40. }  
  41.   
  42. main()  
  43. {  
  44.     UART_init();  
  45.       
  46.     while (1)  
  47.     {  
  48.         UART_send_string(Buf);  
  49.         delay(20000);  
  50.     }  
  51.   
  52. }  

效果:串口助手连接后会不停显示 hello world。(串口助手波特率要设成和单片机发送波特率一样,COM口也是)



电脑发送数据到单片机:

 

  1. #include<reg52.h>  
  2. #define uchar unsigned char  
  3. #define uint  unsigned int  
  4. uchar buf;  
  5. void main(void)  
  6. {  
  7. SCON=0x50;//设定串口工作方式0101 0000  
  8. PCON=0x00;  
  9. TMOD=0x20;  
  10. EA=1;  
  11. ES=1;  
  12. TL1=0xfd;//波特率9600  
  13. TH1=0xfd;  
  14. TR1=1;  
  15. while(1);  
  16. }  
  17.   
  18. //串行中断服务函数  
  19. void serial() interrupt 4  
  20.     {  
  21.     ES=0;       //暂时关闭串口中断  
  22.     RI=0;  
  23.     buf=SBUF;   //把收到的信息从SBUF放到buf中。  
  24.     switch(buf)  
  25.     {  
  26.     case 0x31: P1=0xfe;break;   //二进制 0011 0001  十进制 49 控制字符 1  16进制 0X31  
  27.     case 0x32: P1=0xfd;break;    //1111 1101  
  28.     case 0x33: P1=0xfb;break;  
  29.     case 0x34: P1=0xf7;break;  
  30.     case 0x35: P1=0xef;break;     
  31.     case 0x36: P1=0xdf;break;     
  32.     case 0x37: P1=0xbf;break;  
  33.     case 0x38: P1=0x7f;break;  
  34.     }  
  35.     ES=1;       //重新开启串口中断  
  36.   
  37. }  

效果:当用电脑的串口助手向单片机发送数字1的时候,单片机会亮起LED0,以此类推。