STM32串口卡死问题

news/2024/11/24 19:29:39/

本次遇到的问题是USART串口发送函数卡死程序,究其原因原来是串口发送函数中的发送空寄存器没有置位,且超时时间设置的太大导致程序死循环,直到发送超时退出。

在调用CUBE的串口发送函数时一定要注意写的方式。关于传送完毕,有人用如下方法等待传送完毕虽然方案可行
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));
#elseCLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE));
#endifCLEAR_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倍即可。


http://www.ppmy.cn/news/370660.html

相关文章

【啃】《Java核心卷 一》 | 第一,二章

文章目录 《Java核心技术卷 一》第一章 概述第二章 Java编程环境 图书推荐 《Java核心技术卷 一》 第一章 概述 前言:本书与一些”0基础入门“的书定位感觉是不太一样的,可能就像书名所说,是”核心技术“叭。书中经常将Java语言与 c 进行对比…

TypeScrip-03(接口和对象类型)

目录 interface 重名 、重合 任意属性 [propName: string] 可选 ? 操作符、 readonly 只读 interface 接口继承 interface 定义函数类型 在 ts 中,定义对象的方式要用关键字 interface(接口),我的理解是使用interface来定义…

读书笔记:《德鲁克管理思想精要》- 6

《德鲁克管理思想精要》 美 . 彼复 . 德鲁克 著 李维安 王世权 刘金岩 译 《The Essential Drucker》The Best of Sixty Years of Peter Druckers Essential Writings on Management - 18,19,20,21,22 - 发挥沟通作用 …

想了解会计软件吗?来看看Zoho Books的功能和特点

Zoho Books 是一款功能强大的在线会计软件,为企业提供多合一解决方案,该解决方案可定制、可扩展,并使始终保持合规。 轻松生成电子发票 在Zoho Books中,您可以通过包含电子发票架构中提到的所有必填字段来创建电子发票格式的发票。…

STM32中重映射的功能和机理

在STM32系列微控制器中,GPIO端口具有多种功能,如输入、输出、模拟输入/输出等。为了提高GPIO的灵活性和可用性,STM32系列微控制器提供了重映射(Remap)功能。 重映射功能允许将一个GPIO端口重新映射到另一个GPIO端口上…

SSR渲染-初识Nuxt-01

SSR服务端渲染 SSR服务端渲染:在后端将html页面处理好,前端直接展示(可以解决为后端给你传了一个html脚本,全段渲染) 为什么要有SSR服务端渲染? 可以解决单页面首屏加载慢的问题,同时有利于用…

大学物理(上)-期末知识点结合习题复习(5)——刚体力学-转动惯量、力矩、线密度 面密度 体密度、平行轴定理和垂直轴定理、角动量定理和角动量守恒定律

目录 刚体的定轴转动 题1 题目描述 题解 题2 题解 题3 题目描述 题解 题4 题目描述 题解 题5 题目描述 题解 角动量定理和角动量守恒定律 刚体的定轴转动 1.转动动能 由,得 表示质量 表示质量分布点 2.转动惯量 为刚体对给定轴的转动惯量&…

显卡维修之显存位置如何确认

众所周知,一般显卡花屏通常是由显存问题引起,也有可能是核心脱焊。这里主要说的是N卡,即NVIDIA显卡。 通过mats工具可以知道是哪一个位置上的显存出问题,如下图B0报错 知道显存出问题,那么就需要换显存,下…