ARM---------->第四天,点亮led灯、看门狗工作原理、PWM(设置蜂鸣器)

本文详细介绍了裸机编程中的LED灯操作流程,包括设置GPIO引脚、配置寄存器以点亮LED3,以及加入看门狗(WDT)实现定时和中断处理,还涉及了PWM调用来控制灯的亮度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的定时?

需要:

  1. 一个基准时间  1s的定时
  2. 一个计数器    初始值60   
  3. 每过一秒-1,当减到0时60s时间就到

定时器的工作原理:

  1. 有时钟   100Mhz  太大------>变小  分频  假设最终我得到的是一个625Hz的时钟  

            一个时钟周期的时间1/625s

  1. 计数器  初始值:3125
  2. 实现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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值