STM32之串口通信
1. 背景知识
一般情况下,设备之间的通信方式可以分成并行通信和串行通信两种。
并行通信
串行通信
传输原理:数据按位顺序传输。
优点:占用引脚资源少
缺点:速度相对较慢
2. 串行通信
按照数据传送方向分类
- 单工:数据传输只支持数据在一个方向上传输
- 半双工:允许数据在两个方向上传输。但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信,它不需要独立的接收端和发送端,两者可以合并一起使用一个端口。
- 全双工:允许数据同时在两个方向上传输。因此,全双工通信是两个单工通信方式的结合,需要独立的接收端和发送端
按照通信方式分类
- 同步通信:带时钟同步信号传输,比如SPI,I2C通信接口
- 异步通信:不带时钟同步信号,比如UART(通用异步收发器),单总线
在同步通信中,收发设备上方会用一根信号线传输信号,在时钟信号的驱动下双方进行协调,同步数据。例如,通信中通常双方会统一规定在时钟信号的上升沿或者下降沿对数据线进行采样,
在异步通信中不使用时钟信号进行数据同步,他们直接在数据信号中穿插一些用于同步的信号位,或者将主题数据进行打包,以数据帧的格式传输数据。通信中还需要双方约定好数据的传输速率(也就是波特率)等,以便更好地同步。常用的波特率有9600、115200等
在同步通信中,数据信号所传输的内容绝大部分是有效数据,而异步通信中则会包含数据帧的各种标识符,所以同步通信效率高,但是同步通信双方的时钟允许误差小,稍稍始终出错就可能导致数据错乱,异步通信双方的始终允许误差大。
3. STM32的串口通信接口
UART:通用异步收发器
USART:通用同步异步收发器
大容量STM32F10x系列芯片,包含3个USART和2个UART
引脚定义
RXD:数据输入引脚。数据接受。
TXD:数据发送引脚。数据发送。
UART特点
通信过程
参数
串口通信的数据包由发送设备通过自身的TXD接口传输到接收设备的RXD接口,通信双方的数据包格式要规约一致才能正常收发数据。STM32中串口异步通信需要定义的参数:起始位,数据位(8位或者9位),奇偶校验位,停止位,波特率设置
UART串口通信的数据包以帧为单位,常用的帧结构为:1位起始位+8位数据位+1位奇偶校验位(可选)+1位停止位。如下图所示:
奇偶校验位分为奇校验和偶校验两种,是一种简单的数据误码校验方法。奇校验是指每帧数据中,包括数据位和奇偶校验位的全部9个位中1的个数必须为奇数;偶校验是指每帧数据中,包括数据位和奇偶校验位的全部9个位中1的个数必须为偶数。
校验方法除了奇校验(odd)、偶校验(even)之外,还可以有:0 校验(space)、1 校验(mark)以及无校验(noparity)。 0/1校验:不管有效数据中的内容是什么,校验位总为0或者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 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| #include "sys.h" #include "usart.h"
#if SYSTEM_SUPPORT_OS #include "includes.h" #endif
#if 1 #pragma import(__use_no_semihosting)
struct __FILE { int handle; };
FILE __stdout;
int _sys_exit(int x) { x = x; }
int fputc(int ch, FILE *f) { while((USART1->SR&0X40)==0); USART1->DR = (u8) ch; return ch; } #endif
#if EN_USART1_RX
u8 USART_RX_BUF[USART_REC_LEN];
u16 USART_RX_STA=0; void uart_init(u32 bound){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
USART_InitStructure.USART_BaudRate = bound; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE);
}
void USART1_IRQHandler(void) { u8 Res; #if SYSTEM_SUPPORT_OS OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { Res =USART_ReceiveData(USART1); if((USART_RX_STA&0x8000)==0) { if(USART_RX_STA&0x4000) { if(Res!=0x0a)USART_RX_STA=0; else USART_RX_STA|=0x8000; } else { if(Res==0x0d)USART_RX_STA|=0x4000; else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0; } } } } #if SYSTEM_SUPPORT_OS OSIntExit(); #endif } #endif
|
usart.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| #ifndef __USART_H #define __USART_H #include "stdio.h" #include "sys.h"
#define USART_REC_LEN 200 #define EN_USART1_RX 1 extern u8 USART_RX_BUF[USART_REC_LEN]; extern u16 USART_RX_STA;
void uart_init(u32 bound); #endif
|
main.c
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
| #include "delay.h" #include "sys.h" #include "usart.h"
int main(void) { u16 t; u16 len; u16 times=0; delay_init(); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); uart_init(9600); while(1) { if(USART_RX_STA&0x8000) { len=USART_RX_STA&0x3fff; printf("您发送的消息为:"); for(t=0;t<len;t++) { USART_SendData(USART1, USART_RX_BUF[t]); while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET); } USART_RX_STA=0; }else { times++; if(times%30==0)LED0=!LED0; delay_ms(10); } } }
|
CRC16校验
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
| void USART1_IRQHandler(void) { u8 Res; #if SYSTEM_SUPPORT_OS OSIntEnter(); #endif if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { int u; Res =USART_ReceiveData(USART1); if((USART_RX_STA&0X3FFF)==7){ unsigned int current_crc_value; unsigned char hi,lo; int i, j; current_crc_value = 0xFFFF; for (i = 0; i < 5; i++) { current_crc_value = current_crc_value ^ ((unsigned int)USART_RX_BUF[i]); for (j = 0; j < 8; j++) { if (current_crc_value & 0x0001) { current_crc_value = (current_crc_value >> 1) ^ 0xA001; } else { current_crc_value = (current_crc_value >> 1); } } } lo = current_crc_value &0xff; hi=(current_crc_value>>8)&0xff; if(lo==USART_RX_BUF[5]&hi==USART_RX_BUF[6]){ USART_RX_STA|=0x8000; }else{ USART_RX_STA=0; } } else{ USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; } } #if SYSTEM_SUPPORT_OS OSIntExit(); #endif }
|