【前言】
恒子之后的系列文章都是为了记录自己在跟着韦东山老师学习嵌入式Linux开发过程中自己所学知识的梳理与总结。
若恒子的学习记录对您有帮助,那么将是我莫大的荣幸;如果文章当中有写得不当的地方,还望您指出,我将感谢至极!
恒子所用的开发板是韦老师的JZ2440,故之后的代码都是在JZ2440上运行成功的代码(都是裸板程序)。如果您是用其他开发板,也只需对代码进行简单修改。
文章目录
- 一、用LED灯实现流水灯
- 二、用按键控制LED灯的亮灭
一、用LED灯实现流水灯
在解决这个问题之前我们需要先查看JZ2440的原理图来了解如下两点:
- 我们需要用哪几个LED灯,以及对应的LED是连接在哪几个引脚的和对应引脚是通过输出高电平(1)还是低电平(0)来点亮LED;
- 查看S3C2440芯片手册,了解GPIO管脚的配置方法。
首先明确我们要使用LED的为D10、D11和D12来实现跑马灯效果,通过查看原理图我们知道D10–>GPF4、D11–>GPF5、D12–>GPF6(–>表示引脚连接),当对应引脚输出低电平(0)时对应的LED灯点亮,输出高电平(1)时熄灭。
然后通过查看芯片手册我们知道需要配置的GPIO管脚寄存器有GPFCON和GPFDAT,对应的寄存器地址和相应位的配置信息如下图。
C代码文件 led.c 如下:
#define pGPFCON (*(unsigned int *)0x56000050)
#define pGPFDAT (*(unsigned int *)0x56000054)
void delay(volatile int d)
{
while (d--);
}
int main(void)
{
int statu = 7;
pGPFCON &= ~((3<<8) | (3<<10) | (3<<12));
pGPFCON |= ((1<<8) | (1<<10) | (1<<12));
while (1)
{
pGPFDAT &= ~(7<<4);
pGPFDAT |= (statu<<4);
delay(100000);
switch (statu)
{
case 7: statu = 6; break;
case 6: statu = 5; break;
case 5: statu = 3; break;
case 3: statu = 6; break;
default: statu = 7;
}
}
return 0;
}
这里的C文件并不是在我们常用的MDK中编译的,那么这个C文件中的main函数由谁调用呢?这是我们在MDK中编写代码所不需要考虑问题,因为MDK是一个高度集成的软件,它早已将这一切帮我们做好了,而我们需要做的仅仅只是点几个按钮就可以了。MDK中也是需要汇编启动代码去调用main函数的,只不过它帮我们设置好而已。既然是在裸机上开发程序那么我们就得自己实现一个汇编启动代码去调用main函数。
知道了是谁调用main后我们又该怎样才能让这个C代码在我们的裸机开发板上运行呢?因为我们知道局部变量是保存在栈中的,那既然是栈我们就得设置内存了(SRAM),而NOR启动和NAND启动的片内4K SRAM是不一样的,它们的具体地址看下图。因为我们是使用满减的栈,所以我们得让sp指向栈最高的地址处。
汇编启动文件 start.S 如下:
.text
.global _start
_start:
ldr r0 , =0x53000000
ldr r1, =0
str r1, [r0]
mov r1, #0
ldr r0, [r1]
str r1, [r1]
ldr r2, [r1]
cmp r1, r2;
ldr sp, = 0x40000000 + 4096
ldreq sp, = 4096
streq r0, [r1]
bl main
halt:
bl halt
其中的r0、r1、sp为ARM中的寄存器,ARM状态下共有14个通用寄存器r0~r14,另外还有r15、CPSR(当前程序状态寄存器)和SPSR(程序保护状态寄存器),其中 r13 为 lr (连接寄存器)、r14 为 sp (堆栈指针)、r15 为pc (程序计数器)。
二、用按键控制LED灯的亮灭
这里我们要做的事情如下:
- 确定用哪个按键控制哪个LED灯 ;
- 明白按键按下时与按键相连的引脚是高电平(1)还是低电平(0)。
通过查看原理图我们选取按键S2–>D10,S3–>D11,S4–>D12,当按键按下时让对应的LED灯点亮,松开时熄灭。
在原理图中我们还发现当按键下时对应引脚为低电平(0)
C代码文件 key_led.c 如下:
#include "s3c2440_soc.h"
void delay(volatile int d)
{
while (d--);
}
int main(void)
{
int val1, val2;
GPFCON &= ~((3<<0) | (3<<4));
GPGCON &= ~(3<<6);
GPFCON &= ~((3<<8) | (3<<10) | (3<<12));
GPFCON |= ((1<<8) | (1<<10) | (1<<12));
while (1)
{
val1 = GPFDAT;
val2 = GPGDAT;
if ((val1 & (1<<0)) == 0 )
{
GPFDAT &= ~(1<<4);
}
else
{
GPFDAT |= (1<<4);
}
if ((val1 & (1<<2)) == 0 )
{
GPFDAT &= ~(1<<5);
}
else
{
GPFDAT |= (1<<5);
}
if ((val2 & (1<<3)) == 0 )
{
GPFDAT &= ~(1<<6);
}
else
{
GPFDAT |= (1<<6);
}
}
return 0;
}
汇编启动文件 start.S 如下:
.text
.global _start
_start:
ldr r0 , =0x53000000
ldr r1, =0
str r1, [r0]
mov r1, #0
ldr r0, [r1]
str r1, [r1]
ldr r2, [r1]
cmp r1, r2;
ldr sp, = 0x40000000 + 4096
ldreq sp, = 4096
streq r0, [r1]
bl main
halt:
bl halt
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)