Teach you by hand to realize the programming and debugging of MODBUS slave through HAL Library - the improvement of serial port and timing function

Keywords: C Single-Chip Microcomputer stm32

catalogue

1.STM32CubeMX operation

  2. Program perfection

2.1 perfect usart.h

  2.2 improve usart.c

2.2.1 header file improvement

2.2.2 add callback function

2.2.3 serial port initialization function

2.3 perfect tim.h

2.4 improve tim.c

2.4.1 improve header file

  2.4.2 improve callback function and initialization function

2.5 improve main.c

2.6 commissioning

2.6.1 setting of Keil

  2.6.2 program download and debugging

  1.STM32CubeMX operation

This section was in the previous article, and the link is as follows:

Teach you by hand to realize the programming and debugging of MODBUS slave through HAL Library (I) -- STM32CubeMX operation_ Tangxinyu's blog - CSDN blog

  2. Program perfection

2.1 perfect usart.h

In order to ensure that the programs we added will not be deleted when updating STM32CubeMX. When we improve the procedure, we need to add the procedure to the formulated position. For example, in usart.h, we will add programs to:

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

First, define a UART_BUF structure, which contains the received buffer data and size, as well as the size of the transmitted data set.

Then define a serial port initialization function E_USART_INIT to define UART_BUF is initialized. Define a serial port interrupt callback function HAL_UART_RxCpltCallback.

/* USER CODE BEGIN Private defines */
typedef struct
{
	uint8_t *rx_buf;		//Receive buffer array
	uint16_t rx_buf_cnt;	//Receive buffer count value
	uint16_t rx_size;		//Received data size
	uint8_t rx_flag;		//Receive completion flag bit
	
	uint8_t *tx_buf;		//Send buffer array
	uint16_t tx_buf_cnt;	//Send buffer count value
	uint16_t tx_size;		//Actual sent data size
}UART_BUF;					//Serial port structure

extern UART_BUF uart4;		//Serial port structure entity
/* USER CODE END Private defines */

void MX_UART4_Init(void);

/* USER CODE BEGIN Prototypes */
void E_USART_INIT(UART_HandleTypeDef *huart);
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

/* USER CODE END Prototypes */

  2.2 improve usart.c

2.2.1 header file improvement

Add a perfect program between / * USER CODE BEGIN 0 * / and / * USER CODE END 0 * /

/* USER CODE BEGIN 0 */
#include "string.h"
#include "tim.h"
#define UART4_RXSIZE 	 one thousand and twenty-four 	// Maximum value of received data in one frame
#define UART4_TXSIZE 	 one thousand and twenty-four 	// Maximum value of transmitted data in one frame

uint8_t uart4_rx_buf[UART4_RXSIZE];	//Send data buffer array
uint8_t uart4_tx_buf[UART4_TXSIZE];	//Receive data buffer data

UART_BUF uart4;			//Serial port structure entity
uint8_t RxBuffer;		//Receive data intermediate variable
/* USER CODE END 0 */

2.2.2 add callback function

Add callback function Hal in / * USER CODE BEGIN 1 * / and / * USER CODE END 1 * /_ UART_ RxCpltCallback.

The basic principle is to call the callback function (RxBuffer) after receiving a data, and then assign the data to rx_buf this array, then clear the count of the timer and restart the count to prevent the timer from interrupting.

/*****************************Rewrite the callback function to receive serial data**********************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(huart->Instance == UART4)
	{
		if(uart4.rx_buf_cnt >= UART4_RXSIZE-1)	//Received data volume exceeds the limit, error
		{
			uart4.rx_buf_cnt = 0;
			memset(uart4.rx_buf, 0x00, sizeof(uart4.rx_buf));
			HAL_UART_Transmit(huart, (uint8_t *)"data overflow ", 10, 0xFFFF);		
		}
		else									//Normal reception
		{
			uart4.rx_buf[uart4.rx_buf_cnt++] = RxBuffer;	//Store received data in rx_buf
			HAL_TIM_Base_Stop_IT(&htim7);
			__HAL_TIM_SET_COUNTER(&htim7, 0);
			HAL_TIM_Base_Start_IT(&htim7);		//Reset the count value of timer 7 and count again
		}
		HAL_UART_Receive_IT(huart, (uint8_t *)&RxBuffer, 1);
	}
}

2.2.3 serial port initialization function

Add serial port parameter initialization function E under the callback function_ USART_ INIT

/*****************************For UART_ Entity uart4 assignment of buf structure**********************/
void E_USART_INIT(UART_HandleTypeDef *huart)
{
	if(huart->Instance == UART4)
	{
		uart4.rx_buf = uart4_rx_buf;	//Receive data variable initialization
		uart4.rx_buf_cnt = 0;
		uart4.rx_size = 0;
		uart4.rx_flag = 0;
		
		uart4.tx_buf = uart4_rx_buf;	//Send data variable initialization
		uart4.tx_buf_cnt = UART4_TXSIZE;
		uart4.tx_size = 0;		
		
		HAL_UART_Receive_IT(huart, uart4.rx_buf, 1);	//Enable receive interrupt
	}

}

