关于嵌入式学习随笔->8《UART串行通信原理》
1、什么是串口
串口是MCU(Microcontroller Unit;微控制单元)重要的外部接口,同时也是软件开发重要的调试手段,现如今基本上所有的MCU都会带有串口。以STM32F767为例,它的串口资源相当丰富,功能也十分强大,STM32F767IGT6最多可以提供8路串口,支持8/16倍过采样、支持自动波特率检测、支持Modbus通信、支持同步单线通信和半双工单线通信、支持LIN、支持调制解调器操作、智能卡协议和IrDA SIR ENDEC规范、具有DMA等。
处理器与外部设备通信的两种方式:
--》并行通信
-传输原理:数据各个位同时传输。
-优点:速度快
-缺点:占用引脚资源多
--》串行通信
-传输原理:数据按位顺序传输。
-优点:占用引脚资源少
-缺点:速度相对较慢
2、串行通信
按照数据传送方向,分为:
--》单工:数据传输只支持数据在一个方向上传输
--》半双工:允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;
--》全双工:允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。
串行通信的通信方式:
--》同步通信:带时钟同步信号传输(SPI,IIC通信 )
--》异步通信:不带时钟同步信号(UART串口通信(通用异步收发器),单总线通信)
常见的串行通信接口:
通信标准 | 引脚说明 | 通信方式 | 通信方向 |
UART | TXD:发送端 RXD:接收端 GND:公共地 |
异步通信 | 全双工 |
单总线 | DQ:发送/接收端 | 异步通信 | 半双工 |
SPI | SCK:同步时钟 MISO:主机输入,从机输出 MOSI:主机输出,从机输入 |
同步通信 | 全双工 |
IIC | SCL:同步时钟 SDA:数据输入/输出端 |
同步通信 | 半双工 |
3、异步串口通信UART
--》物理层(电气层:接口决定):通信接口(RS232,RS485,RS422,TTL)
-RXD:数据输入引脚。接收数据。
-TXD:数据发送引脚。发送数据。
TTL串口 & RS232 & RS485 & RS422通信接口:
接口类型 | 逻辑1典型值 | 逻辑0典型值 | 说明 | 优缺点 |
TTL | +5/3.3V | 0V | 一般的MCU串口引脚都支持TTL | 优点:接口简单 缺点:距离在1.5米以内 |
RS232 | -3V~-15V | 3V~15V | 三线,全双工 | 优点:距离在1.5~30米 缺点:最高传输速率20kb/s |
RS485 | -3V~-15V | 3V~15V | 两线,利用压差传输 | 优点:距离可达1219米, 最大传输速率10Mb/s(12米内) |
RS422 | -3V~-15V | 3V~15V | 不用共地,两线, 平衡驱动差分接收,两组电源独立 |
优点:隔离抗干扰性能强, 距离可达1219米,最大传输速率10Mb/s |
--》 数据格式(数据层:芯片决定)
STM32串口异步通信数据格式:
-->起始位:1个逻辑0数据位开始
-->数据位(8位或者9位)
-->奇偶校验位(第9位)
-->停止位(1,1.5,2位)
-->波特率设置
STM32串口通信过程:
通信协议往往由用户自己根据需要来编写。
1 void bbsapp_data_cheak(void) 2 { 3 switch(rxState) 4 { 5 case waitForStart: 6 if(aRxBuffer2[0] == 0x66) /*起始符正确*/ 7 { 8 USART2_RX_STA=1; 9 USART2_RX_BUF[0] = aRxBuffer2[0]; 10 rxState = waitForData; 11 } else /*起始符错误*/ 12 { 13 rxState = waitForStart; 14 } 15 break; 16 case waitForData: 17 USART2_RX_BUF[USART2_RX_STA] = aRxBuffer2[0]; 18 USART2_RX_STA++; 19 if (USART2_RX_STA == 6) /*数据接收完成,校验*/ 20 { 21 rxState = waitForChksum; 22 } 23 break; 24 case waitForChksum: 25 USART2_RX_BUF[6] = aRxBuffer2[0]; 26 if (wifi_cheak(USART2_RX_BUF)) /*校验正确,判断结束符*/ 27 { 28 rxState = waitForEnd; 29 } else 30 { 31 rxState = waitForStart; /*校验错误*/ 32 } 33 break; 34 case waitForEnd: 35 if (aRxBuffer2[0] == 0x99) /*结束符正确*/ 36 { 37 USART2_RX_BUF[7] = aRxBuffer2[0]; 38 printf("USART3_RX_BUF is %d %d %d %d %d %d %d %d \r\n",USART2_RX_BUF[0],USART2_RX_BUF[1],USART2_RX_BUF[2],USART2_RX_BUF[3],USART2_RX_BUF[4],USART2_RX_BUF[5],USART2_RX_BUF[6],USART2_RX_BUF[7]); 39 wifiDataHandle(); 40 app_ok=1; 41 // LCD_ShowNum(0,0,app_flap,10,8); 42 } else 43 { 44 rxState = waitForStart; /*结束符错误*/ 45 46 } 47 rxState = waitForStart; 48 break; 49 default: 50 break; 51 } 52 53 }
1 void wifiDataHandle(void) 2 { 3 app_flap = USART2_RX_BUF[1]; //副翼 横向 4 app_elevator = USART2_RX_BUF[2]; //升降舵 前后 5 app_pwm = USART2_RX_BUF[3]; //油门 6 app_rudder = USART2_RX_BUF[4]; //方向舵 7 if((USART2_RX_BUF[5]&0x01)==0){ keyFlight=0; }else {keyFlight=1;} //一键起飞 先置1,1秒后置0 8 if((USART2_RX_BUF[5]&0x02)==0){ keyLand=0; }else {keyLand=1;} //一键降落 先置1,1秒后置0 9 if((USART2_RX_BUF[5]&0x04)==0){ emerStop=0; }else {emerStop=1;} //紧急停机 每次取反 10 if((USART2_RX_BUF[5]&0x08)==0){ flipOne=0; }else {flipOne=1;} //固定翻转 11 if((USART2_RX_BUF[5]&0x10)==0){ flightMode=0; }else {flightMode=1;} //1无头 0有头 12 if((USART2_RX_BUF[5]&0x20)==0){ flipFour=0; }else {flipFour=1;} //一键翻转 点击后置1,当方向键移动过一半时清0 13 if((USART2_RX_BUF[5]&0x40)==0){ ledControl=0; }else {ledControl=1;} //光控制 14 if((USART2_RX_BUF[5]&0x80)==0){ gyroCalib=0; }else {gyroCalib=1;} //陀螺仪校准 先置1,1秒后置0 15 16 printf("app_flap app_elevator %d %d ",app_flap,app_elevator); 17 }