目录
1.STM32CubeMX操作
2、程序完善
2.1完善usart.h
2.2完善usart.c
2.2.1头文件完善
2.2.2增加回调函数
2.2.3串口初始化函数
2.3完善tim.h
2.4完善tim.c
2.4.1完善头文件
2.4.2完善回调函数和初始化函数
2.5完善main.c
2.6调试
2.6.1KEIL的设置
2.6.2程序下载调试
此部分在上一个文章,链接如下:
手把手教你,通过HAL库实现MODBUS从机程序编写与调试(一)-----STM32CubeMX操作篇_tangxianyu的博客-CSDN博客
为了确保在更新STM32CubeMX的时候,我们自己增加的程序不会被删除掉。我们在完善程序的时候需要将程序增加到制定的位置。例如在usart.h内的,我们将需要增加的程序到:
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
首先定义一个UART_BUF结构体,里面包含接收的缓冲数据和大小,以及发送的数据集大小。
然后定义一个串口的初始化函数E_USART_INIT来对定义的UART_BUF进行初始化。定义一个串口中断回调函数HAL_UART_RxCpltCallback.
/* USER CODE BEGIN Private defines */
typedef struct
{
uint8_t *rx_buf; //接收缓冲数组
uint16_t rx_buf_cnt; //接收缓冲计数值
uint16_t rx_size; //接收数据大小
uint8_t rx_flag; //接收完成标志位
uint8_t *tx_buf; //发送缓冲数组
uint16_t tx_buf_cnt; //发送缓冲计数值
uint16_t tx_size; //实际发送数据大小
}UART_BUF; //串口结构体
extern UART_BUF uart4; //串口结构体实体
/* 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 */
在/*USER CODE BEGIN 0*/和/*USER CODE END 0*/中间添加完善程序
/* USER CODE BEGIN 0 */
#include "string.h"
#include "tim.h"
#define UART4_RXSIZE 1024 //一帧接收数据的最大值
#define UART4_TXSIZE 1024 //一帧发送数据的最大值
uint8_t uart4_rx_buf[UART4_RXSIZE]; //发送数据缓冲数组
uint8_t uart4_tx_buf[UART4_TXSIZE]; //接收数据缓冲数据
UART_BUF uart4; //串口结构体实体
uint8_t RxBuffer; //接收数据中间变量
/* USER CODE END 0 */
在/* USER CODE BEGIN 1 */和/* USER CODE END 1 */增加回调函数HAL_UART_RxCpltCallback。
基本原理为接收到一个数据调用回调函数(RxBuffer),然后将数据赋值给rx_buf这个数组,然后清除定时器的计数,重新开始计数,防止定时器产生中断。
/*****************************重写回调函数,实现串口数据接收**********************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == UART4)
{
if(uart4.rx_buf_cnt >= UART4_RXSIZE-1) //接收数据量超限,错误
{
uart4.rx_buf_cnt = 0;
memset(uart4.rx_buf, 0x00, sizeof(uart4.rx_buf));
HAL_UART_Transmit(huart, (uint8_t *)"数据溢出", 10, 0xFFFF);
}
else //接收正常
{
uart4.rx_buf[uart4.rx_buf_cnt++] = RxBuffer; //接收数据存储到rx_buf
HAL_TIM_Base_Stop_IT(&htim7);
__HAL_TIM_SET_COUNTER(&htim7, 0);
HAL_TIM_Base_Start_IT(&htim7); //将定时器7的计数值清零后重新计数
}
HAL_UART_Receive_IT(huart, (uint8_t *)&RxBuffer, 1);
}
}
在回调函数下方增加串口参数初始化函数E_USART_INIT
/*****************************对UART_BUF结构体的实体uart4赋值**********************/
void E_USART_INIT(UART_HandleTypeDef *huart)
{
if(huart->Instance == UART4)
{
uart4.rx_buf = uart4_rx_buf; //接收数据变量初始化
uart4.rx_buf_cnt = 0;
uart4.rx_size = 0;
uart4.rx_flag = 0;
uart4.tx_buf = uart4_rx_buf; //发送数据变量初始化
uart4.tx_buf_cnt = UART4_TXSIZE;
uart4.tx_size = 0;
HAL_UART_Receive_IT(huart, uart4.rx_buf, 1); //开启接收中断
}
}
在初始化过程中最后一句话是开启中断,让每接收一个数据进入一次回调函数。
增加在tim.c中的函数声明,在/* USER CODE BEGIN Prototypes */和/* 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 */
在头文件增加一个函数引用
/* USER CODE BEGIN 0 */
#include "usart.h"
/* USER CODE END 0 */
在/* USER CODE BEGIN 1 */和/* USER CODE END 1 */内部增加时间回调函数和时间初始化函数。具体含义已在注释内说明,此处不赘述。
/* USER CODE BEGIN 1 */
/*****************************重写时间回调函数**********************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim7)
{
__HAL_TIM_CLEAR_FLAG(&htim7, TIM_FLAG_UPDATE); //产生中断证明超过4ms没有接收到数据了,一帧接收完成
HAL_TIM_Base_Stop_IT(&htim7); //中断之后停止定时器,开启在下一次接收到数据开始
uart4.rx_size = uart4.rx_buf_cnt; //将接收到数据数量赋值
uart4.rx_buf_cnt = 0; //清零
uart4.rx_flag = 1; //接收完成,置1
}
}
void E_TIM_INIT(TIM_HandleTypeDef *htim)
{
if(htim == &htim7)
{
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_UPDATE); //手动添加
HAL_TIM_Base_Start_IT(htim);
}
}
/* USER CODE END 1 */
上面的函数完善都是为了处理数据发送和接收的函数,通过以上处理可以完成数据的发送和接受。在移植MODBUS函数之前可以对数据发送和接受是否正常进行测试。此处的main.c就是完成数据的转发功能,即接收到什么数据就向外转发什么数据。
首先在 /* USER CODE BEGIN 2 */和 /* USER CODE END 2 */内部增加定时器和串口的初始化函数
/* USER CODE BEGIN 2 */
E_USART_INIT(&huart4);
E_TIM_INIT(&htim7);
/* USER CODE END 2 */
然后再在主函数的while循环内增加程序:
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 此处是用来测试收啥发啥的。
if(uart4.rx_flag == 1) //如果一帧数据接收完成,其在tim7的回调函数置位
{
HAL_UART_Transmit(&huart4, (uint8_t *)(uart4.rx_buf), uart4.rx_size, 500);//向外转发收到的数据
while(__HAL_UART_GET_FLAG(&huart4,UART_FLAG_TC)!=SET); //死循环等待
uart4.rx_buf_cnt = 0; //计数值清零
uart4.rx_flag=0; //接收完成标志位清零
}
HAL_Delay(5); //每间隔5ms循环一次
}
/* USER CODE END 3 */
}
为了确保每次程序下载完成后后自动复位运行,需要对KEIL进行的debug进行设置,设置步骤如下:将Reset and Run前面的√点上。
编译无误后将程序下载到电路板中,然后将电路板的UART4的串口与电脑口相连。打开串口调试助手,按照程序在串口调试助手内进行相应配置。
配置完成之后,打开串口就可以进行数据发送接收了。