起航,第一个程序——还是LED灯
如同学基本语言一样,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灯相关推荐
- 模型预测控制c语言程序_搭建第一个程序控制电路LED灯,体会C语言的魅力
学习C语言,先从读程序开始!这一点是过来人的经验之谈.本文建议大家选择一款图形编程软件,本文选择了Mixly. 一.首先,介绍一下arduino UNO控制器内部电压的问题. v 高电平(5V):对应 ...
- linux开发板led怎么亮,飞凌OK6410开发板(裸板) 第一个点亮LED灯程序
飞凌OK6410开发板(裸板) 第一个点亮LED灯程序,主要的C程序,完整程序请下载附件. #define rGPMCON (*(volatile unsigned *)(0x7F0 ...
- Linux并发与竞争实验(一次只允许一个应用程序操作LED灯)
目录 原子操作实验 实验程序编写 运行测试(运行多个APP抢占资源) 自旋锁实验 实验程序编写 运行测试 信号量实验 实验程序编写 运行测试(第二条命令因为获取信号量失败而进入休眠状态) 互斥体实验( ...
- 单片机c语言led灯闪烁程序,单片机LED灯闪烁程序
点亮 LED 小灯的程序我们第二课完成了,就是让 LED = 0.熄灭小灯的程序也很简单,就是 LED = 1.点亮和熄灭都会了,那么如果我们在亮和灭中间加个延时,反复不停的点亮和熄灭小灯,就成了闪烁 ...
- 52单片机led灯闪烁c语言程序,单片机LED灯闪烁程序
原标题:单片机LED灯闪烁程序 点亮 小灯的程序我们第二课完成了,就是让 LED = 0.熄灭小灯的程序也很简单,就是 LED = 1.点亮和熄灭都会了,那么如果我们在亮和灭中间加个延时,反复不停的点 ...
- 52单片机led灯闪烁c语言程序,单片机 LED 灯闪烁程序
点亮 LED 小灯的程序我们第二课完成了,就是让 LED = 0.熄灭小灯的程序也很简单,就是 LED = 1.点亮和熄灭都会了,那么如果我们在亮和灭中间加个延时,反复不停的点亮和熄灭小灯,就成了闪烁 ...
- 合宙AIR32F103CBT6入门第一步——点亮LED灯
一.准备工作 1.材料 AIR32F103CBT6一块 ST linkv2一块 杜邦线若干 2.电脑安装 STM32 CubeMx123 [STM32]STM32 CubeMx使用教程一--安装教程_ ...
- 浮沙筑塔——protues仿真C51程序之LED灯闪烁
零.闲话三两 不得不惊叹于计算机功能的强大且全面,分明与51单片机是不同宗不同源的两样机种,其效用却能在计算机上完美复现.在21世纪的新世代人类眼里,"电脑"或许只是"网 ...
- 蓝桥杯嵌入式第一篇 点亮LED灯开启成功之路
文章目录 前言 一.准备工作 1.拿到开发板第一步看原理图 2.下载STM32cubeMX 二.开始点灯 1.查看LED原理图 2.cubeMX配置 3.代码实现 总结 前言 从这篇文章开始将为大家带 ...
最新文章
- HDU 5836 Rubik's Cube BFS
- 回归框架下的人脸对齐和三维重建
- ida demangled names
- 未来教育计算机二级为什么分数很低,计算机二级考试失分了却不知道为什么?...
- mysql load 占位符_Mysql占位符插入
- python网络爬虫与信息提取视频_Python网络爬虫与信息提取入门5
- Nginx handler模块
- jquery学习之路jquery之一:jquery选择元素的方法,太神了 2012.8.2
- DataView筛选出最新的十条数据的方法总结;
- 水经注叠加cad_相见恨晚的50个CAD技巧
- cmd imp导入dmp文件_dmp文件导入抽取方法(示例代码)
- 1、前端背景图自适应
- 对极几何基本概念与极线约束
- scikit-learn中的OneHotEncoder用法
- win7系统dhcp服务器设置方法,win7设定固定ip和同时支持dhcp的方法
- imx6 vpu程序分析
- 镭速raysync介绍文件传输软件的进史
- win7关机一直卡在正在关机
- 考虑蒙特卡洛考虑风光不确定性的配电网运行风险 评估 由于风电光伏出力的不确定性,造成配电网运行风险,运用蒙特卡洛概率潮流计算分析电压和线路支路越限
- 网上跨行转账将实时生效 第三方支付前景渺茫
热门文章
- android内核模块签名,android安装内核module,提示Required key not available
- html php 混编 H1,在一个HTML中h1标签能出现几次?h1标签和标题标签的差别是什么?...
- json文件中的双引号隐藏
- vim 改变当前工作路径和创建文件夹
- 注意力机制中的Q、K和V的意义
- java的json导出excel_利用json生成excel表格
- js排序的时间复杂度_JavaScript插入排序算法通俗说明
- elasticsearch入门hello world (macos)【一】下载运行
- 百练OJ:2810:完美立方
- 信息系统项目管理师-项目合同管理考点笔记