kinetis 学习之(二)中断
来源:互联网 发布:大数据分析与挖掘平台 编辑:程序博客网 时间:2024/06/06 07:33
中断是微控制器处理异步事件的一种机制。一般而言,每个中断源都能够选择打开和关闭,默认状态下都是关闭的。为了能让 CPU 响应中断源的中断请求,必须打开对应的中断。
不同的的单片机中断的原理都大同小异,但是在具体编写代码时可能会不一样。这里介绍的freescale的K20是基于ARM的M4内核的,所以和其他的ARM芯片类似,需要在三个地方配置:①中断源本身存在中断使能寄存器位,该位决定中断源是否产生中断请求,比如GPIO就在这个引脚对应的寄存器里会有相应的中断使能位;②中断控制器( NVIC)相应的中断通道(各个中断源的中断请求连接在 NVIC 的不同的中断通道, NVIC 负责管理系统所有的中断信号,比如赋予各中断优先级等)需要被打开;③全局中断屏蔽位需要打开,该位能够屏蔽和打开所有的可屏蔽中断(换句话说,有一些中断是没有打开全局中断也可以进入中断的,它们是不可屏蔽中断,在K20里面一共有16个)。
这里介绍一种比较基础的中断,GPIO的中断。结合前面的GPIO的内容,我们使用按键来控制灯的闪烁方式。
依然是分三步。先看原理图。当按键没有按下时,引脚上是高电平,当按下时C1上的电荷释放,相对较慢变为0,但是这个滤波的效果其实并不好,所以在中断处理函数中最好通过软件的方法再处理,来去抖动。LED灯D1和D2的引脚对应到K20上的PTB11和PTB18两个引脚,按键UP对应的是K20上的PTA5引脚。
图1 按键的原理图
再看数据手册和参考手册上的寄存器。在PORTx_PCRn中有关于引脚功能的描述。其中ISF:中断状态标志位,w1c表示向该位写1将会将其清零;IRQC:中断配置,配置在什么情况下产生中断;MUX选择引脚启用的功能。如图2所示。
图2 中断功能选择
接下来思考实现用按键控制灯状态的整体思路:首先打开PORTA和PORTB的端口时钟,配置D1和D2对应的引脚为GPIO模式,设置为输出方向。对按键UP对应的引脚要配置为GPIO,选择下降沿触发和启用引脚的低通滤波功能(根据参考手册上当有用信号的频率大于2MHz时就不应该开启低通滤波功能)。接着使能PORTA的中断(根据参考手册可知PORTA的中断号(IRQ)为87),使能全局中断(在ARM中专门的一条汇编指令为asm(“ CPSIE i” ))。接下来需要编写中断服务函数,并把它写在保存有中断向量表的Project_Settings/Startup_Code/kinetis_sysinit.c这个文件中,且在中断向量表中对应IRQ号对应处保存到中断函数名,在中断函数中需要实现对一个标志符号led_mode的值翻转。最后,在主函数中使用while()循环,根据led_mode来判断要LED的闪烁方式。
这里需要注意的一点是如何将在kinetis_sysinit.h中定义的led_mode变量既可以在kinetis_sysinit.c又可以在main.c中调用。具体是:在kinetis_sysinit.h中声明一个变量extern char led_mode ;在main.c中也要申明char led_mode ;在kinetis_sysinit.c中可以直接使用。需要注意的是在kinetis_sysinit.h中的含有extern申明时不可以赋初值。
由于暂时找不到上次文件的按钮,所以贴代码如下。
#define GPIO_PIN_MASK 0xFFu
#define GPIO_PIN(x) (((1)<<(x & GPIO_PIN_MASK)))
char led_mode = 0;
void enable_irq (int irq)
{
int div;
/* Determine which of the NVICISERs corresponds to the irq */
div = irq/32;
switch (div)
{
case 0x0:
NVICICPR0 = 1 << (irq%32);
NVICISER0 = 1 << (irq%32);
break;
case 0x1:
NVICICPR1 = 1 << (irq%32);
NVICISER1 = 1 << (irq%32);
break;
case 0x2:
NVICICPR2 = 1 << (irq%32);
NVICISER2 = 1 << (irq%32);
break;
}
}
//delay 1ms , unit is ms
void delay_1ms(int Ms)
{
unsigned short i,j;
for(i=0;i<Ms;i++)
{
for(j=0;j<2000;j++)
asm("nop");
}
}
void flashing()
{
GPIOB_PDOR |= (GPIO_PIN(18) ); // turn off
GPIOB_PDOR &= ~GPIO_PIN(11); // turn on
delay_1ms(1000);
GPIOB_PDOR &= ~(GPIO_PIN(18)); // turn on
GPIOB_PDOR |= GPIO_PIN(11); // turn off
delay_1ms(1000);
}
void twinkle()
{
GPIOB_PDOR |= (GPIO_PIN(18) | GPIO_PIN(11)); // turn off
delay_1ms(1000);
GPIOB_PDOR &= ~(GPIO_PIN(18) | GPIO_PIN(11)); // turn on
delay_1ms(1000);
}
int main(void)
{
// turn on port D clocks
SIM_SCGC5 |= (SIM_SCGC5_PORTB_MASK|SIM_SCGC5_PORTA_MASK);
// Set pin18 of PORTB as GPIO
PORTB_PCR18 |= PORT_PCR_MUX(1);
// set pin11 of PORTB as GPIO
PORTB_PCR11 |= PORT_PCR_MUX(1);
// set pin18, pin11 to be output
GPIOB_PDDR |= GPIO_PIN(18)|GPIO_PIN(11);
//key as gpio port,falling interrupt
PORTA_PCR5 |= ( PORT_PCR_IRQC(10)|PORT_PCR_MUX(1)|PORT_PCR_PFE_MASK);
// open globe intterrupt
asm("CPSIE i");
// enable irq
enable_irq(87);
while(1)
{
if(led_mode)
flashing(); // flashing leds
else
twinkle(); // twinkle leds
}
return 0;
}
- kinetis 学习之(二)中断
- kinetis 学习之(一) GPIO
- 飞思卡尔kinetis L系列MCU之中断5扇门
- 嵌入式操作系统分析(二):中断之中断机制
- s3c6410裸机学习笔记(二)--中断
- RT-Thread 学习笔记(二)---线程创建及任务间通信之中断锁
- 西门子PLC学习笔记二十一-(中断处理二)
- (七)c52学习之旅-中断
- linux中断之二(s5pv210)
- 【51单片机学习过程记录】16 中断之 串口中断的应用2(中断方式)
- 十.ARM裸机学习之中断系统2(S5PV210按键外部中断及中断处理)
- 中断 Linux 中断学习之前言篇
- 汇编--学习笔记(十三)-中断(二)- 自我总结
- ARM 学习笔记(二) S3C2440 中断配置
- C51学习笔记(二)---中断及数码管应用
- 西门子PLC学习笔记二十一-(中断处理一)
- C51单片机学习(二):中断系统和定时器
- ARM-Linux s3c2440 之中断分析(二)
- 《c程序设计语言》读书笔记-5.9-指针转换天数和日期
- CString和string的互相转换
- 你会用eclipse导入项目吗?eclipse如何导入非eclipse项目
- Linux 下使用Screen
- C#一个非常使用的寻找字符串函数
- kinetis 学习之(二)中断
- The Struts dispatcher cannot be found. This is usually caused by using Struts tags without the asso
- ArcObjects帮助文档翻译--接口转换 Casting between interfaces
- 在加密和签名中使用数字证书
- 初学Unity3D
- Cocos2d – x学习笔记[4] 动画
- Network socket programming using the NetLib library
- 中文乱码问题
- 我自己的修炼之道--根据大神的程序员修炼之道整理