锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

51单片机学习笔记(清翔版)(19)——串口通信

时间:2023-08-13 15:07:00 贴片温度传感器接温度变送器

学好了中断再学串口通信

今天的课程是关于数据传输的,这在工业控制和商业控制中非常重要。数据传输包括串口和并行通信。

由于工作方式相同,这里提到的计算机可以理解为单片机。

单片机通信是指单片机与外部设备之间的温度传感器(温度传感器,使单片机知道温度传感器收集的温度)。

控制数码管是并行通信P0直接赋位选择或段选,P一次传输8条数据,如08条线P0=0x01,一次性传输8位数据。

询问和响应是指询问的工作方式。询问是否准备好接收数据,并通过响应线传输准备。然后发送8位数据。

从这节课开始,我们学习的数据传输大多使用串行通信,前8个*8点阵也是串行通信。

缺点:数据传输的控制比平行复杂,这意味着数据传输不止一条数据线,但也需要控制线,控制数据传输的节奏是多长,是一个接一个的数据传输,所以告诉每个传输需要多长时间,比如前8*8点阵有时钟线。

右侧是单片机的串行通信。一个发送引脚,一个接收引脚,另一个接收引脚另一个接收引脚,通过这两行数据交换。以下是相互共享的地方。

下面是异步通信的图片。发送一个字节数据,前面有起始位置,后面有停止位置。读取起始位置,知道数据何时来,读取停止位置,知道帧数据已经完成,由硬件设备判断。每帧数据之间的间隔是任意的。

同步通信数据源源不断地发送,有一条控制线,即时钟线,给时钟,发送数据,只要时钟不停止,发送数据就不能停止。

这些理论就是一个了解,单片机串口通信内部硬件有这个功能,我们只需要配置内部的寄存器就可以了,如果要发送数据,只要给寄存器赋值就可以了,如果接收,我们读这个数据就能读到,我们不用关心帧与帧之间和位与位之间的间隔,如果不自带这个功能,我们用软件模拟,我们就需要清除的知道这些理论知识。例如I2C是软件模拟。

LSB是低位,MSB是高位。

检查前面的数据是否在发送过程中受到干扰或其他原因造成错误。

8*8点阵,使用SPI通信,就是外同步的方式,发送机是单片机,接收机是点阵内部的595,发送机有一个时钟引脚,控制接收机,直接传到595的时钟引脚上,每来一个时钟就发一个数据,收到时钟就接一个数据,源源不断的时钟就源源不断的发,间隔由时钟控制的,可以看出同步通信比异步通信效率高很多,因为时钟是源源不断的,数据是源源不断的过去,异步通信是一帧一帧的,中间夹杂着起始位置、停止位置、验证位置,这三个是无用的东西,也不能说无用,在异步通信中有用,但在同步通信中可以节省,所以效率高,同步通信是连续的,所以更快。

自同步以来,双方同意时钟是一样的。一个时钟发送一个数据,另一边接收一个数据。外同步是最常用的。开发板上一些,比如I2C设备数模转换芯片,E2PROM芯片,都是用的同步通信的外同步。

我们的串口是异步通信,后面是I2C和SPI是同步。

我们单片机串口是全双工的。

只需了解一下验证,就不多说了。因为我们的单片机有自己的串口,所以我们不需要奇偶验证,只需要配置寄存器。

这是指异步通信的传输速率。每帧数据的间隔是任意的,但每帧都是固定的,这是由传输速率的比特率决定的。

现在我们实际上没有使用这两个接口。

25针相对较少,早期的工业设备也可以看到,如90年出厂,分为公头和母头,或阳头和阴头。阳头有针脚,母头有孔。

还能看到9针式。

每个引脚的功能和如何排列都是统一的,否则就无法通信,所以需要这个标准。

我们现在不使用这两种板上用的微型usb内部只有4只脚,只有4只脚TXD、RXD,电源和地。

工业上有9英尺,家用电器很少

非平衡屏蔽双绞线是一种抗干扰线,将两条绞在一起。网多地用于网络电缆。当信号传输时,会有噪声和磁场干扰。使用它和屏蔽层,以尽可能地屏蔽干扰。

电容允许值是上述电气特性。

分布式电容(寄生电容)和电感将在线形成。线越长,分布式电容越大,电容式电感将形成LC当信号传输时,低通滤波电路会受到电路的影响而衰减。这个电容器不是人工添加的,而是自动生成的布线方式。该电容器存在于三极管和场效应管中,直接影响开关速度。电容器尺寸与两条线之间的距离成反比,与导体面积成正比。

看到实际的电容器,容量越大,体积就越大。例如,电解电容器片瓷片电容器(内部有许多金属片,它们是分开的,金属片是绝缘的,然后形成电容器。金属片面积越大,电容器越大,间隔越短,电容器越大)。

