PLC解密网-PLC培训学习-工控自动化人才技术交流

超级管理员

453

帖子

1378

回复

3110

积分

楼主
发表于 2020-10-18 10:40:35 | 查看: 5858 | 回复: 16

/*

 *文件名:led.s

 *作者:宗虎冬

 *描述:这是arm裸机点亮led灯第一个程序

 *

 */

 .globl _start

 _start:

//第一步:把0x11111111写入到0xE0200240(GPJ0CON)位置

ldr r0, =0x11111111

ldr r1, =0xE0200240

str r0, [r1]

//第二部:把oxE0200244(GPJ0DAT)位置

ldr r0, =0x0

ldr r1, =0xE0200244

ldr r1, =0xE0200244

flag:

b flag


超级管理员

453

帖子

1378

回复

3110

积分
沙发
发表于 2020-10-18 10:48:49

注意事项:

    1、新建文件led.S  后缀为大写

    image.png

    2、 文件开始加.globl _start 不然报错: warning: cannot find entry symbol _start; defaulting to 00000000

    image.png

image.png

3、删除编译出来文件可以执行:make clean

image.png

make clean 指令执行前

image.png

make clean 指令执行后

image.png

image.png

超级管理员

453

帖子

1378

回复

3110

积分
板凳
发表于 2020-10-18 10:59:49

设置GPJ0CON 8个I/O口全部为输出

image.png

如果GPJ0CON设置为输入,那么GPJ0DAT b0到b7对应输入的状态


如果GPJ0CON设置为输出,那么GPJ0DAT b0到b7对应设置输出状态

image.png

超级管理员

453

帖子

1378

回复

3110

积分
地板
发表于 2020-10-18 11:14:34
提示: 该作者的回复内容被删除屏蔽

超级管理员

453

帖子

1378

回复

3110

积分
4#
发表于 2020-10-18 11:16:13
提示: 该作者的回复内容被删除屏蔽

超级管理员

453

帖子

1378

回复

3110

积分
5#
发表于 2020-10-18 11:18:09

/*

 *文件名:led.s

 *作者:宗虎冬

 *描述:这是arm裸机点亮led灯第一个程序

 *

 */

 .globl _start

 _start:

//第一步:把0x11111111写入到0xE0200240(GPJ0CON)位置

ldr r0, =0x11111111 //从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数

ldr r1, =0xE0200240 //是合法立即数还是非法立即数。一般写代码都用ldr伪指令

str r0, [r1] //寄存器间接寻址,功能是把r0的数写入到r1中的数为地址的内存中去

//第二部:把oxE0200244(GPJ0DAT)位置

ldr r0, =0x0

ldr r1, =0xE0200244

ldr r0, =[r1] //把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮

flag: //这两行写了一个死循环。以为裸机程序是直接在CPU上运行

b flag //逐行运行裸机程序直到CPU断电关机,如果我们的程序所有

//执行完了CPU就会跑飞(跑飞以后是未定义的,所以千万不能

//跑飞),不让CPU跑飞的方法就是在我们的整个程序执行完成加死循环程序


代码分享:


1.leds_s.zip


解压后打开

超级管理员

453

帖子

1378

回复

3110

积分
6#
发表于 2020-10-18 11:28:29

查阅数据手册可知,GPJ0相关的寄存器有以下:

GPJ0CON, (GPJ0 control)GPJ0控制寄存器,用来配置各引脚的工作模式

GPJ0DAT, (GPJ0 data)当引脚配置为input/output模式时,寄存器的相应位和引脚的电平高低相对应。

GPJ0PUD, (pull up down)控制引脚内部弱上拉、下拉

GPJ0DRV, (driver)配置GPIO引脚的驱动能力

GPJ0CONPDN,(记得是低功耗模式下的控制寄存器)

GPJ0PUDPDN  (记得是低功耗模式下的上下拉寄存器)

注:在驱动LED点亮时,应该将GPIO配置为output模式。

实际上真正操控LED的硬件,主要的有:GPJ0CON, GPJ0DAT 这么2个。

如何点亮LED,编程的步骤是:

1、操控GPJ0CON寄存器中,选中output模式

2、操控GPJ0DAT寄存器,相应的位设置为0

一步步点亮LED3_从零开始手写汇编点亮LED

GPxCON、GPxDAT寄存器分析

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引脚就成为输出模式了)

从零开始写代码操作寄存器

需要哪些先决条件才能写呢?

1. 硬件接法和引脚:GPJ0_3 GPJ0_4 GPJ0_5 低电平亮/高电平灭

2. GPJ0CON(0xE0200240)寄存器和GPJ0DAT(0xE0200244)寄存器

3. 工程管理:Makefile等

根据以上分析,我们就知道代码的写法了,代码所要完成的动作就是:

把相应的配置数据写入相应的寄存器即可。

编译、下载、运行看结果

编译时用我们的工程管理,直接make编译得到led.bin和210.bin

下载运行可以用usb启动dnw下载;也可以用sd卡烧录下载,根据自己的情况用

一般都用usb下载,因为方便。如果电脑主板插上dnw会死机没法解决,那只有sd卡下载启动了。

注意:开发板上按下电源键之后4颗LED默认都是半亮的,当我们下载程序后其中3颗变的很亮,这说明我们的程序已经运行了。

总结和回顾(软件控制硬件思想、寄存器意义、原理图数据手册的作用)

软件到底是怎么控制硬件的?为什么程序一运行硬件就能跟着动?

软件编程控制硬件的接口就是:寄存器


超级管理员

453

帖子

1378

回复

3110

积分
7#
发表于 2020-10-18 11:30:35

一步步点亮LED4_使用位运算实现复杂点亮要求

上节回顾:代码写的更漂亮一些

1. 用宏定义来定义寄存器名字,再来操作。

2. 用 b . 来实现死循环

3. 用.global把_start链接属性改为外部,消除链接时的警告


/*

 *文件名:led.s

 *作者:宗虎冬

 *描述:这是arm裸机点亮led灯第一个程序

 *

 */

 .global _start    //用.global把_start链接属性改为外部,消除链接时的警告

 

 #define GPJ0CON 0xE0200240    //1. 用宏定义来定义寄存器名字,再来操作。

 #define GPJ0DAT 0xE0200244

 

 _start:

//第一步:把0x11111111写入到0xE0200240(GPJ0CON)位置

ldr r0, =0x11111111 //从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数

ldr r1, =GPJ0CON //是合法立即数还是非法立即数。一般写代码都用ldr伪指令

str r0, [r1] //寄存器间接寻址,功能是把r0的数写入到r1中的数为地址的内存中去

//第二部:把oxE0200244(GPJ0DAT)位置

ldr r0, =0x0

ldr r1, =GPJ0CON

ldr r0, =[r1] //把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮

b . //.代表当前这一句指令的地址,这个就是高大上的死循环

                                                //2. 用 b . 来实现死循环


超级管理员

453

帖子

1378

回复

3110

积分
8#
发表于 2020-10-18 11:46:35

问题提出:如何只点亮中间1颗(两边是熄灭的)LED

分析:程序其实就是写了GPJ0CON和GPJ0DAT这2个寄存器而已,功能更改也要从这里下手。

GPJ0CON寄存器不需要修改,GPJ0DAT中设置相应的输出值即可。

image.png

 .global _start //把_start链接属性改为外部,这样其他文件就可以看见_start了

 

 #define GPJ0CON 0xE0200240

 #define GPJ0DAT 0xE0200244

 

 _start:

//第一步:把所有引脚都设置为输出模式,代码不变

ldr r0, =0x11111111 //从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数

ldr r1, =GPJ0CON //是合法立即数还是非法立即数。一般写代码都用ldr伪指令

str r0, [r1] //寄存器间接寻址,功能是把r0的数写入到r1中的数为地址的内存中去

//第二部:把中间LED(GPJ0_4)的输出设置为0,其余两颗设置为1,剩下的其他位不管

ldr r0, =0x28

ldr r1, =GPJ0CON

ldr r0, =[r1] //把0写入到GPJ0DAT寄存器中,引脚即输出低电平,LED点亮

