首页 > 编程知识 正文

串口通信代码C语言,单片机串口通信原理

时间:2023-05-04 20:31:17 阅读:175951 作者:1543

在现实生活中,我们要经常与人交往,互通有无。 单片机也同样需要与各种设备进行交互。 例如,汽车显示器需要知道汽车的转速和电动机的运行参数,显示器需要从汽车的基础控制器获取数据。 这个数据的获取进程是通信进程。 类似地,控制器通常是单片机或PLC与变频器的通信。 通信双方必须遵守一组既定的规则。 这也称为协议。 这就像我们之间的对话,双方必须遵守一组语言语法规则。

通信协议分为硬件层协议和软件层协议。 硬件层协议主要规范了物理连接、传输电平信号及传输秩序等硬件性质的内容。 典型的硬件协议包括串行端口、IIC、SPI、RS485、CAN和USB。 软件层协议的重点是上层APP应用程序的规范,如modbus协议。

这里是51单片机的串行通信协议,以下简称串行。 串行端口的六个特征如下。

)1)、物理连接线至少为3条,分别是Tx数据发送线、Rx数据接收线、GND共用地线。

)2)、0和1的约定。 RS232电平约定-5v到-25v之间的电压信号为1,(5v到) 25v之间的电压信号为0。 TL电平,约5V的电压信号为1,0 v的电压信号为0。 CMOS电平,约3.3V的电压信号为1,0v的电压信号为0。 其中,CMOS电平一般用于ARM芯片。

(3)、发送秩序。 低位首发。

) 4、波特率。 收发双方共同约定的一个数据位(0或1 )在数据传输线上维持的时间。 也可以理解为每秒能够传输的位数。 常用的波特率为300bit/s、600bit/s、2400bit/s、4800bit/s、9600bit/s。

) 5、通信启动信号。 发送方在没有发送数据时,应该将Tx设置为1。 需要发送时,首先将Tx设置为0,保持1位的时间。 接受方不断检测Rx,发现Rx始终升高后,如果突然下降(0),则视为发送方要发送数据,迅速开始自己的定时器,调整收发双方定时器的同步时间

(6)、停止信号。 发送方发送完最后一个有效位后,必须再将Tx保持1位的时间为停止位。

好了,理论暂时到此为止。 现在我们做一个从51单片机向电脑串行调试助手发送字节的实验。 该实验的目的是掌握串行通信协议的收发过程。

虚拟串口

实验一、虚拟串口实验

典型的单片机具有专用的串行端子,51中分别具有P3.0和P3.1,因为这些端子具有串行端口的硬件电路,所以不需要为了使用它们而设定信号发送停止。 为了了解协议,我们使用其他引脚模拟串行端口,因此也称为虚拟串行端口。 这里选择了P1.0,我们51单片机向电脑发送数据需要通过串口传输到USB设备。 也就是说,从TTL电平转换为RS232电平。 但是,仅限于我们的开发板,只有P3.0和P3.1连接到串行USB设备上,因此能够将P1.0较短地连接到P3.1上。 下图是该串行USB的原理图。

好的,直接坐代码吧。

将#include'reg51.h'/*p1.0虚拟化为串行端口发送引脚TX,以9600bit/s的比特率向外部发送数据的波特率为9600bit/s,所以me发送1 bit的时间为t=1000000 P1^0 output TTL signal,need to transferred to rs232 signal,canbeconnectedtop3^1# defineu 16 unsigned int//宏定义#defineU8unnal voiddelay(u16x ) {while ) x--}; }void Timer0_Init () {TMOD |=0x01; TH0=65440/256; TH0=65440%6 TR0=0; }void Isr_Init () {EA=1; ET0=1; }voidsend_byte(U8dat ) {sbuf=dat; //通过导入全局变量sbuf,可以保存形参dattx=0//a开始位TR0=1; wile(ti==0); //等待发送完成的ti=0; //清除发送完成标志} void tf0 _ ISR (每interrupt1//104 us中断一次) {static u8 i; //记录进入中断的次数TH0=65440/256; TL0=65440%6; I; if(I=1I=8) if ) ) sbuf(1) i-1 ) ) )0)sbuf )1) i-1 ) ) )取出i-1位) ) {TX=0; }else{TX=1; }if(I==9) /停止位) {TX=1; (if ) I==10 ) {TR0=0; i=0; ti=1; //发送完成}}void main () ) {TX=1; 使//tx空闲的Timer0_Init (; Isr_Init (; while(1) send_byte ) 65; //0x 41延迟(60000; }在实验中,引入了计时器0以控制发送线上各个比特的保持时间。 首先输入main函数,如果TX被设置为1,则发送线路将被设置为

空闲,这时候发送方和接受方都处于空闲。接下来初始化定时器0,TR0置0表示还不要启动定时器0。接着中断系统初始化,此时中断系统已经开启。进入while循环,先进Send_Byte()函数,将65传给形参dat,dat再将65赋值给sbuf,到这里准备工作就做好了。接着TX置0,这个是起始位,要保持这个起始位104us。于是就启动定时器TR0置1,计时器开始计数。当第一次溢出的时候,也就是过了104us,进入中断,同时接收方也侦测到了这个突然被拉低的信号,于是迅速启动自己的定时器。进入中断子函数后,先是重装定时器初值,然后i加1,也就是当i=1时,就应该发送数据的最低位了,总共有8位数据,所以使用条件语句if(i>=1 && i<=8)来判断是否发送完数据位。然后再通过if(i==9) 来发送停止位,最后当i=10时,也就是发送完了,这时候要关闭定时器(那么程序也就),同时i置0,ti置1(才能跳出while(ti==0)循环),最后将ti置0,保证下次要发送字节时让程序停留在while(ti==0)。


