艾巴生活网

您现在的位置是:主页>科技 >内容

科技

串口通信原理图,串口通信的原理及USB转串口通信

2024-04-07 16:47:02科技帅气的蚂蚁
串行通信的原理串行通信的概念非常简单。串行端口逐位发送和接收字节。虽然比逐字节并行通信慢,但串口可以用一条线发送数据,用另一条线接

串口通信原理图,串口通信的原理及USB转串口通信

串行通信的原理

串行通信的概念非常简单。串行端口逐位发送和接收字节。虽然比逐字节并行通信慢,但串口可以用一条线发送数据,用另一条线接收数据。简单,可以实现远距离通信。比如IEEE488在定义并行流量状态时,规定设备线路总长度不超过20米,任意两个设备之间的长度不超过2米;对于串口,长度可以达到1200米。通常,串行端口用于传输ASCII字符。通信是用三根线完成的,即地线、发送和接收。因为串行通信是异步的,端口可以在一条线路上发送数据,在另一条线路上接收数据。其他线是用来握手的,但不是必须的。串行通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个通信端口,这些参数必须匹配。

a、波特率:这是一个衡量符号传输速率的参数。是指调制后信号在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒传输240个字符,每个字符格式包含10位(1个起始位,1个停止位,8个数据位)。此时,波特率为240Bd,比特率为10位*240位/秒=2400bps。一般调制速率大于波特率,如曼彻斯特编码)。通常电话线的波特率是14400,28800和36600。波特率可以比这些值高得多,但波特率与距离成反比。高波特率通常用于放置在附近的仪器之间的通信,一个典型的例子是GPIB设备之间的通信。

b、数据位:这是一个衡量通信中实际数据位的参数。计算机发送数据包时,实际数据往往不是8位。标准值为6、7和8位。如何设置取决于你想发送的信息。比如标准的ASCII码是0 ~ 127 (7位数)。扩展ASCII码为0 ~ 255 (8位)。如果数据使用简单文本(标准ASCII码),则每个数据包使用7位数据。每个包指一个字节,包括开始/停止位、数据位和奇偶校验位。由于实际的数据比特取决于通信协议的选择,所以术语“分组”指的是任何通信情况。

c、停止位:用于指示单个包的最后一位。典型值为1、1.5和2位。因为数据是在传输线上计时的,并且每个设备都有自己的时钟,所以两个设备在通信时可能会有一点不同步。因此,停止位不仅表示传输结束,还为计算机提供了纠正时钟同步的机会。适合停止位的位数越多,不同时钟同步的容忍度越大,但数据传输速率越慢。

d、奇偶校验位:串行通信中一种简单的检错方法。有四种错误检测方法:偶数、奇数、高和低。当然,没有奇偶校验位。在奇偶校验的情况下,串行端口将设置一个奇偶校验位(数据位后一位),以确保传输的数据具有带值的偶数或奇数逻辑高位。例如,如果数据是011,那么对于偶数奇偶校验,奇偶校验位是0,保证逻辑高的位数是偶数。如果是奇数校验,奇偶校验位为1,所以有三个逻辑高位。高位和低位并不真正检查数据,只是设置逻辑高或逻辑低检查。这使得接收设备能够知道比特的状态,并且有机会判断噪声是否干扰通信或者数据的发送和接收是否不同步。

RS232概述

在我们的电脑上,通常有一个9针串行接口,叫做RS232接口,和UART通信有关。但由于笔记本电脑没有9针串口,所以越来越多的使用USB虚拟串口与单片机进行通信。

九针串口分线头和母头

男头上,5下4,前5从左到右是1 . 2 . 3 . 4 . 5;接下来的4个从左到右是6.7.8.9;

女头上5下4,女头上从左到右5 . 4 . 3 . 2 . 1;接下来的4个从左到右是9.8.7.6;

RS232接口有9个管脚,定义为1、载波检测DCD;2、接收数据RXD;3、发送数据TXD;4、 DTR数据终端准备就绪;5、信号地SG;6、数据就绪data;7、请求发送RTS;8、清除发送CTS;9、振铃提示RI。我们希望这个串口与我们的单片机通信,我们只需要关心两个管脚RXD,三个管脚TXD和五个管脚GND。