b . //.代表当前这一句指令的地址,这个就是高大上的死循环


超级管理员

453

帖子

1378

回复

3110

积分
9#
发表于 2020-10-18 12:09:08

直接解法(不使用位运算)和它的弊端

GPJ0DAT = 0x28

代码见<3.led_s>

总结:1. 这样写可以完成任务。

  2. 这样写有缺陷。缺陷就是需要人为的去计算这个特定的设置值,而且看代码的也不容易看懂。

解决方案:在写代码时用位运算去让编译器帮我们计算这个特定值。

常用位运算:与、或、非、移位

位与(&)  位或(|)  位非(取反 ~) 移位(左移<< 右移>>)

使用位运算实现功能

1<<3  等于 0b1000

1<<5  等于 0b100000

(1<<3)|(1<<5)  等于 0b101000

扩展一下:如何只熄灭中间1颗而点亮旁边2颗

ldr r0, =((0<<3) | (1<<4) | (0<<5))

image.png

ldr r0, =((1<<3) | (1<<5))

image.png


    //ldr r0, =((1<<3) | (1<<5)) //中间LED(GPJ0_4)亮,其余两颗不亮

    ldr r0, =((1<<3) | (0<<4) | (1<<5)) //中间LED(GPJ0_4)亮,其余两颗不亮

    //ldr r0, =((0<<3) | (1<<4) | (0<<5)) //中间LED(GPJ0_4)不亮,其余两颗亮


超级管理员

453

帖子

1378

回复

3110

积分
10#
发表于 2020-10-18 14:39:07

/*

 *文件名:led.s

 *作者:宗虎冬

 *描述:这是arm裸机led灯亮灭三次效果

 *

 */

 .global _start //把_start链接属性改为外部,这样其他文件就可以看见_start了

 

 #define GPJ0CON 0xE0200240

 #define GPJ0DAT 0xE0200244

 

 _start:

//第一步:把所有引脚都设置为输出模式,代码不变

ldr r0, =0x11111111 //从后面的=可以看出用的是ldr伪指令,因为需要编译器来判断这个数

ldr r1, =GPJ0CON //是合法立即数还是非法立即数。一般写代码都用ldr伪指令

str r0, [r1] //寄存器间接寻址,功能是把r0的数写入到r1中的数为地址的内存中去

//第二部:全部点亮

ldr r0, =((0<<3) | (0<<4) | (0<<5))

ldr r1, =GPJ0CON

ldr r0, =[r1]

bl delay

//第三部:全部灭

ldr r0, =((1<<3) | (1<<4) | (1<<5))

ldr r1, =GPJ0CON

ldr r0, =[r1]

bl delay

//第四部:全部点亮

ldr r0, =((0<<3) | (0<<4) | (0<<5))

ldr r1, =GPJ0CON

ldr r0, =[r1]

bl delay

//第五部:全部灭

ldr r0, =((1<<3) | (1<<4) | (1<<5))

ldr r1, =GPJ0CON

ldr r0, =[r1]

//第六部:全部点亮

ldr r0, =((0<<3) | (0<<4) | (0<<5))

ldr r1, =GPJ0CON

ldr r0, =[r1]

bl delay

//第七部:全部灭

ldr r0, =((1<<3) | (1<<4) | (1<<5))

ldr r1, =GPJ0CON

ldr r0, =[r1]

b . //.代表当前这一句指令的地址,这个就是高大上的死循环

delay:

ldr r2, =100000

ldr r3, =0x0

delay_loop:

sub r2, r2, #1 //r2 = r2 - 1

cmp r2, r3 //cmp会影响z标志位,如果r2等于r3则z=1,下一句中eq就会成立

bne delay_loop //不相等就跳回delay_loop

mov pc, lr //函数调用返回


您需要登录后才可以回帖 登录 | 立即注册

技术支持 KZYPLC V2.1 © 2020-2027

欢迎光临昆山中宇工控PLC论坛!您是第 6523387 位访问者, 日访问量: 19763 总访问量: 16039431,当前 2024-04-25 21:29:27 在线人数:122

ICP备案证书号: 苏ICP备14003016-2号