STM32 serial port idle interrupt receives indefinite length data

Publisher:红尘清梦Latest update time:2018-12-10 Source: eefocusKeywords:STM32 Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

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;

 

 

  }


Keywords:STM32 Reference address:STM32 serial port idle interrupt receives indefinite length data

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

Introduction to STM32 SPI library functions
First, for some basic introduction to SPI, refer to the library functions or user manuals of related chips. The following introduces the basic usage of SPI library functions and the definition of parameters. 1.The function of SPI_DeInit is to reset the peripheral SPIx register to the default value. The input paramet
[Microcontroller]
STM32 library function development project template
After reading a lot of information and writing a lot of programs myself, I found that although they are all developed with library functions, the organization of files is different. For example, some people like to have OBJ, while others use LISTING. So which one is better? The organization of files is really a headac
[Microcontroller]
OV7740 STM32 source code
/* Includes ------------------------------------------------------------------*/   #include "stm32f10x.h"   #include "stm32f10x_exti.h"   #include "OV7740.h"   #include "OV7740Reg.h"   #include "sccb.h"   #include "misc.h"   #include "delay.h"   /* Private define ----------------------------------------------
[Microcontroller]
STM32 Learning Notes-TIM3 Overflow Timing
TIM3 is a general-purpose timer. The program uses the APB1 clock (PCLK1), 72MHz. In the program, TIM3 overflows, that is, overflows when 0-ARR. The frequency of TIM3 in the above program is (PCLK1*2)/(36000-1+1)=2KHz, where PCLK1 is 36MHz, so counting 2000 times is 1s. Steps to use timer timing: 1
[Microcontroller]
DMA demo for STM32, USART
#include "stm32f10x_lib.h" #include "stdio.h" #define USART1_DR_Base 0x40013804 #define SENDBUFF_SIZE 10240 vu8 SendBuff ; vu8 RecvBuff ; vu8 recv_ptr; void RCC_Configuration(void); void GPIO_Confi guration(void); void NVIC_Configuration(void); void DMA_Configuration(void); void USART1_Configuration(void); int fput
[Microcontroller]
STM32-PWM output summary
          After learning, I found that the timer function of stm32 is really powerful. A small summary is convenient for reference in the future. Stm32 timers are divided into three types: tim1 and tim8 are advanced timers, 6 and 7 are basic timers, and 2-5 are general timers. The main functional differences can be see
[Microcontroller]
Serial port pins in stm32
USART1_CK ------ PA8 USART1_TX ------  PA9 USART1_RX ----- PA10 USART1_CTS ----- PA11 USART1_RTS ----- PA12  USART2_CTS ----- PA0 USART2_RTS ----- PA1 USART2_TX   ----- PA2 USART2_RX   ----- PA3 USART2_CK  ----- PA4 USART3_TX   ----- PB10 USART3_RX  -----  PB11 USART3_CK -----  PB12 USART3_CTS ----- PB
[Microcontroller]
STM32 DMA buffersize meaning and setting
in conclusion: My understanding is that multiple data is transmitted at a time, no matter your data is 8 bits, 16 bits or 32 bits, which is equivalent to the amount of data buffered in the receiving data part. buf is this bufe_size. 1. Look at the library function DMAy_Channelx- CNDTR = DMA_InitStruct- DMA_
[Microcontroller]
Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号