LED灯我们接触了管脚输出功能,有出就有入,这一章将利用管脚的输入功能来获取按键的输入值。进而控制LED灯的亮灭。
依然是三步骤:
- 看原理图 ----- 确定引脚连线
- 看芯片手册 ----- 确定引脚功能
- 写程序 ----- 完成功能开发
1、按键输入
按键采用轮询方式,也就是在死循环不断检测引脚电平。再LED C语言版本上开发。
Ⅰ、看门狗
这里先介绍一下看门狗,看门狗的作用:当长时间没有“喂狗”,系统会重启,这是为了让芯片出现死机时,能够自己复位,重新运行。如何关闭呢?看芯片手册。
搜索dog可以找到关于看门狗的寄存器,bit0表明写入0可以关闭复位功能
汇编代码:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
Ⅱ、按键原理图
可以看出,按键按下是低电平
按键与soc的接线管脚是GPF0
Ⅲ、按键芯片手册
只需要在bit[1:0]写入00即可设置为输入模式
Ⅳ、按键编程
GPFCON &= ~((3<<0) | (3<<4)); /* gpf0,2 */
GPGCON &= ~((3<<6)); /* gpg3 */
Ⅴ、完整代码
main.c
"s3c2440_soc.h"包含了所有寄存器的操作地址
#include "s3c2440_soc.h"
void delay(volatile int d)
{
while (d--);
}
int main(void)
{
int val1, val2;
/* 设置GPFCON让GPF4/5/6配置为输出引脚 */
GPFCON &= ~((3<<8) | (3<<10) | (3<<12));
GPFCON |= ((1<<8) | (1<<10) | (1<<12));
/* 配置3个按键引脚为输入引脚:
* GPF0(S2),GPF2(S3),GPG3(S4)
*/
GPFCON &= ~((3<<0) | (3<<4)); /* gpf0,2 */
GPGCON &= ~((3<<6)); /* gpg3 */
/* 循环点亮 */
while (1)
{
val1 = GPFDAT;
val2 = GPGDAT;
if (val1 & (1<<0)) /* s2 --> gpf6 */
{
/* 松开 */
GPFDAT |= (1<<6);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<6);
}
if (val1 & (1<<2)) /* s3 --> gpf5 */
{
/* 松开 */
GPFDAT |= (1<<5);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<5);
}
if (val2 & (1<<3)) /* s4 --> gpf4 */
{
/* 松开 */
GPFDAT |= (1<<4);
}
else
{
/* 按下 */
GPFDAT &= ~(1<<4);
}
}
return 0;
}
start.S
这里为了区分nand启动还是nor启动,利用了nor不能直接写的特性进行判断。
.text
.global _start
_start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
moveq sp, #4096 /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */
bl main
halt:
b halt
Ⅵ、运行
将代码编译烧录进ARM开发板,可以看到按下s2键LED3亮,按下s3键LED2亮,按下s4键LED1亮