一、CPU与硬件的交互方式
轮询
CPU执行程序时不断地询问硬件是否需要其服务,若需要则给予其服务,若不需要一段时间后再次询问,周而复始
中断
CPU执行程序时若硬件需要其服务,对应的硬件给CPU发送中断信号,CPU接收到中断信号后将当前的程序暂停下来,转而去执行中断服务程序,执行完成后再返回到被打断的点继续执行
DMA
硬件产生数据后,硬件控制器可将产生的数据直接写入到存储器中,整个过程无需CPU的参与
二、轮询方式实现按键实验
先找到K2按键。
正常状态下,UART_RING是高电平,当K2按下,变成低电平,松手以后,重新变回高电平。
使用GPIO的输入功能来检测引脚的电平状态。
#include "exynos_4412.h"int main()
{/*将GPX1_1设置成输入功能*/GPX1.CON = GPX1.CON & (~(0xF << 4));while(1){if(!(GPX1.DAT & (1 << 1))){printf("Key2 Pressed\n");}else{}}return 0;
}
CPU执行速度很快,所以K2按键按一下就会打印出很多"Key2 Pressed"
#include "exynos_4412.h"int main()
{/*将GPX1_1设置成输入功能*/GPX1.CON = GPX1.CON & (~(0xF << 4));while(1){/*判断GPX1_1引脚的状态,即判断按键是否按下*/if(!(GPX1.DAT & (1 << 1))){printf("Key2 Pressed\n");/*等待松手*/while(!(GPX1.DAT & (1 << 1)));}else{}}return 0;
}
此时,K2按键按一下只会打印一边"Key pressed"
三、GPIO中断相关寄存器详解
如果把GPX0设置成中断功能后,中断的细节就在以下带40的里设置,GPX1对应41,依次类推。
GPX1_1对应EXT_INT41_CON[1],用于管理和配置中断相关功能。
设置中断触发方式:
0x1:低电平可以触发信号
0x2:高电平可以触发信号
0x3:下降沿可以触发信号(即从高电平变为低电平时)
0x4:上升沿可以触发信号(即从低电平变为高电平时)
0x5:上升沿或下降沿都可以触发信号
本次实验使用的是K2按键,① 如果使用低电平触发方式,可能会多次触发中断。② 如果使用高电平触发方式,我们没按下K2按键时,就处于高电平状态,即会一直发送中断信号。③ 使用下降沿触发方式没有问题,还可以避免按一次就触发好几次中断。④ 设置成上升沿,则松手时会触发信号。⑤ 设置成双边沿,按一次会触发两次。
EXT_INT41_FLTCON1是滤波寄存器,因为手可能会抖导致产生奇怪的波形这个电路会把波形变成我们想要的。(本次实验不使用)
EXT_INT41_MASK用于设置中断的开关,每一位对应一个引脚,也就是EXT_INT41_MASK[1]对应GPX1_1的开和关。0x0打开中断,0x1关闭中断。
EXT_INT41_PEND是挂起寄存器,由于CPU在执行别的中断时会自动屏蔽同时给他发送到中断信号,为了不丢失这个信号,我们可以使用挂起功能,在CPU做别的东西时我们把信号挂起,等CPU空闲了我们在发送信号。(这个寄存器一般不用自己写,引脚产生中断后,会自动置1)
四、GPIO中断编程
中断挂起寄存器,当有中断产生时,会自动置1,当中断处理完后,我们需要把它置0.(本次实验暂时不设置)
#include "exynos_4412.h"int main()
{/*将GPX1_1设置成中断功能*/GPX1.CON = GPX1.CON | (0xF << 4);/*设置GPX1_1中断触发方式:下降沿触发*/EXT_INT41_CON = EXT_INT41_CON & (~(0x7 << 4)) | (0x2 << 4);/*使能GPX1_1的中断功能*/EXT_INT41_MASK = EXT_INT41_MASK & (~(1 << 1)); return 0;
}
作业
使用轮询的方式检测Key3按键的状态,实现按一次按键,LED2点亮,再次按下,LED2熄灭
#include "exynos_4412.h"int main()
{/*将GPX2_7设置成输出功能(LED2)*/GPX2.CON = GPX2.CON & (~(0xF << 28)) | (1 << 28);/*将GPX1_2设置成输入模式(K3)*/GPX1.CON = GPX1.CON | (~(0xF << 8));while(1){/*判断GPX1_2引脚的状态,即判断按键是否按下*/if(!(GPX1.DAT & (1 << 2))){/*判断LED3当前的状态*/if(!(GPX2.DAT & (1 << 7)))GPX2.DAT = GPX2.DAT | (0x1 << 7);elseGPX2.DAT = GPX2.DAT & (~(0x1 << 7));/*等待松手*/while(!(GPX1.DAT & (1 << 2)));}else{}}return 0;
}