解决STM32G474单片机_HAL_UART_Transmit_IT()连续发送之问题

news2024/9/17 21:05:47

在使用STM32G474单片机的HAL库时,使用“在中断服务程序中发送数据”和“在中断程序中接收数据”,是一种很常用的方法,特别是RS485通讯中。首次使用,肯定会踩坑。要么出现第一个数据收不到,要么出现连续发送,要么发送象是乱码,总之怪象连篇,搜索网络,发现能解决问题的成功案例很少。

1、串口初始化

//将PA9复用为USART1_TX
//将PA10复用为USART1_RX

UART_HandleTypeDef HardwareUSART1;
uint8_t USART1_RX_Data;

uint8_t USART1_RX_Buffer[USART1_RX_Buffer_Size];
//USART1接收缓冲区数组
uint8_t USART1_RX_Buffer_Load_Index;
//USART1_RX_Buffer[]的装载索引值

uint8_t USART1_TX_Buffer[USART1_TX_Buffer_Size];
//USART1发送缓冲区数组
uint8_t USART1_TX_Buffer_Load_Index;
//USART1_TX_Buffer[]的装载索引值
uint8_t *pUSART1_TX_Buffer;

void USART1_Init(uint32_t baudrate);
void print_USART1_Receive_Data(void);
void Start_USART1_Send_Data(void);

void USART1_Init(uint32_t baudrate)
{
  HardwareUSART1.Instance = USART1;
  HardwareUSART1.Init.BaudRate = baudrate;              //波特率
  HardwareUSART1.Init.WordLength = UART_WORDLENGTH_8B;  //字长为8位数据格式
  HardwareUSART1.Init.StopBits = UART_STOPBITS_1;       //一个停止位
  HardwareUSART1.Init.Parity = UART_PARITY_NONE;        //无奇偶校验位
  HardwareUSART1.Init.Mode = UART_MODE_TX_RX;           //收发模式
  HardwareUSART1.Init.HwFlowCtl = UART_HWCONTROL_NONE;  //无硬件流控
  HardwareUSART1.Init.OverSampling = UART_OVERSAMPLING_16; //过采样率
  HardwareUSART1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    HardwareUSART1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  HardwareUSART1.AdvancedInit.AutoBaudRateEnable = UART_ADVFEATURE_AUTOBAUDRATE_DISABLE;
  HardwareUSART1.AdvancedInit.AutoBaudRateMode = UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT;
  HardwareUSART1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    HardwareUSART1.FifoMode=UART_FIFOMODE_DISABLE;
  if (HAL_UART_Init(&HardwareUSART1) != HAL_OK)
  {
    Error_Handler();
  }

    __HAL_UART_CLEAR_FLAG(&HardwareUSART1, UART_CLEAR_TCF);
    //Transmission Complete Clear Flag
    __HAL_UART_ENABLE_IT(&HardwareUSART1,UART_IT_RXNE);
    //使能USART1接收到数据时产生中断
    //"UART read data register" not empty interruption

    __HAL_UART_DISABLE_IT(&HardwareUSART1, UART_IT_TXE);
    //串口发送数据时,不使能"串口发送数据寄存器为空"产生中断(位TXE=0)
    //Disable the UART Transmit Complete Interrupt

    __HAL_UART_DISABLE_IT(&HardwareUSART1,UART_IT_TC);
    //串口发送数据时,不使能"串口发送完成"产生中断(位TC=1)
//    __HAL_UART_ENABLE_IT(&HardwareUSART1, UART_IT_TXE);
//    __HAL_UART_ENABLE_IT(&HardwareUSART1,UART_IT_TC);

    //使能USART1发送完成时产生中断
    
    HAL_NVIC_EnableIRQ(USART1_IRQn);
    HAL_NVIC_SetPriority(USART1_IRQn,8,0);
    //设置NVIC中断分组4:4位抢占优先级,0位响应优先级
    //选择中断优先级组4,即抢占优先级为4位,取值为0~15,响应优先级组为0位,取值为0

    USART1_RX_Buffer_Load_Index=0;
}

