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

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

时间:2022-09-23 15:00:00 100pin母头连接器led串电容公头母头25针串口并口连接器

串口通信的原理

串口通信(SerialCommunicaTIons)概念很简单,串口按位(bit)发送和接收字节。尽管比较字节(byte)并行通信缓慢,但串口可以用另一根线接收数据,同时使用一根线发送数据。实现远距离通信非常简单。比如IEEE488定义并行通行状态时,规定设备线总长度不得超过20米,任何两个设备之间长度不得超过2米;串口长度可达1200米。串口用于典型ASCII传输代码字符。通信由地线、发送和接收三条线完成。由于串口通信是异步的,端口可以在另一条线上发送数据并接收数据。握手用其他线,但不必要。波特率、数据位、停止位和奇偶校验是串口通信最重要的参数。对于两个进行通信的端口,这些参数必须匹配。

dcc4e297a9896a3a39e816bcaea0834a.png

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,则有3个逻辑高位。高低不真实的检查数据,简单的位置逻辑高或低逻辑验证。这样,接收设备就可以知道一个位置的状态,并有机会判断是否有噪音干扰通信或传输和接收数据是否不同步。

RS232概述

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

九针串口分工头和母头

公头5下4,上5从左到右.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;准备好数据终端DTR;5、信号地线SG;6.准备好数据DSR;7、请求发送RTS;8、清除发送CTS;9、振铃提示RI。我们要让这个串口和我们单片机进行通信,我们只需要关心其中的2脚RXD、3脚TXD和5脚GND即可

虽然这三个引脚的名字和我们单片机上的串口名字一样,但是却不能直接和单片机对连通信,这是为什么呢?随着我们知道的内容越来越多,我们必须知道并非所有的电路都是5V代表高电平和0V代表低电平。对于RS就232标准而言,它是一种反逻辑,也称为负逻辑。为什么叫负逻辑?它的TXD和RXD的电压,-3V~-15V电压代表为1, 3~ 15V电压代表是0。低电平代表的是1,而高电平代表的是0,所以称之为负逻辑。所以电脑9针RS232串口不能直接与单片机连接,芯片需要电平转换MAX232来完成

这个芯片可以实现标准RS232串口电平转换为我们单片机能够识别和承受的UART0V/5V电平。从这里我们似乎慢慢明白了一点,事实上,RS232串口和UART串口,它们的协议类型相同,但电平标准不同,MAX232这个芯片起着中间人的作用,它把UART电平转换成RS232电平,也把RS232电平转换成UART实现标准的电平RS232接口和单片机UART通信连接。

USB转串口通信

随着技术的发展,还有工业RS大量使用232串口通信,但商业技术的应用已经缓慢使用USB转UART技术取代了RS232串口,绝大多数笔记本电脑都没有串口,那么我们应该如何实现单片机和电脑之间的通信呢?

只需在电路上添加一个USB可成功实现转串口芯片USB通信协议和标准UART在我们的开发板上,我们使用串行通信协议的转换CH340T这个芯片

我们需要用跳线帽把中间和下面的针短接在一起。CH340T这个电路很简单。连接电源和晶振后,6脚和7脚DP和DM分别接USB口的两个数据引脚,三脚和四脚通过跳线接收我们的单片机TXD和RXD上去。

CH340T在电路的三脚位置加一根4148二极管,是一个小技巧。因为STC89C52单片机下载程序时需要冷启动,即先下载后上电,上电时单片机会先检测是否需要下载程序。虽然单片机VCC它由开关控制,但因为CH340T三脚是输出引脚,如果没有这个二极管,开关后单片机断电,CH340T三脚和单片机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所示。第一步选择串口助手菜单,第二步选择16进制显示,第三步选择16进制发送,第四步选择COM口,这个COM自己电脑设备管理器里的嘴和嘴COM口是一样的。波特率是根据我们的程序设置的。在我们的程序中,数据位的持续时间是1/9600秒。在这个地方选择波特率是9600验证位置的选择N,数据位8,停止位1。

串口调试助手的本质是利用电脑UART通信接口,向我们的单片机发送数据,也可以将我们的单片机发送的数据接收到调试助手界面。

因为我第一次接触通信技术,我把后面的技术放在后面IO模拟串口通信程序进行解释可以边看我的解释边看程序,先彻底理解底层原理。

不用说,直接看变量定义部分main主函数。首先是通信波特率的设置,这里我们配置的波特率是9600,那么串口调试助手也必须是9600。配置波特率的时候,我们用的是定时器T0的模式2。模式2中,不再是TH0代表高8位,TL0代表低8位,只有TL计数,当TL0溢出后,不仅会让TF0变1,还会TH0中的内容自动重新安装TL0中。这样做的好处之一是,我们可以提前存在我们想要的定时器的初始值TH0中,当TL0溢出后,TH自动重新输入初始值TL0,全自动,不需要程序TL0重新赋值,配置方法很简单,可以自己看程序,计算初始值。

