前言:

stm32是嵌入式MCU开发中最多应用的芯片,很早之前我们开发ST芯一般都是标准库开发,标准库简洁好读,现在要配合CubeMX生成代码,所以官方主推HAL库和LL库,但是HAL代码冗杂很绕,因为出来也不久,有些代码使用之后不是那么好用。

这次我就来分享两个实际使用过程中遇到的两个问题,一个是使用uart的发送中断进行数据发送产生的数组访问越界的问题。一个是stop模式下,dma相关的外设休眠唤醒需要注意重新初始化。

这篇是uart使用的介绍:

作者:良知犹存

转载授权以及围观:欢迎关注微信公众号:羽林君

或者添加作者个人微信:become_me


情节介绍:

串口是我们经常是用的一个外设,一般我们为了发送速度变快,会使用DMA或者中断发送接收。而CubeMX配置下,HAL调用了自己的一套函数 HAL_UART_IRQHandler 层层调用。

在官方提供的 stm32f4xx_hal_uart.c 文件中你可以看到如下函数:

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

{

.....

  /* UART in mode Transmitter ------------------------------------------------*/
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
UART_Transmit_IT(huart);
return;
} ...... }

其中在UART_Transmit_IT 函数中 有一段 函数为

if (--huart->TxXferCount == 0U)
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_TXE); /* Enable the UART Transmit Complete Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TC);
}

这里会把发送的 TxXferCount 的计数值自减,并判断是否为零。正常工作都没有问题,可是我们的设备实际使用过程中,上层的部分断电之后,会给底层通讯串口带了一个中断,这个时候继续减下去就会出现出现一个很大值,这个是因为 TxXferCount 是一个无符号的16位数据。

  __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter */

debug看到如下数据,原因上文提到。就是我遇到我们Linux核心板掉电之后会产生一个中断,导致这里判断时候自动减一,TxXferCount从 0 变成 -1 因为是无符号数据,所以数据表现为65535。

在全局搜索TxXferCount调用,我们可以看到TxXferSize 是发送buf的长度数据

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
/* 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->pTxBuffPtr = pData;
huart->TxXferSize = Size;
huart->TxXferCount = Size; huart->ErrorCode = HAL_UART_ERROR_NONE;
huart->gState = HAL_UART_STATE_BUSY_TX; /* Process Unlocked */
__HAL_UNLOCK(huart); /* Enable the UART Transmit data register empty Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TXE); return HAL_OK;
}
else
{
return HAL_BUSY;
}
}

此外我们还会发现一处 huart->TxXferCount 计数 自减 使用。

此处的函数如下, 伴随着一个很大的 TxXferCount开始自减, pdata16bits开始自加。刚开始越界的时候由于该内存被初始化过,所以没有问题,该循环执行一会之后,程序就会进入hardfault

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
{
...... huart->TxXferSize = Size;
huart->TxXferCount = Size; while (huart->TxXferCount > 0U)
{
if (UART_WaitOnFlagUntilTimeout(huart, UART_FLAG_TXE, RESET, tickstart, Timeout) != HAL_OK)
{
return HAL_TIMEOUT;
}
if (pdata8bits == NULL)
{
huart->Instance->DR = (uint16_t)(*pdata16bits & 0x01FFU);
pdata16bits++;
}
else
{
huart->Instance->DR = (uint8_t)(*pdata8bits & 0xFFU);
pdata8bits++;
}
huart->TxXferCount--;
}
......
}

修改建议:

和硬件沟通过,他们的掉电机制,就是如此无法修改。所以我们进行软件的一些修改,因为会产生一个中断导致计数值自减,所以我们初步确认进行自减处进行限制,先增加一个零值判断。

huart->TxXferCount == 0U

又考虑到我们单包数据单次不会超过150byte,所以又加上150字节的控制。(此处的数据流控制大家可以按照自己实际使用的情况进行酌情使用)

huart->TxXferCount   > 150U

原函数:

static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
......
if (--huart->TxXferCount == 0U)
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_TXE); /* Enable the UART Transmit Complete Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TC);
}
......
}

改为:

static HAL_StatusTypeDef UART_Transmit_IT(UART_HandleTypeDef *huart)
{
......
if (huart->TxXferCount == 0U || --huart->TxXferCount == 0U || huart->TxXferCount > 150U )
{
/* Disable the UART Transmit Complete Interrupt */
__HAL_UART_DISABLE_IT(huart, UART_IT_TXE); /* Enable the UART Transmit Complete Interrupt */
__HAL_UART_ENABLE_IT(huart, UART_IT_TC);
}
......
}

最后代码可以正常的使用。

结语

这就是我分享的项目中遇到一个st官方库使用的问题,如果大家有更好的想法和需求,也欢迎大家加我好友交流分享哈。


作者:良知犹存,白天努力工作,晚上原创公号号主。公众号内容除了技术还有些人生感悟,一个认真输出内容的职场老司机,也是一个技术之外丰富生活的人,摄影、音乐 and 篮球。关注我,与我一起同行。

                              ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

推荐阅读

【1】C++的智能指针你了解吗?

【2】嵌入式底层开发的软件框架简述

【3】CPU中的程序是怎么运行起来的 必读

【4】cartographer环境建立以及建图测试

【5】设计模式之简单工厂模式、工厂模式、抽象工厂模式的对比

本公众号全部原创干货已整理成一个目录,回复[ 资源 ]即可获得。

stm32-HAL使用usart发送中断判断发送标志库问题的更多相关文章

  1. A7139 无线通信驱动(STM32) 添加FIFO扩展模式,能够发送超大数据包

    A7139 拥有电磁波唤醒以及10mW的发射功率,很easy实现长距离通信,眼下測试有障碍物能够轻松达到300m以上. 通过几天的调试,眼下能够发送随意大小的数据包,大小为1-16KB.所有使用中断收 ...

  2. STM32学习笔记——USART

    STM32的USART组件支持异步.同步.单线半双工.多处理器.IrDA.LIN.SmartCard等模式,本文介绍的是异步即UART模式. 总线通信有三种模型:轮询.中断和DMA.DMA对我来说是陌 ...

  3. STM32 HAL库之串口详细篇

    一.基础认识 (一) 并行通信 原理:数据的各个位同时传输 优点:速度快 缺点:占用引脚资源多,通常工作时有多条数据线进行数据传输 8bit数据传输典型连接图: 传输的数据是二进制:11101010, ...

  4. STM32 HAL库与标准库的区别_浅谈句柄、MSP函数、Callback函数

    最近笔者开始学习STM32的HAL库,由于以前一直用标准库进行开发,于是发现了HAL库几点好玩的地方,在此分享. 1.句柄在STM32的标准库中,假设我们要初始化一个外设(这里以USART为例)我们首 ...

  5. STM32学习笔记——USART串口

    转载自:http://www.cnblogs.com/microxiami/p/3752715.html 一.USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异 ...

  6. STM32学习笔记——USART串口(向原子哥和火哥学习)

    一.USART简介 通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换.USART利用分数波特率发生器提供宽范围的波特率选择. S ...

  7. stm32 hal库串口通信资料汇集

    串口的发送接收函数:HAL_UART_Transmit();串口轮询模式发送,使用超时管理机制.HAL_UART_Receive();串口轮询模式发送,使用超时管理机制.HAL_UART_Transm ...

  8. 【有趣的全彩LED | 编程】用STM32 HAL库让WS2812B为你所动

    一.效果展示 观看演示效果:https://www.bilibili.com/video/BV1dv411Y7x3 使用STM32 HAL库编程 PWM+DMA控制输出,CubeMX生成初始工程 实现 ...

  9. 【情人节选帽子】TCS34725颜色传感器和Python图形界面编程(STM32 HAL库)

    截图 描述: l  STM32 HAL库编程 l  使用模拟IIC通信,方便程序移植 l  Python界面编写,蘑菇头的帽子是什么颜色 l  STM32 HAL库串口通信 l  Python界面使用 ...

随机推荐

  1. PipedInputStream and PipedOutputStream example

    必须要有PipedInputStream ,PipedOutputStream 在不同线程,不然死锁 Java.io.PipedOutputStream and java.io.PipedInputS ...

  2. vue中的v-cloak指令

    v-cloak不需要表达式,它会在vue实例结束编译时从绑定的html元素上移除,经常和display:none;配合使用: <div id="app" v-cloak> ...

  3. 小程序生成商品分享二维码海报解决方案和实现方式JAVA

    使用技术:  Graphics , 七牛云 , 微信sdk(github上非常出名的wxjava,地址https://github.com/Wechat-Group/WxJava/)直接上干货代码,每 ...

  4. VS2017 提示找不到某个.dll库,或某个dll库丢失,原因

    可能因为那个dll的确不存在 可能因为需要在环境变量->系统环境变量->添加该dll所在目录

  5. JDK1.8源码阅读笔记(1)Object类

    JDK1.8源码阅读笔记(1)Object类 ​ Object 类属于 java.lang 包,此包下的所有类在使⽤时⽆需⼿动导⼊,系统会在程序编译期间⾃动 导⼊.Object 类是所有类的基类,当⼀ ...

  6. JS_DOM操作之查找标签

    1 - 直接查找标签 // 方式1:获取元素 document.getElementsByTagName("标签名") document.getElementById(" ...

  7. Django图片上传和前端展示

    1 - 模型 class Book(models.Model): #定义图书模型 book_name = models.CharField(max_length=100,verbose_name='书 ...

  8. adb 常用命令大全(2)- 基础命令

    adb 基本语法 adb [-d|-e|-s <serialNumber>] <command> 命令行参数 -d:指定当前唯一通过 USB 连接的 Android 设备为命令 ...

  9. element-ui 弹出组件的遮罩层在弹出层dialog模态框的上面

     造成的原因: 因为dialog的组件外层div设置了 position:absolute: 属性所以导致遮罩层会在最上面. 解决方法: 在属性内加上这段代码 :append-to-body=&quo ...

  10. golang sync.noCopy 类型 —— 初探 copylocks 与 empty struct

    问题引入 学习golang(v1.16)的 WaitGroup 代码时,看到了一处奇怪的用法,见下方类型定义: type WaitGroup struct { noCopy noCopy ... } ...