虽然这三个管脚的名字和我们单片机上的串口名字一样,但是它们不能和单片机直接通信。为什么?随着我们了解的越来越多,也要慢慢学习,不是所有的电路高电平都是5V,低电平都是0V。对于RS232标准,它是反逻辑的,也叫负逻辑。为什么是否定逻辑?它的TXD和RXD电压,-3V ~-15V代表1,3 ~ 15V代表0。低电平代表1,高电平代表0,所以叫负逻辑。因此,计算机的9针RS232串口不能直接与单片机连接,需要一个电平转换芯片MAX232来完成。

这个芯片可以把标准的RS232串口电平转换成我们单片机可以识别和承受的UART0V/5V电平。从这里开始,大家似乎都明白了一点。其实RS232串口和UART串口的协议类型是一样的,只是级别标准不同。芯片MAX232起着中间人的作用,它将UART电平转换成RS232电平,也将RS232电平转换成UART电平,从而实现标准RS232接口与MCU UART之间的通信连接。

USB转串行通信

随着技术的发展,RS232串行通信在工业中的应用越来越广泛,但是在商业技术的应用中,USB转UART技术已经逐渐取代了RS232串行通信,而大多数笔记本电脑都没有串行通信这一项。要实现单片机和计算机的通讯,应该怎么做?

我们只需要在电路中增加一个USB转串行芯片,就可以成功实现USB通信协议和标准UART串行通信协议之间的转换。在我们的开发板上,我们使用芯片CH340T。

我们需要用跳线帽将中下针短接在一起。右边的CH340T的电路很简单。接通电源和晶振后,6号针和7号针的DP和DM分别接USB口的两个数据针,3号针和4号针通过跳线接我们单片机的TXD和RXD。

在CH340T的电路中的3脚位置加一个4148二极管是个小技巧。因为STC89C52在下载程序时需要冷启动,即先下载后上电。上电的瞬间,微控制器会先检测是否需要下载程序。虽然单片机的VCC是由开关控制的,但由于CH340T的3脚是输出脚,如果没有二极管,在掉电的情况下,CH340T的3脚会与单片机的P3.0脚(RXD)相连,电流会通过这个脚流入后级电路,给后级的电容充电,导致后级有一定的电压。虽然这个电压值只有两三伏左右,但可能会有影响。加了二极管后,一方面通信不会受影响,另一方面可以消除这种不好的影响。这个地方暂时可以作为一个了解。如果自己做这种电路,可以参考一下。

IO端口模拟UART串行通信

UART串行波特率,常用值有300、600、1200、2400、4800、9600、14400、19200、28800、38400、57600、115200等。IO口模拟UART串行通信程序,是一个简单的演示程序。我们用串口调试助手发送一个数据,数据加1,然后自动返回。

串口调试助手,这里我们直接用STC-ISP软件自带的串口调试助手。先说一下串口调试助手的使用,如图11-6。第一步选择串口助手菜单,第二步选择十六进制显示,第三步选择十六进制传输,第四步选择COM口。这个COM口要和你自己的电脑设备管理器里的COM口一致,波特率要根据我们的程序来选择。在我们的程序中,一个数据位的持续时间是1/9600秒,所以在这个地方选择波特率就是选择9600,校验位N,数据位8,停止位1。

串口调试助手的本质就是利用计算机上的UART通信接口向我们的单片机发送数据,同时也接收我们的单片机发送到这个调试助手接口的数据。

因为我是通信技术新手,所以我将在后面解释IO模拟串行通信程序。你可以一边看程序,一边看我的解释,先把底层原理吃透。

变量定义部分就不用说了,直接看主函数。首先是通信波特率的设置。我们在这里配置的波特率是9600,所以串口调试助手必须是9600。配置波特率时,我们使用定时器T0的模式2。在模式2下,TH0不再是高8位,TL0不再是低8位,但只有TL0在计数。当TL0溢出时,不仅会将TF0改为1,还会自动将TH0中的内容重新加载到TL0中。这样有一个好处,就是我们可以提前在TH0中存储想要的定时器初始值。当TL0溢出时,TH0自动将初始值发回给TL0,这是全自动的,不需要在程序中重新赋值TL0。配置方法非常简单。你可以看看程序,自己算初值。

