谨慎处理单片机中断,中断等价于比主程序优先级更高的线程

单片机 专栏收录该内容
3 篇文章 1 订阅

 有些小伙伴喜欢在单片机中断里做任务,殊不知可能会因此遇到棘手的bug,然后查半天查不出个所以然。本文为了纠正这个不良习惯,对单片机中断进行阐述。

 无中断时,单片机跑着主程序,当中断时,单片机进入中断服务程序。所以,中断其实是比主程序优先级更高的线程,定时中断、串口中断,每一个中断都是一个线程。既是多线程,那必然有资源共享冲突问题。所以,小小单片机,背负着“多线程”的重任。共享资源冲突,可能是全局变量访问冲突,或是函数调用冲突。

 全局变量访问冲突,是在主程序中读写一个全局变量时,中断来了,在中断服务程序中又同时读写一个全局变量,得到了意想不到的结果。我举个例子,8位机的,有一个变量是Cnt,16位的,在主程序执行

Cnt = 0;
EA = 1;        //开中断
while (1)
{
	if (Cnt < 300)
	{
		Cnt++;
	}
	else
	{
		Cnt = 1;
	}
}

 在一个1毫秒中断里

if (Cnt == 0)
{
	printf("error");
	while (1);
}

 按照程序,Cnt原本是在1~100之前循环,不会是0。但实际上,经过一段时间最终却会输出error,说明在中断中把Cnt判断为0了。原因Cnt++一句话,在汇编上就是很多行组成的了,大致分成低8位加1,跟高8位进1。当Cnt等于255时,汇编先把低8位加1变成了0,再对高8位加1,如果在低8位变0,还未对高8位加1时,刚好到达1毫秒中断,进入中断服务函数,这时在中断服务函数中就会把Cnt判断成0了。

 有的小伙伴会问,如果是32位机,是不是就不会有问题了。确实,32位机情况下,上述例子就不会输出error了。但资源冲突,只要是多线程就会发生了,主要情况是主程序在写一个变量,而中断也可能会同时写这个变量,这种情况下对这个变量的读操作都是不安全的。所以,其它情况的冲突都是可能的。也就是说,要保证主程序跟中断不同时写一个变量 。

 调用函数冲突,是主程序调用一个函数,而中断也可能会同时调用这个函数的情况。这是因为单片机的资源非常有限,所以它的函数默认是设计不可重入的,一个函数用到的局部变量是固定地址的,如果主程序调用一个函数的过程中,中断也同时调用了,那中断改变了局部变量,中断退出后,主程序继续用变中断改变的局部变量,就出现不可预测的结果了。

 而且,有些编译器开了优化后,不同函数用到的局部变量可能是相同地址,这样,就算主程序跟中断调用不同的函数,也会发生冲突。

 为了防止中断的冲突,要怎样做才合适呢。办法就是尽量减少中断的处理,让所有的处理都在主程序中进行,有一个合适的框架,能防止资源冲突。有兴趣可以看我的另外的文章:一个简单实用的MCU程序框架(非操作系统,简单调度任务) 。这个框架简单实用,又没有中断冲突问题,不同单片机中程序移植也轻而易举。

  • 0
    点赞
  • 0
    评论
  • 2
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值