ARM裸机:一步步点亮LED(汇编)

news2025/1/9 21:54:25

硬件工作原理及原理图查阅

  • LED物理特性介绍
    LED本身有2个接线点,一个是LED的正极,一个是LED的负极。LED这个硬件的功能就是点亮或者不亮,物理上想要点亮一颗LED只需要给他的正负极上加正电压即可,要熄灭一颗LED只需要去掉电压即可。

  • 查阅原理图了解板载LED硬件接法
    查阅原理图,发现开发板上一共有5颗LED。其中一颗D26的接法是:正极接5V,负极接地。因此这颗LED只要上电就会常亮。因此我们分析这颗LED是电源指示灯。
    剩下4颗LED的接法是:正极接3.3V,负极接了SoC上的一个引脚(GPIO),具体详细接法是:
    D22:GPJ0_3
    D23:GPJ0_4
    D24:GPJ0_5
    D25:PWMTOUT1(GPD0_1)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 分析如何点亮及熄灭LED(GPIO)
    分析:LED点亮的要求是:正极和负极之间有正向电压差。
    思考:在开发板上如何为LED制造这个电压差让它点亮呢?
    解答:因为正极已经定了(3.3V),而负极接在了SoC的引脚上,可以通过SoC中编程来控制负极的电压值,因此我们可以通过程序控制负极输出低电平(0V),这样在正负极上就有了压差,LED即可点亮。

数据手册查阅及相关寄存器浏览

  • GPIO概念的引入
    GPIO:general purpose input output 通用输入输出
    GPIO就是芯片的引脚(芯片上的引脚有些不是GPIO,只有一部分是),作为GPIO的这类引脚,他的功能和特点是可以被编程控制它的工作模式,也可以编程控制他的电压高低等。
    通过之前的分析我们知道,我们设计电路时就把LED接在了一个GPIO上,这样我们就可以通过编程控制GPIO的模式和输入输出值来操控LED亮还是灭;如果你当时设计电路时把LED接在非GPIO上那就不可能了。

  • 阅读数据手册中有关部分
    当我们想要通过编程操控GPIO来操作LED时,我们首先需要通读一下S5PV210的数据手册中有关于GPIO的部分,这部分在数据手册的Section2.2中。
    《S5PV210_UM_REV1.1.pdf》
    在这里插入图片描述

  • GPIO相关的寄存器介绍
    回忆下之前说过的,软件操作硬件的接口是:寄存器。
    我们当前要操作的硬件是LED,但是LED实际是通过GPIO来间接控制的,所以当前我们实际要操作的设备其实是SoC的GPIO。要操作这些GPIO,必须通过设置他们的寄存器。
    在这里插入图片描述

    查阅数据手册可知,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

开始手写汇编点亮LED

D22:GPJ0_3
D23:GPJ0_4
D24:GPJ0_5

在这里插入图片描述
在这里插入图片描述

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

第一步:设置引脚模式为输出模式(向GPxCON寄存器写入0001)
第二步:写入控制的数据(向GPxDAT寄存器写入0输出低电平,LED亮;1输出高电平,LED灭)

文件目录:
在这里插入图片描述

led.S:

_start:
	//把0x1111 1111 写入 GPJ0CON(0xE0200240)
	//这里 ldr 是Load Register(加载寄存器)的缩写,
	//用于从给定的地址加载数据到处理器寄存器r0。
	//=0x11111111是一个立即数常量,
	//表示存储在内存中的十六进制数值 11111111
	ldr r0, =0x11111111 //ldr伪指令,编译器判断立即数是否合法

	//将立即数 0xE0200240加载到寄存器r1中
	ldr r1, =0xE0200240

	//str是Store Register(存储寄存器)的缩写,
	//它将寄存器r0中的值存储到[r1]所指向的位置。
	//这里的[r1]是对另一个内存地址的操作符,
	//意味着将r0的内容放到r1当前内容指明的那个内存位置
	//将r0的值存储到r1指向的内存地址处
	str r0, [r1] //寄存器间接寻址去

	; //LED灭:将0xff放到GPJ0DAT(0xE0200244)寄存器
	; ldr r0, =0xff
	; ldr r1, =0xE0200244
	; str r0, [r1]

	//LED亮:将 0x0 放到GPJ0DAT(0xE0200244)寄存器
	ldr r0, =0x0
	ldr r1, =0xE0200244
	str r0, [r1]

