企业内部网站制作模板,莱芜房产网站,业务系统管理软件,wordpress 下载文件插件问题#xff1a;
最近发现#xff0c;stm32cubemx最新版本f1系列的hal库#xff08;1.85版本#xff09;生成的hal库#xff0c;其中stm32f1xx_hal_uart.c的库文件中#xff0c;其串口发送接收存在一些问题#xff1a;
1.没有使用 __HAL_LOCK 和 __HAL_UNLOCK 宏…问题
最近发现stm32cubemx最新版本f1系列的hal库1.85版本生成的hal库其中stm32f1xx_hal_uart.c的库文件中其串口发送接收存在一些问题
1.没有使用 __HAL_LOCK 和 __HAL_UNLOCK 宏锁机制。
2.pdata8bits 和 pdata16bits 未初始化为 NULL可能会导致未定义行为。
3.在遇到超时错误时没有恢复 huart-RxState 状态。
这样子会出现什么问题呢
1.串口中断进不去主机发送消息从机无回应
2.轮询模式下打开串口其会不断给电脑串口发信息直到几千几万条后溢出。
也有可能是我没理解到位如果知道原因的大佬可以在评论区给点意见
解决方法
我将stm32cubemx的hal库版本进行了修改改成了1.81版本进行通信实验成功。
步骤如下
1.点击库管理 2.找到自己芯片库 如果你是1.85版本如果前面框为绿色选中然后下面点击移除就行。 点击1.81版本进行安装。下图2框取消勾选3框选择1.81。 其他配置和上篇文章一致
STM32-hal库学习4--usart/uart通信 单向通信同时显示在oled-CSDN博客 1.轮询模式
什么是轮询模式
轮询模式利用阻塞模式收发数据 HAL_UART_Transmit()串口发送数据使用超时管理机制 HAL_UART_Receive() 串口接收数据使用超时管理机制 其用于在没有中断机制或DMA机制的情况下主动等待并处理外设的状态变化。在轮询模式下CPU不断地检查外设的状态寄存器以确定是否有数据可供处理。这种方式简单易用但效率较低因为CPU在等待期间不能处理其他任务。
程序
main.c中加入
#include stdio.h
uint8_t RxDate[256];
因为oled函数里面没有显示hex类型函数所以编写oled.c的hex显示函数
void OLED_ShowHexArray(uint8_t x, uint8_t y, uint8_t *numArray, uint8_t Length, uint8_t size2, uint8_t Color_Turn)
{uint8_t i;uint8_t highNibble, lowNibble;for (i 0; i Length; i){highNibble (numArray[i] 4) 0x0F;lowNibble numArray[i] 0x0F;// 显示高半字节if (highNibble 10){OLED_ShowChar(x (size2 / 2) * (2 * i), y, highNibble 0, size2, Color_Turn);}else{OLED_ShowChar(x (size2 / 2) * (2 * i), y, highNibble - 10 A, size2, Color_Turn);}// 显示低半字节if (lowNibble 10){OLED_ShowChar(x (size2 / 2) * (2 * i 1), y, lowNibble 0, size2, Color_Turn);}else{OLED_ShowChar(x (size2 / 2) * (2 * i 1), y, lowNibble - 10 A, size2, Color_Turn);}}
}
在oled.h加入
void OLED_ShowHexArray(uint8_t x, uint8_t y, uint8_t *numArray, uint8_t Length, uint8_t size2, uint8_t Color_Turn);
在main.c实现轮询
#include string.h
#include stdio.h
uint8_t RxDate[256];
unsigned int num 0;
while(1)加入
switch(HAL_UART_Receive(huart1, RxDate, 200, 1)){case HAL_OK:HAL_Delay(1);HAL_UART_Transmit(huart1, RxDate, 200, 1);break;case HAL_TIMEOUT:if (huart1.RxXferCount ! 200-1){HAL_UART_Transmit(huart1, RxDate, 200-1 - huart1.RxXferCount, 1);}else{HAL_Delay(1);}break;case HAL_ERROR:// 错误处理逻辑可以根据需要添加// 例如重置 UART 或重新初始化huart1.RxState HAL_UART_STATE_READY;__HAL_UNLOCK(huart1);break;case HAL_BUSY:// 处理 UART 忙碌状态的逻辑// 可以选择等待一段时间再重试HAL_Delay(1);break;default:break;}OLED_ShowHexArray(48, 4, RxDate,1, 16, 0); // len 设置为 8具体根据显示需求调整}
代码解释HAL_UART_Receive接收huart1句柄的数据RxDate长度为200等待时间为0xffff也就是1。若接收完毕返回HAL_OK则发送数据回电脑。
测试 2.中断模式 USART的中断模式是一种数据传输方式在这种模式下当特定事件如接收到一个字符或发送完一个字符发生时会触发中断请求中断服务程序ISR负责处理这些事件。使用中断模式可以提高系统效率因为在等待数据的过程中CPU可以执行其他任务而不需要不断轮询USART状态。
.中断模式收发数据 HAL_UART_Transmit_IT()串口中断模式发送 HAL_UART_Receive_IT() 串口中断模式接收
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);这个函数的目的是启动UART传输并以非阻塞的方式发送一定数量的数据。
参数说明中断方式的收发函数只有三个参数 第一个参数是要使用的串口句柄地址 第二个参数是发送缓冲区的首地址用于存放要发送的数据 第三个参数是发送缓冲区长度
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);参数说明与发送函数类似只是把第二个和第三个参数变为了接收缓冲区 程序
main.c加入
uint8_t TxDate[64], RxDate[64];
uint8_t rxstate;
int main加入
HAL_UART_Receive_IT(huart1,RxDate,1);接收中断函数我这里将长度设为了1表示接收到一个字节便接收完毕返回一个字节比如0x11 是一个十六进制数表示的是一个字节8位数据。在计算机系统中十六进制数 0x11 对应的二进制数是 00010001占用一个字节的存储空间。因此0x11 占用1个字节。
while1加入
if(rxstate 1)
{rxstate 0;HAL_UART_Transmit_IT(huart1,TxDate,1);
}
当接收标志位为1则表示接收完成如果标志位为1便发送数据
最下面加上
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{if(huart-Instance USART1){memcpy(TxDate,RxDate,1);rxstate 1;HAL_UART_Receive_IT(huart1,RxDate,1);}
}
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{if(huart-Instance USART1){}
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{if(huart-Instance USART1){}
memcpy(TxDate, RxDate, 1);将接收到的一个字节的数据从 RxDate 复制到 TxDate。这里假设 RxDate 是接收缓冲区TxDate 是发送缓冲区。memcpy 函数用于内存拷贝将 RxDate 中的一个字节数据复制到 TxDate 中。拷贝完成标志位变成1
测试 3.DMA模式
什么是dma模式 DMADirect Memory Access直接内存访问是一种计算机系统中用于数据传输的机制。它允许数据在外设和内存之间直接传输而不需要CPU的介入从而减轻了CPU的负担提高了数据传输的效率。
举个例子 想象一下我们搬家的场景你要把家里的一些东西从旧房子搬到新房子。在传统的情况下你可能要亲自搬每一箱东西把它们从旧房子搬到新房子。这就相当于CPU传统地处理数据传输的方式。 现在有一支搬家队他们专门负责搬家。你只需要告诉他们从哪里搬搬到哪里然后他们就会自己完成这项任务。而你可以利用这段时间去做其他事情不需要亲自动手。这就有点类似于DMA的工作原理。 在计算机中CPU通常会处理数据的传输工作就像你亲自搬家一样。但有了DMA就好比有了一支专门负责数据传输的队伍。CPU只需要告诉DMA从哪里搬搬到哪里然后就可以去处理其他任务了。DMA负责在外设和内存之间直接传输数据而不需要CPU一直参与。 简而言之DMA就像是一支搬家队伍负责在不需要CPU亲自操劳的情况下完成数据传输任务从而提高了系统的效率。
DMA模式的优势
效率高DMA能够以较高的效率传输数据因为传输过程不需要经过CPU。释放CPU资源在数据传输过程中CPU可以执行其他任务避免了CPU因数据传输而被阻塞。传输速度快由于DMA控制器专门用于数据传输其速度通常比通过CPU进行传输要快。
DMA模式的工作原理
配置DMA控制器在使用DMA模式之前需要配置DMA控制器包括源地址、目的地址、传输数据的大小等。启动DMA传输配置完成后启动DMA传输。DMA控制器将接管数据传输任务。传输完成中断在传输完成后DMA控制器会生成一个中断通知CPU传输已经完成。
DMA发送函数
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);参数类型和中断模式发送函数相同
DMA接收函数
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);参数类型和中断模式接收函数相同
HAL_UART_Transmit_DMA();串口DMA模式发送
HAL_UART_Transmit_DMA();串口DMA模式接收
HAL_UART_DMAPause() 暂停串口DMA
HAL_UART_DMAResume();恢复串口DMA
HAL_UART_DMAStop(); 结束串口DMA 因为比较多关于代码部分在日后文章中将具体写一下