• 正文
  • 相关推荐
申请入驻 产业图谱

为什么在main函数里加了点函数调用,中断就不正常了?

8小时前
149
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

近日某工程师向我反馈,他遇到如下问题:

现象是:系统中存在一个 10 ms 定时器中断,中断服务函数中会翻转 PB5。但在 main 函数中调用了他自己实现的 Ht1621DataUp()函数后,PB5 不再按 10 ms 周期翻转,而是出现无规律的跳变。根据此现象,他认为该函数影响了中断。

为此他还换过MCU芯片,看来是想验证下是不是MCU出了问题。

这个问题其实一看就可以判断出是软件使用问题。拿到他的代码后我首先进行了测试,现象确实如他所说:

这个是PB5正常翻转的波形:

下面是加了函数调用后异常翻转波形:

Ht1621DataUp()函数本身并没有定时器TIM1相关的任何代码,所以TIM1的10ms 定时本身不可能出现问题。发生此问题的原因到底是什么呢?

原因是他在Ht1621DataUp()函数里也有GPIO的相关操作,

看起来是只操作了PB2、PB3、PB4三个引脚,并没有操作PB5,但是实际上会影响到PB5的输出。所以上述现象本质上是PB5的电平被“定时器中断翻转”和“HT1621刷新位操作”交替改写了。

原因出在GPIOB->ODR |= xxxxxx;的使用上,这条语句实际上执行的读-改-写操作。

以上述异常波形中的局部一段为例说明,

刚开始是正常的输出PB5高电平,while(1)里程序里读取的ODR PB5也是高电平,紧接着定时器中断改写PB5为低电平,之后while(1)里继续往下执行后续的改和写操作,基于之前读到的高电平,所以又把PB5改写成了高电平,这就导致 PB5 的低电平被覆盖,从而产生异常波形。在下一个10ms定时器中断到了之后又会执行PB5输出高的操作。所以整体就看到了上述的异常波形。

但是while(1)就基于之前的高电平,把它又改为了高电平。到10ms再之后,中断又弄成了高电平,就看到了上述波形。

Ht1621Wr_Data()并不直接操作 PB5,但由于它与 TIM1 中断都在对同一 GPIO 端口执行“读‑改‑写”操作,因此会间接干扰 PB5 的状态,造成竞态问题。

解决该问题的方法也很简单:把ODR 改成 BSR寄存器,这样每次置位/复位只会影响它自己的脚,不会把其他不相关的引脚一起带着改。

ODR(Output Data Register)寄存器:本身不是原子操作,对其的位操作需要读-改-写三步,可能被中断打断导致竞态。

BSRR(Bit Set Reset Register)寄存器:是原子操作(通过一次写操作完成,无需读-改-写)。

关注我们:扫码加入嵌入式交流群:

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录