【XNUCLEO-F030R8试用体验】之五:mbed开发之中断 在前面的 mbed 数字输入输出中我们已经学会了通过读取管脚的电平状态来判断用户的输入,但这种实现方式会浪费大量的MCU 时间在检查管脚的状态上,应用效果并不理想。那么有没有另外的方式无需检查就可以处理管脚状态的变化呢?答案是肯定的,那就是MCU 的中断系统。 MCU 的中断系统不但可以处理管脚的变化,还可以处理更复杂的计时器的变化、MCU 通讯状态的变化等,是微处理器中最重要的概念之一。我们把原先通过不断查询来处理事件的方式叫做轮询,它和中断方式一起构成微处理器最常用的事件处理解决方案。在现实生活中,中断和查询也是常用的事务处理方式。举个例子,例如我们想在每天早上七点起床,如果采用轮询的方式,我们每隔一定的时间就要看看时钟有没有到七点,如果采用中断的方式,就好比设置了一个闹钟,当时间到的时候,闹钟会叫醒我们,其他时间我们可以做别的事情。中断的处理过程如下图所示:
(图片选自傅骞《mbed学习指南》) 能够引起中断的事件称为中断源,一个MCU的中断源种类越多,能处理的中断类型越多,相应的功能也就越强大。那么STM32的MCU有多少常用中断源呢?我们可以在芯片的头文件中看到,下面的图片来自stm32f030x8.h。
最前面5种中断属于内核中断,用来完成对异常事件的响应,后面的WWDG_IRQn到USART2_IRQn属于内部外设中断,这些中断可以由用户配置使用,编号越小的中断优先级越高,实际使用时也可以通过修改优先级以满足使用要求。那么STM32F030R8芯片有多少中断优先级呢?
从第三行我们可以看到中断优先级有两位,也就意味着cortex M0内核支持四种中断优先级。对于中断优先级高的中断,在执行过程中可以打断优先级低的中断。 通过上面的讲解我们对芯片的中断有了一定的了解,这里没有讲到STM32芯片的中断线与外设中断的连接方式,感兴趣的读者可以参考芯片的数据手册。接下来我们看看mbed中提供了哪些中断。 mbed经常用到的中断有:GPIO中断、串口中断、定时器中断,每一种中断给出了相应的方法,首先看看GPIO中断方法:
还记得我们在“mbed开发之数字输入输出”写的按键改变小灯状态的程序吗?这次我们用中断来改写,代码如下: #include"mbed.h" DigitalOutled(LED1); Interruptinbutton(PC_13); void flip() // 下降沿中断处理函数 { wait_ms(10); //延时消抖 if(button == 0) led=!led; } int main() { button.fall(&flip); while (1); } 需要注意的是,这里没有设置管脚模式,是因为按键在外部连接了上拉电阻,如果错误地将模式设置为内部下拉,会导致出错。如果用户外接按键,可以利用芯片内部的上下拉电阻设置管脚模式,简化电路设计。 串口的使用及串口中断 通过上面的图片我们可以看到芯片提供了两个串口USART1和UASRT2,芯片手册的引脚图部分标出了对应的复用引脚为PA2和PA3。
文件PinNames.h中也定义了串口对应的引脚: // Generic signals namings LED1 = PA_5, LED2 = PA_5, LED3 = PA_5, LED4 = PA_5, USER_BUTTON = PC_13, SERIAL_TX = PA_2, SERIAL_RX = PA_3, USBTX = PA_2, USBRX = PA_3, I2C_SCL = PB_8, I2C_SDA = PB_9, SPI_MOSI = PA_7, SPI_MISO = PA_6, SPI_SCK = PA_5, SPI_CS = PB_6, PWM_OUT = PC_7, // Not connected NC = (int)0xFFFFFFFF } PinName; 软件部分,我们来看看mbed提供的串口相关的方法:
可以看到提供了很多常用的方法,其中void attach(void(*fptr)(void),IrqType type=RxIrq)为中断服务函数,中断形式为接收中断。下面我们通过一个简单的串口中断程序来学习一下。程序的功能是,当串口收到PC端发来的数据后,进行判断,如果是1,2,3,4,就分别点亮LED1,LED2,LED3,LED4。 #include"mbed.h" Serialpc(USBTX,USBRX); DigitalOutmyled1(LED1); DigitalOutmyled2(LED2); DigitalOutmyled3(LED3); DigitalOutmyled4(LED4); void pc_proc(void); //串口中断处理函数声明 int main() { pc.baud(9600); pc.attach(&pc_proc,SerialBase::RxIrq);//串口中断处理函数,中断类型为接收中断 while(1); } void pc_proc(void) { int i; i=pc.getc(); pc.printf("i=%cn",i); //打印收到的字符 switch(i) { case 49: myled1 = 1; //49为‘1’的ASCII码,后面依次类推 break; case 50: myled2 = 1; break; case 51: myled3 = 1; break; case 52: myled4 = 1; break; default: break; } } 程序运行截图:
学习了上面两个程序之后,我们把两个中断组合起来,设置不同的中断优先级,看看会有什么现象,代码如下: #include"mbed.h" DigitalOutled1(LED1); DigitalOutled2(PC_5); InterruptInbtn(PC_13); Serialpc(USBTX,USBRX); void btnflip() { led1=!led1; wait(5); led1=!led1; } void uartflip() { led2=!led2; pc.getc(); wait(5); pc.printf("%cn",pc.getc()); led2=!led2; } int main() { __disable_irq(); wait(1); __enable_irq(); btn.fall(&btnflip); pc.attach(&uartflip); NVIC_SetPriority(USART1_IRQn, 1); NVIC_SetPriority(EXTI4_15_IRQn, 3);//PC_13按键属于EXTI4_15_IRQn while (1); } 实验现象是,当按下按键时,LED1点亮,此时若通过PC给开发板发数据,LED4会点亮。若先给开发板发数据,再按下按键,会发现LED1不会点亮,这是因为优先级低的中断无法打断优先级高的中断。
|