99H,H是HEX也就是说,16进制,这是地址,不需要关心reg52.h定义,直接写SBUF就可以。

我们通过程序发送要发送的值SBUF,然后通过门电路、发送控制器和波特率生成器控制每个发送速度(设置比特率),然后通过TXD(P3.1接口)发送出去。

通过RXD接收数据,通过移位寄存器发送到接收SBUF中间。如果我们想读取数据,直接读取SBUF当然也要设置比特率,要和发送一样。

这些都是内部具有串口功能的硬件。很简单。

使用比特率发生器T1做的,计算T一是计算波特率。

SCON是串口工作方式的选择。

串口也可以有查询和中断。查询方法由标志位控制。根据两个标志位,判断是否发送和接收完成。完成后将被放置1。我们直接中断。

必须使用中断IE寄存器。

SCON可位寻址。

SM0和SM1.设置工作模式。SM多机通信。REN是接收控制。TB8和RB8是第九位。TI和RI是发送和接收中断标志位,发送和接收将被放置1。

这两个是最重要的。

波特率时系统时钟的12分频为0。SMOD是波特率倍增。

方法1使我们使用最多,方法2、3是多机通信。

REN位0时,发送的数据不会存储SBUF是的。所以接收需要软件置1。

一定要记住软件把TI和RI清零,否则会一直中断。

什么时候用?SMOD外部时钟是11.0592,如果波特率较高,受时钟影响,波特率最大值有限,那么我们可以使用它SMOD加倍。

fosc是外部晶振,11.0592.

T1的初始值可以自己计算,也可以用软件计算。或者直接记住T1=0xFD。

若使用晶振12MHz,误差很大,导致传输过程中数据可能出错,比如我发1,可能接收3。

尽管机器周期1.085,再做软件延时,感觉没有12M好吧,但是软件延迟不重要,有一点误差也没关系,但是传输数据很重要。


然后开始编程

就这样来吧。

计算机(上位机)发送值,单片机收到的值以十进制的形式显示。

 1 #include   2   3 #define uchar unsigned char  4 #define uint  unsigned int  5   6 sbit we = P2^7;    //定义数码管位选择定器接口  7 sbit du = P2^6;     //定义数码管位选择锁定器接口  8   9 uchar num; 10 //数码管0~9段选表 11 uchar code leddata[]={0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; 12 //数码管1~3位选表 13 uchar code DPY[]={0xfe, 0xfd, 0xfb}; 14 void display(uchar i) 15 { 16     static uchar wei; 17     P0=0xff; 18     we=1; 19     P0=DPY[wei]; 20     we=0; 21     switch(wei) 22     { 23         case 0:du=1;P0=leddata[i/100];du=0;break; 24         case 1:du=1;P0=leddata[i0/10];du=0;break; 25         case 2:du=1;P0=leddata[i];du=0;break; 26     } 27         wei  ; 28         if(wei==3) 29             wei=0; 30 } 31 ///中断服务特殊功能寄存器配置 32 void init() 33 { 34      35     TMOD |= 0x01;  //定时器16为计数工作模式 36     TH0 =0xED; 37     TL0 =0xFF; //5ms 38     ET0 = 1; ///开定时器0中断 39     TR0 = 1.//启动定时器0 40     EA = 1;    ///开总中断 41 } 42 void UART_init() 43 { 44     EA=1;///开总中断 45     ES=1;//开串口中断 46     SM0=0;SM1=1.//串口工作方式1 47    REN=1;//串口接受允许
48     TR1=1; //打开定时器1
49     TMOD|=0x20;//定时器1,工作模式2,八位自动重装
50     TH1=0xFD;
51     TL1=0xFD;//253,波特率(比特率)9600
52 }
53 void main()
54 {
55     init();//初始化定时器0
56     UART_init();//串口初始化
57     while(1)
58     {
59         
60     }
61 }
62 void UART() interrupt 4
63 {
64     if(RI)
65     {
66         num=SBUF;
67         RI=0;
68     }
69     
70 }
71 //定时器0中断服务程序  做数码管动态扫描,不用软件延时
72 void timer0() interrupt 1
73 {
74     TH0 =0xED;
75     TL0 =0xFF; //5ms  模式1非自动重装需要手动重装
76     display(num);
77 }

 

发16进制的数字。刚打开串口时,会接收到别的数,没关系,下载也是通过串口的。

下面把接收到的数据+1再发送出去。

 1 #include 
 2 
 3 #define uchar unsigned char
 4 #define uint  unsigned int
 5 
 6 sbit we = P2^7;    //位定义数码管位选锁存器接口
 7 sbit du = P2^6;     //位定义数码管位选锁存器接口
 8 
 9 uchar num;
