STM32F412 串口接收不到数据的问题

发布者:春林初盛最新更新时间:2022-06-01 来源: eefocus关键字:STM32F412  串口接收  数据 手机看文章 扫描二维码
随时随地手机看文章

使用的是STM32F412RETx的芯片,板子是电子工程师做的

使用STM32CubeMX V5.2.1、Keil uVision5做开发,使用HAL库

使用过程中多次出现串口接收的问题,最后都解决了,这里记录一下

串口的HAL有3类API


// 同步堵塞收发
HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
// 异步中断传输
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
// 异步DMA传输(Direct Memory Access,DMA),不经过CPU,外设直接读写内存
HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);


我使用的是异步中断HAL_UART_Receive_IT的进行串口数据接收,这个需要用到

接收完成中断回调
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);
在中断回调中只进行数据的解析,不做过多其他处理,避免中断时间过长,中断中也不要使用延时函数,尽量不在中断中进行IO输出操作。


第一种串口接收问题:现象为开机后串口可以接收数据,一会儿后就一直没有数据了。

查看错误为:HAL_UART_Receive_IT返回HAL_BUSY

先说一下我的使用方法:使用HAL_UART_Receive_IT接收数据,需要在每次接收完成后,再次调用HAL_UART_Receive_IT函数,一般是在HAL_UART_RxCpltCallback函数的末尾再次HAL_UART_Receive_IT。

HAL_UART_Receive_IT有个状态返回值,可以自己看一下这个函数的实现,代码也就几十行

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
{
  /* Check that a Rx process is not already ongoing */
  if (huart->RxState == HAL_UART_STATE_READY)
  {
    if ((pData == NULL) || (Size == 0U))
    {
      return HAL_ERROR;
    }
 
    /* Process Locked */
    __HAL_LOCK(huart);
 
    huart->pRxBuffPtr = pData;
    huart->RxXferSize = Size;
    huart->RxXferCount = Size;
 
    huart->ErrorCode = HAL_UART_ERROR_NONE;
    huart->RxState = HAL_UART_STATE_BUSY_RX;
 
    /* Process Unlocked */
    __HAL_UNLOCK(huart);
 
    /* Enable the UART Parity Error Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_PE);
 
    /* Enable the UART Error Interrupt: (Frame error, noise error, overrun error) */
    __HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
 
    /* Enable the UART Data Register not empty Interrupt */
    __HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);
 
    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}


一般这个函数失败都是返回HAL_BUSY居多,这里有两种情况会返回HAL_BUSY

1. huart->RxState != HAL_UART_STATE_READY,串口没准备好或者串口正在接收数据中,如果时正在接收数据,意味着其他地方已经调用过HAL_UART_Receive_IT,直接忽略等待接收完成就好,而我知道只有在HAL_UART_RxCpltCallback有再次调用,所以其他地方调用不存在,而且失败时查看过状态huart->RxState 是等于 HAL_UART_STATE_READY


2. __HAL_LOCK(huart);加锁失败,锁被占用。

看一下__HAL_LOCK(__HANDLE__)的定义

#define __HAL_LOCK(__HANDLE__)                                          
                                do{                                        
                                    if((__HANDLE__)->Lock == HAL_LOCKED)  
                                    {                                      
                                       return HAL_BUSY;                    
                                    }                                      
                                    else                                  
                                    {                                      
                                       (__HANDLE__)->Lock = HAL_LOCKED;    
                                    }                                      
                                  }while (0U)
这里就判断了一次,如果锁被占用,直接返回,从我这边测试可以看到,一般都是因为锁被暂用然后返回了HAL_BUSY,那么就要看一下哪里占用了锁。


接收数据使用的是异步中断的函数HAL_UART_Receive_IT(),然而发送数据我使用的是同步堵塞的函数HAL_UART_Transmit(),可以自己看一下HAL_UART_Transmit()的实现,这里不列代码了,HAL_UART_Transmit()函数内从开始发送开始加锁,等待全部数据发送完成后才解锁,所以占用锁的时间是比较长的。而数据发送也比较多,所以基本判定是发送造成的加锁。


有两种方法可以解决发送造成的加锁问题:

1. 使用异步函数发送,这样占用锁时间就短,不过也有概率锁占用,可以选择重试几次可能就可以了

2. huart->RxState=HAL_UART_STATE_READY,且保证不存在多处代码同时发送,那么可以选择暴力解锁,我使用这种方案


下面确认一下被加锁的代码

加锁一般是因为要操作一下公用的数据。

下面我们分析一下串口UART_HandleTypeDef结构体

