- 分析原理图
- 理解控制硬件的控制原理
- 找到对应的寄存器,并理解寄存器控制流程
- 根据寄存器地址访问硬件
- 实现硬件的控制
(1)分析原理图
硬件底板四个LED灯分别对应 D7、 D8、 D9、 D10。(原理图查看连接引脚)
(2)理解控制硬件的控制原理
(D7->GPIO13 D8->GPIOC17 D9->GPIOC8 D10->GPIOC7)
接VCC3P3_SYS(3.3v高电平),引脚输出低电平产生电势差,灯亮
(3)找到对应的寄存器,并理解寄存器控制流程
代码实现:
1.配置某个端口某个引脚为输出模式
GPIOE多功能寄存器,设置对应的位为00(这里的00是二进制)
Mechanical Dimension & IO Function Description(机械尺寸及IO功能描述)(手册)
GPIOE13-->Alternate(备用) Function(函数) 0 --- 复用功能0
GPIOE13 复用功能0 为普通I/O功能
GPIOCxLTFN0 //复用功能寄存器0(0~15) ~~1//复用功能寄存器0(16~31)
00 = ALT Function0
GPIOEALTFN0 &= ~(0x03<<26); //设置为普通I/O功能 GPIOE13--> Function0
2.使能GPIOE13的引脚输出使能
GPIOE输出使能寄存器对应的位设置为1
Register Description(寄存器描述) GPIOxOUTENB //输入/输出功能选择寄存器(手册)
0 = Disable
1 = Enable
GPIOEOUTENB |= (0x01<<13)//设置引脚为输出功能 GPIOE13 共31位 [13] = 1
3.输出高低电平
GPIOE寄存器对应的位设置为1/0(即可控制灯亮与灭)(手册)
0 = Low Level 低电平(灯亮)
1 = High Level 高电平(灯灭)
定义寄存器地址
寄存器地址 = 寄存值组基地址 + 偏移地址
Base Address 基地址:0xC001_E000
Offset 偏移地址:GPIOxOUT偏移地址:0x0000(将字母换成0(手册不是全对的))
Description 描述 GPIOx output regiset(输出寄存器)
Reset Value (寄存器)复位值
使用交叉编译器进行编译
检查ubuntu是否有交叉编译器
gec@ubuntu:~$ arm-linux-gcc -v
Using built-in specs.
COLLECT_GCC=/usr/local/arm/5.4.0/usr/bin/arm-linux-gcc.br_real
COLLECT_LTO_WRAPPER=/usr/local/arm/5.4.0/usr/bin/../libexec/gcc/arm-none-linux-gnueabi/5.4.0/lto-wrapper
进入共享目录去编译led.c裸机程序
gec@ubuntu:~$ cd /mnt/hgfs/share/002/demo1/
将led.c编译为目标文件led.o,且不使用标准C库
arm-linux-gcc -o led.o -c led.c -nostdlib
将目标文件led.o链接到内存地址0x40000000,输出新的执行文件led.elf
arm-linux-ld -Ttext 0x40000000 -o led.elf led.o
因为uboot不是linux操作操作系统,不支持直接运行应用程序,需要转换为bin文件。
arm-linux-objcopy -O binary led.elf led.bin
代码:
//定义寄存器
#define GPIOEOUT (*(volatile unsigned int*)(0xC0010000 + 0xE000))//输出的电平
#define GPIOEOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xE004))//输入/输出功能选择寄存器
#define GPIOEALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xE020))//复用功能寄存器0(0~15)
#define GPIOEALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xE024))//复用功能寄存器1(16~31)
#define GPIOCOUT (*(volatile unsigned int*)(0xC0010000 + 0xC000))//输出的电平
#define GPIOCOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xC004))//输入/输出功能选择寄存器
#define GPIOCALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xC020))//复用功能寄存器0(0~15)
#define GPIOCALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xC024))//复用功能寄存器1(16~31)
//值强制转换为地址,通过解引用访问地址
/***************************
* 引脚说明:
*
* D7LED --> GPIOE13(GPIOEALTFN0)
* D8LED --> GPIOC17
* D9LED --> GPIOC8
* D10LED -> GPIOC7
* volatile(确保本条指令不会因编译器的优化而省略,且要求每次直接读值)
* ************************/
void delay(void); //函数声明
//程序的入口,不能使用标准c库,因此入口函数名字: _start
void _start(void)
{
/*(数据手册->2.3.1 Ball List Tabie(球(引脚)列表)
GPIOE13->function0 [27:26] = 0:0 (27和26位置0)*/
/*数据手册GPIO Controller(GPIO控制器)->Register Description(寄存器描述)
->GPIOExLTFN0(表格中GPIOx13占位[27:26]) 00 = ALT Function0*/
GPIOEALTFN0 &= ~(0x03<<26); //设置为普通I/O功能 GPIOE13 00
GPIOCALTFN1 |= (0x01<<1); //GPIOC17 01 function1
GPIOCALTFN0 |= ((0x01<<14)|(0x01<<16));//复用不同 要看手册!
//0x03->0000 ... 0011 左移26 27和26为1 取反 &(位与)同时为1 才为1
//设置引脚为输出功能 GPIOE13 共31位 [13] = 1 查找同上
GPIOEOUTENB |= (0x01<<13);
GPIOCOUTENB |= ((0x01<<17)|(0x01<<8)|(0x01<<7));//D8(GPIOC17) D9(GPIOC8) D10(GPIOC7)
while(1)
{
//点亮D7 LED
GPIOEOUT &= ~(0x01<<13);//输出低电平
delay();
//点亮D8 LED
GPIOCOUT &= ~(0x01<<17);//输出低电平
delay();
//点亮D9 LED
GPIOCOUT &= ~(0x01<<8);//输出低电平
delay();
//点亮D10 LED
GPIOCOUT &= ~(0x01<<7);//输出低电平
delay();
//熄灭D7 LED
GPIOEOUT |= (0x01<<13);//输出高电平
delay();
//熄灭D8 LED
GPIOCOUT |= (0x01<<17);//输出高电平
delay();
//熄灭D9 LED
GPIOCOUT |= (0x01<<8);//输出高电平
delay();
//熄灭D10 LED
GPIOCOUT |= (0x01<<7);//输出高电平
delay();
}
}
//函数实现
void delay(void)
{
volatile unsigned int i = 0x3000000;
while(i--);
}
按键控制灯
//定义寄存器
//KEY
#define GPIOAPAD (*(volatile unsigned int*)(0xC0010000 + 0xA018))//输入电平寄存器
#define GPIOAOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xA004))//输入/输出功能选择寄存器
#define GPIOAALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xA020))//复用功能寄存器0(0~15)
#define GPIOAALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xA024))//复用功能寄存器1(16~31)
#define GPIOBPAD (*(volatile unsigned int*)(0xC0010000 + 0xB018))//输入电平寄存器
#define GPIOBOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xB004))//输入/输出功能选择寄存器
#define GPIOBALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xB020))//复用功能寄存器0(0~15)
#define GPIOBALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xB024))//复用功能寄存器1(16~31)
//LED
#define GPIOEOUT (*(volatile unsigned int*)(0xC0010000 + 0xE000))//输出的电平
#define GPIOEOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xE004))//输入/输出功能选择寄存器
#define GPIOEALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xE020))//复用功能寄存器0(0~15)
#define GPIOEALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xE024))//复用功能寄存器1(16~31)
#define GPIOCOUT (*(volatile unsigned int*)(0xC0010000 + 0xC000))//输出的电平
#define GPIOCOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xC004))//输入/输出功能选择寄存器
#define GPIOCALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xC020))//复用功能寄存器0(0~15)
#define GPIOCALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xC024))//复用功能寄存器1(16~31)
/********************
* 引脚说明:
* KEY2 -> GPIOA28 (GPIOAALTFN1)[25:24] function0 00
* KEY3 -> GPIOB30 (GPIOBALTFN1)[29:28] function1 01
* KEY4 -> GPIOB31 (GPIOBALTFN1)[31:30] function1 01
* KEY6 -> GPIOB9 (GPIOBALTFN0)[19:18] function0 00
*
* D7LED --> GPIOE13(GPIOEALTFN0)
* D8LED --> GPIOC17
* D9LED --> GPIOC8
* D10LED -> GPIOC7
* *****************/
void delay();
void _start(void)
{
//LED
//设置为普通I/O功能
GPIOEALTFN0 &= ~(0x03<<26); //LED7
GPIOCALTFN1 |= (0x01<<1); //LED8
GPIOCALTFN0 |= ((0x01<<14)|(0x01<<16)); //LED9 LED10
//设置引脚为输出功能 GPIOE13 共31位 [13] = 1 查找同上
GPIOEOUTENB |= (0x01<<13);
GPIOCOUTENB |= ((0x01<<17)|(0x01<<8)|(0x01<<7));//D8(GPIOC17) D9(GPIOC8) D10(GPIOC7)
//KEY
//设置为普通I/O功能
GPIOAALTFN1 &= ~(0x03<<24); // KEY2
GPIOBALTFN1 |= ((0x01<<28)|(0x01<<30)); // KEY3 KEY4
GPIOBALTFN0 &= ~(0x03<<18); // KEY6
//设置引脚为输入功能
GPIOAOUTENB &= ~(0x01<<28); //KEY2 28位置0
GPIOBOUTENB &= ~((0x01<<30)|(0x01<<31)|(0x01<<9));// KEY3 KEY4 KEY6 30 31 9位置0
//熄灭D7 LED
GPIOEOUT |= (0x01<<13);//输出高电平
//熄灭D8 LED
GPIOCOUT |= (0x01<<17);//输出高电平
//熄灭D9 LED
GPIOCOUT |= (0x01<<8);//输出高电平
//熄灭D10 LED
GPIOCOUT |= (0x01<<7);//输出高电平
while(1)
{
/**KEY变更LED状态**/
/**0->低电平 1->高电平 默认高电平 按下接地 低电平**/
if( (GPIOAPAD & (0x01<<28)) == 0 ) // KEY2
{
delay(); //消抖
if( (GPIOAPAD & (0x01<<28)) == 0 )
{
while( (GPIOAPAD & (0x01<<28)) == 1 );
//变更LED状态 LED7->GPIOE13 ^= 不等为1
GPIOEOUT ^= (0x01<<13); //0->输出低电平
}
}
if( (GPIOBPAD & (0x01<<30)) == 0 ) // KEY3
{
delay(); //消抖
if( (GPIOBPAD & (0x01<<30)) == 0 )
{
while( (GPIOBPAD & (0x01<<30)) == 1 );
//变更LED状态 LED8->GPIOE17 ^= 不等为1
GPIOCOUT ^= (0x01<<17); //0->输出低电平
}
}
if( (GPIOBPAD & (0x01<<31)) == 0 ) // KEY4
{
delay(); //消抖
if( (GPIOBPAD & (0x01<<31)) == 0 )
{
while( (GPIOBPAD & (0x01<<31)) == 1 );
//变更LED状态 LED9->GPIOE8 ^= 不等为1
GPIOCOUT ^= (0x01<<8); //0->输出低电平
}
}
if( (GPIOBPAD & (0x01<<9)) == 0 ) // KEY6
{
delay(); //消抖
if( (GPIOBPAD & (0x01<<9)) == 0 )
{
while( (GPIOBPAD & (0x01<<9)) == 1 );
//变更LED状态 LED10->GPIOE7 ^= 不等为1
GPIOCOUT ^= (0x01<<7); //0->输出低电平
}
}
}
}
void delay()
{
volatile unsigned int i = 0x1000000;
while(i--);
}
按键控制蜂鸣器
//定义寄存器
//KEY
#define GPIOAPAD (*(volatile unsigned int*)(0xC0010000 + 0xA018))//输入电平寄存器
#define GPIOAOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xA004))//输入/输出功能选择寄存器
#define GPIOAALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xA020))//复用功能寄存器0(0~15)
#define GPIOAALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xA024))//复用功能寄存器1(16~31)
#define GPIOCOUT (*(volatile unsigned int*)(0xC0010000 + 0xC000))//输出的电平
#define GPIOCOUTENB (*(volatile unsigned int*)(0xC0010000 + 0xC004))//输入/输出功能选择寄存器
#define GPIOCALTFN0 (*(volatile unsigned int*)(0xC0010000 + 0xC020))//复用功能寄存器0(0~15)
#define GPIOCALTFN1 (*(volatile unsigned int*)(0xC0010000 + 0xC024))//复用功能寄存器1(16~31)
/********************
* 引脚说明:
* KEY2 -> GPIOA28 (GPIOAALTFN1)[25:24] function0 00
* BEEP -> PWM2 -> GPIOC14 (GPIOCALTFN0)[29:28] function1 01
* *****************/
void delay();
void _start(void)
{
//KEY
//设置为普通I/O功能
GPIOAALTFN1 &= ~(0x03<<24); // KEY2
GPIOAALTFN0 |= (0x01<<28); //BEEP
//设置引脚为输入功能
GPIOAOUTENB &= ~(0x01<<28); //KEY2 28位置0
//设置引脚为输出功能
GPIOCOUTENB |= (0x01<<14); //BEEP 14位置1
//输出低电平 三极管截止 不响 GND(负极)
GPIOCOUT &= ~(0x01<<14);
while(1)
{
/**KEY变更LED状态**/
/**0->低电平 1->高电平 默认高电平 按下接地 低电平**/
if( (GPIOAPAD & (0x01<<28)) == 0 ) // KEY2
{
delay(); //消抖
if( (GPIOAPAD & (0x01<<28)) == 0 )
{
while( (GPIOAPAD & (0x01<<28)) == 1 );
GPIOCOUT ^= (0x01<<14); //变更状态
}
}
}
}
void delay()
{
volatile unsigned int i = 0x1000000;
while(i--);
}