STM32 Getting Started Notes 11_USART serial port data packet + case: USART receives HEX data packet USART receives text data packet

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