1.点亮led灯----裸机编程流程
裸机编程:
1.查看原理图,找到引脚
点亮LED3
查看devboard文档找到led3
在coreboard文档里找CHG_FLT
找到引脚是GPX1_0
2.查看芯片手册,找寄存器
在数据手册里搜gpx1,找到下面两个寄存器
GPX1_0 ... GPX1_7都是由这两个寄存器控制的
设置GPX1_0为输出功能:将GPX1CON的0-3位设置为0x1 地址:0x1100 0c20
设置GPX1_0输出1:将GPX1DAT的第0位设置为1 地址:0x1100 0c24
3.编程
led.h文件:
#ifndef _LED_H_
#define _LED_H_
//volatile--->防止编译器优化
#define GPX1CON *((volatile unsigned int *)0x11000c20) //将0x11000c20(地址)的内容取出来
#define GPX1DAT *((volatile unsigned int *)0x11000c24)
void led3_init();
void led3_on();
void led3_off();
#endif
led.c文件:
#include "led.h"
void led3_init()
{
//设置GPX1_0的功能为输出 0-3位设置为0x1
GPX1CON = GPX1CON & ~(0xf << 0) | 0x01 << 0;
}
void led3_on()
{
//让GPX1_0输出1 0为设置1
GPX1DAT |= 0x01 << 0;
}
void led3_off()
{
GPX1DAT &= ~(0x01 << 0);
}
main.c文件:
#include "led.h"
void delay()
{
int i;
for(i = 0; i < 500000; i++);
}
int main()
{
led3_init();
while(1)
{
led3_on();
delay();
led3_off();
delay();
}
return 0;
}
makefile工程文件:
CROSS = arm-none-linux-gnueabi-
CC=$(CROSS)gcc
LD=$(CROSS)ld
OBJCOPY=$(CROSS)objcopy
all:
$(CC) -g -c -o led.o led.c
$(CC) -g -c -o start.o start.s
$(LD) start.o led.o -Tmap.lds -o led.elf
$(OBJCOPY) -O binary -S led.elf led.bin
$(CROSS)objdump -D led.elf > led.dis
clean:
rm -f *.o *.elf *.bin *.dis
其中:
elf是linux系统下二进制可执行、可链接文件的文件格式
bin格式是在裸机上运行的二进制文件的格式
所以:需要将elf先转换为bin格式,才可以直接在板子上运行,本质就是把elf文件中一些符号给删掉了
objdump:反汇编,将机器码反汇编成汇编指令,一般用于调试
map.lds链接脚本文件:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0; @链接地址
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.data :
{ *(.data) }
. = ALIGN(4);
.bss :
{ *(.bss) }
}
注意:如果是相对寻址,链接地址可以和运行地址不一样,而如果是绝对寻址,链接地址和运行地址必须一样,比如中断
start.s汇编文件:
.global _start @定义一个全局的符号_start
_start:
.text
b main
.end
2.看门狗
定时器的工作原理:
回忆qt中如何通过一个1s的定时器实现60s的定时?
需要:
- 一个基准时间 1s的定时
- 一个计数器 初始值60
- 每过一秒-1,当减到0时60s时间就到
定时器的工作原理:
- 有时钟 100Mhz 太大------>变小 分频 假设最终我得到的是一个625Hz的时钟
一个时钟周期的时间1/625s
- 计数器 初始值:3125
- 实现5s的定时
每隔1/625s,计数器的值就减1,当减到0时,5s的时间就到了
看门狗:
while(1)
{
//喂狗
给计数器重新赋值为3125
....
....
...
....
//如果在这里卡死了,计数器的值就会减为0,复位
}
在点亮led灯的文件下添加wdt.c文件、wdt.h文件,修改makefile工程文件
wdt.h文件:
#ifndef _WDT_H_
#define _WDT_H_
#define WTCON *((volatile unsigned int *)0x10060000) //将0x10060000(地址)的内容取出来
#define WTCNT *((volatile unsigned int *)0x10060008)
void led3_init();
void led3_on();
void led3_off();
#endif
wdt.c文件:
#include "wdt.h"
void wdt_init()
{
//设置一级分频值为250 WTCON的8-15位 249
WTCON = WTCON & ~(0xff << 8) | 249 << 8;
//设置二级分频值为128 WTCON的3-4位 b11
WTCON |= 0x3 << 3;
//实现5s的计时 WTCNT=3125*5
WTCNT = 15625;
//使能复位信号
WTCON |= 0x1;
//启动定时器
WTCON |= 0x1 << 5;
}
makefile工程文件:
CROSS = arm-none-linux-gnueabi-
CC=$(CROSS)gcc
LD=$(CROSS)ld
OBJCOPY=$(CROSS)objcopy
all:
$(CC) -g -c -o main.o main.c
$(CC) -g -c -o led.o led.c
$(CC) -g -c -o start.o start.s
$(CC) -g -c -o wdt.o wdt.c
$(LD) start.o led.o main.o wdt.o -Tmap.lds -o led.elf
$(OBJCOPY) -O binary -S led.elf led.bin
$(CROSS)objdump -D led.elf > led.dis
clean:
rm -f *.o *.elf *.bin *.dis
main.c文件:
#include "led.h"
#include "wdt.h"
void delay()
{
int i;
for(i = 0; i < 500000; i++);
}
int main()
{
wdt_init(); //初始化看门狗
led3_init();
while(1)
{
WTCNT = 15625; //喂狗
led3_on();
delay();
led3_off();
delay();
}
return 0;
}
3.PWM
在点亮led灯、wdt的文件下添加pwm.c文件、pwm.h文件,修改makefile工程文件
pwm.h文件:
#ifndef _PWM_H_
#define _PWM_H_
#define GPD0CON *((volatile unsigned int *)0x114000A0)
#define TCFG0 *((volatile unsigned int *)0x139D0000)
#define TCFG1 *((volatile unsigned int *)0x139D0004)
#define TCNTB0 *((volatile unsigned int *)0x139D000C)
#define TCMPB0 *((volatile unsigned int *)0x139D0010)
#define TCON *((volatile unsigned int *)0x139D0008)
void pwm_init();
void pwn_no();
void pwm_off();
#endif
pwm.c文件:
#include "pwm.h"
void pwm_init()
{
//设置GPD0_0为pwm输出 0-3 0X2
GPD0CON = GPD0CON & ~0xf | 0x2;
//设置一级分频 0-7位设置为249
TCFG0 = TCFG0 & ~0xff | 249;
//设置二级分频 1/16
TCFG1 = TCFG1 & ~0xf | 0x4;
//设置三级分频 625hz 给计数器赋值为40
TCNTB0 = 40;
//设置占空比为20%
TCMPB0 = 8;
}
void pwm_no()
{
//更新计数寄存器影子寄存器的值
TCON = TCON &~0xf | 0xA;
//启动
TCON = TCON &~0xf | 0x9;
}
void pwm_off()
{
//暂停
TCON = TCON &~0xf;
}
makefile工程文件:
CROSS = arm-none-linux-gnueabi-
CC=$(CROSS)gcc
LD=$(CROSS)ld
OBJCOPY=$(CROSS)objcopy
all:
$(CC) -g -c -o main.o main.c
$(CC) -g -c -o led.o led.c
$(CC) -g -c -o start.o start.s
$(CC) -g -c -o wdt.o wdt.c
$(CC) -g -c -o pwm.o pwm.c
$(LD) start.o led.o main.o wdt.o pwm.o -Tmap.lds -o led.elf
$(OBJCOPY) -O binary -S led.elf led.bin
$(CROSS)objdump -D led.elf > led.dis
clean:
rm -f *.o *.elf *.bin *.dis
main.c文件:
#include "led.h"
#include "wdt.h"
#include "pwm.h"
void delay()
{
int i;
for(i = 0; i < 1000000; i++);
}
int main()
{
wdt_init();
led3_init();
pwm_init();
while(1)
{
WTCNT = 15625;
led3_on();
pwm_no();
delay();
led3_off();
pwm_off();
delay();
}
return 0;
}
流水灯的实现:
led.h文件:
#ifndef _LED4_H_
#define _LED4_H_
//宏定义
//volatile--->防止编译器优化
//led4
#define GPF3CON *((volatile unsigned int *)0x114001E0) //将0x114001E0(地址)的内容取出来
#define GPF3DAT *((volatile unsigned int *)0x114001E4) //将0x114001E4(地址)的内容取出来
//led3
#define GPX1CON *((volatile unsigned int *)0x11000c20)
#define GPX1DAT *((volatile unsigned int *)0x11000c24)
//led2
#define GPX2CON *((volatile unsigned int *)0x11000C40)
#define GPX2DAT *((volatile unsigned int *)0x11000C44)
//led5----->和led4所用的配置寄存器和数据寄存器一样
#define GPF3CON *((volatile unsigned int *)0x114001E0)
#define GPF3DAT *((volatile unsigned int *)0x114001E4)
//函数声明
//led4
void led4_init();
void led4_no();
void led4_off();
//led3
void led3_init();
void led3_on();
void led3_off();
//led2
void led2_init();
void led2_on();
void led2_off();
//led5
void led5_init();
void led5_no();
void led5_off();
#endif
led.c文件:
#include "led4.h"
//led4
void led4_init()
{
//设置GPF3_4的功能为输出 16-19位设置为0x1
GPF3CON = GPF3CON & ~(0xf << 16) | 0x1 << 16; //&--->清零,|---->置1
}
void led4_on()
{
//让GPF3_4输出1 第4位设置1
GPF3DAT |= 0x01 <<4; //|---->置1
}
void led4_off()
{
GPF3DAT &= ~(0x01 << 4); //&--->清零
}
//led3
void led3_init()
{
//设置GPX1_0的功能为输出 0-3位设置为0x1
GPX1CON = GPX1CON & ~(0xf << 0) | 0x01 << 0;
}
void led3_on()
{
//让GPX1_0输出1 0为设置1
GPX1DAT |= 0x01 << 0;
}
void led3_off()
{
GPX1DAT &= ~(0x01 << 0);
}
//led2
void led2_init()
{
//设置GPX2_7的功能为输出 28-31位设置为0x1
GPX2CON = GPX2CON & ~(0xf << 28) | 0x1 << 28; //&--->清零,|---->置1
}
void led2_on()
{
//让GPX2_7输出1 第7位设置1
GPX2DAT |= 0x01 <<7; //|---->置1
}
void led2_off()
{
GPX2DAT &= ~(0x01 << 7); //&--->清零
}
//led5
void led5_init()
{
//设置GPF3_5的功能为输出 20-23位设置为0x1
GPF3CON = GPF3CON & ~(0xf << 20) | 0x1 << 20; //&--->清零,|---->置1
}
void led5_on()
{
//让GPF3_5输出1 第5位设置1
GPF3DAT |= 0x01 <<5; //|---->置1
}
void led5_off()
{
GPF3DAT &= ~(0x01 << 5); //&--->清零
}
main.c文件:
#include "led4.h"
void delay()
{
int i;
for(i = 0; i < 10000000; i++);
}
int main()
{
//初始化Led灯
led5_init();
led4_init();
led3_init();
led2_init();
while(1)
{
//实现led2-led5的流水点灯,延时间隔为delay()
led5_off();
led2_on();
delay();
led2_off();
led3_on();
delay();
led3_off();
led4_on();
delay();
led4_off();
led5_on();
delay();
}
return 0;
}
makefile工程文件:
CROSS = arm-none-linux-gnueabi-
CC=$(CROSS)gcc
LD=$(CROSS)ld
OBJCOPY=$(CROSS)objcopy
all:
$(CC) -g -c -o main.o main.c
$(CC) -g -c -o led4.o led4.c
$(CC) -g -c -o start.o start.s
$(LD) start.o led4.o main.o -Tmap.lds -o led4.elf
$(OBJCOPY) -O binary -S led4.elf led4.bin
$(CROSS)objdump -D led4.elf > led4.dis
clean:
rm -f *.o *.elf *.bin *.dis
map.lds链接脚本文件:
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0;
. = ALIGN(4);
.text :
{
*(.text)
}
. = ALIGN(4);
.data :
{ *(.data) }
. = ALIGN(4);
.bss :
{ *(.bss) }
}
start.s汇编文件:
.global _start @定义一个全局的符号_start
_start:
.text
b main
.end