//HAL_UART_Init()执行时,会先调用HAL_UART_MspInit()
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(uartHandle->Instance==USART1)
  {
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
    PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    { //HAL_RCCEx_PeriphCLKConfig()初始化USART1外设时钟
            //Initializes the peripherals clocks

      Error_Handler();
    }

    __HAL_RCC_USART1_CLK_ENABLE(); //使能USART1外设时钟

    __HAL_RCC_GPIOA_CLK_ENABLE();  //使能GPIOA外设时钟
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;//选择引脚编号9和10
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;      //复用功能推挽模式
    GPIO_InitStruct.Pull = GPIO_NOPULL;          //不用上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //引脚速度为低速
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1; //将引脚复用为USART1
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }
}

//HAL_UART_DeInit()执行时,会先调用HAL_UART_MspDeInit()
void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
    __HAL_RCC_USART1_CLK_DISABLE();//不使能USART1外设时钟
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
  }
}

2、启动发送

void Start_USART1_Send_Data(void)
{
    char i;
    uint16_t k;

    for(i=0;i<USART1_RX_Buffer_Size;i++)//串口接送测试
    {
        if(USART1_RX_Buffer[i-1]=='\r'&&USART1_RX_Buffer[i]=='\n')//收到结束符号
        {
        USART1_RX_Buffer_Load_Index = 0;
            memset(USART1_TX_Buffer,0,USART1_TX_Buffer_Size);
            strcpy((char*)USART1_TX_Buffer,(char*)USART1_RX_Buffer);
            memset(USART1_RX_Buffer,0,USART1_RX_Buffer_Size);

        k=strlen((char*)USART1_TX_Buffer);
        USART1_TX_Buffer_Load_Index = k;
            __HAL_UART_ENABLE_IT(&HardwareUSART1,UART_IT_TC);
            pUSART1_TX_Buffer=USART1_TX_Buffer;//启动发送
        }
  }
}

3、接收函数

//UART_RxISR_8BIT()会调用HAL_UART_RxCpltCallback()处理接收到的数据
//HAL_UART_Receive_IT()会调用UART_RxISR_8BIT()
//在中断中调用HAL_UART_Receive_IT()

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    USART1_RX_Buffer[USART1_RX_Buffer_Load_Index]=USART1_RX_Data;
    USART1_RX_Buffer_Load_Index++;
    if(USART1_RX_Buffer_Load_Index>=USART1_RX_Buffer_Size-2)
    {//USART1_RX_Buffer[]防止溢出
        USART1_RX_Buffer[USART1_RX_Buffer_Load_Index]='\0';
        USART1_RX_Buffer_Load_Index=0;
    }
    if(USART1_RX_Buffer[USART1_RX_Buffer_Load_Index-2]=='\r'&&USART1_RX_Buffer[USART1_RX_Buffer_Load_Index-1]=='\n')
    {//收到"\r\n"结束符号
        USART1_RX_Buffer[USART1_RX_Buffer_Load_Index]='\0';
        USART1_RX_Buffer_Load_Index++;
    }
}

4、接收中断函数

void USART1_IRQHandler(void)
{
  HAL_UART_IRQHandler(&HardwareUSART1);

    HAL_UART_Receive_IT(&HardwareUSART1, &USART1_RX_Data, sizeof(USART1_RX_Data));
    //从USART1接收一个字节


    HAL_UART_Transmit_IT(&HardwareUSART1, pUSART1_TX_Buffer, USART1_TX_Buffer_Load_Index);
    pUSART1_TX_Buffer=NULL;//USART1_TX_Buffer[]被发送完成后,停止发送
//    USART1_TX_Buffer_Load_Index=0;//USART1_TX_Buffer[]被发送完成后,停止发送

//实测,发现HAL_UART_Transmit_IT()会在中断中将USART1_TX_Buffer[]全部发完,才会退出HAL_UART_Transmit_IT();
}

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)

在STM32G474的HAL库中,HAL_UART_Transmit_IT()会将所有数据发送完了,才会退出中断,具体HAL库是怎么做到的,不必浪费时间分析。若要防止HAL_UART_Transmit_IT()连续发送,要么将pData设置为NULL,要么将Size设置为0。否则,串口会不停往外发送数据,十分恼火。搞了好几天才搞好。

