在STM32HAL库里定义很多状态变量,用于对各自外设模块的状态管理,比方ready,busy,idle,timeout,error等,以便正确使用各个外设,避免使用上的混乱。
以usart为例,库里为USART的发送、接收操作分别定义了两个状态变量,即gState和RxState。其中gState表示USART的发送状态,RxState表述接收时可能的状态。
是ready还是busy或其它出错、超时状态。USART初始化后gState为reddy状态,当要调用UART发送函数时软件将其设置为Busy.当usart完成发送或中止发送时,软件将gState设置回Ready。
如果说你调用的查询式发送函数,即HAL_UART_Transmit(),则在该函数里查询到数据发送完毕或发生超时都会将gState设置为Ready.
如果说你调用的是中断式发送函数,即HAL_UART_Transmit_IT(),同时你沿用CubeMx创建的中断服务程序代码框架,在相应的发送中断服务程序里检测到发送完毕时,也会将gState修改为ready为下次发送做准备。 如果说你调用API函数是HAL_UART_Transmit_IT(),而中断服务程序是另外组织的,要记得在发送完成时将gState改为Ready,不然下次调用HAL_UART_Transmit_IT()函数会因为gstate检查不通过而不能得以执行。
如果说你调用的是DMA方式发送函数,即HAL_UART_Transmit_DMA(),同样,也沿用CubeMx创建的中断服务程序代码框架,且开启了DMA完成中断和UART事件的中断,

在相应的DMA完成中断代码里也会适时地将gState从busy改为ready。如果说,你虽然调用了HAL_UART_Transmit_DMA()函数,但没有开启DMA完成中断,也没有在适当的位置将gState改为ready,这时就会发生即使你多次调用HAL_UART_Transmit_DMA()函数而只会做一次发送的情形。因为在后续的HAL_UART_Transmit_DMA()函数里做gState检查发现是busy而强行退出。当然,这时手动将其改为Ready也是可以的,但要保证合适的时间点。
比方,我就是不想开启DMA相关中断,只是想通过DMA方式发送几次字符串而已,像下面这样
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String1, sizeof(String1));
HAL_Delay(200);
huart2.gState = HAL_UART_STATE_READY;
huart2.hdmatx->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(huart2.hdmatx);
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String2, sizeof(String2));
HAL_Delay(200);
huart2.gState = HAL_UART_STATE_READY;
huart2.hdmatx->State = HAL_DMA_STATE_READY;
__HAL_UNLOCK(huart2.hdmatx);
当然,这里还有一种情况,尽管当我们基于中断或DMA方式调用UART发送,也开启了相关中断并沿用库函数的写法,还是可能出现只有第一次发送有效的
情况,比方像下面这样:
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String1, sizeof(String1));
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String2, sizeof(String2));
HAL_UART_Transmit_DMA(&huart2, (uint8_t *)String3, sizeof(String3));
这里的三次调用太近了,第一次调用时软件将gstate改为busy,当运行第二个第三个调用时,第一次的uart发送可能根本没有完成,自然也就没法
基于它的完成中断将gstate改为ready,这样导致后续的两次调用都无效了。所以像这种情况,第二次调用前要确保上次传输完成了。
2378