设置波特率后,打开中断,然后等待接收串口调试助手发布的数据。接收数据时,应先进行低电平检测while(PIN_RXD),如果没有低电平,则表示没有数据。一旦检测到低电平,就进入启动接收函数StartRXD()。接收函数开始启动半个波特率周期,初学者在这里可能不太了解。让我们回顾一下我们图11-2中的串数据示意图。如果在数据位电平变化时读取,由于时间顺序上的误差和信号稳定性,很容易读取错误的数据,因此我们希望在信号最稳定时读取数据。除了信号变化的边缘位置外,其他位置都非常稳定,所以我们现在同意在信号中间读取电平状态,以确保我们读得正确。

一旦读取起始信号,我们将当前状态设置为接收状态,并打开定时器中断。第一次,在半个周期中断后,我们将对起始位置进行第二次判断,以确认起始位置为低电平,而不是干扰信号。之后每1/9600秒进入一次中断,读取引脚状态RxdBuf里边。接收完成后,我们将再次接收这个RxdBuf加1,再通过TXD发送引脚时,还需要先发送一个起始位,然后发送8个数据位,然后发送结束位。发送后,程序运行到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:REN:0;5:SM2:0;6:SM1:0;7:SM0:0;

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

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

2位RB8:模式2和3中接收到的第9位数据(很少用),模式1用来接收停止位。

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

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

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

6位SM1和7位SM0:

这两位共同决定了串口通信的模式0~模式3共4种模式。我们最常用的就是模式1,也就是SM0=0,SM1=1,下边我们重点就讲模式1,其它模式从略。

对于串口的四种模式,模式1是最常用的,就是我们前边提到的1位起始位,8位数据位和1位停止位。下面我们就详细介绍模式1的工作细节和使用方法,至于其它3种模式与此也是大同小异,真正遇到需要使用的时候大家再去查阅相关资料就行了。

在我们使用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是说1个机器周期等于12个时钟周期,值得关注的是这个16,我们来重点说明。在IO口模拟串口通信接收数据的时候,采集的是这一位数据的中间位置,而实际上串口模块比我们模拟的要复杂和精确一些。他采取的方式是把一位信号采集16次,其中第7、8、9次取出来,这三次中其中两次如果是高电平,那么就认定这一位数据是1,如果两次是低电平,那么就认定这一位是0,这样一旦受到意外干扰读错一次数据,也依然可以保证最终数据的正确性。

串口通信的发送和接收电路在物理上有2个名字相同的SBUF寄存器,它们的地址也都是0x99,但是一个用来做发送缓冲,一个用来做接收缓冲。意思就是说,有2个房间,两个房间的门牌号是一样的,其中一个只出人不进人,另外一个只进人不出人,这样的话,我们就可以实现UART的全双工通信,相互之间不会产生干扰。但是在逻辑上呢,我们每次只操作SBUF,单片机会自动根据对它执行的是“读”还是“写”操作来选择是接收SBUF还是发送SBUF,后边通过程序,我们就会彻底了解这个问题。

UART串口程序:

一般情况下,我们编写串口通信程序的基本步骤如下所示:

1、配置串口为模式1。

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

3、根据波特率计算TH1和TL1的初值,如果有需要可以使用PCON进行波特率加倍。

4、打开定时器控制寄存器TR1,让定时器跑起来。

这里还要特别注意一下,就是在使用T1做波特率发生器的时候,千万不要再使能T1的中断了。

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

通信实例与ASCLL码

先抛开我们使用的汉字不谈,那么我们常用的字符就包含了0~9的数字、A~Z/a~z的字母、还有各种标点符号等。那么在单片机系统里面我们怎么来表示它们呢?ASCII码(AmericanStandardCodeforInformationInterchange,即美国信息互换标准代码)可以完成这个使命:我们知道,在单片机中一个字节的数据可以有0~255共256个值,我们取其中的0~127共128个值赋予了它另外一层涵义

我们用字符格式发送一个小写的a,返回一个十六进制的0x61,数码管上显示的也是61,ASCII码表里字符a对应十进制是97,等于十六进制的0x61;我们再用字符格式发送一个数字1,返回一个十六进制的0x31,数码管上显示的也是31,ASCII表里字符1对应的十进制是49,等于十六进制的0x31。这下大家就该清楚了:所谓的十六进制发送和十六进制接收,都是按字节数据的真实值进行的;而字符格式发送和字符格式接收,是按ASCII码表中字符形式进行的,但它实际上最终传输的还是一个字节数据。这个表格,当然不需要大家去记住,理解它,用的时候过来查就行了。

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

#include《reg52.h》

//------------------串口通信协议-----------------//

