@A@166 2022-02-25 16:18 采纳率: 100%
浏览 65
已结题

stm的USART通讯不正常

问题遇到的现象和发生背景

在STM32F103上软件的USART通讯不正常,经常不能正常地收发数据包。哪里需要特别注意的吗?用中断方式接收数据,主流程发送数据。加了调试代码,发现接收数据包不完整。哪怕无视所有接收出错也还是不完整。有人知道吗?

问题相关代码,请勿粘贴截图
运行结果及报错内容
我的解答思路和尝试过的方法
我想要达到的结果
  • 写回答

4条回答 默认 最新

  • ilmss 2022-02-27 19:05
    关注

    ◉异常一:数据传输中会出现乱码
    数据传输中会出现乱码,很有可能是数组溢出,或者定义的数组长度不够。或者中断被打断。
    ◉异常二:程序卡在中断函数里面无法跳出执行主函数的逻辑
    中断标志位没有被清除,在这里要注意一点,串口中断标志位自动清空的前提是软件需要先读USART_SR寄存器,然后读USART_DR寄存器来自动清除。即串口中断事件发生后,如果使能的接收中断,而中断函数里面什么都不执行的话,接收中断标志位是无法自动清空的,故而,函数会一直卡在中断函数里面。
    比如一下这个函数,该函数没有逻辑问题,但会引发以上问题,代码如下

    extern unsigned char star_time_led ;  //计时开始变量
    unsigned char recv_flag = 0;//定义接受标志位
    unsigned long recv_cnt = 0;//串口1接收数据缓存
    unsigned char recv_buf[MAX_REV_NUM];//串口1接收数据缓存
    extern unsigned char star_time;
    extern unsigned char recv_time_cnt;
    /*
    以下写法有严重问题
    如果没有这句函数→USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
    串口接收中断标志位将文法被清空,会导致函数卡在中断函数里面一直循环,无法正常运行主函数
    原因分析:
    中断条件成立后,中断标志位将会标记,程序将会进入中断函数运行,软件自动轻触中断标志位的条件是
    先读USART_SR寄存器,再读USART_DR寄存器。
    void USART1_IRQHandler(void)                    //串口1中断服务程序
    {
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //是否发送中断事件
            {
                star_time = 1;         //接受到一帧数据的时候,打开软件定时器,去计数
                if(recv_cnt < MAX_REV_NUM)//数组长度是否超过缓存区
                {
                    recv_buf[recv_cnt] =USART_ReceiveData(USART1);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
                    recv_cnt++;
                }
                else
                {
                    recv_cnt = MAX_REV_NUM
                    ;    //限制数组长度,超过缓存区则不再接收
                }
                recv_time_cnt = 0; //每接收到一帧数据,把定时计数器清零,相当于喂狗
                                   //但是在定时器中断里面会不断的累加
                USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
            }
    } 
    */
    

    上述代码优化后如下:

    void USART1_IRQHandler(void)                    //串口1中断服务程序
    {
        static char ch;
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //是否发送中断事件
            {
                ch = USART_ReceiveData(USART1);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
                star_time = 1;         //接受到一帧数据的时候,打开软件定时器,去计数
                if(recv_cnt < MAX_REV_NUM)//数组长度是否超过缓存区
                {
                    recv_buf[recv_cnt] =ch;//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
                    recv_cnt++;
                }
                else
                {
                    recv_cnt = MAX_REV_NUM
                    ;    //限制数组长度,超过缓存区则不再接收
                }
                recv_time_cnt = 0; //每接收到一帧数据,把定时计数器清零,相当于喂狗
                                   //但是在定时器中断里面会不断的累加
                USART_ClearFlag(USART1,USART_FLAG_RXNE); //清空中断标志位
            }
    } 
    

    ◉异常三:数据发送中间歇性数据异常漏发乱发等

    对于这些奇奇怪怪的问题,首先要了解一下发送函数是怎么发送的

    USART_DR 包含了已发送的数据或者接收到的数据。 USART_DR 实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR 写入数据会自动存储在 TDR 内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。

    TDR 和 RDR 都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接收时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。

    当 TDR 内容转移到发送移位寄存器,还没有发送出去的,就再次把TDR 内容转移到发送移位寄存器里,就会出现少发的现象。

    什么时候会有这种情况呢?错误操作代码如下:

    void USART2_IRQHandler(void)                    //串口2中断服务程序
    {
        if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //是否发送中断事件
            {
                Usart1RecBuf[RxCounter] =USART_ReceiveData(USART2);//将接收到的数据存在数组Usart1RecBuf[RxCounter]里
                RxCounter++;//指向数组地址自加
                if(RxCounter==2) 
                {    
                    USART_SendData(USART1, Usart1RecBuf[0]);//发送Usart1RecBuf[0]
                    USART_SendData(USART1, Usart1RecBuf[1]);//发送Usart1RecBuf[1]
                    USART_SendData(USART1, Usart1RecBuf[2]);//发送Usart1RecBuf[2]
                }
            }
    }
    

    上述代码连续运行了3次USART_SendData(USART1, Usart1RecBuf);这个函数,这种情况一般都会出现只有最后一个数据发送成功出去。原因可能就是数据还没有发送出去,发送移位寄存器就更新了。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

问题事件

  • 系统已结题 3月10日
  • 已采纳回答 3月2日
  • 赞助了问题酬金5元 2月25日
  • 创建了问题 2月25日

悬赏问题

  • ¥15 qt+ffmpeg报错non-existing PPS 0 referenced
  • ¥15 FOC simulink
  • ¥15 咨询一下有关于王者荣耀赢藏战绩
  • ¥50 MacOS 使用虚拟机安装k8s
  • ¥500 亚马逊 COOKIE我如何才能实现 登录一个亚马逊账户 下发新 COOKIE ..我使用下发新COOKIE 导入ADS 指纹浏览器登录,我把账户密码 修改过后,原来下发新COOKIE 不会失效的方式
  • ¥20 玩游戏gpu和cpu利用率特别低,玩游戏卡顿
  • ¥25 oracle中的正则匹配
  • ¥15 关于#vscode#的问题:把软件卸载不会再出现蓝屏
  • ¥15 vimplus出现的错误
  • ¥30 怎么使用AVL fire ESE软件自带的优化模式来优化设计Soot和NOx?