数据通信基础
串行/并行通信

单工/半双工/全双工通信

同步/异步通信

波特率

常见通信接口
| 名称 |
引脚 |
双工 |
时钟 |
电平 |
设备 |
| USART |
TX、RX |
全双工 |
异步 |
单端 |
点对点 |
| I2C |
SCL、SDA |
半双工 |
同步 |
单端 |
多设备 |
| SPI |
SCLK、MOSI、MISO、CS |
全双工 |
同步 |
单端 |
多设备 |
| CAN |
CAN_H、CAN_L |
半双工 |
异步 |
差分 |
多设备 |
| USB |
DP、DM |
半双工 |
异步 |
差分 |
点对点 |
串口
概念

RS232 VS CMOS/TTL

串口参数及时序

RS232通信


USB通信

电平的区别

USART
简介

主要特征

框图
串口数据低位先行

框图简化版


数据帧
这里的字长就是数据位长度,空闲帧和断开帧是局域网协议用的,我们的串口用不到

停止位分别为1、1.5、2、0.5,意思就是0.5个时长

要保证在采样的时候,数据在时钟边沿的中间,这样可以保证数据的可靠性

设置波特率
波特率的产生实际上就是一个预分频的过程,这里的16就是上面的内部还有一个16倍的采样时钟




数据模式

实验
简单的发送数据
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
| void serial_init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin = SERIAL_TX_PIN; GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz; GPIO_Init(SERIAL_PORT,&GPIO_InitStruct); USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART2,&USART_InitStruct); USART_Cmd(USART2,ENABLE); }
void serial_sendByte(u8 byte) { USART_SendData(USART2,byte); while(USART_GetFlagStatus(USART2,USART_FLAG_TXE) == RESET); }
void serial_sendArray(u8 *array,u16 length) { for(u16 i = 0; i < length; i++){ serial_sendByte(array[i]); } }
void serial_sendString(char *str) { for(u8 i = 0;str[i] != '\0';i++){ serial_sendByte(str[i]); } }
u32 serial_pow(u32 x, u32 y) { u32 result = 1; while(y--){ result *= x; } return result; }
void serial_sendNum(u32 number, u8 length) { for(u8 i = 0; i < length; i++){ serial_sendByte(number / serial_pow(10,length - i -1) % 10 + '0'); } }
int main(void){ char str[50]; u8 test[] = {0x42,0x43,0x44,0x45};
serial_init(); serial_sendArray(test,4); serial_sendNum(12345,5);
while(1){
} }
|
printf重定向
如果想要使用printf函数,需要先使用microlib库

注意需要引入stdio头文件,还需要重写fputc
1 2 3 4 5 6 7 8
|
int fputc(int ch, FILE *file) { serial_sendByte(ch); return ch; }
|
重写完这个函数就可以正常使用printf函数了
如果想要让printf使用多个串口,那么就需要sprintf函数
1 2 3 4
| sprintf(str,"%x: %hu %hu\n",(u32)adValue,adValue[0],adValue[1]); serial_sendString(str);
|
为了方便,我们也可以封装sprintf函数,在封装sprintf的时候需要引入头文件stdarg.h头文件。
1 2 3 4 5 6 7 8 9 10 11
| void serial_printf(char *format, ...) { char string[100]; va_list arg; va_start(arg,format); vsprintf(string,format,arg); va_end(arg); serial_sendString(string); }
|
解决汉字乱码的情况,如果使用的编码格式为utf-8,则需要先设置编译参数–no-multibyte-chars

接收数据
需要修改初始化函数,分为查询式和中断式
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 117 118 119 120 121 122
| void serial_init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin = SERIAL_TX_PIN; GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz; GPIO_Init(SERIAL_PORT,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin = SERIAL_RX_PIN; GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz; GPIO_Init(SERIAL_PORT,&GPIO_InitStruct); USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART2,&USART_InitStruct); USART_Cmd(USART2,ENABLE); }
int main(void){ u8 rxData;
serial_init();
while(1){ if(USART_GetFlagStatus(USART2,USART_FLAG_RXNE) == SET){ rxData = USART_ReceiveData(USART2); serial_printf("receive: %x\n",rxData); } } }
void serial_init() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStruct.GPIO_Pin = SERIAL_TX_PIN; GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz; GPIO_Init(SERIAL_PORT,&GPIO_InitStruct); GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; GPIO_InitStruct.GPIO_Pin = SERIAL_RX_PIN; GPIO_InitStruct.GPIO_Speed =GPIO_Speed_50MHz; GPIO_Init(SERIAL_PORT,&GPIO_InitStruct); USART_InitTypeDef USART_InitStruct; USART_InitStruct.USART_BaudRate = 115200; USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_InitStruct.USART_Parity = USART_Parity_No; USART_InitStruct.USART_StopBits = USART_StopBits_1; USART_InitStruct.USART_WordLength = USART_WordLength_8b; USART_Init(USART2,&USART_InitStruct); USART_ITConfig(USART2,USART_IT_RXNE,ENABLE); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitTypeDef NVIC_InitStruct; NVIC_InitStruct.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; NVIC_Init(&NVIC_InitStruct); USART_Cmd(USART2,ENABLE); }
u8 serial_rxData,serial_rxFlag; void USART2_IRQHandler(void) { if(USART_GetFlagStatus(USART2,USART_IT_RXNE) == SET){ serial_rxData = USART_ReceiveData(USART2); serial_rxFlag = 1; USART_ClearITPendingBit(USART2,USART_IT_RXNE); } }
u8 serial_getRxFlag(void) { if(serial_rxFlag == 1){ serial_rxFlag = 0; return 1; } return 0; }
u8 serial_getRxData(void) { return serial_rxData; }
int main(void){ u8 rxData;
serial_init();
while(1){ if(serial_getRxFlag() == 1){ rxData = serial_getRxData(); serial_printf("receive %x\n",rxData); } } }
|
数据包的收发
HEX数据包


文本数据包


实验代码
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
| void serial_sendPacket(void) { serial_sendByte(0xFF); serial_sendArray(serial_txPacket,4); serial_sendByte(0xFE);
}
u8 serial_rxData,serial_rxFlag; u8 serial_txPacket[4],serial_rxPacket[4]; void USART2_IRQHandler(void) { static u8 rxState = 0; static u8 counter = 0; if(USART_GetFlagStatus(USART2,USART_IT_RXNE) == SET){ u8 rxData = USART_ReceiveData(USART2); if(rxState == 0){ if(rxData == 0xff){ rxState = 1; counter = 0; } }else if(rxState == 1){ serial_rxPacket[counter++] = rxData; if(counter >= 4){ rxState = 2; } }else if(rxState == 2){ if(rxData == 0xfe){ rxState = 0; serial_rxFlag = 1; } } } }
|