//结束死循环
falt:
	b falt //直到CPU断电关机

编译结果:
LED常亮

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

  • 如何只点亮中间1颗(两边是熄灭的)LED
    //LED亮:将 0xf7 放到GPJ0DAT(0xE0200244)寄存器 亮1颗
    中间一颗:0xEF
    最后一颗:0xdf

  • 常用位运算:与、或、非、移位
    位与(&) 位或(|) 位非(取反 ~) 移位(左移<< 右移>>)

  • 使用位运算实现功能
    1<<3 等于 0b1000
    1<<5 等于 0b100000
    (1<<3)|(1<<5) 等于 0b101000

  • 扩展一下:如何只熄灭中间1颗而点亮旁边2颗
    ldr r0, =((0<<3) | (1<<4) | (0<<5))

汇编编写延时函数并实现LED闪烁效果

延时就是编写一些没有目的的代码,占用CPU的时间。

//延时函数
delay:
	ldr r2, =0x900000
	ldr r3, =0x0
delay_loop:
	cmp r3, r2
	//比较r3 r2  会影响Z标志位  如果r2==r3 则Z=1 下一句当中的ne就会成立
	sub r2, r2, #1 //r2=r2-1
	bne delay_loop //如果r2==r3 就不会执行这句
	mov pc, lr //函数调用返回
#define  GPJ0CON  0xE0200240
#define  GPJ0DAT  0xE0200244
//3、添加链接属性添加
.globl _start //将-start 修改为外部链接属性,其他文件就能找到_start
_start:
	//把0x1111 1111 写入 GPJ0CON(0xE0200240)
	//这里 ldr 是Load Register(加载寄存器)的缩写,
	//用于从给定的地址加载数据到处理器寄存器r0。
	//=0x11111111是一个立即数常量,
	//表示存储在内存中的十六进制数值 11111111
	ldr r0, =0x11111111 //ldr伪指令,编译器判断立即数是否合法

	//将立即数 0xE0200240加载到寄存器r1中
	ldr r1, =GPJ0CON

	//str是Store Register(存储寄存器)的缩写,
	//它将寄存器r0中的值存储到[r1]所指向的位置。
	//这里的[r1]是对另一个内存地址的操作符,
	//意味着将r0的内容放到r1当前内容指明的那个内存位置
	//将r0的值存储到r1指向的内存地址处
	str r0, [r1] //寄存器间接寻址

delay_loop_ok:
	//熄灭中间1颗而点亮旁边2颗
	ldr r0, =((0<<3) | (1<<4) | (0<<5))
	ldr r1, =GPJ0DAT
	str r0, [r1]

	//延时一下:
	bl delay

	ldr r0, =((1<<3) | (0<<4) | (1<<5))
	ldr r1, =GPJ0DAT
	str r0, [r1]

	//延时一下:
	bl delay

	; bne delay_loop_ok
	b delay_loop_ok //死循环

再难一点的流水灯效果

12321的点亮LED

#define  GPJ0CON  0xE0200240
#define  GPJ0DAT  0xE0200244
//3、添加链接属性添加
.globl _start //将-start 修改为外部链接属性,其他文件就能找到_start
_start:
	//把0x1111 1111 写入 GPJ0CON(0xE0200240)
	//这里 ldr 是Load Register(加载寄存器)的缩写,
	//用于从给定的地址加载数据到处理器寄存器r0。
	//=0x11111111是一个立即数常量,
	//表示存储在内存中的十六进制数值 11111111
	ldr r0, =0x11111111 //ldr伪指令,编译器判断立即数是否合法

	//将立即数 0xE0200240加载到寄存器r1中
	ldr r1, =GPJ0CON

	//str是Store Register(存储寄存器)的缩写,
	//它将寄存器r0中的值存储到[r1]所指向的位置。
	//这里的[r1]是对另一个内存地址的操作符,
	//意味着将r0的内容放到r1当前内容指明的那个内存位置
	//将r0的值存储到r1指向的内存地址处
	str r0, [r1] //寄存器间接寻址

