Linux学习笔记—驱动篇(三) 按键与汇编

  1. 按键输入实验
    #define GPIOEOUT (*(volatile unsigned int )0xC001E000) // 输出的电平
    #define GPIOEOUTENB (
    (volatile unsigned int )0xC001E004) // 输出使能
    #define GPIOEALTFN0 (
    (volatile unsigned int )0xC001E020) // 对应的焊脚功能选择
    #define GPIOEALTFN1 (
    (volatile unsigned int )0xC001E024) // 对应的焊脚功能选择
    GPIOA28 输入
    #define GPIOAOUTENB (
    (volatile unsigned int )0xC001A004) // 输出使能
    #define GPIOAALTFN0 (
    (volatile unsigned int )0xC001A020) // 低16位 对应的焊脚功能选择
    #define GPIOAALTFN1 (
    (volatile unsigned int )0xC001A024) // 高16位 对应的焊脚功能选择
    #define GPIOAPAD (
    (volatile unsigned int *)0xC001A018) // 读GPIO值
    void delay(int val);

void _start(void)
{

// 灯设置成输出
GPIOEALTFN0 &= ~(3<<(13*2)); //function0--GPIOE13
GPIOEOUTENB |= (1<<13);//GPIOE13--OUTOPUT
// 按键设置成输入
GPIOAALTFN1 &= ~(3<<((28-16)*2)); //function0--GPIOA28
GPIOAOUTENB &= ~(1<<28);//GPIOA28--INPUT	
while(1)
{
	if(! (GPIOAPAD&(0x01<<28))) // 真就表示读到低电平,按下
	{
		delay(0x40000);	//消抖
		if(! (GPIOAPAD&(0x01<<28)))
			GPIOEOUT &= ~(1<<13);//GPIOE13 output 0			
	}
	else	
		GPIOEOUT |= (1<<13);//GPIOE13 output 1		
}
}

void delay(int val)
{
	volatile int i=val;
	while(i--);	
}
  1. 用汇编来写点灯程序
    程序如下

.global _start // 全局变量定义

_start:
	LDR R0, =0XC001E020  	// 将0XC001E020作为地址赋给R0   	
	LDR R1, [R0]			//将R0即地址0XC001E020的内容赋给R1
	BIC R1, R1, #(3<<26)	//R1=R1 & ~(3<<26),因为BIC自动取反
	STR R1,[R0]			//将R1存储到地址0xC001E020

	LDR R0, =0xC001E004  // 设置成输出
	LDR R1, [R0]
	ORR R1, R1, #(1<<13);
	STR R1,[R0]; 

_loop:        // 循环
	LDR R0 , =0xC001E000  // 设置输出值
	LDR R1, [R0]
	BIC R1 , R1,#0X2000   // (1<<13) 与操作,设置为0  灯亮
	STR R1,[R0];

	bl  _delay      // 执行延时函数	
	LDR R1, [R0]
	ORR R1 , R1,#0X2000  // (1<<13) 或操作,设置为1  灯灭
	STR R1,[R0];
	bl  _delay    // 执行延时函数
	b  _loop     // 继续循环

_delay:
	MOV R4, #0x4000000	
d_loop:
	subs R4,R4,#1 
	cmp R4,#0 
	bne d_loop
	mov  pc , lr

注意:
在这里插入图片描述

1)文件的后缀是大写的S,小写的.s编译会不过的(编译环境ubuntu18.04 arm-linux-gcc)
2)mov PC ,LR ---- 相当于子函数调用返回return
3)代码块可以直接用 name: 表示
4)对于_start 函数入口,需要在文件头定义成全局变量
.global _start // 全局变量定义

5)LDR和MOV 的区别
LDR 是ARM指令集中的
.LDR伪指令用于加载32位的立即数或一个地址值到指定寄存器;
若加载的常数未超出 MOV 或 MVN 的范围,则使用 MOV 或 MVN 指令代替该 LDR 伪指令
MOV 是 16位的;
数据传送指令.将 8 位立即数或寄存器(operand2)传送到目标寄存器(Rd)

6)BIC 和 AND 的区别
BIC 会把对应位先取反再相与
位清除指令.将寄存器Rn的值与operand2的值的反码按位作逻辑与操作,结果保存到 Rd 中.指令格式如下:
BIC{cond}{S}Rd,Rn,operand2
BIC R1,R1,#0x0F ;将 R1 的低 4 位清零,其它位不变

AND 直接和对应数相与
逻辑与操作指令.将 operand2 值与寄存器 Rn 的值按位作逻辑与操作,结果保存到Rd 中.指令格式如下:
AND{cond}{S} Rd,Rn,operand2
ANDS R0R0#x01 ;R0=R0&0x01取出最低位数据

7)STR 的作用
STR Rd,addressing 存储字数据 [addressing]←Rd,addressing 索引 STR{cond}
;STR 指令用于将寄存器中的数据保存到内存(存储器地址).

8)BL和B的区别
B 跳转指令.跳转到指定的地址执行程,不能返回,使用于循环操作
BL带链接的跳转指令.指令将下一条指令的地址拷贝到 R14(即 LR)链接寄存器中,然后跳转到指定地址运行程序.可以用mov PC , LR 返回到调用处

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
学习 Linux 驱动开发需要掌握以下几个方面的知识: 1. Linux 操作系统的内核架构和基本原理。 2. C 语言编程基础和数据结构。 3. 设备驱动的基本概念和工作原理。 4. Linux 驱动程序的开发方法和调试技巧。 以下是我给出的学习笔记: 1. Linux 操作系统的内核架构和基本原理 - Linux 内核的基本组成部分 - 进程管理 - 内存管理 - 文件系统 - 网络协议栈 - 设备驱动 - Linux 内核的编译和安装 - 下载内核源码 - 配置内核选项 - 编译内核 - 安装内核 - Linux 内核的模块化 - 模块的编写和编译 - 模块的加载和卸载 - 模块的依赖关系 - Linux 内核的调试方法 - printk 函数 - kerneloops 机制 - oops 分析工具 2. C 语言编程基础和数据结构 - C 语言基础 - 变量和常量 - 运算符和表达式 - 控制语句 - 函数和指针 - 数据结构 - 数组和指针 - 链表和树 - 栈和队列 - 散列表和堆 3. 设备驱动的基本概念和工作原理 - 设备驱动的分类 - 字符设备驱动 - 块设备驱动 - 网络设备驱动 - 设备驱动的基本概念 - 设备文件 - 设备节点 - 设备号 - 设备驱动的工作原理 - 设备文件的打开和关闭 - 设备文件的读和写 - 设备文件的控制 4. Linux 驱动程序的开发方法和调试技巧 - 设备驱动的开发方法 - 设备驱动的框架 - 设备驱动的初始化和清理 - 设备驱动的操作函数 - 设备驱动的中断处理函数 - 设备驱动的调试技巧 - printk 函数的使用 - ftrace 工具的使用 - gdb 调试工具的使用 以上是我给出的 Linux 学习笔记,希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值