完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本次遇到的问题是USART串口发送函数卡死程序,究其原因原来是串口发送函数中的发送空寄存器没有置位,且超时时间设置的太大导致程序死循环,直到发送超时退出。
在调用CUBE的串口发送函数时一定要注意写的方式。关于传送完毕,有人用如下方法等待传送完毕虽然方案可行 while(HAL_OK !=HAL_UART_Transmit(&huart2, transmit,len, timeout)); 这容易卡死,一般也不要这样写这是第一种情况,使用while有几个弊端,不仅程序写的难看 万一,HAL_UART_Transmit()返回的不是HAL_OK而是HAL_TIMEOUT,程序卡死在这里。 还有一种情况就是上边提到的超时时间太长导致程序短暂的卡死,下边简单介绍。 while(HAL_OK !=HAL_UART_Transmit(&huart2, transmit,len, timeout)); 这容易卡死,一般也不要这样写这是第一种情况,使用while有几个弊端,不仅程序写的难看 万一,HAL_UART_Transmit()返回的不是HAL_OK而是HAL_TIMEOUT,程序卡死在这里。 还有一种情况就是上边提到的超时时间太长导致程序短暂的卡死,下边简单介绍。 HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) { uint16_t *tmp; uint32_t tickstart = 0U; /* Check that a Tx process is not already ongoing */ if (huart->gState == HAL_UART_STATE_READY) { if ((pData == NULL) || (Size == 0U)) { return HAL_ERROR; } /* Process Locked */ __HAL_LOCK(huart); huart->ErrorCode = HAL_UART_ERROR_NONE; huart->gState = HAL_UART_STATE_BUSY_TX; /* Init tickstart for timeout managment*/ tickstart = HAL_GetTick(); //这里每次在发送前拿到systick中断中的计数值,作为计数的初值。 huart->TxXferSize = Size; huart->TxXferCount = Size; while (huart->TxXferCount > 0U) { //下边这个函数会去判断每一个字节是否发送 UART_FLAG_TXE,并进行超时判断。 if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK) { return HAL_TIMEOUT; } if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE)) { tmp = (uint16_t *) pData; huart->Instance->TDR = (*tmp & (uint16_t)0x01FFU); pData += 2U; } else { huart->Instance->TDR = (*pData++ & (uint8_t)0xFFU); } huart->TxXferCount--; } if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TC, RESET, tickstart, Timeout) != HAL_OK) { return HAL_TIMEOUT; } /* At end of Tx process, restore huart->gState to Ready */ huart->gState = HAL_UART_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(huart); return HAL_OK; } else { return HAL_BUSY; } } HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout) { /* Wait until flag is set */ while ((__HAL_UART_GET_FLAG(huart, Flag) ? SET : RESET) == Status)//在这里对发送空寄存器进行判断,如果为0,进行超时判断。 { /* Check for the Timeout */ if (Timeout != HAL_MAX_DELAY) { if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))//这里拿到SYSTICK的最新计数值减去传入的初值与超时时间进行比较,当大于超时时间时,退出。 { /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */ #if defined(USART_CR1_FIFOEN) CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE_RXFNEIE | USART_CR1_PEIE | USART_CR1_TXEIE_TXFNFIE)); #else CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE)); #endif CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE); huart->gState = HAL_UART_STATE_READY; huart->RxState = HAL_UART_STATE_READY; /* Process Unlocked */ __HAL_UNLOCK(huart); return HAL_TIMEOUT; } } } return HAL_OK; } USART的各个寄存器描述如下: WAKE:唤醒的方法 (Wakeup method) 0:被空闲总线唤醒; 1:被地址标记唤醒。 PCE:检验控制使能 (Parity control enable) PS:校验选择 (Parity selection) 0:偶校验;1:奇校验。 PEIE:PE中断使能 (PE interrupt enable) TXEIE:发送缓冲区空中断使能 (TXE interrupt enable) TCIE:发送完成中断使能 (Transmission complete interrupt enable) RXNEIE:接收缓冲区非空中断使能 (RXNE interrupt enable) IDLEIE:IDLE中断使能 (IDLE interrupt enable) 0:禁止产生中断; 1:当USART_SR中的IDLE为’1’时,产生USART中断。 TE:发送使能 (Transmitter enable) RE:接收使能 (Receiver enable) RWU:接收唤醒 (Receiver wakeup) 0:接收器处于正常工作模式; 1:接收器处于静默模式。 TXE:发送数据寄存器空 (Transmit data register empty) 当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。如果USART_CR1寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。 0:数据还没有被转移到移位寄存器; 1:数据已经被转移到移位寄存器。 TC:发送完成 (Transmission complete) 当包含有数据的一帧发送完成后,并且TXE=1时,由硬件将该位置’1’。如果USART_CR1中的TCIE为’1’,则产生中断。由软件序列清除该位(先读USART_SR,然后写入USART_DR)。TC位也可以通过写入’0’来清除,只有在多缓存通讯中才推荐这种清除程序。在我遇到的问题中改发送空标志位没有置位,并且我的超时时间又设置的比较大,导致一直等待知道超时退出为止,所以合理的设置超时时间可以有效的保证硬件没有及时置位(或者芯片抽风了硬件未能自动置位)程序超时退出,不至于等太久。 HAL_UART_Transmit(UART_HandleTypeDef huart, uint8_t pData, uint16_t Size, uint32_t Timeout) 这个Timeout是按照毫秒级的,就是ms 因为timeout = HAL_GetTick() + Timeout;HAL_GetTick()是毫秒级的....所以当传输一个字节的数据的时候超时时间可以设定为传输时间,当你波特率是9600 bit/s的时候,那么一秒能传输9600位数据,8位数据一个字节,这样1s就传输了1200字节,即1200byte,那么一个字节传输的时间就是1000ms/1200byte=0.84ms,于是当在波特率为9600传输一个字节的数据的时候超时时间可以设定为1ms,写作:HAL_UART_Transmit (&huart6 ,(uint8_t *)&ucByte,1,0x01);,那么当你波特率是115200的时候,传输一个字节的超时时间理论是大于0.0695ms也即最小1ms,写作:HAL_UART_Transmit (&huart6 ,(uint8_t *)&ucByte,1,0x01);,同理要是传输10个字节,传输时间乘以10,就是0x0A了,那么这个时间要根据发送的数据量进行调整,个人经验设置为最大发送字节时间的2倍即可。 |
|
|
|
只有小组成员才能发言,加入小组>>
3253 浏览 9 评论
2933 浏览 16 评论
3435 浏览 1 评论
8936 浏览 16 评论
4027 浏览 18 评论
9663浏览 3评论
1060浏览 3评论
551浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
548浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2283浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-3 16:16 , Processed in 1.045996 second(s), Total 79, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号