波特率设置好之后,打开中断,然后等待接收串口调试助手发送的数据。接收数据时,应首先检测低电平的while(PIN_RXD)。如果没有低水平,就说明没有数据。一旦检测到低电平,将启动开始接收功能StartRXD()。接收函数开头是半个波特率周期开始,这里初学者可能不太清楚。让我们回头看看图11-2中的串口数据示意图。如果在数据位电平变化的时候读取数据,由于时序误差和信号稳定性的原因,很容易读取错误的数据,所以我们希望在信号最稳定的时候读取数据。除了信号变化的边缘位置,其他位置都很稳定,所以我们现在同意读取信号中间的电平状态,这样可以保证我们读取的东西一定是正确的。

一旦我们读取了开始信号,我们将把当前状态设置为接收状态,并启动定时器中断。第一次中断半个周期后,我们会对起始位进行第二次判断,确定起始位为低电平,不是干扰信号。以后每隔1/9600秒中断一次,该引脚的状态将被读入RxdBuf。在等待接收之后,我们将在这个RxdBuf上加1,然后通过TXD pin发送出去。同样,我们需要先发送一个起始位,然后是八个数据位,再发送一个结束位。发送后,程序将运行到while(PIN_RXD)并等待第二轮信号接收。

uart模块介绍

IO口模拟串口通信,让大家了解串口通信的本质。但是我们的单片机程序需要不断地检测和扫描单片机IO口接收到的数据,占用了单片机大量的运行时间。这个时候,聪明的人会想一想。其实我们并不太在意沟通的过程。我们只需要一个通信结果,最后得到接收到的数据。这样就可以在单片机内部做一个硬件模块,让它自动接收数据。完成后请告诉我们。我们的51单片机内部就有这样一个UART模块。要正确使用,当然要先配置相应的特殊功能寄存器。

51单片机UART串口的结构由三部分组成:串口控制寄存器SCON、发送和接收电路。让我们先了解一下串口控制寄存器SCON。

SCON串行控制器的位分配(地址:0x98)

位:符号:复位值:0:ri:0;1:TI:0;2:RB8:0;3:TB8:0;4:任:0;5:SM2:0;6:SM1:0;7:SM0:0;

0位RI:接收中断标志位。当接收电路接收到停止位的中间位置时,RI由硬件设置,必须由软件清零。

1位TI:发送中断标志位。当发送电路发送到停止位的中间位置时,TI由硬件设置,必须由软件清零。

2位RB8:在模式2和3下接收的第9位数据(很少使用),模式1用于接收停止位。

3位TB8:在模式2和3下发送的第9位数据(很少使用)。

4位REN:使能串行接收。由软件置1使能接收,由软件清0禁止接收。

5位SM2:多机通信控制位(很少使用),模式1下直接清零。

6位SM1和7位SM0:

这两者共同决定了串行通信的四种模式:模式0 ~模式3。最常用的模式是模式1,即SM0=0,SM1=1。下面我们重点讲模式1,其他模式省略。

串口的四种模式中,模式1是最常用的,也就是前面说的1位起始位、8位数据位和1位停止位。下面,我们将详细介绍模式1的工作细节和使用方法。至于其他三种模式,都差不多。当你真的需要用到它们的时候,只需要查阅相关资料就可以了。

当我们用IO口模拟串口通信时,串口的波特率是通过定时器T0的中断来体现的。在硬件串行模块中,有一个专门的波特率发生器来控制发送和接收数据的速度。对于STC89C52单片机来说,这个波特率发生器只能由定时器T1或定时器T2产生,而不能由定时器T0产生,这和我们的模拟通信完全不同。

如果使用定时器2,则需要配置额外的寄存器。默认情况下使用定时器1。在本章中,我们主要使用定时器T1作为波特率发生器。模式1下的波特率发生器必须使用定时器T1的模式2,即自动重载模式。计时器过载值的计算公式为:

TH1=TL1=256-晶振值/12/2/16/波特率

还有一个与波特率相关的寄存器,它是一个电源管理寄存器PCON。其最高位可以使波特率翻倍,即如果写PCON |=0x80,计算公式变为:

TH1=TL1=256晶振值/12/16/波特率

请解释公式中数字的含义。256是8位定时器的溢出值,也就是TL1的溢出值。我们开发板上的晶振值是11059200,12表示一个机器周期等于12个时钟周期。这个16值得关注。大家重点关注一下。IO口模拟串口通信接收数据时,采集的是这一位数据的中间位置,但实际上串口模块比我们模拟的要复杂和精确。他采取的方式是16次采集一个比特的信号,第一次拿出来7、8、9。如果这三次中有两次是高电平,那么这一位数据就被确定为1,如果两次是低电平,那么这一位就被确定为0,这样一旦数据被意外干扰读错,最终数据的正确性仍然可以得到保证。

串行通信的发送和接收电路有两个同名的SBUF寄存器,地址也是0x99,但一个用于发送缓冲,一个用于接收缓冲。也就是说有两个房间,两个房间的门牌号是一样的。其中一个只进不出,另一个只进不出。这样就可以实现UART的全双工无干扰通信。但逻辑上我们一次只操作SBUF,单片机会根据是读还是写自动选择是接收还是发送SBUF。以后通过节目,我们会彻底了解这个问题。

UART串行端口程序:

一般来说,编写串行通信程序的基本步骤如下:

1、将串行端口配置为模式1。

2、将定时器T1配置为模式2,即自动重载模式。

3、根据波特率计算TH1和TL1的初始值,必要时使用PCON使波特率加倍。

4、打开定时器控制寄存器TR1,让定时器运行。

这里需要特别注意的是,当使用T1作为波特率发生器时,不要再使能T1的中断。

我们先来看看直接用IO口模拟串口通讯时的程序代码,看看程序是不是简单很多,因为大部分工作的硬件模块都给我们做了。程序功能和IO口模拟的完全一样。

通信示例和ASCLL代码

抛开我们使用的汉字不谈,那么我们常用的字符包括从0到9的数字,从A到Z/A到Z的字母,以及各种标点符号。那么我们如何在单片机系统中表达它们呢?ASCII(美国信息交换标准码)可以完成这个任务:我们知道一个字节的数据在单片机中可以有0到255的256个值,我们取0到127的128个值赋予它另一种含义。

我们发送一个字符格式的小写A,返回一个十六进制的0x61,同样显示在数码管上。ASCII码表中字符A的十进制为97,等于十六进制0x61我们发送一个字符格式的数字1,并返回一个十六进制的0x31,它也显示在数码管上。ASCII表中字符1对应的十进制数是49,等于十六进制0x31。大家应该很清楚:所谓的十六进制发送和十六进制接收都是按照字节数据的真值进行的;字符格式发送和字符格式接收是以ASCII码表中的字符形式进行的,但它实际上传输的是一个字节的数据。当然不需要记住这个表格,理解它,用的时候查一下就可以了。

51单片机串行通信实例(字符串接收和发送)

#包括《reg52.h》

//-串行通信协议//

char buf _ string[16];//定义数据包长度为15个字符。

# define device ID _ 1 bit ' 0 '//用于串行通信时,定义本地设备ID的第一位。

# define device ID _ 2 bit ' 2 '//用于串行通信时,定义本地设备ID的第2位。

# define data package _ headline ' a '//用于串行通信时,定义数据包报头的验证标记。

char data package _ ds18b 20[16]={ data package _ head flag,deviceID_1Bit,deviceID_2Bit,' _ '' S '' e '' n '' T '' X '' X '' X '' X '' # ' };

char heart beat[16]={ data package _ head flag,deviceID_1Bit,deviceID_2Bit,' _ '' B '' e '' a '' t '' X '' X '' X '' X '' # ' };

//- //

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

串行通信

微控制器:89C52RC 11.0592MHz

//11.0592MHz0xd0 1200bps

//12MHz0xcc 1200bps

//11.0592MHz0xfa 9600bps