10 //数码管0~9段选表
11 uchar code leddata[]={0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
12 //数码管1~3位选表
13 uchar code DPY[]={0xfe, 0xfd, 0xfb};
14 void display(uchar i)
15 {
16     static uchar wei;
17     P0=0xff;
18     we=1;
19     P0=DPY[wei];
20     we=0;
21     switch(wei)
22     {
23         case 0:du=1;P0=leddata[i/100];du=0;break;
24         case 1:du=1;P0=leddata[i%100/10];du=0;break;
25         case 2:du=1;P0=leddata[i%10];du=0;break;
26     }
27         wei++;
28         if(wei==3)
29             wei=0;
30 }
31 //中断服务特殊功能寄存器配置
32 void init()
33 {
34     
35     TMOD |= 0x01;  //定时器16为计数工作模式
36     TH0 =0xED;
37     TL0 =0xFF; //5ms
38     ET0 = 1; //开定时器0中断
39     TR0 = 1;//启动定时器0
40     EA = 1;    //开总中断
41 }
42 void UART_init()
43 {
44     EA=1;//开总中断
45     ES=1;//开串口中断
46     SM0=0;SM1=1;//串口工作方式1
47     REN=1;//串口接受允许
48     TR1=1; //打开定时器1
49     TMOD|=0x20;//定时器1,工作模式2,八位自动重装
50     TH1=0xFD;
51     TL1=0xFD;//253,波特率(比特率)9600
52 }
53 void main()
54 {
55     init();//初始化定时器0
56     UART_init();//串口初始化
57     while(1)
58     {
59         
60     }
61 }
62 void UART() interrupt 4
63 {
64     uchar temp;
65     if(RI)
66     {
67         num=SBUF;//读SBUF,读出串口接收到的数据
68         RI=0;//软件清零接受标志位
69         temp=num;
70         SBUF=++temp;//写SBUF,把要发送的数据送给发送缓冲器,然后单片机硬件会自动把数据发到TXD引脚
71     }
72     if(TI)//判断是否发送完成
73         TI=0;//清零发送完成标志位
74 }
75 //定时器0中断服务程序  做数码管动态扫描,不用软件延时
76 void timer0() interrupt 1
77 {
78     TH0 =0xED;
79     TL0 =0xFF; //5ms  模式1非自动重装需要手动重装
80     display(num);
81 }

上方式计算机接收端。

如果我们选择文本格式发送,发送1后,数码管会显示49,因为发文本格式是以asc码格式发送的。

看到图中1是49。发送1,文本格式的1变为数字是asc的49,那么数码管接收到的就是49,而发给单片机,又以文本格式显示,那么又变回了文本格式,49+1是50,也就是2。文本发送9,那么单片机显示57,计算机接收到文本格式是冒号。

接下来如何通过串口发送汉字?

发送汉字可以使用标准库函数,可以使用printf()和puts(),需要#include

这个串口初始化没有用到中断,我们用的查询方式。

 puts()上面为什么TI=1,因为我们给SBUF送值后,串口会自动发送,发送完,硬件置1,我们为什么用软件置1?

puts()是调用了putchar()函数,这个函数发送前先进行while(!TI)判断,如果TI没置1,那么会一直在这里等待,那么要发送的字符就送不到SBUF里,所以就一直不会发送,所以要是用puts()和printf()都应该先把TI置1。

我们也可以在帮助中看到。

然后选择uVision help

 

putchar()函数就是把字符c发送到串口。

 1 #include 
 2 #include
 3 
 4 #define uchar unsigned char
 5 #define uint  unsigned int
 6 
 7 void UART_init()
 8 {
 9     SM0=0;SM1=1;//串口工作方式1
10     TR1=1; //打开定时器1
11     TMOD|=0x20;//定时器1,工作模式2,八位自动重装
12     TH1=0xFD;
13     TL1=0xFD;//253,波特率(比特率)9600
14 }
15 void Delay1ms()        //@12.000MHz
16 {
17     unsigned char i, j;
18 
19     i = 12;
20     j = 169;
21     do
22     {
23         while (--j);
24     } while (--i);
25 }
26 void delay(uchar num)
27 {
28     while(num--)
29     {
30         Delay1ms();
31     }
32 }
33 void main()
34 {
35     UART_init();//串口初始化
36     while(1)
37     {
38         TI=1;
39         puts("大家好!欢迎学习单片机");
40         while(!TI);
41         TI=0;
42         delay(1000);
43     }
44 }

接收的时候是以文本接收

1s发一次,且换行,而printf不换行。

锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章