/*

客户端数据包格式解释(长度恒为15):

例如:A01_fmq_01Off___#

A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)

01-----设备代号

fmq_01Off___--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部

#---------数据包的结束标记

服务器端数据包格式解释(长度恒为15):

例如:A02_SenT010250#

A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)

02-----设备代号

SenT010250--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部

#---------数据包的结束标记

*/

char buf_string[16]; //定义数据包长度为15个字符

#define deviceID_1Bit ‘0’ //用于串口通信时,定义本地设备ID的第1位

#define deviceID_2Bit ‘2’ //用于串口通信时,定义本地设备ID的第2位

#define datapackage_headflag ‘A’ //用于串口通信时,定义数据包头部的验证标记

char DataPackage_DS18B20[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,‘_’,‘S’,‘e’,‘n’,‘T’,‘X’,‘X’,‘X’,‘X’,‘X’,‘X’,‘#’};

char HeartBeat[16]={datapackage_headflag,deviceID_1Bit,deviceID_2Bit,‘_’,‘B’,‘e’,‘a’,‘t’,‘X’,‘X’,‘X’,‘X’,‘X’,‘X’,‘#’};

//----------------------------------------------//

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

串口通信

MCU:89C52RC 11.0592MHz

//11.0592MHz 0xd0 1200bps

//12MHz 0xcc 1200bps

//11.0592MHz 0xfa 9600bps

//0xf4 11.0592MHz 0xf3 12MHz 4800bps

//均在SMOD=1的情况下(波特率倍增模式)

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

//串口发送函数

void PutString(unsigned char *TXStr)

{

ES=0;

while(*TXStr!=0)

{

SBUF=*TXStr;

while(TI==0);

TI=0;

TXStr++;

}

ES=1;

}

//串口接收函数

bit ReceiveString()

{

char * RecStr=buf_string;

char num=0;

unsigned char count=0;

loop:

*RecStr=SBUF;

count=0;

RI=0;

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

{

num++;

RecStr++;

while(!RI)

{

count++;

if(count》130)return 0; //接收数据等待延迟,等待时间太久会导致CPU运算闲置,太短会出现“数据包被分割”,默认count=130

}

goto loop;

}

return 1;

}

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

void Init_USART()

{

SCON=0x50; //串口方式1,使能接收

TMOD|=0x20; //定时器1工作方式2(8位自动重装初值)

TMOD&=~0x10;

TH1=0xfa; //9600bps

TL1=0xfa;

PCON|=0x80; //SMOD=1

TR1=1;

TI=0;

RI=0;

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

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

}

//比较指令头部

bit CompareCMD_head(char CMD_head[])

{

unsigned char CharNum;

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

{

if(!(buf_string[CharNum+4]==CMD_head[CharNum]))

{

return 0; //指令头部匹配失败

}

}

return 1; //指令头部匹配成功

}

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

bit CompareCMD_tail(unsigned char start,unsigned char quality,char CMD_tail[])

{

unsigned char CharNum;

for(CharNum=0;CharNum《quality;CharNum++)

{

if(!(buf_string[start+CharNum]==CMD_tail[CharNum]))

{

return 0;

}

}

return 1;

}

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

{

//PutString(buf_string);

if(buf_string[0]==datapackage_headflag&&buf_string[14]==‘#’) //进行数据包头尾标记验证

{

switch(buf_string[1]) //识别发送者设备ID的第1位数字

{

case ‘0’:

switch(buf_string[2]) //识别发送者设备ID的第2位数字

{

case ‘3’:

if(CompareCMD_head(“Ligt”)) //判断指令头部是否为“Ligt”

{

//下面是指令尾部分析

switch(buf_string[8])

{

case ‘0’:

switch(buf_string[9])

{

case ‘0’:

return 0;

case ‘1’:

if(CompareCMD_tail(10,3,“Off”)) //A03_Ligt01Off_#

{

//要执行的代码

return 1;

}

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

{

return 1;

}

return 0;

default:

return 0;

}

case ‘1’:

default:

return 0;

}

}

if(CompareCMD_head(“SenT”))

{

}

if(CompareCMD_head(“jdq_”))

{

}

if(CompareCMD_head(“Try!”))

{

}

return 0;

default:

return 0;

}

default:

return 0;

}

}

return 0;

}

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

中断函数

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

//串口中断服务函数-----------

void USART() interrupt 4 //标志位TI和RI需要手动复位,TI和RI置位共用一个中断入口

{

if(ReceiveString())

{

//数据包长度正确则执行以下代码

Deal_UART_RecData();

}

else

{

//数据包长度错误则执行以下代码

//LED1=~LED1;

}

RI=0; //接收并处理一次数据后把接收中断标志清除一下,拒绝响应在中断接收忙的时候发来的请求

}

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

主函数

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

void main()

{

EA=1;

Init_USART();

while(1)

{

//PutString(buf_string);//空格20H,回车0DH

}

}

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

相关文章