delay_loop_ok:

	ldr r0, =((0<<3) | (1<<4) | (1<<5))
	ldr r1, =GPJ0DAT
	str r0, [r1]

	//延时一下:
	bl delay

	ldr r0, =((1<<3) | (0<<4) | (1<<5))
	ldr r1, =GPJ0DAT
	str r0, [r1]

	//延时一下:
	bl delay

	ldr r0, =((1<<3) | (1<<4) | (0<<5))
	ldr r1, =GPJ0DAT
	str r0, [r1]


	//延时一下:
	bl delay

	ldr r0, =((1<<3) | (0<<4) | (1<<5))
	ldr r1, =GPJ0DAT
	str r0, [r1]

	//延时一下:
	bl delay
	
	; bne delay_loop_ok
	b delay_loop_ok //死循环



//结束死循环 2、高级点的死循环
	b .  //直到CPU断电关机 .:当前指令的地址


//延时函数
delay:
	ldr r2, =0x900000
	ldr r3, =0x0
delay_loop:
	cmp r3, r2
	//比较r3 r2  会影响Z标志位  如果r2==r3 则Z=1 下一句当中的ne就会成立
	sub r2, r2, #1 //r2=r2-1
	bne delay_loop //如果r2==r3 就不会执行这句
	mov pc, lr //函数调用返回

位取反操作:

//1、使用宏定义
#define  GPJ0CON  0xE0200240
#define  GPJ0DAT  0xE0200244
//3、添加链接属性添加
.globl _start //将-start 修改为外部链接属性,其他文件就能找到_start
_start:
	//把0x1111 1111 写入 GPJ0CON(0xE0200240)
	//这里 ldr 是Load Register(加载寄存器)的缩写,
	//用于从给定的地址加载数据到处理器寄存器r0。
	//=0x11111111是一个立即数常量,
	//表示存储在内存中的十六进制数值 11111111
	ldr r0, =0x11111111 //ldr伪指令,编译器判断立即数是否合法

	//将立即数 0xE0200240加载到寄存器r1中
	ldr r1, =GPJ0CON

	//str是Store Register(存储寄存器)的缩写,
	//它将寄存器r0中的值存储到[r1]所指向的位置。
	//这里的[r1]是对另一个内存地址的操作符,
	//意味着将r0的内容放到r1当前内容指明的那个内存位置
	//将r0的值存储到r1指向的内存地址处
	str r0, [r1] //寄存器间接寻址

delay_loop_ok:

	ldr r0, =~(1<<3)
	ldr r1, =GPJ0DAT
	str r0, [r1]
	//延时一下:
	bl delay

	ldr r0, =~(1<<4)
	ldr r1, =GPJ0DAT
	str r0, [r1]
	//延时一下:
	bl delay

	ldr r0, =~(1<<5)
	ldr r1, =GPJ0DAT
	str r0, [r1]
	//延时一下:
	bl delay


	; bne delay_loop_ok
	b delay_loop_ok //死循环



//结束死循环 2、高级点的死循环
	b .  //直到CPU断电关机 .:当前指令的地址


//延时函数
delay:
	ldr r2, =0x900000
	ldr r3, =0x0
delay_loop:
	cmp r3, r2
	//比较r3 r2  会影响Z标志位  如果r2==r3 则Z=1 下一句当中的ne就会成立
	sub r2, r2, #1 //r2=r2-1
	bne delay_loop //如果r2==r3 就不会执行这句
	mov pc, lr //函数调用返回

反汇编工具objdump的使用简介

反汇编的原理&为什么要反汇编
arm-linux-objdump -D led.elf > led_elf.dis
objdump是gcc工具链中的反汇编工具,作用是由编译链接好的elf格式的可执行程序反过来得到汇编源代码
-D表示反汇编 > 左边的是elf的可执行程序(反汇编时的原材料),>右边的是反汇编生成的反汇编程序

  • 反汇编的原因
    1、逆向破解
    2、调试,理解程序链接脚本、链接地址
    3、理解C语言和汇编语言的关系

(汇编 assembly 反汇编 Disassembly)
标号的实质是地址
指令被转换为机器码
地址池实现非法立即数
在这里插入图片描述

