裸机LED

  1. 分析原理图
  2. 理解控制硬件的控制原理
  3. 找到对应的寄存器,并理解寄存器控制流程
  4. 根据寄存器地址访问硬件
  5. 实现硬件的控制

(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--);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物の哀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值