一、关键知识




九位数据一位校验位






二、串口实战


实验成功现象发送一次信息GPIO引脚翻转一次也就是小灯亮或者灭一次
STMCubemx配置

// uint8_t ARR[6]={'H','E','L','L','O'};
uint8_t ARR ;
// HAL_UART_Receive(&huart1,&ARR,1,100)
if(HAL_UART_Receive(&huart1,&ARR,1,100) == HAL_OK) //如果接受收到了信息
{
if(ARR == 0X01)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);//翻转GPIO引脚也就是小灯亮灭
HAL_UART_Transmit(&huart1,&ARR,1,100);//并且发送接收到的信息
}
// HAL_Delay(10);
}
被注释的代码为实验一的代码

三、串口接受中断



如果有多个传感器接收数据或者其他导致延时,上例延时1000ms时接收到18次但是只发送了6次,数据丢失了
!!!有没有方法将上述第一个if到延时函数给他独立出来不受延时函数的影响???--串口接受中断

增加中断
/* USER CODE BEGIN Includes */
uint8_t ARR = 0;// 定义接收缓存变量
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
HAL_UART_Receive_IT(&huart1, &ARR, 1);
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
// 串口接收完成中断回调函数(HAL库规范,接收完成后自动触发)
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 确认是USART1中断
{
if(ARR == 0X01)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
HAL_UART_Transmit(&huart1, &ARR, 1, 500); // 回传数据(此处非中断上下文,可短暂阻塞)
}
// 重新开启接收中断(HAL库中断为单次触发,需手动重启)
HAL_UART_Receive_IT(&huart1, &ARR, 1);
}
}
/* USER CODE END 4 */
HAL_UART_RxCpltCallback 是 STM32 HAL 库中串口接收完成中断的回调函数。
四、不定长度数据包



#define BUF_MAX_LEN 100 // 缓冲区最大长度
uint8_t buf[BUF_MAX_LEN] = {0}; // 接收缓冲区
uint8_t NUM = 0; // 缓冲区索引,初始化为0
uint8_t ARR = 0; // 单个字节接收缓存
/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 确认是USART1中断
{
if (NUM < BUF_MAX_LEN) {
buf[NUM] = ARR;
NUM++;
} else {
// 循环缓冲区:复位索引,覆盖旧数据(也可根据需求丢弃新数据)
NUM = 0;
buf[NUM] = ARR;
NUM++;
}
// 处理接收到的数据(非阻塞)
HAL_UART_Transmit_IT(&huart1, buf, 1); // 非阻塞回传
}
// 重启中断接收,实现下一次接收
HAL_UART_Receive_IT(&huart1, buf, 1);
}
/* USER CODE END 4 */

上述代码存在数据丢失?为什么
优化代码
// UART接收完成中断回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1) // 确认是USART1中断
{
uint8_t temp_arr = ARR; // 保存接收到的字节
// 存储到缓冲区
if (NUM < BUF_MAX_LEN) {
buf[NUM] = temp_arr;
NUM++;
} else {
// 循环缓冲区:复位索引,覆盖旧数据
NUM = 0;
buf[NUM] = temp_arr;
NUM = 1;
}
// 翻转LED指示收到数据
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8);
// 打印接收到的字符
printf("%c", temp_arr);
// ★★★ 关键:重新启动接收中断 ★★★
HAL_UART_Receive_IT(&huart1, &ARR, 1);
}
}
// 添加UART错误回调函数
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance == USART1)
{
// 清除错误标志
__HAL_UART_CLEAR_OREFLAG(huart);
// 重新启动接收
HAL_UART_Receive_IT(&huart1, &ARR, 1);
printf("\r\nUART Error Cleared!\r\n");
}
}
依旧会丢包1!!!!!!
这个代码添加重定向printf ,printf是向屏幕打印的,重定向之后printf可以面向串口,添加下面这个函数即可重定向printf
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}

注释:使用重定向时必须把这个勾上
遇到问题:传输过程中数据丢失
注释:由于使用Cubemax生成的初始化代码所以与教程给出代码相差较大