bin文件内部是机器码,机器码会有指定的指令地址,使用ld链接在一起

总结

1、知道LED点亮原理
2、查看原理图知道接线方式
3、查看数据手册知道寄存器地址
4、开始编程
5、编译可执行文件
6、下载到设备上
7、添加延时达到流水灯
8、位操作增加可读性,同时比较简略
9、反汇编工具objdump可以帮助理解程序

学习记录,侵权联系删除。
来源:朱老师物联网大课堂

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1912361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Dynamics365 UCI下的高级查找(不要留恋Classic了)

UCI界面已经用了多年了&#xff0c;在Classic下的的高级查找按钮(漏斗icon)已不见踪影 但因为使用习惯问题&#xff0c;还是有人会通过右上角高级设置&#xff0c;进入Classic界面找到漏斗Icon来使用高级查找 但新的UCI风格下已经没了高级查找的概念&#xff0c;取而代之的是基…

ComfyUI入门教程

本文主要介绍了通过源码运行comfyui&#xff0c;默认例子介绍&#xff0c;节点管理器的使用&#xff0c;以及界面汉化。可多参考开源工作流&#xff0c;多加实践&#xff0c;从而掌握comfyui操作。 1.源码运行comfyui 执行命令python main.py如下&#xff1a; 安装numpy 1.x最…

JavaScript中的LHS和RHS

LHS和RHS之前我们先来回忆一下最简单的赋值操作! var test100; console.log(test); 以上代码的意思简单我们理解为把右边的值赋值给左边的test变量,然后输出打印结果。 可是我们要是深入理解你就会发现在这个过程当中&#xff0c;还发生了一些其他的事情 而这些事情就是今天…

C++入门基础(1)

因为6月中旬学校事情多&#xff0c;许久未更新&#xff0c;让我们继续学习吧&#xff01; 目录 前言&#xff1a; 一、命名空间&#xff1a; 1、定义&#xff1a; 2、使用&#xff1a; 3、访问命名空间域: 二、C输入、输出函数&#xff1a; 1、输入函数&#xff1a; 2、输出…

vue3源码(六)渲染原理-runtime-core

1.依赖关系 runtime-dom 依赖于runtime-core,runtime-core 依赖于reactivity和sharedruntime-core提供跨平台的渲染方法createRenderer&#xff0c;用户可以自己传递节点渲染的渲染方法renderOptions&#xff0c;本身不关心用户使用什么APIruntime-dom提供了为浏览器而生的渲染…

关闭这八个电脑设置,保护个人隐私

你知道吗&#xff1f;电脑可能一直在偷窥你的小秘密。朋友们&#xff0c;一定要记得关闭这8个电脑设置哦&#xff0c;这样可以有效地保护我们的个人隐私。 按住键盘Windows键加i键&#xff0c;快速打开Windows设置。然后点击隐私选项。 我们来看基本的常规设置。里面有四个设置…

关于put提交不了参数的解决办法

html中form表单只支持GET与POST请求&#xff0c;而DELETE、PUT等method并不支持&#xff0c; 如图所示 参数请求改成RequestBody&#xff0c;用json格式传参即可解决问题

资料分析笔记整理

提升技巧多做题、少动笔、多分析 资料分析认识 国考一般20题(24~28分钟) 统计材料的类型包括单纯的文字、表格、图形以及由这些元素组成的复合类型材料 文字性材料:(30~60秒) 多段落型文字材料(时间、关键词、结构) 孤立段落文字材料(时间、关键词、标点[。;]) 表…

数据挖掘——matplotlib

matplotlib概述 Mat指的是Matlab&#xff0c;plot指的是画图&#xff0c;lib即library&#xff0c;顾名思义&#xff0c;matplotlib是python专门用于开发2D图表的第三方库&#xff0c;使用之前需要下载该库&#xff0c;使用pip命令即可下载。 pip install matplotlib1、matpl…

Idea使用EasyApi插件自动生成接口文档到Yapi

1.安装EasyApi插件 2.配置Yapi 设置-》EasyApi Yapi的Server 配置为Yari项目的地址 tokens&#xff1a;项目名Yapi项目里面的token&#xff1a;例如&#xff1a;test-project0e6cfb3c22c884a0fce108fffe554a20ca12341e421d7201233143ee440af36b mytest-portal0e6cfb3c22c884a…

