OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 354|回复: 4

STM32F103空闲中断接收数据,发现进不了中断

[复制链接]

13

主题

48

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3661
金钱
3661
注册时间
2020-4-30
在线时间
260 小时
发表于 2026-10-12 14:53:26 | 显示全部楼层 |阅读模式
10金钱
最近搞WIFI无线传输,使用原子的8266模块发送数据到平板电脑
因为设备需要监控数据,所以使用状态机+串口空闲中断+DMA方案,代码写好后,测试了几次,能一步步的走下去,但在一次hardfault后,就再也进不了串口中断了
换过模块,模块没问题,串口本身也能正常通信,觉得很奇怪,请教下各位。
代码如下
  1. void  UartGPRS_init(u32 bound)                                                             //串口1
  2. {
  3.         //GPIO端口设置
  4.         GPIO_InitTypeDef GPIO_InitStructure;
  5.         USART_InitTypeDef USART_InitStructure;
  6.         NVIC_InitTypeDef NVIC_InitStructure;
  7.         DMA_InitTypeDef DMA_InitStructure;
  8.        
  9.        
  10.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);       
  11.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);        //使能USART1时钟
  12.        
  13.        
  14.         USART_DeInit(USART1);                                   //复位串口1
  15.         //USART1_TX   PA.9
  16.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;               
  17.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  18.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                //复用推挽输出
  19.         GPIO_Init(GPIOA, &GPIO_InitStructure);                  //初始化PA9

  20.         //USART1_RX          PA.10
  21.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  22.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  23. //        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;   //浮空输入
  24.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;           //上拉输入
  25.         GPIO_Init(GPIOA, &GPIO_InitStructure);                  //初始化PA10
  26.        
  27.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;               //PA.8
  28.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  29.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            //复用推挽输出
  30.         GPIO_Init(GPIOA, &GPIO_InitStructure);                  //初始化PA8       
  31.        
  32.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;              //PA.11
  33.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  34.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;            //复用推挽输出
  35.         GPIO_Init(GPIOA, &GPIO_InitStructure);                  //初始化PA11

  36.         GPIO_SetBits(GPIOA,GPIO_Pin_8);                                   //模块IO_0引脚,上电拉高为运行模式;拉低为烧写模式,这个模式不用
  37.         GPIO_SetBits(GPIOA,GPIO_Pin_11);                                   //WIFI模块复位(低电平有效)上电拉高,
  38.        
  39.         //Usart1 NVIC 配置
  40.         NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  41.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
  42.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                //子优先级3
  43.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
  44.         NVIC_Init(&NVIC_InitStructure);                                //根据指定的参数初始化VIC寄存器

  45.         //USART 初始化设置
  46.     USART_InitStructure.USART_BaudRate = bound;                                    //一般设置为115200;
  47.     USART_InitStructure.USART_WordLength = USART_WordLength_8b;                    //字长为8位数据格式
  48.     USART_InitStructure.USART_StopBits = USART_StopBits_1;                         //一个停止位
  49.     USART_InitStructure.USART_Parity = USART_Parity_No;                            //无奇偶校验位
  50.     USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
  51.     USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                      //收发模式
  52.     USART_Init(USART1, &USART_InitStructure);               //初始化串口
  53.        
  54.         USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);               //使能DMA接收请求
  55.     USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);          //开启空闲中断
  56.     USART_Cmd(USART1, ENABLE);                              //使能串口
  57.        
  58.                
  59.     DMA_DeInit(DMA1_Channel5);
  60.     DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(USART1->DR);                //外设地址:USART1数据寄存器
  61.     DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&usart1_rcv_buf;                   //内存地址:接收缓冲区
  62.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                              //方向:外设→内存     
  63.     DMA_InitStructure.DMA_BufferSize = 128;           //传输数据量
  64.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外设地址不递增
  65.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;             //内存地址递增
  66.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  67.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;     
  68.     DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //普通模式开启,单次搬运,下次重新开始
  69.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  70.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
  71.     DMA_Init(DMA1_Channel5, &DMA_InitStructure);
  72.     //配置完成后,启动DMA通道
  73.     DMA_Cmd(DMA1_Channel5, ENABLE);
  74. }
复制代码
  1. void  USART1_IRQHandler(void)
  2. {
  3.     /* 判断是否为空闲中断(IDLE) */
  4.     if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)
  5.     {
  6.         /* --- 清除IDLE标志:必须"先读SR,再读DR" --- */
  7.         volatile uint16_t temp;
  8.         temp = USART1->SR;    // 先读状态寄存器
  9.         temp = USART1->DR;    // 再读数据寄存器(清除IDLE标志)
  10.         (void)temp;

  11.         /* --- 计算本次接收到的数据长度 --- */
  12.         /* DMA_CNDTR寄存器保存的是剩余待传输的数据量 */
  13. //        USART1_RxLen = USART1_RX_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);

  14.         /* --- 置位接收完成标志,由主循环处理数据 --- */
  15.         USART1_RxFlag = 1;

  16.         /* --- 重新装载DMA,准备下一次接收 --- */
  17.         DMA_Cmd(DMA1_Channel5, DISABLE);                              // 先关闭DMA
  18.         DMA_SetCurrDataCounter(DMA1_Channel5, USART1_RX_BUFFER_SIZE);// 重设传输量
  19.         DMA_Cmd(DMA1_Channel5, ENABLE);                               // 重新使能
  20.     }
  21. }
