用LED实现流水灯和用按键控制LED的亮灭

【前言】
  恒子之后的系列文章都是为了记录自己在跟着韦东山老师学习嵌入式Linux开发过程中自己所学知识的梳理与总结。
  若恒子的学习记录对您有帮助,那么将是我莫大的荣幸;如果文章当中有写得不当的地方,还望您指出,我将感谢至极!
  恒子所用的开发板是韦老师的JZ2440,故之后的代码都是在JZ2440上运行成功的代码(都是裸板程序)。如果您是用其他开发板,也只需对代码进行简单修改。

一、用LED灯实现流水灯

在解决这个问题之前我们需要先查看JZ2440的原理图来了解如下两点:

  1. 我们需要用哪几个LED灯,以及对应的LED是连接在哪几个引脚的和对应引脚是通过输出高电平(1)还是低电平(0)来点亮LED;
  2. 查看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;	/* 初始三盏灯全熄灭,0b111 */

	/*  配置GPF4\5\6为输出引脚 */
	pGPFCON &= ~((3<<8) | (3<<10) | (3<<12));
	pGPFCON |=  ((1<<8) | (1<<10) | (1<<12));
	
	/* 循环点亮LED0\1\2,对应GPF4\5\6 */
	while (1)
	{
		pGPFDAT &= ~(7<<4);
		pGPFDAT |= (statu<<4);
		delay(100000);	/* 延时一会儿 */
		switch (statu)	/* 状态切换 */
		{
			case 7: statu = 6; break;	/* 状态1: 6 = 0b110, 点亮D10 */
			case 6: statu = 5; break;	/* 状态2: 5 = 0b101, 点亮D11 */
			case 5: statu = 3; break;	/* 状态3: 3 = 0b011, 点亮D12 */
			case 3: statu = 6; break;	/* 返回状态 1 以达到循环的目的 */
			default: statu = 7;			/* 如果都不是则熄灭D10\D11\D12 */
		}
	}
	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]

	/* 设置内存,SP栈 
 	 * 先判断是nor启动还是nand启动
 	 * 可以nand flash进行写,它相当于ram,但不能对nor flash进行写
 	 * 往nand flash的0地址写0,随后读取0地址的值,判断是否为0
	 * 若为0,则为nand启动
	 * 否则则为nor启动
	 */
	mov r1, #0
	ldr r0, [r1]	/* 读原来的值 */
	str r1, [r1]	/* 往0地址写0 */
	ldr r2, [r1]	/* 读写后的值 */
	cmp r1, r2;
	ldr sp, = 0x40000000 + 4096		/* 先假设为nor启动 */
	ldreq sp, = 4096		/*如果相等则为nand启动 */
	streq r0, [r1]

	bl main		/* 跳转到c中的main函数并将返回地址保存在lr中 */

halt:	/* 死循环 */
	bl halt

其中的r0、r1、sp为ARM中的寄存器,ARM状态下共有14个通用寄存器r0~r14,另外还有r15、CPSR(当前程序状态寄存器)和SPSR(程序保护状态寄存器),其中 r13 为 lr (连接寄存器)、r14 为 sp (堆栈指针)、r15 为pc (程序计数器)。
在这里插入图片描述

二、用按键控制LED灯的亮灭

这里我们要做的事情如下:

  1. 确定用哪个按键控制哪个LED灯 ;
  2. 明白按键按下时与按键相连的引脚是高电平(1)还是低电平(0)。

通过查看原理图我们选取按键S2–>D10,S3–>D11,S4–>D12,当按键按下时让对应的LED灯点亮,松开时熄灭。
在原理图中我们还发现当按键下时对应引脚为低电平(0)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
C代码文件 key_led.c 如下:


#include "s3c2440_soc.h"	/* 包含寄存器地址的头文件,读者可根据前一个led.c 中对寄存器宏定义的方法自行定义 */

void delay(volatile int d)
{
	while (d--);
}

int main(void)
{
	int val1, val2;

	/* 用按键s2\s3\s4分别控制led0\led1\led2 
	 * s2->GPF0, s3->GPF2, s4->GPG3
	 * 配置GPF0、GPF2、GPG3为输入引脚
	 */
	GPFCON &= ~((3<<0) | (3<<4));
	GPGCON &= ~(3<<6);
	 
	/*  配置GPF4\5\6为输出引脚 */
	GPFCON &= ~((3<<8) | (3<<10) | (3<<12));
	GPFCON |=  ((1<<8) | (1<<10) | (1<<12));

	/* 用按键控制LED */
	while (1)
	{
		val1 = GPFDAT;
		val2 = GPGDAT;

		if ((val1 & (1<<0)) == 0 )	/* s2->GPF4 */
		{
			/* s2 按下 */
			GPFDAT &= ~(1<<4);
		}
		else
		{
			/* s2 松开 */
			GPFDAT |= (1<<4);
		}
		if ((val1 & (1<<2)) == 0 )	/* s3->GPF5 */
		{
			/* s3 按下 */
			GPFDAT &= ~(1<<5);
		}
		else
		{
			/* s3 松开 */
			GPFDAT |= (1<<5);
		}
		if ((val2 & (1<<3)) == 0 )	/* s4->GPF6 */
		{
			/* s4 按下 */
			GPFDAT &= ~(1<<6);
		}
		else
		{
			/* s4 松开 */
			GPFDAT |= (1<<6);
		}
	}
	return 0;
}

汇编启动文件 start.S 如下:


.text
.global _start

_start:
	/* 关闭看门口 */
	ldr r0 , =0x53000000
	ldr r1, =0
	str r1, [r0]

	/* 设置内存,SP栈 
 	 * 先判断是nor启动还是nand启动
 	 * 可以nand flash进行写,它相当于ram,但不能对nor flash进行写
 	 * 往nand flash的0地址写0,随后判断0地址是否为0
	 * 若为0,则为nand启动
	 * 否则则为nor启动
	 */
	mov r1, #0
	ldr r0, [r1]	/* 读原来的值 */
	str r1, [r1]	/* 往0地址写0 */
	ldr r2, [r1]	/* 读写后的值 */
	cmp r1, r2;
	ldr sp, = 0x40000000 + 4096		/* nor启动 */
	ldreq sp, = 4096		/*如果相等则为 nand启动 */
	streq r0, [r1]

	bl main			/* 跳转到c中的main函数并将返回地址保存在lr中 */

halt:	/* 死循环 */
	bl halt
  • 5
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值