关于Qt模型插入最后一行数据中存在未填满的项,点击导致崩溃的解决办法

在使用Qt模型视图框架的时候&#xff0c;你可能会遇见这种情况&#xff1a;给QTableView设置设置模型的时候&#xff0c;网模型里面插入数据&#xff0c;因为数据是一行一行插入的&#xff0c;即要使用model的appandRow函数&#xff0c;但有时候最后一行数据没有填满一行&#…

Temu是什么?Temu自养号测评有什么优势?

一、 Temu是什么&#xff1f;Temu是拼多多于海外线的跨境电商平台&#xff0c;“Temu”这个名字的含义也和拼多多的意思相近。Temu跨境电商自上线以来&#xff0c;下载量不断攀升&#xff0c;发展势头一片大好&#xff0c;击穿地板价的商品在欧美市场掀起了一阵狂潮&#xff0c…

html H5 dialog弹窗学习,实现弹窗显示内容 替代confirm、alert

html H5 dialog弹窗学习,实现弹窗内容 替代confirm 框架使用的mui,使用mui.confirm() 弹窗内容过多时,弹窗被撑的到屏幕外去了,使用H5 dialog 标签自定义一个固定大小的弹窗,内容过多时可下拉显示 效果展示 隐私政策内容很多,可以下拉显示 代码 myDialog.css dialog{p…

Java虚拟机面试题汇总

目录 1. JVM的主要组成部分及其作用&#xff1f; 1.1 运行时数据区划分&#xff1f; 1.2 哪些区域可能会发生OOM&#xff1f; 1.3 堆和栈的区别&#xff1f; 1.4 内存模型中的happen-before是什么&#xff1f; 2. HotSpot虚拟机对象创建流程&#xff1f; 2.1 类加载过程…

Xilinx zc706 USB电路解析

作者 QQ群&#xff1a;852283276 微信&#xff1a;arm80x86 微信公众号&#xff1a;青儿创客基地 B站&#xff1a;主页 https://space.bilibili.com/208826118 参考 USB OTG检测原理 USB3320 USB_ID为低电平时候&#xff0c;为host模式&#xff0c;USB_ID为悬空&#xff08;高…

如何快速实现一个无缝轮播效果

&#x1f9d1;‍&#x1f4bb; 写在开头 点赞 收藏 学会&#x1f923;&#x1f923;&#x1f923; 需求简介 轮播图是我们前端开发中的一个常见需求&#xff0c;在项目开发中&#xff0c;我们可以使用element、ant等UI库实现。某些场景&#xff0c;为了一个简单的功能安装一…

数据结构作业/2024/7/9

2>实现双向循环链表的创建、判空、尾插、遍历、尾删、销毁 fun.c #include "head.h" //1.双向循环链表的创建 doubleloop_ptr create_list() …

面经-计算机网络-数据结构-堆

1.什么是堆 堆是一种满足以下条件的树&#xff1a; 堆中的每一个节点值都大于等于&#xff08;或小于等于&#xff09;子树中所有节点的值。或者说&#xff0c;任意一个节点的值都大于等于&#xff08;或小于等于&#xff09;所有子节点的值。 2.堆的用途 当我们只关心所有数…

Raylib 实现超大地图放大缩小与两种模式瓦片地图刷新

原理&#xff1a; 一种刷新模式&#xff1a; 在宫格内整体刷新&#xff0c;类似九宫格移动到边缘&#xff0c;则九宫格整体平移一个宫格&#xff0c;不过这里是移动一个瓦片像素&#xff0c;实际上就是全屏刷新&#xff0c;这个上限是 笔记本 3060 70帧 100*100个瓦片每帧都…

16:9横屏短视频素材库有哪些?横屏短视频素材网站分享

在这个视觉内容至关重要的时代&#xff0c;16:9横屏视频因其宽广的画面和优越的观赏体验&#xff0c;已经成为无数创作者和营销专家的首选格式。但要创造出吸引人的横屏视频&#xff0c;高质量的视频素材库是不可或缺的。不管你是资深视频制作人还是刚入行的新手&#xff0c;下…