typedef struct __UART_HandleTypeDef
{
  USART_TypeDef                 *Instance;        /*!< UART registers base address        */
 
  UART_InitTypeDef              Init;             /*!< UART communication parameters      */
 
  uint8_t                       *pTxBuffPtr;      /*!< Pointer to UART Tx transfer Buffer */
 
  uint16_t                      TxXferSize;       /*!< UART Tx Transfer size              */
 
  __IO uint16_t                 TxXferCount;      /*!< UART Tx Transfer Counter           */
 
  uint8_t                       *pRxBuffPtr;      /*!< Pointer to UART Rx transfer Buffer */
 
  uint16_t                      RxXferSize;       /*!< UART Rx Transfer size              */
 
  __IO uint16_t                 RxXferCount;      /*!< UART Rx Transfer Counter           */
 
  DMA_HandleTypeDef             *hdmatx;          /*!< UART Tx DMA Handle parameters      */
 
  DMA_HandleTypeDef             *hdmarx;          /*!< UART Rx DMA Handle parameters      */
 
  HAL_LockTypeDef               Lock;             /*!< Locking object                     */
 
  __IO HAL_UART_StateTypeDef    gState;           /*!< UART state information related to global Handle management
                                                       and also related to Tx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */
 
  __IO HAL_UART_StateTypeDef    RxState;          /*!< UART state information related to Rx operations.
                                                       This parameter can be a value of @ref HAL_UART_StateTypeDef */
 
  __IO uint32_t                 ErrorCode;        /*!< UART Error code                    */
 
 
} UART_HandleTypeDef;
结合HAL_UART_Receive_IT()、HAL_UART_Transmit()两个函数,发现其实收发数据时使用的成员变量基本是分开的,

发送使用pTxBuffPtr、TxXferSize、TxXferCount、hdmatx、gState

接收使用pRxBuffPtr、RxXferSize、RxXferCount、hdmarx、RxState

共用部分:ErrorCode

gState也可能是公用的,不过暂时在函数HAL_UART_Receive_IT中没发现有使用gState

检查自己的代码,发现确实是HAL_UART_Transmit()造成的锁,既然基本上主要成员没有共用,那就暴力解锁

在判断接收状态为HAL_UART_STATE_READY时,且被加锁,直接暴力解锁
if(HAL_UART_STATE_READY == huart->RxState && HAL_LOCKED == huart->Lock)

      __HAL_UNLOCK(huart);      // 暴力解锁
}


至此由于加锁问题而造成的串口突然接收不到数据的问题暂时解决了,很暴力的方式

第一种串口接收问题:同样是上电后串口可以接收数据,接收一段时间后没数据了,

而且HAL_UART_Receive_IT()函数返回的是HAL_OK

检查了HAL_UART_GetError(),获取到错误HAL_UART_ERROR_ORE,应该是串口溢出的意思。


只是为什么溢出后就直接停止接收了?就算是丢包也不要给我直接停止工作了呀!!!删库后跑路了???


解决方法如下

既然知道报错,那就考虑清楚错误标志,特地也看了一下函数HAL_UART_IRQHandler(UART_HandleTypeDef *huart);内,的确是有错误标志的时候,不会调用接收完成回调

看了多篇文章,试了几种方法后终于找到一个清除错误标志有效的

使用__HAL_UART_CLEAR_OREFLAG(__HANDLE__)可以清空错误标志

[1] [2]
关键字:STM32F412  串口接收  数据 引用地址:STM32F412 串口接收不到数据的问题

上一篇:KEIL 配置STM32 SRAM启动,调试
下一篇:STM32F103_外部RAM用作运存

推荐阅读最新更新时间:2024-11-16 23:08

