转发:ARM®mbed OS入门开发(六 A)mbedGPIO中断应用
已移植到nucleo f70r ,本文有改动在前面的mbed数字输入输出初步应用中我们已经学会了如果通过读取管脚的电平状态来判断用户的输入,但我们发现这种实现方式会浪费大量的MCU时间在检查管脚的状态上,应该说应用效果并不理想,那么有没有另外的方式无需检查就可以处理管脚状态的变化呢,答案是肯定的,那就是MCU的中断系统。MCU的中断系统不但可以处理管脚的变化,还可以处理更复杂的计时器的变化、MCU通讯状态的变化等,是微处理器中最重要的概念之一。
我们把原先通过不断查询来处理事件的方式叫做轮询,它和中断方式一起构成微处理器最常用的事件处理解决方案。在现实生活中,中断和查询也是常用的事务处理方式,举个例子,假设我们5点要出门办事,如果采用轮询方式,那我们就需要定时地去查看当前的时间,一旦发现时间到了5点就出门;而如果采用中断方式,我们就可以订个闹钟,在其它时间我们并不需要关心时间问题,只有闹钟响了我们才中断当前的工作出门。微处理对于中断的处理和这类似,下图是微处理器中断响应的流程图(至于说怎么检测到中断是微处理器系统自动实现的,用户只要把某个中断设成可检测状态,用户的程序就能响应这个中断,当然,具体的中断类型和微处理器的型号相关): http://mbed.smeshlink.com/images/handbook/int1.png中断处理流程中的中断处理向量是从中断处理向量表中查询的,该表设定了所有中断处理流程的入口,它是在mbed的启动代码中被初始化的,一般都在.S汇编文件中。GPIO中断是微处理器中断系统中最简单也是最常用的中断类型,它可以让用户在某个管脚状态发生特定的变化时执行相应的代码。需要注意的是,并不是所有的GPIO管脚都具备中断处理能力。Mbed使用InterruptIn对象来处理GPIO中断,它提供的主要方法有:
类名方法用途
InterruptIn
InterruptIn(PinName pin);构造函数,把pin管脚设成中断处理管脚
int read();读取管脚的当前状态
void rise(void (*fptr)(void));设置管脚上升沿触发的中断处理函数
void fall(void (*fptr)(void));设置管脚下降沿触发的中断处理函数
void mode(PinMode pull);设置管脚的模式,一般来说,上升沿处理应设成PullDown,下降沿触发设成PullUp
这样的话,我们就可以采用更好的方式来监测nucleo按钮的状态了,由于nucleo 外部已经用上拉电阻固定到高电平,所以我们最好采用下降沿触发的方式,下面的代码可以实现用户每按一下,LED灯变换一次:DigitalOut led(D13);//采用arduino简称,导出的项目PinNames.h 里有详细说明InterruptIn btn(PC_13);//void flip(){ led=!led;}int main() { btn.fall(&flip); while (1) ;}需要注意的是,设置管脚对应的中断处理函数只需一次都可以在程序运行的整个生命周期发挥作用,另外,while(1);这句话不可少,否则,相当于程序运行完退出,那么中断处理函数也就不会发挥作用了。前面的GPIO中断演示了ARM单片机中断系统的简单应用,但在实际的应用中,我们有可能遇到这样的情况,多个中断同时发生或者系统在做中断处理的时候又有新的中断发生,此时系统会怎么处理呢。为了回答此问题,我们必须从ARM中断的优先级开始。首先我们来看一个例子:DigitalOut led(D13);InterruptIn btn(PC_13);void flip(){ led=!led; wait(1); led=!led;}int main() { btn.fall(&flip); while (1) ;}该代码同样利用按钮实现LED的翻转,不过,它是每按一次,LED亮一秒钟。在这里,实际上用到了两种类型的中断,一种就是GPIO中断,另外一种则是wait函数用到的计时器中断,从此代码的运行效果上看,显然,在GPIO中断时又被新的中断打断了,这是因为计时器的中断优先级比外部中断高,可以实现嵌套中断,但如果你在中断的过程中再次按下按钮,你会发现对应的中断处理程序并没有执行,这是因为中断处理程序只能被比自己优先级高的中断打断。ARM中断优先级及嵌套中断的具体描述已经超过了本书的内容,我们只需要记住,ARM的中断是有优先级的,而优先级的具体规定有些中断是固定的,而有些中断的优先级是用户可配置的。用户的中断处理程序只能被比自己中断优先级高的中断打断,而且可以实现循环嵌套,即新的中断处理程序又会被优先级更高的中断打断。为了验证GPIO中断嵌套的效果,我们另外介绍和中断相关的方法:__disable_irq():禁止所有可屏蔽中断;__enable_irq():允许所有未屏蔽中断;void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority):设置中断的优先级,IRQn表示需要设置的中断号,后面表示优先级,数字越小表示优先级越高。下面是这三个方法的综合应用,这里用到了串口中断和GPIO中断,默认情况下,两者的中断优先级是一样的,所以谁也不能中断谁,现象就是led1亮的时候,led2就不会亮,但我们把uart0的优先级调高一下就可以了:DigitalOut led1(D13);DigitalOut led2(D15);//第二个LED连接D15InterruptIn btn(PC_13);Serial pc(USBTX,USBRX);void btnflip(){ led1=!led1; wait(10); led1=!led1;}void uartflip(){ led2=!led2; pc.getc(); wait(10); led2=!led2;}int main() { __disable_irq(); wait(5); __enable_irq(); btn.fall(&btnflip); pc.attach(&uartflip); NVIC_SetPriority(UART0_IRQn, 5); NVIC_SetPriority(EINT3_IRQn, 255); while (1) ;}
该代码还应用了屏蔽中断功能,其现象就是前5秒系统不能响应用户按键和串口发送,其中的UART0_IRQn中断号就对应着UART0,而EINT3_IRQn,对应着所有管脚中断
mbedGPIO中断应用原帖地址 http://mbed.smeshlink.com/cookbook/30-mbed-int1
占楼备用 :):):):):):) 谢楼主分享 好资料,学习中。。。。 好东西,学习中
谢谢分享 不错的教程 感谢分享 写的不错
页:
[1]