一 通信的基本概念
1.串口并行与串行
数电课讲过,并行速度快但占用的门电路多,耗费空间
串行速度慢但节约空间
2.数据通信方向
。全双工:TX,RX同时收发数据
。半双工:不能同时收发数据,可分时收发数据
。单工:任何时刻都只能往某一个固定的方向传输数据
3.数据同步方式
。同步
。异步
4.通信速率
。比特率:每秒钟传输的二进制位数,单位(bit/s)
。波特率:每秒中传输的码元个数
一个码元就是一个脉冲信号,一个脉冲信号有可能携带1bit数据,也有可能携带2bit数据、4bit数据!你发送一个脉冲信号,如果就可以携带4bit数据,肯定发送速率更快啊!
那么怎么实现一个脉冲信号就能携带多个bit数据呢?就需要一定的技术了,比如设置模拟信号中信号的频率、相位、振幅啥的。举个例子:把振幅分成四种,低(00)、中(01)、高(10)、很高(11),这样我发一个脉冲信号,它的振幅是低,那就说明发送的是00(也就是2bit),它的振幅是中(01),发送的就是01(也就是2bit)……也就实现了一个脉冲信号,携带2bit的功能…(举个不恰当的例子让大家理解而已,明白啥意思就行)
再说一次,一个码元就是一个脉冲信号!波特率指的就是1秒能发送多少个码元,也就是1秒能发送多少个脉冲信号!
一个码元能携带1bit数据,那么比特率 = 波特率!
一个码元能携带2bit数据,那么比特率 = 2倍的波特率!
一个码元能携4bit数据,那么比特率 =4倍的波特率
- 一个二进制表示码元
0V——0
3.3V——1
- 两个二进制表示一个码元
0V——00
3V——01
6V——10
9V——11
- 通常情况下波特率等于比特率
二 串口通信协议
1.RS232标准
2.USB转串口
用于设备和电脑的通讯,电平转化芯片一般是CH340
3.串口到串口:串口一次只能发1个字节的数据( UART_SendByte())
三 串口数据包的组成
起始位 | 数据位 | 校验位 | 停止位 |
0 | 位0—位7 | 1 |
校验位
- 奇校验
有效数据和校验位“1”总的个数为奇数
- 偶校验
偶数
四 串口的功能框图
1.引脚作用
。TX:数据发送
。RX:数据接受
。SCLK:时钟,仅同步通信使用
。nRTS:Request to send.请求发送
。nCTS:Clear to send.允许发送
2.USART:S是同步。USART1~USART3都有SCLK引脚
UART:异步。无SCLK引脚
3.数据寄存器DR
31——9 bit | 8——0 bit |
保留 | DR[8:0] |
- 31-9 bit:保留位,始终为1
- 8-0 bit:数据位,由TDR(发送寄存器),RDR(接收寄存器),包含发送和接受功能
五 程序流程
- 串口初始化结构体
typedef struct { uint32_t USART_BaudRate; //波特率 BRR uint16_t USART_WordLength; //字长 CR1_M uint16_t USART_StopBits; //停止位 CR2_STOP uint16_t USART_Parity; //校验位 CR1_PCE CR1_PS uint16_t USART_Mode; //模式选择 CR1_TE CR1_RE uint16_t USART_HardwareFlowControl; //硬件流选择 CR3_CTSE,CR3_RTSE } USART_InitTypeDef;
。USART_WordLength
。USART_StopBits
#define USART_StopBits_1 ((uint16_t)0x0000) #define USART_StopBits_0_5 ((uint16_t)0x1000) #define USART_StopBits_2 ((uint16_t)0x2000) #define USART_StopBits_1_5 ((uint16_t)0x3000)
。USART_Parity
#define USART_Parity_No ((uint16_t)0x0000) #define USART_Parity_Even ((uint16_t)0x0400) #define USART_Parity_Odd ((uint16_t)0x0600)
。USART_Mode
#define USART_Mode_Rx ((uint16_t)0x0004) #define USART_Mode_Tx ((uint16_t)0x0008) #define IS_USART_MODE(MODE) ((((MODE) & (uint16_t)0xFFF3) == 0x00) && ((MODE) != (uint16_t)0x00))
。USART_HardwareFlowControl
#define USART_HardwareFlowControl_None ((uint16_t)0x0000) #define USART_HardwareFlowControl_RTS ((uint16_t)0x0100) #define USART_HardwareFlowControl_CTS ((uint16_t)0x0200) #define USART_HardwareFlowControl_RTS_CTS ((uint16_t)0x0300)
硬件流功能:当外设处于准备好的状态时,硬件启动自动控制,而不需要软件再进行干预,在串口中,当串口已经准备好接收新的数据时,硬件流自动把RTS拉低;准备发送数据前,硬件流自动检查CTS是否为低(表示是否可以发送数据)。此功能需要有RTS,CTS两个引脚。
- 同步时钟结构体
typedef struct { uint16_t USART_Clock; //同步时钟 CR2_CLKEN uint16_t USART_CPOL; //极性 CR2_CPOL uint16_t USART_CPHA; //相性 CR2_CPHA uint16_t USART_LastBit; //最后一个位的时钟脉冲 CR2_LBC } USART_ClockInitTypeDef;
- 流程
- 初始化串口需要用到的GPIO
- 初始化串口,USART_InitTypeDef
- 中断配置(接收中断,中断优先级)
- 使能串口
- 编写发送和接收函数
- 编写中断服务函数
- 发送接收函数
/* * @函数名:UART_SendByte(USART_TypeDef *p_USARTx, uint8_t ch) * @功能:发送一个字节 * @入口参数:USARTx,ch(想发送的字节) */ static void UART_SendByte(USART_TypeDef *p_USARTx, uint8_t ch) { /*发送一个字节的数据到USART*/ USART_SendData(p_USARTx,ch); /*等待发送数据的寄存器为空*/ while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); }
/* * @函数名:UART_SendString(USART_TypeDef *p_USARTx,char *str) * @功能:发送字符串 * @入口参数:USARTx,str(想发送的字符) */ void UART_SendString(USART_TypeDef *p_USARTx,char *str) { unsigned int k=0; do { UART_SendByte(p_USARTx,*(str+k)); k++; } while(*(str+k) != '\0'); /*等待发送完成*/ while (USART_GetFlagStatus(USART1,USART_FLAG_TC)== RESET) {} }
USART_FLAG_TC 与 USART_FLAG_TXE的区别:
- USART_FLAG_TC是干嘛用的呢?
当发送移位寄存器中的1字节数据已经通过TX脚一位一位的移出去后,该标志位就会被置1,从而引发该事件的中断。所以,其实USART_FLAG_TC就是用来标志“发送移位寄存器中的数据有没有全部发送出去”这件事的。
- USART_FLAG_TXE是干嘛用的呢?
当发送数据寄存器中的数据已经取完了,该标志位就会被置1,从而引发该事件的中断。所以,其实USART_FLAG_TXE就是用来标志一个事件的,通过它的值可以知道该事件有没有发生(即发送数据寄存器中的数据有没有被取走)。
- 对于USART_FLAG_TXE来说,只是说明数据寄存器中的数据已经被发送移位寄存器取走了(但发送移位寄存器中可能还没有启动发送过程),通过中断就可以提醒CPU可以往数据寄存器中填充数据了,发送移位寄存器中的数据往外发送的过程其实还是比较耗时的,相对于C语言代码执行时间来说,这个过程的耗时极大,所以每次发送数据寄存器中的数据被发送移位寄存器取走后,都应该产生中断来提醒CPU对该数据寄存器填写数据;
- 而对于USART_FLAG_TC来说,没必要每次当发送移位寄存器中的数据发送完成后都发生中断,而应该是整个串口数据帧全部发送完毕,包括最后一个字节也发送出去之后才应该开中断,这代表的就是一个数据帧发送完成事件了
六 知识重难点
- 当数组作函数形参时,由于形参变量和实参变量是由编译系统分配的两个不同单元。在函数调用的时发生的值传送是把实参变量的值赋予给形参变量。在用数组名作函数参数的时候,不是进行值的传送,既不是把实参数组的每一个元素的值都赋予形参数组的各个元素。因为实际上形参数组并不存在,编译系统不为形参数组分配内存。那么数据的传输是如何实现的呢?数组名就是数组的首地址。因此在数组名作函数参数时所进行的传送知识地址传送,也就是说把实参数组的首地址赋予给形参数组名。形参数组取得该首地址之后,也就等于有了实在的数组。实际上,形参数组和实参数组为同一数组,共同拥有一段内存空间。
- USART1的TX,RX通过CH340连接micro USB,所以你可以用数据线给电脑发送数据
但USART2,USART3需要额外接CH340,才能和电脑通信(PCB设计问题)
相关代码:串口的接受与发送