中富电路:生产的PCB有服务于华为的数据中心等应用领域
2月23日,中富电路在投资者互动平台表示,公司是华为技术有限公司的供应商,且生产的印制电路板(PCB)有服务于华为的数据中心、通信电源、逆变器、4G/5G天线、车载等应用领域。 据了解,中富电路是一家专业从事印刷电路板研发、生产和销售的高新技术企业。印制电路板的主要功能是使各种电子元件形成预定电路的连接,起到信号传输、电源供给等重要作用。中富电路生产的PCB产品包括单面板、双面板、多层板等。 同时,PCB行业是全球电子元件细分产业中产值占比最大的产业,随着研发的深入和技术的不断升级,PCB产品逐步向高密度、小孔径、大容量、轻薄化的方向发展。根据Prismark统计,2018年全球PCB产业总产值达623.96亿美元,同比增长6.0
[手机便携]
如何挖掘开发区的电力数据“宝藏”
华北电力大学(保定) 调研队员:宋志鹏 周登利 张志涛 江韩雪 朱金铭 曾剑峰 张继祖 指导老师:张梅梅 韩凤舞 01 调研背景概述 电力大数据是以业务趋势预测、数据价值挖掘为目标,利用数据集成管理、数据存储、数据计算、分析挖掘等方面的核心关键技术,实现面向典型业务场景的模式创新及应用提升 。电力数据与经济社会发展具有较大联动关系,当前学术界正在积极挖掘电力统计数据价值,从而更好地为企业与电力市场发展,乃至经济社会转型服务 。电力数据既能反映电力企业发展的脉络,也在很大程度上体现了经济社会发展和能源结构需求的变化,发挥着经济社会发展“晴雨表”的作用。 高新技术开发区是所有产业区的前沿,发挥领导带
[新能源]
电网企业的转型之路:让数据矿山变数据钢铁
前两天看到一组统计:目前国家电网数据总量达到约5PB级别,若用普通DVD光盘存储,叠加高度超过1500米,其中包括海量的报表、图片、音视频、日志、地理空间数据、时标量测数据等等。只看统计,电网企业积累的数据量已经足够大,就像一座待开发的矿山,但有了矿山不等于炼成了钢铁,对于志在转型的电网企业来说,无论是建设泛在电力物联网还是数字南网,只有大量数据还远远不够。想要最终完成转型,最关键的还是要激活这些数据,让矿山变钢铁,只有这样,才能真正发挥它的最大价值。 数据大不是大数据 对外业务有待探索 电网企业有大数据吗?乍听起来这似乎是个伪命题。一手监管发电,一手负责用电,连接发用两端,一直拥有垄断优势的电网企业,怎么可能没有
[新能源]
如何解决数据缺失问题?
一、概述 当处理数据时,常常会遇到缺失数据的情况。缺失数据可能由于各种原因引起,例如传感器故障、人为错误、数据采集问题等。对于数据分析和建模任务来说,缺失数据可能会导致结果不准确或无法进行有效分析。因此,重建缺失数据是数据预处理的重要步骤之一。 二、缺失数据的重建 缺失数据的重建是通过利用已有的数据信息来推断和填补缺失数据点。下面将介绍几种常见的缺失数据重建方法: 删除缺失数据:当缺失数据量较大或缺失数据对分析结果影响较大时,可以选择删除缺失数据所在的样本或特征。这种方法的优点是简单直接,但可能导致数据集的减少和信息损失。 (1)均值、中位数或众数填补:这是最简单的缺失数据重建方法之一。对于数值型数据,可以使用均值、中位数或其
[嵌入式]
如何解决<font color='red'>数据</font>缺失问题?
ST新款IC为谷歌下一代48V数据中心架构提供最高转换能效
48V电源架构的创新的可扩展、隔离型功率转换架构降低功耗、空间和成本 新系列的三款IC现已量产出货 中国,2016年3月31日 横跨多重电子应用领域、全球领先的半导体供应商意法半导体(STMicroelectronics,简称ST;纽约证券交易所代码:STM)日前发布新系列48V电源架构专用功率转换IC,三款新产品即日起批量出货。 为满足对性能需求越来越高的客户,服务器和处理器采用多核芯片提高计算能力,但是耗电量也随之水涨船高。意法半导体的下一代功率转换架构旨在于大幅降低数据中心服务器的耗电量,同时符合谷歌发布的新一代48V电源架构的技术要求。 意法半导体开发出一系列支持全部数据中心功率转换应用的IC
[电源管理]
ST新款IC为谷歌下一代48V<font color='red'>数据</font>中心架构提供最高转换能效
便携数据库管理系统的网络连接与安全
摘要:介绍掌上电脑无线网络配置,涉及PocketDBA应用程序的组成、Web裁剪技术、通信协议、无线网络连接的相关设备及其功能;PocketDBAw使用时安全设置,包括数据的机密性、完整性,对用户访问验证和许可、本地网络安全与防火墙设置。 关键词:掌上电脑 无线网络 PocketDBA Web裁剪技术 加密 数据完整性 防火墙 引言 计算技术和无线通信技术的发展与结合使得一种全新的计算模式——移动计算机模式成为现实。Internet为信息传递、数据交互提供了一种无处不在的便捷方法。移动计算(mobile computing)是使人们能够在任何时间和任何地点获得所需信息的技术和设备的总称。未来的网络将是一无线、有线与Inter
[嵌入式]
西部数据申请国际仲裁,与东芝正式撕破脸
集微网消息,西部数据表示,上周已向国际法院启动仲裁程序,要求东芝撤回合资业务独立为东芝半导体的决定,并停止未经西部数据旗下SanDisk同意的让售行为。 业界认为,此举等同与东芝正式撕破脸。 对此,东芝尚未有响应。 西部数据CEO Steve Milligan指出,透过法院强制仲裁,不是解决此事的第一选择,但公司至今用各种方法都徒劳无功,所以现在采许司法行动是必要的下一步。 Steve Milligan 表示,合资本质上是密切的商业关系,为了防止被强制与不合意的当事人形成关系,没有 SanDisk 的同意下,东芝不应试图将其合资企业的利益转移。 Steve Milligan 更表示,与东芝的合作,在过去 17 年来都非常成功,对整
[手机便携]
韩国Hynix开发出1GB手机芯片 明年开始量产
8月13日消息,据国外媒体报道,韩国海力士(Hynix)半导体公司周日宣布,公司已开发出了全球最快和最小的1GB手机芯片,Hynix打算在明年早些时候将新芯片投入量产。 全球第二大电脑内存芯片制造商称,新芯片每秒钟可处理1.6GB字节数据。 Hynix公司宣称,公司将在2008年早些时候开始量产芯片,这种新型手机芯片可用于“超小型电子设备和内存产品”。通过对下一代产品的积极投资,Hynix希望在十年内成为全球顶级芯片制造商。
[焦点新闻]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved