本文主要是介绍s5pv210 用汇编点亮led灯,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一,分析硬件工作原理
1.LED灯的物理特性
LED本身有2个接线点,一个是LED的正极,一个是LED的负极。LED这个硬件的功能就是点亮或者不亮
物理上想要点亮一颗LED只需要给他的正负极上加正电压即可,要熄灭一颗LED只需要去掉电压即可。
二, 分析原理图
通过原理图分析,发现LED灯 D22, D23, D24, D25 分别受 寄存器 GPJ0_3 , GPJ0_4, GPJ0_5, PWMTOUT1 控制
4个LED灯的阳极都连接到3.3v的电源 VDD_IO 上, 四个阴极连接到Soc的引脚上,通过Soc来控制LED阴极来输出正电平(1)或负电平(0),使得LED灯两端电压发生改变 控制LED灯的亮灭 。
三, 分析数据手册
1. 通过原理图分析发现,LED灯的阴极受GPJ0寄存器的控制,所以得先了解GPJ0寄存器
2 .通过编程控制Soc中的GPJ0寄存器来操控LED的亮灭
3. GPJ0 :general purpose input output 通用输入输出
4. GPIO就是芯片的引脚(芯片上的引脚有些不是GPIO,只有一部分是),作为GPIO的这类引 脚,他的功能和特点是可以被编程控制它的工作模式,也可以编程控制他的电压高低等。
5. GPJ0相关的寄存器有以下:
GPJ0CON, (GPJ0 control)GPJ0控制寄存器,用来配置各引脚的工作模式
GPJ0DAT, (GPJ0 data)当引脚配置为input/output模式时,寄存器的相应位和引脚的电平高低 相对应。
GPJ0PUD, (pull up down)控制引脚内部弱上拉、下拉
GPJ0DRV, (driver)配置GPIO引脚的驱动能力
GPJ0CONPDN,(记得是低功耗模式下的控制寄存器)
GPJ0PUDPDN (记得是低功耗模式下的上下拉寄存器)
注:在驱动LED点亮时,应该将GPIO配置为output模式。
(写)输出 CPU向外部输出, (读)输入 CPU接收外部数据
6 .实际上真正操控LED的硬件,主要的有:GPJ0CON, GPJ0DAT 这么2个。
7. 如何点亮LED,编程的步骤是:
1、操控GPJ0CON寄存器中,选中output模式
2、操控GPJ0DAT寄存器,相应的位设置为0
GPJ0端口一共有8个引脚,分别记住:GPJ0_0 ~ GPJ0_7 , 相关重要寄存器就是GPJ0CON和GPJ0DAT
GPJ0CON寄存器中设置8个引脚的工作模式(32/8=4,每个引脚可以分到4位,譬如GPJ0_0对应的bit位为bit0~bit3,GPJ0_3对应的位为bit12~bit15。工作方法是:给相应的寄存器位写入相应的值,该引脚硬件就会按照相应的模式去工作。譬如给bit12~bit15写入0b0001,GPJ0_3引脚就成为输出模式了)
四, 找到相关的SFR(特殊功能寄存器)
即GPJ0C0N GPJ0DAT 这两个寄存器
GPJODAT 寄存器中有8个bit为 0——7每一个位 写0或1来控制 GPJOCON寄存器的 GPJOCON_0———7的7个引脚
每一个寄存器是32位的,用到的位就配置,其他未用到的未就随便配置都没有影响
五, 写代码设置寄存器得到想要的效果
1. 汇编实现流水灯
//实现led流水灯效果#define GPJ0CON 0xE0200240
#define GPJ0DAT 0xE0200244.global _start
_start: //_start 是一个符号,是汇编程序的的默认入口标号,每一 //个汇编程序的开头都要有// r0 --r17 通用寄存器//第一步对GPJ0CON寄存器进行模式设置ldr r0, =0x11111111 //从后面的“=” 可以看出 ldr 是伪指令, 因为需要编译器 //来判断这个数是合法立即数还是非法立即数 一般写代码都 //用ldr伪指令ldr把0x11111111数据读到 r0 通用寄存器中ldr r1, =GPJ0CON str r0, [r1] //寄存器的间接寻址, 功能是把r0中的数写入到r1中的数为 //地址的内存中去//循环体,led亮灭循环
flash://D4亮ldr r0, =(0<<3 | 1<<4 | 1<<5) //把0写入到GPJODAT寄存器中,引脚即输出低电平,LED亮ldr r1, =GPJ0DATstr r0, [r1]//延时函数bl delay //调用函数//D5亮 D4灭ldr r0, =(1<<3 | 0<<4 | 1<<5)ldr r1, =GPJ0DATstr r0, [r1]//延时bl delay //调用函数//D6亮 D5灭ldr r0, =(1<<3 | 1<<4 | 0<<5)ldr r1, =GPJ0DATstr r0, [r1]//延时bl delay //调用函数b flash //跳转到flash的位置执行delay:ldr r2, =9000000ldr r3, =0x0
delay_loop: //循环体 相当于while()sub r2, r2, #1 //r2 = r2-1cmp r2, r3 //判断r2 是否与 r3相等 影响z位bne delay_loop // 如果不相等则 继续执行循环mov pc, lr //函数返回值
使用位运算进行改进
对GPJODAT寄存器进行赋值 用位运算(&与 |或 ~非(取反) 位移(<<左移 >>右移))的方式
// 改进流水灯 代码#define GPJ0CON 0xE0200240
#define GPJ0DAT 0xE0200244.global _start
_start://对GPJ0CON寄存器进行模式设置ldr r0, =0x11111111ldr r1, =GPJ0CONstr r0, [r1]//用循环来实现流水灯效果flash://点亮 D4ldr r0, =~(1<<3) //位移与取反 0000 1000 取反得 1111 0111ldr r1, =GPJ0DATstr r0, [r1]//延时bl delay //调用延时函数//点亮 D5ldr r0, =~(1<<4)ldr r1, =GPJ0DATstr r0, [r1]//延时bl delay //调用延时函数//点亮 D6ldr r0, =~(1<<5) ldr r1, =GPJ0DATstr r0, [r1]//延时bl delay //调用延时函数b flash
delay:ldr r2, =9000000ldr r3, =0x0
delay_loop:sub r2, r2, #1cmp r2, r3bne delay_loopmov pc, lr
六, 用到的相关汇编代码
.global 伪指令 在外部对汇编头的声明,保证 _start在文件外部也能用 (.global把_start链接属性改为外部,消除链接时的警告)
ldr 伪指令 用于从存储器中将一个32位的字数据传送到目的寄存器中。并检查立即数是否
例 ldr r0 ,=0x11111111
立即数 我们通常把在立即寻址方式指令中给出的数称为立即数
b是跳转指令 .代表当前这一句指令的地址,
b . 表示跳转到 . 执行 即死循环
str 是ARM汇编中的内存访问指令,表示字数据写入,用于将一个32位的字数据写入到指令中指定的内存单元
例 str r0, [r1] 把r0中的数据写到r1中指定的内存单元
sub 汇编中 是减的意思
例 sub r0 , r0, #1 意思为 r0 = r0 - 1
cmp (比较)指令执行从目的操作数中减去源操作数的隐含减法操作,并且不修改任何操作数。
cmp 目的操作数, 源操作数 例 cmp r2, r3 比较 r2 和r3 中的 数据是否相等 cmp会影响CPSR寄存器中的z位
bl 函数调用
例 bl 函数名
mov pc, lr 函数返回
ARM中的通用寄存器
r0~r3 主要用于子程序间传递参数, r4~r11 主要用于保存局部变量,但在 Thumb 程序中,通常只能使用 r4~r7 来保存局部变量; r12 用作子程序间scratch 寄存器,即 ip 寄存器; r13 通常用做栈指针,即 sp; r14 寄存器又被称为连接寄存器(lr),用于保存子程序以及中断的返回地址; r15 用作程序计数器(pc),由于 ARM 采用了流水线机制,当正确读取了 PC 的值后,该值为当前指令地址加 8 个字节,即 PC 指向当前指令的下两条指令地址。
这篇关于s5pv210 用汇编点亮led灯的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!