DAY16. 轮询与中断
如果出现图片无法查看可能是网络问题,我用的GitHub+图床保存的图片,可以参考我另外一篇文章GitHub的使用方法含网络问题解决
GitHub使用教程含网络问题_github加速器_肉丸子QAQ的博客-CSDN博客
相关作业和资料已上传,请在主页自行查看
1. CPU与硬件的交互方式
1. 轮询
CPU执行程序时不断地询问硬件是否需要其服务,若需要则给予其服务,若不需要一段时间后再次询问,周而复始
2. 中断
CPU执行程序时若硬件需要其服务,对应的硬件给CPU发送中断信号,CPU接收到中断信号后将当前的程序暂停下来,转而去执行中断服务程序,执行完成后再返回到被打断的点继续执行
3. DMA
硬件产生数据后,硬件控制器可将产生的数据直接写入到存储器中,整个过程无需CPU的参与
2. 轮询方式实现按键实验
- 查看原理图寻找按键(本次使用K2)
正常状态按键不按下时,有上拉电阻的存在所以是高电平,按下是低电平
- 查看芯片引脚
GPX1_1
- 查看相关寄存器
读取GPXDAT寄存器对应位的数值,0表示读取的低电平,1表示高电平
#include "exynos_4412.h"
int main()
{
GPX1.CON = GPX1.CON & (~(0xF << 4));// [7:4]清零
while(1)
{
/*判断GPX1_1引脚的状态,即判断按键是否按下*/
if(!(GPX1.DAT & (1 << 1))) //除了自己要读的位保持不变,其他位全部清零,读取到低电平表示按下所以要取非才能做出判断
{
printf("key2 pressed\n");
}
else
{
}
}
return 0;
}
C语言中!
代表的是非,~
代表的是取反,!
是逻辑运算符, ~
一般是用于设置标志位
按键按下一次会打印很多个,因为我们按下一次的时间已经能运行很多次循环了,所以需要一个等待按键松开的程序
#include "exynos_4412.h"
int main()
{
GPX1.CON = GPX1.CON & (~(0xF << 4));// [7:4]清零
while(1)
{
/*判断GPX1_1引脚的状态,即判断按键是否按下*/
if(!(GPX1.DAT & (1 << 1))) //除了自己要读的位保持不变,其他位全部清零,读取到低电平表示按下所以要取非才能做出判断
{
printf("key2 pressed\n");
/*等待松手*/
while(!(GPX1.DAT & (1 << 1)));
}
else
{
c
}
}
return 0;
}
按下一次只打印一次内容
3. GPIO中断相关寄存器
1. GPIO中断
当按键按下的时候会给CPU发送信号,执行中断程序,就不需要一遍又一遍的去问了
2. 设置中断流程及相关寄存器
- 通过查看芯片手册可以知道
GPX1_1
拥有中断的功能
- 单纯将IO设置成中断模式还无法达到要求,需要其他的一些寄存器进行更加细节的设置
根据芯片手册
GPX0
的引脚对应EXT_INT40_FLTCON1
中的40,以此类推GPX1
对应41
EXT_INT41CON寄存器
EXT_INT41_FLTCON1寄存器
滤波寄存器,本次实验不用
设置滤波电路,可以防止按键抖动
也可以设置滤波类型
(实际测试这个寄存器没什么用,效果没太大区别)
EXT_INT41_MASK寄存器
设置中断开关
EXT_INT41_PEND寄存器
挂起寄存器:当cpu在处理其他的中断请求的时候,没办法及时的处理当前的中断,可以等待其他中断处理后再来执行当前中断
这个寄存器一般来说不用自己写,前期初始化不用管 , 但是在中断处理结束后需要手动清零
4. GPIO中断编程
5. 作业
1.简述轮询和中断两种方式的本质区别是什么
轮询是cpu每隔一段时间就要查看一次是否有信号,中断是当有信号产生的时候发送给CPU,一个CPU主动接收信号,一个CPU被动接收信号
2.使用轮询的方式检测Key3按键的状态,实现按一次按键,LED2点亮,再次按下,LED2熄灭
第一种思路:
#include "exynos_4412.h"
void LED_INIT(void)
{
GPX2.CON = GPX2.CON & (~(0XF << 28)) | (0x1 << 28);
}
void LED_ON(void)
{
GPX2.DAT = GPX2.DAT | (0x1 << 7);
}
void LED_OFF(void)
{
GPX2.DAT = GPX2.DAT & (~(0x1 << 7));
}
int main()
{
LED_INIT();
LED_OFF();
int a = 0;
GPX1.CON = GPX1.CON & (~(0xF << 8));// [11:0]清零,0表示输入模式
while(1)
{
/*判断GPX1_2引脚的状态,即判断按键是否按下*/
if((!(GPX1.DAT & (1 << 2))) && (a == 0)) //除了自己要读的位保持不变,其他位全部清零,读取到低电平表示按下所以要取非才能做出判断
{
LED_ON();
printf("ON\n");
/*等待松手*/
while((!(GPX1.DAT & (1 << 2))) && (a == 0))
{
;
}
a = 1;
}
if((!(GPX1.DAT & (1 << 2))) && (a == 1)) //除了自己要读的位保持不变,其他位全部清零,读取到低电平表示按下所以要取非才能做出判断
{
LED_OFF();
printf("OFF\n");
while((!(GPX1.DAT & (1 << 2))) && (a == 1))
{
;
}
a = 0;
}
}
return 0;
}
第二种思路:
#include "exynos_4412.h"
void LED_INIT(void)
{
GPX2.CON = GPX2.CON & (~(0XF << 28)) | (0x1 << 28);
}
void LED_ON(void)
{
GPX2.DAT = GPX2.DAT | (0x1 << 7);
}
void LED_OFF(void)
{
GPX2.DAT = GPX2.DAT & (~(0x1 << 7));
}
int main()
{
LED_INIT();
LED_OFF();
int a = 0;
GPX1.CON = GPX1.CON & (~(0xF << 8));// [11:0]清零,0表示输入模式
while(1)
{
/*判断GPX1_2引脚的状态,即判断按键是否按下*/
if(!(GPX1.DAT & (1 << 2))) //除了自己要读的位保持不变,其他位全部清零,读取到低电平表示按下所以要取非才能做出判断
{
printf("Key2 Pressed\n");
/*等待松手*/
while(!(GPX1.DAT & (1 << 2)))
{
;
}
a++;
}
if(a%2)
{
/*点亮LED2*/
printf("NO\n");
LED_ON();
}
else
{
/*熄灭LED2*/
printf("OFF\n");
LED_OFF();
}
}
return 0;
}