7.ARM-LED灯实验

ARM-LED灯实验

  • 一、查看原理图

    • (1)查看外设板原理图(搜索LED2

      • LED原理图
      • 分析
        • 该板子有4个LED,是发光二极管,都接了上拉电阻;
        • 三极管的基极接了SOC的某个GPIO引脚。
          比如GPX2 _ 7,当该引脚为高电平时,三极管PN结导通,于是LED2两侧就有了电势差,LED2被点亮,如果该引脚为低电平,PN结截止,LED2两侧就没有了电势差,LED2熄灭。
    • (2)查看外设板原理图(搜索CHG_COK

      • LED外设板
      • 通过搜索发现CHG_COK连接到外设板CON2的66号引脚
    • (3)查看核心板原理图(搜索CHG_COK

      • 通过开发板丝印发现核心板CON1连接到外设板CON2上
      • CON1+CON2
      • LED核心板
      • 通过搜索发现CHG_COK连接到核心板GPX2_7,这个引脚为GPX2的第7个引脚,只需要配置对应的引脚为输出高电平即可
  • 二、查看芯片手册(DataSheet)

    • 芯片手册搜索GPX2

      • GPX2CON
  • 三、操作GPIO

    • LED_GPX2寄存器图解

    • (1)GPX2CON寄存器(配置寄存器)

      • 用于配置(Configure)选择引脚功能
    • (2)GPX2DAT寄存器(数据寄存器)

      • 用于读/写引脚;当引脚被设为输入时,读此寄存器可知相应引脚的电平状态是高还是低;当引脚被设为输出时,写此寄存器相应位可以令此引脚输出高电平或是低电平。
      • GPX2DAT
      • GPX2DAT的地址是0x1100C44
        LED2对应的输出引脚是GPX2DAT[0],点灯只需要将该引脚置1,灭灯将该引脚置0
  • 四、编写代码(VS Code中新建工程)

    • 如果要进入C语言执行环境,那么就必须设置栈空间,函数调用参数和返回值会压栈,需要写汇编代码

    • //head.h
      #define GPX2_CON 0x11000C40 //控制输入/输出 LED2
      #define GPX2_DAT 0x11000C44 //控制高/低电平 LED2
      
      #define GPX1_CON 0x11000C20 //控制输入/输出 LED3
      #define GPX1_DAT 0x11000C24 //控制高/低电平 LED3
      
      #define GPF3_CON 0x114001E0 //控制输入/输出 LED4、LED5
      #define GPF3_DAT 0x114001E4 //控制高/低电平 LED4、LED5
      
    • //led.c
      #include "head.h"
      
      //GPX2_7:GPX2的第7个引脚(每个引脚4位)LED2
      //GPX1_0:GPX1的第0个引脚(每个引脚4位)LED3
      //GPF3_4:GPF3的第4个引脚(每个引脚4位)LED4
      //GPF3_5:GPF3的第5个引脚(每个引脚4位)LED5
      
      //LED2初始化
      void led2_init(void)
      {
          //将GPX2CON寄存器配置为输出模式
          int *p = (int *)GPX2_CON;
          *p = *p & ~(0xf << 28); //[31,28]置0
          *p = *p | (0x1 << 28); //[31,28]设置为0x1
          return ;
      }
      
      //LED3初始化
      void led3_init(void)
      {
          //将GPX1CON寄存器配置为输出模式
          int *p = (int *)GPX1_CON;
          *p = *p & ~0xf; //[3,0]置0
          *p = *p | 0x1; //[3,0]设置为0x1
          return ;
      }
      
      //LED4初始化
      void led4_init(void)
      {
          //将GPF3CON寄存器配置为输出模式
          int *p = (int *)GPF3_CON;
          *p = *p & ~(0xf << 16); //[19,16]置0
          *p = *p | (0x1 << 16); //[19,16]设置为0x1
          return ;
      }
      
      //LED5初始化
      void led5_init(void)
      {
          //将GPF3CON寄存器配置为输出模式
          int *p = (int *)GPF3_CON;
          *p = *p & ~(0xf << 20); //[23,20]置0
          *p = *p | (0x1 << 20); //[23,20]设置为0x1
          return ;
      }
      
      //点亮LED2
      void led2_on(void)
      {
          //将GPX2DAT寄存器配置为高电平
          int *p = (int *)GPX2_DAT;
          *p = *p | (0x1 << 7); //将[7,0]第7位设置为1(高电平)
          return ;
      }
      
      //熄灭LED2
      void led2_off(void)
      {
          //将GPX2DAT寄存器配置为低电平
          int *p = (int *)GPX2_DAT;
          *p = *p & ~(0x1 << 7); //将[7,0]第7位设置为0(低电平)
          return ;
      }
      
      //点亮LED3
      void led3_on(void)
      {
          //将GPX1DAT寄存器配置为高电平
          int *p = (int *)GPX1_DAT;
          *p = *p | 0x1; //将[7,0]第0位设置为1(高电平)
          return ;
      }
      
      //熄灭LED3
      void led3_off(void)
      {
          //将GPX1DAT寄存器配置为低电平
          int *p = (int *)GPX1_DAT;
          *p = *p & ~0x1; //将[7,0]第0位设置为0(低电平)
          return ;
      }
      
      //点亮LED4
      void led4_on(void)
      {
          //将GPF3DAT寄存器配置为高电平
          int *p = (int *)GPF3_DAT;
          *p = *p | (0x1 << 4); //将[5,0]第4位设置为1(高电平)
          return ;
      }
      
      //熄灭LED4
      void led4_off(void)
      {
          //将GPF3DAT寄存器配置为低电平
          int *p = (int *)GPF3_DAT;
          *p = *p & ~(0x1 << 4); //将[5,0]第4位设置为0(低电平)
          return ;
      }
      
      //点亮LED5
      void led5_on(void)
      {
          //将GPF3DAT寄存器配置为高电平
          int *p = (int *)GPF3_DAT;
          *p = *p | (0x1 << 5); //将[5,0]第5位设置为1(高电平)
          return ;
      }
      
      //熄灭LED5
      void led5_off(void)
      {
          //将GPF3DAT寄存器配置为低电平
          int *p = (int *)GPF3_DAT;
          *p = *p & ~(0x1 << 5); //将[5,0]第5位设置为0(低电平)
          return ;
      }
      
      //同时初始化LED2~LED5
      void led_all_init(void)
      {
          led2_init();
          led3_init();
          led4_init();
          led5_init();
          return ;
      }
      
      //同时点亮LED2~LED5
      void led_all_on(void)
      {
          led2_on();
          led3_on();
          led4_on();
          led5_on();
          return ;
      }
      
      //同时熄灭LED2~LED5
      void led_all_off(void)
      {
          led2_off();
          led3_off();
          led4_off();
          led5_off();
          return ;
      }
      
      //简易延迟函数(单位为ms)
      void delay(int ms)
      {
          int i = 0, j = 0;
          while (ms--)
          {
              for(i = 0; i < 5; i++)
              {
                  for(j = 0; j < 514;j++)
                  {
                      ;
                  }
              }
          }
          return ;
      }
      
      //流水灯函数
      void waterfall_light(void)
      {
          led2_on();
          delay(500);
          led2_off();
          delay(500);
      
          led3_on();
          delay(500);
          led3_off();
          delay(500);
      
          led4_on();
          delay(500);
          led4_off();
          delay(500);
      
          led5_on();
          delay(500);
          led5_off();
          delay(500);
      
          return ;
      }
      
      //LED测试
      void led_test(void)
      {
          led_all_init();
      
          while (1)
          {
              /*灯的点亮和熄灭
               *led_all_on();
               *delay(1000);
               *led_all_off();
               *delay(1000);
               */
              waterfall_light(); //开启流水灯
          }
          
          return ;
      }
      
    • //main.c
      extern void led_test(void); //函数声明
      
      int main(int argc, char const *argv[])
      {
          led_test();
      
          return 0;
      }
      
    • //start.s启动文件
      .global _start
      
      _start:
          ldr sp,=0x40100000 @0x40000000为起始地址,偏移1M(2^20)空间
          bl main
      
      stop:
          b stop
      
      
  • 五、编译代码

    • //编译(VS Code终端输入以下指令)
      arm-none-eabi-gcc -c start.s -o start.o
      arm-none-eabi-gcc -c led.c -o led.o
      arm-none-eabi-gcc -c main.c -o main.o
      //链接生成elf文件,start.o一定要放在最开始的位置
      arm-none-eabi-ld -Ttext=0x40000000 start.o main.o led.o -o led.elf
      //去掉头部信息(O必须是大写)
      arm-none-eabi-objcopy -O binary led.elf led.bin
      
    • 终端代码编译

    • LED工程文件结构

    • elf(executable and link format)文件和bin(binary)文件的区别?

      • gcc 编译出来的是elf文件。通常 gcc test.c 生成的 a.out 文件就是elf格式的,在 linux shell 下输入 ./a.out 可以执行。elf文件里面包含了符号表、汇编等。
      • bin 文件是经过压缩的可执行文件,去掉elf格式的东西。是直接的内存映像的表示。在系统没有加载操作系统的时候可以执行。bin文件是将 elf 文件中的代码段、数据段,还有一些自定义的段抽取出来做成的一个内存镜像
      • 在嵌入式(Embedded)中,上电开始运行,没有 OS 系统,如果将 elf 格式的文件烧写进去,包含一些 elf 格式的东西,ARM 运行碰到这些指令,就会导致失败,如果用 objcopy 生成纯粹的汇编 bin 文件,程序就可以一步一步运行。机器最终只认 bin,elf 格式是在有操作系统时,操作系统会根据 elf 解析出代码、数据等,最终仍是以 bin 运行
  • 六、下载代码到开发板上

    • (1)超级终端下载代码(Win7)

      • 超级终端
      • 连接时选择COM3,属性设置:位/秒(B)->115200、数据流控制(F)->
        • COM3属性
      • 拨动FS4412的开关后,出现显示倒计时3s内按下回车,进入FS4412#命令行
        • FS4412界面
      • 在FS4412#后写入
        • loadb 0x40000000
          
      • 这里的binary是kermit格式的,所以在选择传输格式的时候,选择Kermit格式
        • Kermit传送
          bin文件
    • (2)运行代码

      • go 0x40000000 //go 40000000也可以,都会被识别成地址
        
      • 流水灯
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

0x2

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

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

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

打赏作者

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

抵扣说明:

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

余额充值