如同学基本语言一样,helloworld是很多语言的第一个程序。在嵌入式开发中,点亮LED灯也是各种架构和开发板的第一个程序,其中很多东西是和单片机例如stm32是类似的,只是,现在我们没有了库函数,我们要自己完成一些东西。

先说启动文件,st官方已结给我们做好了,但是jz2440开发板没有统一的启动文件,需要自己编写,那么,基础的arm汇编就得有所熟悉,在之后的学习中,遇到一个指令就学习一个。

(汇编)指令是CPU机器指令的助记符,经过编译后会得到一串1、0组成的机器码,可以由CPU读取执行。 (汇编)伪指令本质上不是指令(只是和指令一起写在代码中),它是编译器环境提供的,目的是用来指导编译过程,经过编译后伪指令最终不会生成机器码。

ARM官方的ARM汇编风格:指令一般用大写、Windows中IDE开发环境(如ADS、MDK等)常用。如: LDR R0, [R1] GNU风格的ARM汇编:指令一般用小写字母、linux中常用。如:ldr r0, [r1]

ARM采用RISC架构,CPU本身不能直接读取内存,而需要先将内存中内容加载入CPU中通用寄存器中才能被CPU处理。 ldr(load register)指令将内存内容加载入通用寄存器。 str(store register)指令将寄存器内容存入内存空间中。 ldr/str组合用来实现 ARM CPU和内存数据交换。

先看流水灯的一段启动代码:

 1 @******************************************************************************
 2 @ File:crt0.S
 3 @ 功能:通过它转入C程序
 4 @******************************************************************************
 5
 6 .text
 7 .global _start
 8 _start:
 9             ldr     r0, =0x53000000     @ WATCHDOG寄存器地址
10             mov     r1, #0x0
11             str   r1, [r0]              @ 写入0,禁止WATCHDOG,否则CPU会不断重启
12
13             ldr     sp, =1024*4         @ 设置堆栈,注意:不能大于4k, 因为现在可用的内存只有4K
14                                         @ nand flash中的代码在复位后会移到内部ram中,此ram只有4K
15             bl      main                @ 调用C程序中的main函数
16 halt_loop:
17             b       halt_loop

预备知识:摘自 http://blog.csdn.net/qq506124204/article/details/7952966

mov   r1, #0x53000000   //立即数寻址方式 
mov   r2, #0x0 
str   r2, [r1]        
立即数寻址方式,立即数要求以“#”作前缀,对于十六进制的数,还要求在#后面加上0x或者&。STR是比较重要的指令了,跟它对应的是LDR。 ARM指令集是加载/存储型的,也就是说它只处理在寄存器中的数据。那么对于系统存储器的访问就经常用到STR和LDR了。STR是把寄存器上的数据传输 到指定地址的存储器上。它的格式我个人认为很特殊:
STR(条件) 源寄存器,<存储器地址>
比如 STR R0, [R1] ,意思是R0-> [R1],它把源寄存器写在前面,跟MOV、LDR都相反。
LDR应该是非常常见了。LDR就是把数据从存储器传输到寄存器上。而且有个伪指令也是LDR,因此我有个百思不得其解的问题。看这段代码:
mov r1, #GPIO_CTL_BASE 
add   r1, r1, #oGPIO_F 
ldr   r2,=0x55aa   // 0x55aa是个立即数啊,前面加个=干什么? 
对于当中的ldr 那句,我就不明白了,如果你把=去掉,是不能通过编译的。我查了一些资料,个人感觉知道了原因:这个=应该表示LDR不是ARM指令,而是伪指令。作为伪指令的时候,LDR的格式如下:
LDR 寄存器, =数字常量/Label
它的作用是把一个32位的地址或者常量调入寄存器。嗬嗬,那大家可能会问,
“MOV r2,#0x55aa”也可以啊。应该是这样的。不过,LDR是伪指令啊,也就是说编译时编译器会处理它的。怎么处理的呢?——规则如下:如果该数字常量 在MOV指令范围内,汇编器会把这个指令作为MOV。如果不在MOV范围中,汇编器把该常量放在程序后面,用LDR来读取,PC和该常量的偏移量不能超过 4KB。

然后说一下跳转指令。ARM有两种跳转方式。
(1) mov pc <跳转地址〉
这种向程序计数器PC直接写跳转地址,能在4GB连续空间内任意跳转。
(2)通过 B BL BLX BX 可以完成在当前指令向前或者向后32MB的地址空间的跳转(为什么是32MB呢?寄存器是32位的,此时的值是24位有符号数,所以32MB)。
B是最简单的跳转指令。要注意的是,跳转指令的实际值不是绝对地址,而是相对地址——是相对当前PC值的一个偏移量,它的值由汇编器计算得出。
BL非常常用。它在跳转之前会在寄存器LR(R14)中保存PC的当前内容。

