C语言LED实验

1、汇编激活CPU

首先要明白对于没有系统开发板(也就是裸机)来说,是没办法直接对C进行识别。所以需要一段汇编语言,来配置CPU的资源,选择CPU运行模式,初始化指针位置。

代码如下:

.global _start /* 全局标号 */

_start:

    /*进入SVC模式 */
mrs r0, cpsr
bic r0, r0, #0x1f/* 将 r0 的低 5 位清零,也就是 cpsr 的 M0~M4 */
orr r0, r0, #0x13/* r0 或上 0x13,表示使用 SVC 模式 */
msr cpsr, r0/* 将 r0 的数据写入到 cpsr_c 中 */ ldr sp, =0X80200000/*设置栈指针 */ /*因为 I.MX6U-ALPHA 开
发 板 上 的 DDR3 地 址 范 围 是 0X80000000~0XA0000000(512MB) 或 者
0X80000000~0X90000000(256MB),不管是 512MB 版本还是 256MB 版本的,其 DDR3 起始地
址都是 0X80000000。由于 Cortex-A7 的堆栈是向下增长的,所以将 SP 指针设置为 0X80200000,
因此 SVC 模式的栈大小 0X80200000-0X80000000=0X200000=2MB,2MB 的栈空间已经很大了,
如果做裸机开发的话绰绰有余。 */ b main/*跳转到main函数 */

这里又学到了两个新的汇编指令:

BIC——位清除指令

指令格式:

BIC{cond}{S} Rd,Rn,operand2

BIC指令将Rn 的值与操作数operand2 的反码按位逻辑”与”,结果存放到目的寄存器Rd 中。指令示例:BIC R0,R0,#0x0F ;将R0最低4位清零,其余位不变。

ORR——位置为1

ORR 指令的格式为:

ORR{条件}{S} 目的寄存器,操作数 1,操作数 2

ORR 指令用于在两个操作数上进行逻辑或运算,并把结果放置到目的寄存器中。操作数 1

应是一个寄存器,操作数 2 可以是一个寄存器,被移位的寄存器,或一个立即数。该指令常用于设置操作数 1 的某些位。

指令示例:

ORR R0,R0,#3 ; 该指令设置R0的0、1位,其余位保持不变。

2、头文件配置相关的寄存器

也就是把相关寄存器的地址,用某个变量名存起来

代码如下:

#ifndef _MAIN_H
#define _MAIN_H /*CCM相关寄存器到配置——也就是时钟到地址 */
#define CCM_CCGR0 *((volatile unsigned int *)0X020C4068)
#define CCM_CCGR1 *((volatile unsigned int *)0X020C406C)
#define CCM_CCGR2 *((volatile unsigned int *)0X020C4070)
#define CCM_CCGR3 *((volatile unsigned int *)0X020C4074)
#define CCM_CCGR4 *((volatile unsigned int *)0X020C4078)
#define CCM_CCGR5 *((volatile unsigned int *)0X020C407C)
#define CCM_CCGR6 *((volatile unsigned int *)0X020C4080) /*IOMUX相关到寄存器地址*/
#define SW_MUX_GPIO1_IO03 *((volatile unsigned int *)0X020E0068)
#define SW_PAD_GPIO1_IO03 *((volatile unsigned int *)0X020E02F4) /*GPIO1相关寄存器到地址*/
#define GPIO1_DR *((volatile unsigned int *)0X0209C000)
#define GPIO1_GDIR *((volatile unsigned int *)0X0209C004)
#define GPIO1_PSR *((volatile unsigned int *)0X0209C008)
#define GPIO1_ICR1 *((volatile unsigned int *)0X0209C00C)
#define GPIO1_ICR2 *((volatile unsigned int *)0X0209C010)
#define GPIO1_IMR *((volatile unsigned int *)0X0209C014)
#define GPIO1_ISR *((volatile unsigned int *)0X0209C018)
#define GPIO1_EDGE_SEL *((volatile unsigned int *)0X0209C01C) #endif

这里可以复习一下关键字volatile的作用:

volatile:

指的是“易变的”意思,可以避免在编译的时候被编译器优化,而导致意想不到的结果。

一般还有下面的作用:

  1. 表明变量可以被后台程序修改
  2. 防止编译器优化操作变量的语句
  3. 防止编译器优化变量的存取对象
  4. 访问被volatile修饰的变量时,强制访问内存中的值,而不是缓存中的。

3、C文件指令

这个时候环境已经搭建好了,可以开始写自己的应用程序了

代码如下:

#include "main.h"

/*时钟使能函数*/
void clk_enable(void)
{
CCM_CCGR0 = 0xffffffff;
CCM_CCGR1 = 0xffffffff;
CCM_CCGR2 = 0xffffffff;
CCM_CCGR3 = 0xffffffff;
CCM_CCGR4 = 0xffffffff;
CCM_CCGR5 = 0xffffffff;
CCM_CCGR6 = 0xffffffff; } /*初始化led对应到GPIO*/
void led_init(void)
{
/*IO复用为GPIO1_IO03*/
SW_MUX_GPIO1_IO03 = 0x5; /*配置GPIO1_IO03的相关属性*/
/*
*bit 16:0 HYS 关闭
*bit [15:14]: 00 默认下拉
*bit [13]: 0 kepper 功能
*bit [12]: 1 pull/keeper 使能
*bit [11]: 0 关闭开路输出
*bit [7:6]: 10 速度 100Mhz
*bit [5:3]: 110 R0/6 驱动能力
*bit [0]: 0 低转换率
*/
SW_PAD_GPIO1_IO03 = 0X10B0;//上面寄存器按配置要求输入相应数字后,就变成了0X10B0 GPIO1_GDIR = 0X0000008;//初始化 GPIO, GPIO1_IO03 设置为输出 GPIO1_DR = 0X0;//设置 GPIO1_IO03 输出低电平,打开 LED0
} /*开灯函数*/
void led_on(void)
{
GPIO1_DR &= ~(1<<3);//将 GPIO1_DR 的 bit3 清零
} /*关灯函数*/
void led_off(void)
{
GPIO1_DR |= (1<<3);// 将 GPIO1_DR 的 bit3 置 1
} /*短时间延时函数*/
void short_delay(volatile unsigned int n)
{
while(n--){}
}
/*延时函数 1ms*/
void delay(volatile unsigned int n)
{
while(n--)
{
short_delay(0x7ff);
}
} /*主函数*/
int main()
{
clk_enable();
led_init(); while (1)
{
led_off();
delay(500); led_on();
delay(500); }
return 0;
}

这里只点一点:就是开灯关灯函数,用的运算符。

GPIO1_DR &= ~(1<<3);//将 GPIO1_DR 的 bit3 清零 开灯
  • 先对1左移3位:0001 -> 1000
  • 再按位取反:1000 -> 0111
  • 最后按位与运算

    就相当于把第3位清零了。
GPIO1_DR |= (1<<3);// 将 GPIO1_DR 的 bit3 置 1 关灯

这个就更简单了,先移位,在按位或运算就行了。

4、makefile文件

先看代码:

objs := start.o main.o

ledc.bin:$(objs)
arm-linux-gnueabihf-ld -Timx6ull.lds -o ledc.elf $^
arm-linux-gnueabihf-objcopy -O binary -S ledc.elf $@
arm-linux-gnueabihf-objdump -D -m arm ledc.elf > ledc.dis %.o:%.s
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $< %.o:%.S
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $< %.o:%.c
arm-linux-gnueabihf-gcc -Wall -nostdlib -c -o $@ $< clean:
rm -rf *.o ledc.bin ledc.elf ledc.dis

有几个变量符需要解释一下:

“$^”的意思是所有依赖文件的集合。

“$<”的意思是依赖目标集合的第一个文件。

“$@”的意思是目标集合。

还有一点就是进行连接的时候,一定要把start.o放在前面。

objs := start.o main.o

大家有没有注意这个连接命令:

arm-linux-gnueabihf-ld -Timx6ull.lds -o ledc.elf $^

这个imx6ull.lds是什么?

这其实就是一个连接的脚本。

5、连接脚本

承接上面,还记得这样一条命令吗?

arm-linux-gnueabihf-ld -Ttext 0X87800000 -o ledc.elf $^

上面语句中我们是通过“-Ttext”来指定链接地址是 0X87800000 的,这样的话所有的文件

都会链接到以 0X87800000 为起始地址的区域。

但是,现实是我们会有很多文件,要放在不同的地址里面(或者说段里),这些段的地址也由我们自由指定。

还有大家常说的text(程序段)、data(数据段)、bss段(没有初始化的变量)等,就是这个意思。(想更直观的话,可以看看很多项目的.map文件,相信你会有新的感受。)

可能有点抽象,这里先举一个简单点的例子:

SECTIONS{
. = 0X10000000;
.text : {*(.text)}
. = 0X30000000;
.data ALIGN(4) : { *(.data) }
.bss ALIGN(4) : { *(.bss) }
}

有下面几个关键点:

1.关键字“SECTIONS”,是必不可少的。

2.特殊符号“.”进行赋值,“.”在链接脚本里面叫做定位计数器,默认的定位计数器为 0,要求代码链接到以 0X10000000 为起始地址的地方,后面的文件或者段都会以 0X10000000 为起始地址开始链接。

3.“.text”是段名,后面的冒号是语法要求,冒号后面的大括号里面可以填上要链接到“.text”这个段里面的所有文件,“(.text)”中的“”是通配符,表示所有输入文件的.text段都放到“.text”中。

4.需要重新设置定位计数器“.”,将其改为 0X30000000。

5.来对“.data”这个段的起始地址做字节对齐的,ALIGN(4)表示4字节对齐。也就是说段“.data”的起始地址要能被 4 整除,一般常见的都是 ALIGN(4)或者 ALIGN(8),也就是 4 字节或者 8 字节对齐。

掌握这些之后,再来看我们需要的连接脚本文件:

SECTIONS{
. = 0X87800000;
.text :
{
start.o
main.o
*(.text)
}
.rodata ALIGN(4) : {*(.rodata*)}
.data ALIGN(4) : { *(.data) }
__bss_start = .;
.bss ALIGN(4) : { *(.bss) *(COMMON) }
__bss_end = .;
}

这个脚本里也有几点需要注意:

就是这个__bss_start和__bss_end,这个就相当于记录下了bss的首尾地址。因为我们后面是需要对bssZ段进行清零的,所以要记录下它的的首尾地址。

END!!!

最后千万别忘了使用imxdownload烧到SD卡里边,还有makefile的文件格式,一定要注意了!!好了就这么多。

用C语言的LED实验,有汇编哦!的更多相关文章

  1. FPGA回忆记事(一):基于Nios II的LED实验

    实验一:基于Nios II的LED实验 一.    创建Quartus II工程 1.打开Quartus II环境.开始->程序->Altera->Quartus II 9.1. 2 ...

  2. 6.裸机C语言控制LED

    C语言版LED灯 汇编完成C语言的环境配置 C语言完成点亮LED灯 程序编写 汇编程序start.S .global _start /* 全局标号 */ /* * 描述: _start函数,程序从此函 ...

  3. 逆向知识第十四讲,(C语言完结)结构体在汇编中的表现形式

    逆向知识第十四讲,(C语言完结)结构体在汇编中的表现形式 一丶了解什么是结构体,以及计算结构体成员的对其值以及总大小(类也是这样算) 结构体的特性 1.结构体(struct)是由一系列具有相同类型或不 ...

  4. 实验4 汇编应用编程和c语言程序反汇编分析

    1. 实验任务1 教材「实验9 根据材料编程」(P187-189)编程:在屏幕中间分别显示绿色.绿底红色.白底蓝色的字符串'welcome to masm!'. 解题思路:根据学习的知识,我知道该页在 ...

  5. 汇编LED实验

    汇编语言点亮LED 拿到一款全新的芯片,第一个要做的事情的就是驱动其 GPIO,控制其 GPIO 输出高低电平. GPIO口是IO口的一个功能之一. 一.接下来的步骤离不开芯片手册: 1.使能所有时钟 ...

  6. 基于Arduino的按键控制LED实验

    I/O 口的意思即为INPUT 接口和OUTPUT 接口,到目前为止我们设计的小灯实验都还只是应用到Arduino 的I/O 口的输出功能,这个实验我们来尝试一下使用Arduino的I/O 口的输入功 ...

  7. 20145205 java语言实现数据结构实验一

    数据结构实验要求 综合类实验设计3 已知有一组数据a1a2a3a4--anb1b2b3b4--bm,其中ai均大于bj,但是a1到an和b1到bm不是有序的,试设计两到三个算法完成数据排序,且把bj数 ...

  8. C语言函数指针实验

    上次看Atmel的示例工程,发现人家使用了函数指针的结构体(函数指针结构体).感叹人家的C语言功夫审核,自己费劲还是只能读懂的份.不过,函数指针确实好用.今天就试试这个超牛的东西.Now let's ...

  9. Cubieboard2裸机开发之(三)C语言操作LED

    前言 前面通过汇编语言点亮LED,代码虽然简单,但并不是很直观.这次使用熟悉的C语言来控制LED,但是需要注意的地方有两点,第一,要想使用C语言,首先需要在调用C语言代码之前设置好堆栈:第二,调用C语 ...

随机推荐

  1. Beta阶段项目终审报告

    先上图 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件主要是用来解决玩狼人杀这款桌游时无牌.无法官.游戏流程不熟悉等情况的.我觉得我们对典型 ...

  2. javascript设计模式学习之十六——状态模式

    一.状态模式的定义 状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模 ...

  3. Mac + nginx + lua + luasocket + cjson

    1. Lua // 官方网站 http://www.lua.org/ 下载源码包// 由于配合 nginx 使用, 所以使用 5.1.X 版本 $ .tar.gz $ cd lua- $ make m ...

  4. VHDL乘除法及转换

    首先鄙视一下这个不智能的语言 1.要进行乘法与除法,数据类型必须是signed 2.两个16位的数相乘,结果必须是32位的 3.乘以2的n次幂的数可以直接乘,之后截位也比较方便,(其实直接移位就可以) ...

  5. SQL server2005学习笔记(一)数据库的基本知识、基本操作(分离、脱机、收缩、备份、还原、附加)和基本语法

    在软件测试中,数据库是必备知识,假期闲里偷忙,整理了一点学习笔记,共同探讨. 阅读目录 基本知识 数据库发展史 数据库名词 SQL组成 基本操作 登录数据库操作 数据库远程连接操作 数据库分离操作 数 ...

  6. Servlet、Filter

    加载顺序是:context-param -> listener -> filter -> servlet ,而同个类型之间的实际程序调用的时候的顺序是根据对应的 mapping 的顺 ...

  7. DAG---矩阵嵌套问题

    矩形嵌套时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 有n个矩形,每个矩形可以用a,b来描述,表示长和宽.矩形X(a,b)可以嵌套在矩形Y(c,d)中当且仅当a<c, ...

  8. Android Studio中使用Git进行代码管理(分支、合并)

    打开Android Studio选择,选择从Git检出代码 也可以从VCS如下点击 去远程仓库复制地址,这里以码云Gitee第三方代码托管为例,类似Github的界面,点击右边复制项目地址 填一下配置 ...

  9. JS——按钮点击事件累加注册问题

    最近在工作上遇到一个点击事件累加的问题,为元素添加点击事件效果,但是总是效果失败,最后发现点击事件被执行了多次,上网查了一下,下边就是解决这个问题的几种思路 案列引自 踮起脚尖眺望6 $(" ...

  10. 【LeetCode每天一题】Pow(x, n)(平方)

    Implement pow(x, n), which calculates x raised to the power n (x,n). Example 1:                 Inpu ...