Recently I wanted to try to send and receive data through DMA of STM32. I found a lot of reference articles on the Internet and finally referred to the method in the blog post https://blog.csdn.net/youmeichifan/article/details/51750435?utm_source=dlogxgwz2.
The serial port transmission and reception were realized according to the method in this article, but it was found in actual use:
The receiving idle interrupt is generated when the data reception stops for one byte. However, sometimes due to the programming problem of the host computer or the hardware problem (the USB to serial port hardware I used has problems), the host computer sends data discontinuously, and there is a time interval greater than one byte in the middle, which makes it impossible to receive the data completely. By analyzing the idle interrupt receiving data method, the code is re-modified to realize the reception of indefinite length data in the specified data format.
Main implementation methods:
1. Define the communication protocol:
The first byte is the start character, I used 0x7B
The second byte is the data length (including the start character)
2. When receiving idle interrupt, determine whether legal data (start character) is received and the length of received data
3. Added timeout processing
Here is the code:
Define the serial port structure:
#define RECEIVELEN 1024
#define USART_DMA_SENDING 1 //Sending is not completed
#define USART_DMA_SENDOVER 0 //Sending completed
typedef struct
{
uint8_t receive_flag:1; //Idle receive flag
uint8_t dmaSend_flag:1; //Send completion flag
uint16_t rx_len; //receive length
uint8_t usartDMA_rxBuf[RECEIVELEN]; //DMA receive buffer
uint16_t timeOutCount; //Timeout count
uint8_t timeOutState; //Timeout state 1: Timeout count allowed 2: Timeout
}USART_REEIVETYPE;
Variable declaration:
USART_RECEIVETYPE UsartType1;
Functions used for serial port sending and receiving:
//DMA send function
void Usart1SendData_DMA(uint8_t *pdata, uint16_t Length)
{
while(UsartType1.dmaSend_flag == USART_DMA_SENDING);
UsartType1.dmaSend_flag = USART_DMA_SENDING;
HAL_UART_Transmit_DMA(&huart1, pdata, Length);
}
//DMA sending completion interrupt callback function
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
__HAL_DMA_DISABLE(huart->hdmatx);
if(huart->Instance==USART1)
UsartType1.dmaSend_flag = USART_DMA_SENDOVER;
if(huart->Instance==USART2)
UsartType2.dmaSend_flag = USART_DMA_SENDOVER;
}
//Serial port receives idle interrupt
void Usart1Receive_IDLE(UART_HandleTypeDef *huart)
{
uint32_t temp;
uint8_t *p;
uint16_t size;
if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
HAL_UART_DMAStop(&huart1);
temp = huart1.hdmarx->Instance->CNDTR;
UsartType1.rx_len += RECEIVELEN - temp; //Calculate the data length, RECEIVELEN - temp is the current length
//Judge whether it is the beginning of data and the starting position
if(UsartType1.usartDMA_rxBuf[0]==0x7b)
{
//Judge whether the received data length meets the requirements
if(UsartType1.rx_len>2)//Prevent the host computer from having an idle interrupt after sending the start bit
{
if(UsartType1.usartDMA_rxBuf[1]<=UsartType1.rx_len) //Data reception is complete, buff[0]: data header, buff[1] data length (including header)
{
//Receive flag = 1,
UsartType1.receive_flag=1;
//Next time the receiving buffer pointer starts from the beginning,
p=UsartType1.usartDMA_rxBuf;
//Receive buffer size = RECEIVELEN,
size=RECEIVELEN;
//Disable the timer to start decrementing timeOutCount
UsartType1.timeOutState=0;
}
else
{
//The next receive buffer pointer is UsartType1.usartDMA_rxBuf + the length already received,
p=UsartType1.usartDMA_rxBuf+UsartType1.rx_len;
//The size is RECEIVELEN-the length that has been received,
size=RECEIVELEN-UsartType1.rx_len;
//Fill in the timeout value
UsartType1.timeOutCount=1000;
UsartType1.timeOutState=1; //Allow the timer to start decrementing timeOutCount
}
}
else
{
//The next receive buffer pointer is UsartType1.usartDMA_rxBuf + the length already received,
p=UsartType1.usartDMA_rxBuf+UsartType1.rx_len;
//The size is RECEIVELEN-the length that has been received,
size=RECEIVELEN-UsartType1.rx_len;
UsartType1.timeOutCount=1000;
UsartType1.timeOutState=1; //Allow the timer to start decrementing timeOutCount
}
}
else
{
UsartType1.rx_len=0;//Reset UsartType1
p=UsartType1.usartDMA_rxBuf;
size=RECEIVELEN;
//Disable the timer to start decrementing timeOutCount
UsartType1.timeOutState=0;
}
HAL_UART_Receive_DMA(&huart1,p,size);//Set DMA receive buffer and size to prepare for the next reception
}
}
Timeout count:
I am using the SYSTick interrupt here, which generates an interrupt every 1ms.
void SysTick_Handler(void)
{
/* USER CODE BEGIN SysTick_IRQn 0 */
if(UsartType1.timeOutCount!=0&UsartType1.timeOutState==1)//USART1 timeout count
{
UsartType1.timeOutCount--;
// Determine if a timeout has occurred
if(UsartType1.timeOutCount==0)
{
UsartType1.timeOutState=2;
UsartType1.rx_len=0;
//After the timeout occurs, reset the DMA buffer
HAL_UART_DMAStop(&huart1);
HAL_UART_Receive_DMA(&huart1,UsartType1.usartDMA_rxBuf,RECEIVELEN);
}
}
/* USER CODE END SysTick_IRQn 0 */
HAL_IncTick();
HAL_SYSTICK_IRQHandler();
/* USER CODE BEGIN SysTick_IRQn 1 */
/* USER CODE END SysTick_IRQn 1 */
}
When the main program is initialized, open the serial port DMA receiving
/* USER CODE BEGIN 2 */
HAL_UART_Receive_DMA(&huart1, UsartType1.usartDMA_rxBuf, RECEIVELEN);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
/* USER CODE END 2 */
Data processing in while(1):
//Data received normally
if(UsartType1.receive_flag)
{
UsartType1.receive_flag=0; //clear flag
Usart1SendData_DMA(UsartType1.usartDMA_rxBuf,UsartType1.rx_len); //The serial port prints the received data.
UsartType1.rx_len=0;
}
//This is the timeout process
if(UsartType1.timeOutState==2)
{
UsartType1.timeOutState=0;
}
Previous article:STM32F103RCT6+ serial port DMA mode receives fixed-length data
Next article:The difference between STM32 timer output comparison mode and PWM output mode
Recommended ReadingLatest update time:2024-11-23 10:57
- Popular Resources
- Popular amplifiers
- Naxin Micro and Xinxian jointly launched the NS800RT series of real-time control MCUs
- How to learn embedded systems based on ARM platform
- Summary of jffs2_scan_eraseblock issues
- Application of SPCOMM Control in Serial Communication of Delphi7.0
- Using TComm component to realize serial communication in Delphi environment
- Bar chart code for embedded development practices
- Embedded Development Learning (10)
- Embedded Development Learning (8)
- Embedded Development Learning (6)
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- Intel promotes AI with multi-dimensional efforts in technology, application, and ecology
- ChinaJoy Qualcomm Snapdragon Theme Pavilion takes you to experience the new changes in digital entertainment in the 5G era
- Infineon's latest generation IGBT technology platform enables precise control of speed and position
- Two test methods for LED lighting life
- Don't Let Lightning Induced Surges Scare You
- Application of brushless motor controller ML4425/4426
- Easy identification of LED power supply quality
- World's first integrated photovoltaic solar system completed in Israel
- Sliding window mean filter for avr microcontroller AD conversion
- What does call mean in the detailed explanation of ABB robot programming instructions?
- STMicroelectronics discloses its 2027-2028 financial model and path to achieve its 2030 goals
- 2024 China Automotive Charging and Battery Swapping Ecosystem Conference held in Taiyuan
- State-owned enterprises team up to invest in solid-state battery giant
- The evolution of electronic and electrical architecture is accelerating
- The first! National Automotive Chip Quality Inspection Center established
- BYD releases self-developed automotive chip using 4nm process, with a running score of up to 1.15 million
- GEODNET launches GEO-PULSE, a car GPS navigation device
- Should Chinese car companies develop their own high-computing chips?
- Infineon and Siemens combine embedded automotive software platform with microcontrollers to provide the necessary functions for next-generation SDVs
- Continental launches invisible biometric sensor display to monitor passengers' vital signs
- Ltspice .save
- SinlinxA33 development board uses MIPI DSI screen
- Amateur Testing of Common Electroacoustic Devices
- Install Runhe Neptune Hongmeng system on w801kit
- DSPC6678 on-chip storage space allocation mechanism
- Ask a silly question about f_mount()!
- Power supply technology and electronic transformers
- TINA-TI
- [Evaluation of SGP40] + Cloud platform configuration for IoT remote monitoring application development
- Satellite DVB system in the European 1112GHz band