总结:HAL库是在没有办法的情况下,不得不用。让HAL_UART_Transmit_IT()停下来,有点耍流氓,还有没有更好的办法

测试结果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2038601.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

米联客-FPGA程序设计Verilog语法入门篇连载-02 Verilog语法_基本设计方法

软件版本&#xff1a;无 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用所有系列FPGA 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑&#xff01; 1概述 本节主要讲解Verilog的基本设…

【屏驱MCU】增加自定义分区指南

说明&#xff1a;本文主要给出基于该款 点屏 MCU。增加自定义分区指南 屏驱MCU系列文章 【屏显MCU】多媒体接口总结&#xff08;一&#xff09; 【DVP接口】0v5640的DVP接口设计分析&#xff08;硬件&#xff09; 【DVP接口】0v5640的DVP接口设计分析&#xff08;软件&#xff…

CCF-GESP8级考试—图论算法及综合应用(最小生成树)

&#x1f349;1 最小生成树的概念 1.1 连通图 &#x1f388; 连通图用于描述图中顶点之间是否存在路径相连。一个无向图中&#xff0c;如果从图中的任意一个顶点出发&#xff0c;都可以通过边的连接到达图中的任意其他顶点&#xff0c;则该图被称为连通图。 连通图的性质&…

为何众多卖家都选择入驻亚马逊VC?有什么优势?——WAYLI威利跨境助力商家

众多卖家选择入驻亚马逊VC&#xff08;Vendor Central&#xff09;&#xff0c;主要是因为VC平台为卖家提供了一系列显著的优势。VC使卖家与亚马逊建立直接供应关系&#xff0c;提升曝光率和销售机会。作为全球领先电商平台&#xff0c;亚马逊拥有庞大用户群和完善物流体系&…

C#窗体自定义快捷操作键的实现 - 开源研究系列文章

这次想到应用程序的窗体的快捷操作键的使用的问题。 上次发布过一个快捷键的例子(https://www.cnblogs.com/lzhdim/p/18342051)&#xff0c;区别在于它是操作系统全局注册的热键&#xff0c;如果其它应用程序注册了对应的热键&#xff0c;那就会失效。此例子是对某个窗体里的按…

AI驱动人才社区革新:智能化探索与实践

一、引言&#xff1a;AI赋能人才新生态 在21世纪的数字化浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;技术以其强大的数据处理能力、学习优化算法及创新应用模式&#xff0c;正深刻地改变着各行各业的面貌&#xff0c;人才管理领域亦不例外。传统的人才社区&#xf…

yolo中的iou是什么意思

在YOLO&#xff08;You Only Look Once&#xff09;算法中&#xff0c;IoU 是“Intersection over Union”的缩写&#xff0c;中文可以理解为“交并比”。IoU 是一个用于衡量两个边界框&#xff08;bounding box&#xff09;重叠程度的指标。具体来说&#xff0c;IoU 是通过计算…

CUDA-MODE 第二课: PMPP 书的第1-3章

我的课程笔记&#xff0c;欢迎关注&#xff1a;https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/cuda-mode 第二课: PMPP 书的第1-3章 这节课非常基础&#xff0c;讲的都是基本概念和初级的注意事项&#xff0c;有CUDA基础的朋友可以不用花时间看。 PMPP …

C#语言基础速成Day06

“心之官则思&#xff0c;思则得之&#xff0c;不思则不得也。” 目录 前言文章有误敬请斧正 不胜感恩&#xff01;||Day06 一、C#属性访问器、方法参数属性访问器&#xff08;Property Accessors&#xff09;方法参数&#xff08;Method Parameters&#xff09;综合示例 二、C…

小红书种草推广丨爆品层出不穷,品牌还能怎么「造新」?

当品牌已经被大众熟知&#xff0c;要如何在茫茫消费市场中脱颖而出&#xff0c;再度吸引用户的目光&#xff1f; 当品牌陷入增长困境&#xff0c;要如何再造爆品&#xff0c;打造增长的第二曲线&#xff0c;延长品牌的生命周期&#xff1f; …… 就这个大家关心的这些问题&…

三菱定位控制(一)

下面小编开始开始总结学习定位控制&#xff0c;以Q系列三菱PLC来展开学习&#xff0c;希望对读者或者小白有所帮助&#xff01;&#xff01;&#xff01; 一 三菱PLC定位模块 为什么需要学习定位模块&#xff08;三菱FXCPU能实现一个伺服电机的控制&#xff0c;多个要买定位模…

结构化输出及其使用方法

在 LLM 应用程序中构建稳健性和确定性 图片来自作者 欢迎来到雲闪世界。OpenAI最近宣布其最新的gpt-4o-2024–08–06模型支持结构化输出。与大型语言模型 (LLM) 相关的结构化输出并不是什么新鲜事——开发人员要么使用各种快速工程技术&#xff0c;要么使用第三方工具。 在本文…

异质性空间自回归模型 (HSAR)及 Stata 具体操作步骤

目录 一、引言 二、文献综述 三、理论原理 四、实证模型 五、稳健性检验 六、程序代码及解释 七、代码运行结果 一、引言 在空间计量经济学中&#xff0c;异质性空间自回归模型&#xff08;Heterogeneous Spatial Autoregressive Model&#xff0c;HSAR&#xff09;是一种…

深度优化Nginx负载均衡策略,携手Keepalived打造高可用服务架构新纪元

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元 个人主页&#xff1a;团儿.-CSDN博客 目录 前言&#…

什么是数据仓库ODS层?为什么需要ODS层?

在大数据时代&#xff0c;数据仓库的重要性不言而喻。它不仅是企业数据存储与管理的核心&#xff0c;更是数据分析与决策支持的重要基础。而在数据仓库的各个层次中&#xff0c;ODS层&#xff08;Operational Data Store&#xff0c;操作型数据存储&#xff09;作为关键一环&am…

NVDLA专题4:具体模块介绍——Convolution DMA

概述 Convolution DMA Module的定义在NV_NVDLA_cmda.v中&#xff0c;其module的定义如下&#xff1a; module NV_NVDLA_cdma (cdma_dat2cvif_rd_req_ready //|< i,cdma_dat2mcif_rd_req_ready //|< i,cdma_wt2cvif_rd_req_ready //|< i,cdma_wt2mcif_rd_r…

【Nacos】docker部署nacos服务

docker部署nacos服务 1.直接执行命令2.如果网络出现问题 1.直接执行命令 docker run -e JVM_XMS256m -e JVM_XMX256m --env MODEstandalone \ --name mynacos -d -p 8848:8848 -p 9848:9848 -p 9849:9849 \ docker.io/nacos/nacos-server:v2.1.12.如果网络出现问题 执行如下命…

计算机系统基础知识:计算机组成和基本原理

文章目录 1. 总线1.1 系统总线1.2 外总线 2. 中央处理单元2.1 CPU组成运算器控制器寄存器组内部总线 2.2 多核处理器 3. 存储系统3.1 分类3.2 层次结构3.3 主存储器3.4 高速缓存3.5 外存储器3.6 云存储 4. 输入/输出技术4.1 接口的功能和分类4.2 主机和外设间的连接方式4.3 编址…

定制化三防平板:满足个性化需求

定制化服务的核心在于理解并满足用户的个性化需求。对于三防平板而言&#xff0c;这意味着设备不仅需要具备防水、防尘、防摔的基本特性&#xff0c;更需根据用户的特定工作环境和使用习惯&#xff0c;进行功能和设计上的优化。 例如&#xff0c;对于在极端温度环境下作业的人…

51单片机-LED灯蜂鸣器数码管按键DS18B20温度传感器

LDE灯的相关程序 LED灯闪烁 LED流水灯 方法1 方法二&#xff1a; 因为P1口可以直接控制P1^0~P1^7的8个led灯&#xff0c;利用一个8位的二进制数字来进行控制即可。如果要点亮P1^0 只需要给P1口传递 1111 1110即可。 蜂鸣器的使用 什么是蜂鸣器&#xff1f; 蜂鸣器是一种一…