片上串口

以上说的是虚拟串口,上文中谈到与串口相关的引脚P3.0与P3.1,事实上51单片机自带片上串口,那这个串口又该怎么使用呢?

片上串口支持同步模式与异步模式。简单来说同步模式就是指有时钟线,而异步模式无时钟线。这里的时钟线是指在同步通信时,用一根线专门传输时钟信号,这个信号用来与要发送的每一位保持同步,这样就避免了例如异步通信中因为采用定时器而引入的时间误差。

片上串口还支持8位模式和9位模式。如下图所示


其中D0-D7是一个字节的8个位。9位模式只是多了一个位TB8,这个TB8的作用是奇偶校验或多机通信。奇偶校验原理这不加分析。多机通信时比如主机只发送数据给网络中的一台地址为0x02的设备,这时候先让TB8为1,前面的D0-D7则为地址即0x02,之后再让TB8为0,前面的D0-D7则为数据了。

上面设置了片上串口的模式,另外还要设置串口的波特率。

片上串口的波特率等于定时器1工作在方式2时溢出率的32分频。如果要定时器1工作在方式2,那么TMOD=0x20。另外要保证为32分频,我们还必须设置计数器初值。设晶振为11.0592Mhz,则定时器的计数脉冲为F=f/12,则定时器每计一个脉冲的时间为T=12/f。又令计数器的起点为x,则溢出一次要计的脉冲数为(256-x)。所以在计数起点为x时,溢出一次的时间为t=12/f*(256-x)。则对应的溢出率为1/t=f/(12*(256-x))。对应的波特率就为b=f/(384*(256-x))。

x=256-f/(384*b)

其中f为晶振频率,b为希望的波特率,x为定时器的计数起点TH1的值。

例如当晶振为11.0592M,希望波特率为9600bit/s,则TH1=253。题外话,我们同样可以演算出在其他常用波特率情况下,TH1始终为一个整数。这里也就解释了为什么51里面选用了11.0592M的晶振而不是12M,这样就保证了串口的时序更加准确,虽然牺牲了定时器的准确度。

实验二,片外串口发送一个字节。

好了现在开始我们的实验之旅。直接看代码吧。

#include "reg51.h"#define u16 unsigned int#define u8 unsigned charvoid delay(u16 x){while(x--);}void Uart_Init() //串口初始化{SCON=0x50; //8位异步模式TMOD|=0x20;//定时器1工作方式2TH1=253;//9600bit/sTR1=1;}void Send_Byte(u8 dat){SBUF=dat; //启动发送,只需要把发送内容给SBUF这个寄存器while(TI==0); //等待发送完成,因为TI为1时表示在发送停止位TI=0;}void main(){Uart_Init();while(1){ Send_Byte('m'); delay(60000);}}
实验二较之实验一,代码减少了很多,而且不用考虑繁琐的位发送时序。只需要明白各个寄存器SCON,TMOD,TCON,SBUF的用法。TI是SCON中的第一位,为发送中断请求标志位。在本方式中,在停止位开始发送时由内部硬件置位,响应中断后TI必须又软件清零。

实验三、片上串口发送一个字符串

上面介绍了如何发送一个字节,那如何发送一个字符串甚至文本呢?这里我们首先介绍下字符串的概念。

字符串:从存储器的某个地址开始,连续存放多个字符的ASCII码,并且在最后一个字符的后面存放一个0,这段连续的内存空间就叫字符串,最后的0叫字符串的结束符。注意这里的0和加单引号的0不是一个概念,加单引号的0是指0的ASCII码。

数组与字符串的关系:字符串是数组的一种特殊情况,数组在特定条件下可当做字符串用。C语言用双引号描述一个字符串,如“abcd”。

下面我们通过一个实验来展示如何发送字符串。我们实验的目标是打印字符串“Hello World ! 第一!”到打印机。直接上代码。

#include "reg51.h"#define u16 unsigned int#define u8 unsigned charvoid delay(u16 x){while(x--);}void Uart_Init() //串口初始化{SCON=0x50; //8位异步模式TMOD|=0x20;//定时器1工作方式2TH1=253;//9600bit/sTR1=1;}void Send_Byte(u8 dat) //串口发送一个字节{SBUF=dat; //启动发送,只需要把发送内容给SBUF这个寄存器while(TI==0); //等待发送完成,因为TI为1时表示在发送停止位TI=0;} void Send_String(u8 *str) //发送一个字符串*str为字符串第一个字符的地址 { abc: //标号 if(*str != 0){Send_Byte(*str);str++;goto abc;} }void main(){Uart_Init();while(1){ Send_String("Hello World! 第一!"); Send_Byte(10); delay(60000); delay(60000);}}

实验效果


这里就不再讲述代码了,如有问题,请及时联系。谢谢观看本文!转载此文请联系本人!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。