为什么要先关闭看门狗?因为板子上电,看门狗是硬件打开的,不关闭会一直复位。

再看Makefile文件:

 1 CFLAGS     := -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -ffreestanding
 2 leds.bin : crt0.S  leds.c
 3     arm-linux-gcc $(CFLAGS) -c -o crt0.o crt0.S
 4     arm-linux-gcc $(CFLAGS) -c -o leds.o leds.c
 5     arm-linux-ld -Ttext 0x0000000 crt0.o leds.o -o leds_elf
 6 #    arm-linux-ld -Tleds.lds  crt0.o leds.o -o leds_elf
 7     arm-linux-objcopy -O binary -S leds_elf leds.bin
 8     arm-linux-objdump -D -m arm  leds_elf > leds.dis
 9 clean:
10     rm -f   leds.dis leds.bin leds_elf *.o

这里用到了arm的交叉编译器,-ld,是链接指令,-Ttext是指明程序段,即程序存储的地方,为什么是从0地址开始,这是因为在我使用的2440中,是以nand flash启动的,nand启动会复制nand flash中4K的内容到2440芯片的SRAM,这4K内容从地址0开始取址启动,nor启动就不需要复制内容到SARM,可以直接启动。前面-c选项,表示只编译不链接,而后面ld,表示把那些.o文件链接起来构成*elf文件,然后通过objcopy,把上面编译链接之后的目标文件转化成二进制文件即.bin文件。objcopy把一种目标文件中的内容复制到另一种类型的目标文件中. -S 表示移出所有的标志及重定位信息 ;
-O binary xyb xyb.bin 表示由xyb生成二进制文件xyb.bin。

objdump指令,-D代表反汇编所有的段,-m代表的是反汇编目标文件使用的构架,这里是arm构架,>重定向成*.dis文件。

关于Makefile中的几个编译选项:参考链接:http://blog.chinaunix.net/uid-20737871-id-1881211.html
-Wall 开启所有警告

-Wstrict-prototypes 如果函数的声明或定义没有指出参数类型,编译器就发出警告。

-O2 优化等级2

-fomit-frame-pointer选项是发布产品时经常会用到的优化选项,它可以优化汇编函数中用edp协助获取堆栈中函数参数的部分,不使用edp,而是通过计算,全部使用esp来完成。参考链接:http://www.cnblogs.com/yamadie/p/3363567.html

-ffreestanding按独立环境编译,该环境可以没有标准库,且对main()函数没有要求。最典型的例子就是操作系统内核。参考链接:http://blog.csdn.net/eroswang/article/details/1966640

终于介绍完了预备知识,这些东西有的需要理解记忆,有的只用了解熟悉即可。现在开始编写程序。就流水灯的C语言程序来说,其实和单片机一样,属于简单的。但是arm版之所以很多人买了之后就吃灰了,就是因为对只是体系的构架不熟悉,还有基本技能的缺失。这也是为什么很多人说,韦老师的课程不适合新手吧。

 1 #define    GPFCON        (*(volatile unsigned long *)0x56000050)
 2 #define    GPFDAT        (*(volatile unsigned long *)0x56000054)
 3
 4 #define    GPF4_out    (1<<(4*2))
 5 #define    GPF5_out    (1<<(5*2))
 6 #define    GPF6_out    (1<<(6*2))
 7
 8 void  wait(volatile unsigned long dly)
 9 {
10     for(; dly > 0; dly--);
11 }
12
13 int main(void)
14 {
15     unsigned long i = 0;
16
17     GPFCON = GPF4_out|GPF5_out|GPF6_out;        // 将LED1,2,4对应的GPF4/5/6三个引脚设为输出
18
19     while(1){
20         wait(30000);
21         GPFDAT = (~(i<<4));         // 根据i的值,点亮LED1,2,4
22         if(++i == 8)
23             i = 0;
24     }
25
26     return 0;
27 }

这是韦老师的参考代码,硬件上是低电平LED亮。

IO口分别对应GPIO_F  4,5,6。虽然老师的代码很好地实现了流水灯,但我觉得这个代码写成一个函数更友好,可移植性也更高,要是我的LED等编程GPI0_F 0,3,7,要实现流水灯就要大改代码了,所以自己做了更改,模仿st的库函数写法,但是由于才接触2440,对它的寄存器还不熟悉,所以先不急于封装,等学了韦老师资料之后再去封装。