The last sentence in the initialization process is to start the interrupt and let each received data enter the callback function.

2.3 perfect tim.h

Add the function declaration in tim.c, and add between / * USER CODE BEGIN Prototypes * / and / * USER CODE END Prototypes * /:

/* USER CODE BEGIN Prototypes */
void E_TIM_INIT(TIM_HandleTypeDef *htim);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
/* USER CODE END Prototypes */

2.4 improve tim.c

2.4.1 improve header file

Add a function reference to the header file

/* USER CODE BEGIN 0 */
#include "usart.h"
/* USER CODE END 0 */

  2.4.2 improve callback function and initialization function

Add time callback function and time initialization function inside / * USER CODE BEGIN 1 * / and / * USER CODE END 1 * /. The specific meaning has been explained in the notes and will not be repeated here.

/* USER CODE BEGIN 1 */
/*****************************Override time callback function**********************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim == &htim7)
	{
		__HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE);	//The generated interrupt proves that no data has been received for more than 4ms, and the reception of one frame is completed
		HAL_TIM_Base_Stop_IT(&htim7);		//After the interrupt, stop the timer and start the next time the data is received
		uart4.rx_size = uart4.rx_buf_cnt;	//Assign the number of received data
		uart4.rx_buf_cnt = 0;				//Clear
		uart4.rx_flag = 1;					//After receiving, set 1
	}

}

void E_TIM_INIT(TIM_HandleTypeDef *htim)
{
	if(htim == &htim7)
	{
		__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE);		//Add manually
		HAL_TIM_Base_Start_IT(htim);
	}

}

/* USER CODE END 1 */

2.5 improve main.c

The above functions are perfect to process the functions of data sending and receiving. Through the above processing, the data sending and receiving can be completed. Before transplanting MODBUS function, you can test whether data sending and receiving are normal. main.c here is to complete the data forwarding function, that is, forward what data is received.

First in   /* USER CODE BEGIN 2 * / and   /* USER CODE END 2 * / the initialization function of timer and serial port is added internally

  /* USER CODE BEGIN 2 */
	E_USART_INIT(&huart4);
	E_TIM_INIT(&htim7);
  /* USER CODE END 2 */

Then add a program in the while loop of the main function:

  while (1)
  {
    /* USER CODE END WHILE */
	  
    /* USER CODE BEGIN 3 */
	  // This is used to test what you receive and send.	  
	  if(uart4.rx_flag == 1)	//If a frame of data is received, it is set in the callback function of tim7
	  {
		HAL_UART_Transmit(&huart4, (uint8_t *)(uart4.rx_buf), uart4.rx_size, 500);//Forward received data outward
		while(__HAL_UART_GET_FLAG(&huart4,UART_FLAG_TC)!=SET);	//Dead cycle waiting
		uart4.rx_buf_cnt = 0;									//Count value reset
		uart4.rx_flag=0;										//The reception completion flag bit is cleared
	  }
	  
	  HAL_Delay(5);		//Cycle every 5ms
  }
  /* USER CODE END 3 */
}

2.6 commissioning

2.6.1 setting of Keil

In order to ensure the automatic reset operation after each program download, you need to set the debug of KEIL. The setting steps are as follows: Click √ in front of Reset and Run.

 

  2.6.2 program download and debugging

After compiling correctly, download the program to the circuit board, and then connect the UART4 serial port of the circuit board to the computer port. Open the serial port debugging assistant and configure it in the serial port debugging assistant according to the program.

After the configuration is completed, open the serial port to send and receive data.

 

 

 

Posted by Gazan on Wed, 03 Nov 2021 21:06:49 -0700