//0x F4 11.0592 MHz0x F3 12 MHz 4800 bps

//两者都是在SMOD=1的情况下(波特率倍增模式)

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

//串口发送功能

void PutString(无符号字符*TXStr)

{

ES=0;

while(*TXStr!=0)

{

SBUF=* TXStr

while(TI==0);

TI=0;

TXStr

}

ES=1;

}

//串行接收器功能

位接收字符串()

{

char * RecStr=buf _ string

字符数=0;

无符号字符计数=0;

循环:

* RecStr=SBUF

count=0;

RI=0;

if(num"14")//数据包长度为15个字符,尝试连续接收15个字符。

{

num

RecStr

而(!RI)

{

数数;

if(计数>130)返回0;//延迟接收数据的等待时间。如果等待时间太长,CPU运行就会闲置。如果太短,数据包将被分割。默认计数是130。

}

转到循环;

}

返回1;

}

//定时器1用作波特率发生器。

void Init_USART()

{

SCON=0x 50;//串行模式1,使能接收。

TMOD |=0x 20;//定时器1工作模式2(8位自动初始值重载)

TMOD=~0x 10;

TH1=0xfa//9600bps

TL1=0xfa

PCON |=0x 80;//SMOD=1

TR1=1;

TI=0;

RI=0;

//PS=1;//提高串口中断的优先级

ES=1;//打开串口中断使能。

}

//比较指令头

位CompareCMD_head(char CMD_head[])

{

无符号字符CharNum

for(CharNum=0;CharNum《4;CharNum) //指令长度为10个字符。

{

如果(!(buf _ string[CharNum 4]==CMD _ head[CharNum])

{

返回0;//指令头匹配失败。

}

}

返回1;//命令头匹配成功。

}

//比较指令的结尾(start:从哪里开始比较,quality:比较多少个字符,cmd _ tail []:要比较的字符串)

位CompareCMD_tail(无符号字符开始,无符号字符质量,字符CMD_tail[])

{

无符号字符CharNum

for(CharNum=0;CharNum《质量;CharNum)

{

如果(!(buf _ string[start CharNum]==CMD _ tail[CharNum])

{

返回0;

}

}

返回1;

}

Bit Deal_UART_RecData() //处理串口接收数据包的函数(数据包处理成功返回1,否则返回0)。

{

//PutString(buf _ string);

if(buf _ string[0]==data package _ headflagbuf _ string[14]==' # ')//验证数据包的头部和尾部标签。

{

switch(buf _ string[1])//标识发送方设备ID的第一个数字。

{

案例“0”:

switch(buf _ string[2])//标识发送方设备ID的第2位数字。

{

案例“3”:

if(compare cmd _ head("Ligt")//判断指令头是否为“Ligt”。

{

//下面是指令尾分析。

开关(buf_string[8])

{

案例“0”:

开关(buf_string[9])

{

案例“0”:

返回0;

案例“1”:

if(CompareCMD_tail(10,3,"Off")//A03 _ ligt 01 Off _ #

{

//要执行的代码

返回1;

}

if(CompareCMD_tail(10,3,“On_”)

{

返回1;

}

返回0;

默认值:

返回0;

}

案例“1”:

默认值:

返回0;

}

}

if(CompareCMD_head("SenT"))

{

}

if(CompareCMD_head("jdq_")

{

}

if(CompareCMD_head("Try!"))

{

}

返回0;

默认值:

返回0;

}

默认值:

返回0;

}

}

返回0;

}

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

中断功能

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

//串行中断服务功能-

Void USART()中断4 //标志TI和RI需要手动复位,它们共享一个中断入口。

{

if(ReceiveString())

{

//如果数据包长度正确,执行下面的代码。

deal _ UART _ RecData();

}

其他

{

//如果数据包长度错误,执行下面的代码。

//le D1=~ le D1;

}

RI=0;//接收并处理一次数据后,清除接收中断标志,当中断接收繁忙时,拒绝响应发送的请求。

}

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

主要功能

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

void main()

{

EA=1;

init _ USART();

while(1)

{

//PutString(buf _ string);//空格20H,回车0DH。

}

}