起航,第一个程序——还是LED灯相关推荐

  1. 模型预测控制c语言程序_搭建第一个程序控制电路LED灯,体会C语言的魅力

    学习C语言,先从读程序开始!这一点是过来人的经验之谈.本文建议大家选择一款图形编程软件,本文选择了Mixly. 一.首先,介绍一下arduino UNO控制器内部电压的问题. v 高电平(5V):对应 ...

  2. linux开发板led怎么亮,飞凌OK6410开发板(裸板) 第一个点亮LED灯程序

    飞凌OK6410开发板(裸板) 第一个点亮LED灯程序,主要的C程序,完整程序请下载附件. #define rGPMCON          (*(volatile unsigned *)(0x7F0 ...

  3. Linux并发与竞争实验(一次只允许一个应用程序操作LED灯)

    目录 原子操作实验 实验程序编写 运行测试(运行多个APP抢占资源) 自旋锁实验 实验程序编写 运行测试 信号量实验 实验程序编写 运行测试(第二条命令因为获取信号量失败而进入休眠状态) 互斥体实验( ...

  4. 单片机c语言led灯闪烁程序,单片机LED灯闪烁程序

    点亮 LED 小灯的程序我们第二课完成了,就是让 LED = 0.熄灭小灯的程序也很简单,就是 LED = 1.点亮和熄灭都会了,那么如果我们在亮和灭中间加个延时,反复不停的点亮和熄灭小灯,就成了闪烁 ...

  5. 52单片机led灯闪烁c语言程序,单片机LED灯闪烁程序

    原标题:单片机LED灯闪烁程序 点亮 小灯的程序我们第二课完成了,就是让 LED = 0.熄灭小灯的程序也很简单,就是 LED = 1.点亮和熄灭都会了,那么如果我们在亮和灭中间加个延时,反复不停的点 ...

  6. 52单片机led灯闪烁c语言程序,单片机 LED 灯闪烁程序

    点亮 LED 小灯的程序我们第二课完成了,就是让 LED = 0.熄灭小灯的程序也很简单,就是 LED = 1.点亮和熄灭都会了,那么如果我们在亮和灭中间加个延时,反复不停的点亮和熄灭小灯,就成了闪烁 ...

  7. 合宙AIR32F103CBT6入门第一步——点亮LED灯

    一.准备工作 1.材料 AIR32F103CBT6一块 ST linkv2一块 杜邦线若干 2.电脑安装 STM32 CubeMx123 [STM32]STM32 CubeMx使用教程一--安装教程_ ...

  8. 浮沙筑塔——protues仿真C51程序之LED灯闪烁

    零.闲话三两 不得不惊叹于计算机功能的强大且全面,分明与51单片机是不同宗不同源的两样机种,其效用却能在计算机上完美复现.在21世纪的新世代人类眼里,"电脑"或许只是"网 ...

  9. 蓝桥杯嵌入式第一篇 点亮LED灯开启成功之路

    文章目录 前言 一.准备工作 1.拿到开发板第一步看原理图 2.下载STM32cubeMX 二.开始点灯 1.查看LED原理图 2.cubeMX配置 3.代码实现 总结 前言 从这篇文章开始将为大家带 ...

最新文章

  1. HDU 5836 Rubik's Cube BFS
  2. 回归框架下的人脸对齐和三维重建
  3. ida demangled names
  4. 未来教育计算机二级为什么分数很低,计算机二级考试失分了却不知道为什么?...
  5. mysql load 占位符_Mysql占位符插入
  6. python网络爬虫与信息提取视频_Python网络爬虫与信息提取入门5
  7. Nginx handler模块
  8. jquery学习之路jquery之一:jquery选择元素的方法,太神了 2012.8.2
  9. DataView筛选出最新的十条数据的方法总结;
  10. 水经注叠加cad_相见恨晚的50个CAD技巧
  11. cmd imp导入dmp文件_dmp文件导入抽取方法(示例代码)
  12. 1、前端背景图自适应
  13. 对极几何基本概念与极线约束
  14. scikit-learn中的OneHotEncoder用法
  15. win7系统dhcp服务器设置方法,win7设定固定ip和同时支持dhcp的方法
  16. imx6 vpu程序分析
  17. 镭速raysync介绍文件传输软件的进史
  18. win7关机一直卡在正在关机
  19. 考虑蒙特卡洛考虑风光不确定性的配电网运行风险 评估 由于风电光伏出力的不确定性,造成配电网运行风险,运用蒙特卡洛概率潮流计算分析电压和线路支路越限
  20. 网上跨行转账将实时生效 第三方支付前景渺茫

热门文章

  1. android内核模块签名,android安装内核module,提示Required key not available
  2. html php 混编 H1,在一个HTML中h1标签能出现几次?h1标签和标题标签的差别是什么?...
  3. json文件中的双引号隐藏
  4. vim 改变当前工作路径和创建文件夹
  5. 注意力机制中的Q、K和V的意义
  6. java的json导出excel_利用json生成excel表格
  7. js排序的时间复杂度_JavaScript插入排序算法通俗说明
  8. elasticsearch入门hello world (macos)【一】下载运行
  9. 百练OJ:2810:完美立方
  10. 信息系统项目管理师-项目合同管理考点笔记