复制代码


回复

使用道具 举报

6

主题

69

帖子

0

精华

高级会员

Rank: 4

积分
581
金钱
581
注册时间
2016-7-29
在线时间
131 小时
发表于 2026-10-12 15:13:20 | 显示全部楼层
本帖最后由 小迷哥 于 2026-10-12 15:14 编辑

能否hardfault定位到,故障时刻运行到哪个函数了,如果可以的话,有可能是这里导致的,
我之前处理hardfalut参考的这个

你写的串口1接收方式:DMA+空闲中断,单帧截断方式,我没看出来哪里有问题
深入解析:STM32跑飞,进入HardFault_Handler如何精准的确定问题 - ljbguanli - 博客园
回复

使用道具 举报

0

主题

165

帖子

0

精华

高级会员

Rank: 4

积分
787
金钱
787
注册时间
2026-1-29
在线时间
63 小时
发表于 2026-10-12 16:20:45 | 显示全部楼层
看到你的代码和问题描述,问题描述得很清晰,是一个很典型的STM32串口接收问题。在进行调试和排查问题时,有几点需要确认和注意:

1. 确保使用正确的回调函数
请确保在初始化时要正确配置中断服务回调函数,并且要在中断向量表中定义:

void USART1_IRQHandler(void) {
    // 你的中断处理代码
}

      
2. 检查DMA的配置
确保DMA配置正确,比如确保DMA的方向(从外设到内存)、数据宽度、缓冲区大小等配置正确:

DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_RX_BUFFER;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = USART1_RX_BUFFER_SIZE;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 采用循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel5, &DMA_InitStructure);

DMA_Cmd(DMA1_Channel5, ENABLE);

      
3. 检查串口初始化配置
确保串口配置正确,包括波特率、数据位、停止位、校验位等配置,并启动串口的IDLE中断:

USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);

USART_DMACmd(USART1, ENABLE);          // 使能DMA
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 使能IDLE中断
USART_Cmd(USART1, ENABLE);             // 使能串口

      
4. HardFault处理
硬件故障发生后,处理器通常进入HardFault_Handler,将所有系统寄存器复位,或者调试时检查HardFault状态位和栈指针,必要时可以强制复位。

void HardFault_Handler(void) {
    // 强制复位
    NVIC_SystemReset();
}

      
5. 中断处理代码调整
确保没有其他可能导致中断失能的情况,特别是在DMA配置部分。

void USART1_IRQHandler(void) {
    /* 判断是否为空闲中断(IDLE) */
    if (USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) {
        /* 清除IDLE标志 */
        volatile uint16_t temp;
        temp = USART1->SR;
        temp = USART1->DR;
        (void)temp;

        /* 计算本次接收到的数据长度 */
        USART1_RxLen = USART1_RX_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);

        /* 置位接收完成标志 */
        USART1_RxFlag = 1;

        /* 重新装载DMA */
        DMA_Cmd(DMA1_Channel5, DISABLE);
        DMA_SetCurrDataCounter(DMA1_Channel5, USART1_RX_BUFFER_SIZE);
        DMA_Cmd(DMA1_Channel5, ENABLE);
    }
}

      
6. 调试
通过调试器检查程序运行状态,看程序在发生HardFault后是否返回正确的执行路径。

总结
确保正确配置DMA和串口,检查HardFault发生后确保系统的复位,逐步排查可能的问题点。希望这些建议能帮你更好地解决问题。
回复

使用道具 举报

13

主题

48

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3661
金钱
3661
注册时间
2020-4-30
在线时间
260 小时
 楼主| 发表于 2026-10-13 08:46:56 | 显示全部楼层
郁闷的是,现在再也没进hardfault了,程序一直运行,就是进不了串口中断
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手入门

积分
11
金钱
11
注册时间
2026-10-14
在线时间
3 小时
发表于 昨天 13:24 来自手机 | 显示全部楼层
chen12345678 发表于 2026-10-13 08:46
郁闷的是,现在再也没进hardfault了,程序一直运行,就是进不了串口中断

怎么感觉和中断标志位有关
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /1 下一条

正点原子公众号

如发现本坛存在违规或侵权内容, 请点击这里发送邮件举报 (或致电020-38271790)。请提供侵权说明和联系方式。我们将及时审核依法处理,感谢配合。

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2026-10-21 16:11

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表