[TOC]
串口
简介
什么是串口
串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方
式的扩展接口。串行接口(Serial
Interface)是指数据一位一位地顺序传送。其特点是通信线路简
单,只要一对传输线就可以实现双向通信(可以直接利用电话线作为传输线),从而大大降低了成
本,特别适用于远距离通信,但传送速度较慢
- 是设备间接线通信的一种方式
- 数据一位一位地顺序传送
- 双向通信,全双工
- 传送速度相对较慢
关于电器标准和协议
串行接口按电气标准及协议来分包括RS-232-C、RS-422、RS485等。RS-232-C、RS-422与RS-485
标准只对接口的电气特性做出规定,不涉及接插件、电缆或协议。
也称标准串口,最常用的一种[串行通讯接口,比如我们的电脑主机的9针串口
,最高速率为20kb/sRS-232是为点对点(即只用一对收、发设备)通讯而设计的,其传送距离最大为约15米。所以RS-232适合本地设备之间的通信
RS-422
由于接收器采用高输入阻抗和发送驱动器比RS232更强的驱动能力,故允许在相同传输线上连接多个接收节点,最多可接10个节点。即一个主设备(Master),其余为从设备(Slave),从设备之间不能通信,所以RS-422支持点对多的双向通信。
RS-422的最大传输距离为1219米,最大传输速率为10Mb/s。平衡双绞线的长度与传输速率成反比
RS-485
是从RS-422基础上发展而来的,无论四线还是二线连接方式总线上可多接到32个设备。
关于串口的电平
经常听说的UART
异步串行是指UART(Universal Asynchronous
Receiver/Transmitter),通用异步接收/发送。
UART包含TTL电平的串口和RS232电平的串口
RS232电平
逻辑1为-3~-15V的电压, 逻辑0为3~15V的电压
TTL是Transistor-Transistor
Logic,即晶体管-晶体管逻辑的简称,它是计算机处理器控制的设备内部各部分之间通信的标准技术。TTL电平信号应用广泛,是因为其数据表示采用二进制规定,
USB转TTL,使用ch340通信
上官一号
串口通信
串口接线方式
印象塑造
- 回忆UART是异步串行接口,通信双方使用时钟不同,因为双方硬件配置不同,但是需要约定通信速度,叫做波特率
对于电脑来说,别人做好了软件,鼠标点点点就能配置好,而苦逼单片机的波特率配置需要我们写代码
点点点配置什么,我们代码也要配置对应参数
字符'a'
是如何从单片机上传到PC的
a的ASSII码是97,16进制就是0x61,
二进制是01010001,这个8位就是数据位
串口工作模式1,一帧数据有10位,起始位(0),数据位,停止位(1)
那么a的一帧数据就是 0 1000 1010 1
起始位,a的低位到高位,停止位
除了速度要求,还要有数据格式,双方暗号
对上了再发数据,所以有起始位,和停止位
的概念
串口代码
发送一个字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #include <REG52.H> sfr AUXR = 0x8E; void Delay1000ms() { unsigned char i, j, k; i = 8; j = 1; k = 243; do { do { while (--k); } while (--j); } while (--i); } void UartInit(void) { PCON &= 0x7F; SCON = 0x50; AUXR &= 0xBF; AUXR &= 0xFE; TMOD &= 0x0F; TMOD |= 0x20; TL1 = 0xFD; TH1 = 0xFD; ET1 = 0; TR1 = 1; }
void main() { char data_msg = 'A'; UartInit(); while (1) { Delay1000ms(); SBUF = data_msg; } }
|
发送一个字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| #include <REG52.H> sfr AUXR = 0x8E; void Delay1000ms() { unsigned char i, j, k; i = 8; j = 1; k = 243; do { do { while (--k); } while (--j); } while (--i); } void UartInit(void) { AUXR = 0x01; SCON = 0x50; TMOD &= 0xF0; TMOD |= 0x20; TH1 = 0xFD; TL1 = 0xFD; TR1 = 1; EA = 1; ES = 1; } void sendByte(char data_msg){ SBUF = data_msg; while (!TI); TI = 0 ; } void SendString(char* str){ while (*str != '\0') { sendByte(*str); str++; } } void main() { UartInit(); while (1) { Delay1000ms(); SendString("xiaoliutongxue NB\r\n"); } }
|
代码中的
TI 是单片机串口发送中断的请求位:
- 当 串行数据发送 结束时 TI=1
- 在发送过程中为 TI = 0 ;
所以 当在发送数据的时候 TI0 通过 while等待 直到数据全部写入完成
想要实现换行 使用会使串口数据换行对齐
PC发送数据 控制开发板的小灯
当RI = 1 的时候 单片机就知道 串口 有数据来了
这里需要和发送请求为TI做区分
接收完数据后需要软件将RI接受位 置0
非中断方式
判断串口数据接受位
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include <REG52.H> #include<STDIO.H> sfr AUXR = 0x8E; sbit LED = P3^6; void Delay1000ms() { unsigned char i, j, k; i = 8; j = 1; k = 243; do { do { while (--k); } while (--j); } while (--i); } void UartInit(void) { AUXR = 0x01; SCON = 0x50; TMOD &= 0xF0; TMOD |= 0x20; TH1 = 0xFD; TL1 = 0xFD; TR1 = 1; EA = 1; ES = 1; } void sendByte(char data_msg){ SBUF = data_msg; while (!TI); TI = 0 ; } void SendString(char* str){ while (*str != '\0') { sendByte(*str); str++; } } void main() { char cmd; UartInit(); while (1) { Delay1000ms(); SendString("xiaoliutongxue NB\r\n"); if(RI == 1){ cmd = SBUF; if (cmd == 'o') { LED = 0 ; }else if (cmd == 'c') { LED = 1; } RI =0; } } }
|
中断方式
中断号为 4 需要开启总中断 使EA = 1 开启串口中断 ES = 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
| #include <REG52.H> #include <STDIO.H> sfr AUXR = 0x8E; sbit LED = P3 ^ 6; void Delay1000ms() { unsigned char i, j, k; i = 8; j = 1; k = 243; do { do { while (--k) ; } while (--j); } while (--i); } void UartInit(void) { AUXR = 0x01; SCON = 0x50; TMOD &= 0xF0; TMOD |= 0x20; TH1 = 0xFD; TL1 = 0xFD; TR1 = 1; EA = 1; ES = 1; } void sendByte(char data_msg) { SBUF = data_msg; while (!TI) ; TI = 0; } void SendString(char *str) { while (*str != '\0') { sendByte(*str); str++; } } char cmd[128]; void main() {
UartInit(); while (1) { Delay1000ms(); SendString("xiaoliutongxue NB\r\n"); } } void UART_Hander() interrupt 4 { static int i = 0 ; if (RI) { RI = 0; cmd[i] = SBUF; i++; if (i == 12 ) { i = 0 } if (cmd == 'o') { LED = 0; } else if (cmd == 'c') { LED = 1; } } }
|
处理 单词命令
头文件string.h 处理字符串 详见[C
标准库 – | 菜鸟教程 (runoob.com)]:
用到的api
strstr(参数1,参数2)
- 参数1 需要在那个字符串中查找
- 参数2 要查找的字符串
memset(参数1,参数2,参数3)
- 参数1 要初始化的字符串数组或指针
- 参数2 要初始化为什么字符
- 参数3 该字符串的大小 根据数组大小或者指针大小而定
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
| #include <REG52.H> #include "STRING.H" #include <STDIO.H> sfr AUXR = 0x8E; sbit LED = P3 ^ 6; #define SIZE 16 void Delay1000ms() { unsigned char i, j, k; i = 8; j = 1; k = 243; do { do { while (--k) ; } while (--j); } while (--i); } void UartInit(void) { AUXR = 0x01; SCON = 0x50; TMOD &= 0xF0; TMOD |= 0x20; TH1 = 0xFD; TL1 = 0xFD; TR1 = 1; EA = 1; ES = 1; } void sendByte(char data_msg) { SBUF = data_msg; while (!TI) ; TI = 0; } void SendString(char *str) { while (*str != '\0') { sendByte(*str); str++; } } char cmd[16]; void main() { LED = 0 ; UartInit(); while (1) { Delay1000ms(); SendString("xiaoliutongxue NB\r\n"); } } void UART_Hander() interrupt 4 { static int i = 0 ; if (RI) { RI = 0; cmd[i] = SBUF; i++; if (i == SIZE) { i = 0 ; } if (strstr(cmd,"en")) { LED = 0; i= 0 ; memset(cmd,'\0',SIZE); } else if (strstr(cmd,"se")) { LED = 1; i = 0 ; memset(cmd,'\0',SIZE); } } }
|