USART serial port data packet
Data mode
- HEX mode/Hex mode/Binary mode: Display in the form of raw data
- Text mode/Character mode
HEX data packet
-
Fixed package length, including header and tail
-
Variable packet length, including header and tail
Text packet
- Fixed package length, including header and tail
- Variable packet length, including header and tail
HEX packet reception
Text packet reception
State machine
State Machine: It actually refers to a mathematical model that can reflect different states of things, which is the State transition diagram of mathematics and electricity.
If you want to make good use of state machine ideas, you need to understand the following four concepts:
- State, state (a state machine has at least two states) That is S in the picture, when S=0, S=1, S=2 correspond to three different states of the state machine
- Event, event In the figure, receiving @’, receiving r’, receiving \\
’, and receiving other data are four different - Action, action Generally speaking, there must be a corresponding action after each event occurs (for example, receiving the LED_ON command (event) and turning on the LED (action))
- Transition, transformation After a specific event occurs, the state of the state machine changes
The idea of state machine is widely used in the writing of various programs
Case 1: USART sends and receives HEX data packets
Main functions
/* Send HEX packet */ void Serial_SendHexPacket(uint8_t * Arr) {<!-- --> Send_Byte(0xFF); // Send header Serial_SendArr(Arr, 4); Send_Byte(0xFE); // Send the end of the packet Serial_SendString("\r\\ "); }
/* Interrupt function, based on the idea of state machine */ void USART1_IRQHandler(void) {<!-- --> static uint8_t i = 0; // subscript if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // The receiving register is not empty {<!-- --> uint8_t Serial_RxData; Serial_RxData = USART_ReceiveData(USART1); // Receive data if(RxState == 0) //Wait for header {<!-- --> if(Serial_RxData == 0xFF) // Get the header {<!-- --> RxState = 1; // Conversion i = 0; } } else if(RxState == 1) //Receive data {<!-- --> \t\t\t RxPacket[i + + ] = Serial_RxData; if(i >= 4) // Finish receiving data {<!-- --> i = 0; RxState = 2; // Conversion state } }else if(RxState == 2) // Wait for the end of the packet {<!-- --> if(Serial_RxData==0xFE) //Receive the end of the packet {<!-- --> RxState = 0; // Conversion state RxFlag = 1; } } // Clear interrupt flag USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }
Main code
main.c
#include "stm32f10x.h" #include "delay.h" #include "OLED.h" #include "key.h" #include "serial.h" // USART serial port receives HEX data packet // April 4, 2023 09:16:55 uint8_t Key_Num; int main(void) {<!-- --> OLED_Init(); Serial_Init(); Init_Key(); OLED_ShowString(1, 1, "TxPacket"); OLED_ShowString(3, 1, "RxPacket"); TxPacket[0] = 0x00; TxPacket[1] = 0x01; TxPacket[2] = 0x02; TxPacket[3] = 0x03; Serial_SendHexPacket((uint8_t*)TxPacket); while(1) {<!-- --> Key_Num = Get_KeyNum(); if(Key_Num == 2) //Send by key {<!-- --> TxPacket[0] + + ; TxPacket[1] + + ; TxPacket[2] + + ; TxPacket[3] + + ; Serial_SendHexPacket((uint8_t*)TxPacket); OLED_ShowHexNum(2, 1, TxPacket[0], 2); OLED_ShowHexNum(2, 4, TxPacket[1], 2); OLED_ShowHexNum(2, 7, TxPacket[2], 2); OLED_ShowHexNum(2, 10, TxPacket[3], 2); } if(RxFlag) //Print the received data to the OLED screen {<!-- --> OLED_ShowHexNum(4, 1, RxPacket[0], 2); OLED_ShowHexNum(4, 4, RxPacket[1], 2); OLED_ShowHexNum(4, 7, RxPacket[2], 2); OLED_ShowHexNum(4, 10, RxPacket[3], 2); RxFlag = 0; } \t\t } }
Serial.c
#include "stm32f10x.h" uint8_t RxPacket[4]; // Save the received data packet uint8_t TxPacket[4]; // Save the data packet to be sent uint8_t RxFlag; // receive flag uint8_t RxState; // receive status void Serial_Init(void) {<!-- --> // RCC enable clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); \t //Initialize GPIO // TX sender GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA, & amp;GPIO_InitStructure); // RX receiving end GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; GPIO_Init(GPIOA, & amp;GPIO_InitStructure); \t // Configure USART serial communication USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate=9600; // Baud rate USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // No flow control USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx; USART_InitStructure.USART_Parity=USART_Parity_No; // Parity check USART_InitStructure.USART_StopBits=USART_StopBits_1; // Stop bits USART_InitStructure.USART_WordLength=USART_WordLength_8b; // 8 bits USART_Init(USART1, & amp;USART_InitStructure); \t // Turn on USART interrupt USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // The receiving register is not empty (receiving) \t // Configure NVIC NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_Init( & amp;NVIC_InitStructure); \t // Start USART USART_Cmd(USART1, ENABLE); } /* Send single data */ void Send_Byte(uint16_t Byte) {<!-- --> USART_SendData(USART1, Byte); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // Wait for sending to complete } /* Send string */ void Serial_SendString(char * String) {<!-- --> uint8_t i; for(i=0; String[i] != '\0'; + + i) {<!-- --> Send_Byte(String[i]); } } /* Send array */ void Serial_SendArr(uint8_t * Arr, uint8_t Length) {<!-- --> for(uint8_t i=0; i<Length; + + i) {<!-- --> Send_Byte(Arr[i]); } } /* Send HEX packet */ void Serial_SendHexPacket(uint8_t * Arr) {<!-- --> Send_Byte(0xFF); Serial_SendArr(Arr, 4); Send_Byte(0xFE); Serial_SendString("\r\\ "); } /* Interrupt function */ void USART1_IRQHandler(void) {<!-- --> static uint8_t i = 0; // subscript if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // The receiving register is not empty {<!-- --> uint8_t Serial_RxData; Serial_RxData = USART_ReceiveData(USART1); // Receive data if(RxState == 0) //Wait for header {<!-- --> if(Serial_RxData == 0xFF) // Get the header {<!-- --> RxState = 1; // Conversion i = 0; } } else if(RxState == 1) //Receive data {<!-- --> \t\t\t RxPacket[i + + ] = Serial_RxData; if(i >= 4) // Finish receiving data {<!-- --> i = 0; RxState = 2; // Conversion state } }else if(RxState == 2) // Wait for the end of the packet {<!-- --> if(Serial_RxData==0xFE) //Receive the end of the packet {<!-- --> RxState = 0; // Conversion state RxFlag = 1; } } // Clear interrupt flag USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }
Serial.h
#ifndef __SERIAL_H #define __SERIAL_H void Serial_Init(void); void Send_Byte(uint16_t Byte); void Serial_SendString(char * String); void Serial_SendArr(uint8_t * Arr, uint8_t Length); void Serial_SendHexPacket(uint8_t * Arr); void Serial_SendTxtPacket(char * String); extern char RxPacket[]; extern char TxPacket[]; extern uint8_t RxFlag; extern uint8_t RxState; #endif
Case 2: USART sends and receives text packets
Main functions
/* Interrupt function state machine idea */ void USART1_IRQHandler(void) {<!-- --> static uint8_t pRxData = 0; if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // The receiving register is not empty {<!-- --> uint8_t Serial_RxData; Serial_RxData = USART_ReceiveData(USART1); // Receive data if(RxState == 0) //Wait for header {<!-- --> if(Serial_RxData == '@' & amp; & amp; RxFlag==0) // Receive header {<!-- --> RxState = 1; // Conversion state pRxData = 0; } } else if(RxState == 1) //Receive data packaging {<!-- --> \t\t\t if(Serial_RxData == '\r') // Complete data received {<!-- --> RxPacket[pRxData + + ] = Serial_RxData; // 'r' RxState = 2; }else {<!-- --> RxPacket[pRxData + + ] = Serial_RxData; } } else if(RxState==2) // Wait for the end of the packet {<!-- --> if(Serial_RxData=='\\ ') {<!-- --> RxState = 0; RxPacket[pRxData + + ] = '\\ '; // '\\ ' RxPacket[pRxData] = '\0'; // 'String end flag' RxFlag = 1; //receive completion flag bit } } // Clear interrupt flag USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }
Main code
main.c
#include "stm32f10x.h" #include "delay.h" #include "OLED.h" #include "serial.h" #include "LED.h" #include <string.h> // String processing function //USART serial port receives text packets // April 6, 2023 19:22:18 uint8_t Key_Num; int main(void) {<!-- --> OLED_Init(); Serial_Init(); // Serial port initialization LED_Init(); OLED_ShowString(1, 1, "TxPacket"); OLED_ShowString(3, 1, "RxPacket"); while(1) {<!-- --> if(RxFlag) // Received a data packet {<!-- --> OLED_ShowString(4, 1, " "); OLED_ShowString(4, 1, RxPacket); // Judgment command if(strcmp(RxPacket, "LED_On\r\\ ")==0) {<!-- --> LED_On(); // Turn on the light Serial_SendString("LED_ON_OK\r\\ "); OLED_ShowString(2, 1, " "); OLED_ShowString(2, 1, "LED_ON_OK"); }else if(strcmp(RxPacket, "LED_Off\r\\ ")==0) // strcmp can compare whether two strings are the same {<!-- --> LED_Off(); // Turn off the light Serial_SendString("LED_OFF_OK\r\\ "); OLED_ShowString(2, 1, " "); OLED_ShowString(2, 1, "LED_OFF_OK"); } else // command error {<!-- --> Serial_SendString("ERROR_COMMAND\r\\ "); OLED_ShowString(2, 1, " "); OLED_ShowString(2, 1, "ERROR_COMMAND"); } RxFlag = 0; // Clear custom flag } \t\t } }
serial.c
#include "stm32f10x.h" char RxPacket[100]; // Save the received data packet char TxPacket[100]; // Save the data packet to be sent uint8_t RxFlag; // receive flag uint8_t RxState; // receive status void Serial_Init(void) {<!-- --> // RCC enable clock RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); \t //Initialize GPIO // TX sender GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA, & amp;GPIO_InitStructure); // RX receiving end GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; GPIO_Init(GPIOA, & amp;GPIO_InitStructure); \t // Configure USART serial communication USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate=9600; // Baud rate USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; // No flow control USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx; USART_InitStructure.USART_Parity=USART_Parity_No; // Parity check USART_InitStructure.USART_StopBits=USART_StopBits_1; // Stop bits USART_InitStructure.USART_WordLength=USART_WordLength_8b; // 8 bits USART_Init(USART1, & amp;USART_InitStructure); \t // Turn on USART interrupt USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // The receiving register is not empty (receiving) \t // Configure NVIC NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_Init( & amp;NVIC_InitStructure); \t // Start USART USART_Cmd(USART1, ENABLE); } /* Send single data */ void Send_Byte(uint16_t Byte) {<!-- --> USART_SendData(USART1, Byte); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); // Wait for sending to complete } /* Send string */ void Serial_SendString(char * String) {<!-- --> uint8_t i; for(i=0; String[i] != '\0'; + + i) {<!-- --> Send_Byte(String[i]); } } /* Send array */ void Serial_SendArr(uint8_t * Arr, uint8_t Length) {<!-- --> for(uint8_t i=0; i<Length; + + i) {<!-- --> Send_Byte(Arr[i]); } } /* Send HEX packet */ void Serial_SendHexPacket(uint8_t * Arr) {<!-- --> Send_Byte(0xFF); Serial_SendArr(Arr, 4); Send_Byte(0xFE); Serial_SendString("\r\\ "); } /* Send text packet */ void Serial_SendTxtPacket(char * String) {<!-- --> Serial_SendString("@"); Serial_SendString(String); Serial_SendString("\r\\ "); } /* Interrupt function */ void USART1_IRQHandler(void) {<!-- --> static uint8_t pRxData = 0; if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) // The receiving register is not empty {<!-- --> uint8_t Serial_RxData; Serial_RxData = USART_ReceiveData(USART1); // Receive data if(RxState == 0) //Wait for header {<!-- --> if(Serial_RxData == '@' & amp; & amp; RxFlag==0) // Receive header {<!-- --> RxState = 1; // Conversion state pRxData = 0; } } else if(RxState == 1) //Receive data packaging {<!-- --> \t\t\t if(Serial_RxData == '\r') // Complete data received {<!-- --> RxPacket[pRxData + + ] = Serial_RxData; RxState = 2; }else {<!-- --> RxPacket[pRxData + + ] = Serial_RxData; } } else if(RxState==2) // Wait for the end of the packet {<!-- --> if(Serial_RxData=='\\ ') {<!-- --> RxState = 0; RxPacket[pRxData + + ] = '\\ '; RxPacket[pRxData] = '\0'; RxFlag = 1; //receive completion flag bit } } // Clear interrupt flag USART_ClearITPendingBit(USART1, USART_IT_RXNE); } }
serial.h
#ifndef __SERIAL_H #define __SERIAL_H void Serial_Init(void); void Send_Byte(uint16_t Byte); void Serial_SendString(char * String); void Serial_SendArr(uint8_t * Arr, uint8_t Length); void Serial_SendHexPacket(uint8_t * Arr); void Serial_SendTxtPacket(char * String); extern char RxPacket[]; extern char TxPacket[]; extern uint8_t RxFlag; extern uint8_t RxState; #endif
Reference materials
Jiangke University STM32 introductory tutorial
What is a state machine? – Peter Wang Guangzhong’s article – Zhihu