【裸机开发】按键输入实验

news2024/11/19 17:43:37

目录

一、硬件原理分析

二、寄存器分析

1、时钟源初始化

2、设置 IO 复用 

3、初始化 IO 复用引脚(设置电气属性)

 4、初始化GPIO

三、汇编代码(start.s)

四、公共头文件(imx6u.h)

四、C 代码编写

1、clk 模块(bsp_clk.c)

2、led 模块(bsp_led.c)

2、delay 模块(bsp_delay.c)

3、key 模块(bsp_key.c)

4、main.c

五、链接脚本(imx6u.lds)

六、Makefile 文件(测试工程的整体结构)


一、硬件原理分析

我们在《imx6ull 底板原理图》中找到按键 KEY 模块。R12 是一个上拉电阻,当按键 KEY0 没有按下时,KEY0 处于高电平;当按键KEY0 按下时,KEY0 接地,此时KEY0 将变为低电平。

接下来我们要去 核心板原理图上找 KEY0 连接的哪个引脚。我们发现是和 UART1_CTS 这个引脚相连。

二、寄存器分析

1、时钟源初始化

这里就不再赘述,可以参考:时钟源初始化

2、设置 IO 复用 

按键属于 IO 的范畴,既然和 IO 有关,那我们就要去找第32章的 IOMUX(IO复用选择器)。根据之前的习惯,我们要找和 UART1_CTS 相关的复用寄存器。

IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B 就是我们要找的寄存器了。UART1_CTS 似乎可以复用为很多功能,我们选择的是复用为 GPIO1_IO18 功能。其他位不变,低四位设为 0101。

寄存器: IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B
基地址: 0x20E008C
初始化值: 0x5    # 低四位为0101,其他位不变

注意:

        虽然找的是 UART,但不代表是复用为 UART功能,UART 是用于数据传输的;GPIO 只是简单控制某个设备的开关,或者读取某个设备的状态。

3、初始化 IO 复用引脚(设置电气属性)

接下来我们要初始化复用引脚,此时要找前缀为 IOMUXC_SW_PAD_xxx 而且和 UART 相关的寄存器。然后设置每一位。多数都和驱动LED时的设置一样。(初始化 IO 复用)

  • 0:0
  • 2-1:00
  • 5-3:000 (这里要禁用输出,相当于用于输入)
  • 7-6:10
  • 10-8:000
  • 11:0
  • 12:1
  • 13:1(选择 pull 功能)
  • 15-14:11(按键 KEY0 默认是上拉状态)
  • 16:0
  • 31-17:剩余为 0
寄存器: IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B
基地址: 0x20E0318
初始化值: 0xF080    

 4、初始化GPIO

从“设置IO复用”部分我们可以知道,UART_CTS 可被复用为 GPIO1_IO18,因此我们需要去初始化 GPIO1_IO18 引脚,设置的方式和驱动LED使用的方式类似。

寄存器: GPIO1_GDIR
基地址: 0x209C004
初始值: GPIO1_GDIR &= ~(1 << 18)    # 因为是GPIO1的第18个引脚设为输入,即第 18 bit应为0
 
寄存器: GPIO1_DR
基地址: 0x209C000
初始值: 
    - 低电平: GPIO1_DR &= ~(1 << 18)
    - 高电平: GPIO1_DR |= (1 << 18)

三、汇编代码(start.s)

汇编代码用于搭建C语言环境。关于汇编代码,可以参考之前驱动LED的汇编代码:汇编代码解析

四、公共头文件(imx6u.h)

公共头文件保存了要用到的寄存器的基地址。

#ifndef _IMX6U_H
#define _IMX6U_H

typedef unsigned int uint32_t;

/*
 * 时钟相关寄存器地址
 */
#define CCM_CCGR0          *((volatile uint32_t*)0x20C4068)
#define CCM_CCGR1          *((volatile uint32_t*)0x20C406C)
#define CCM_CCGR2          *((volatile uint32_t*)0x20C4070)
#define CCM_CCGR3          *((volatile uint32_t*)0x20C4074)
#define CCM_CCGR4          *((volatile uint32_t*)0x20C4078)
#define CCM_CCGR5          *((volatile uint32_t*)0x20C407C)
#define CCM_CCGR6          *((volatile uint32_t*)0x20C4080)

/*
 * IOMUX 相关寄存器地址
 */
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03   *((volatile uint32_t*)0x020E0068)        // IO复用为 GPIO1_IO03
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03   *((volatile uint32_t*)0x020E02F4)        // 设置复用引脚的电气属性

#define IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B *((volatile uint32_t*)0x20E008C)          // IO 复用为 GPIO1_IO18
#define IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B *((volatile uint32_t*)0x20E0318)          // 设置复用引脚的电气属性

/*
 * 设置GPIO输出相关寄存器地址
 */
#define GPIO1_DR            *((volatile uint32_t*)0x0209C000)         // GPIO输出
#define GPIO1_GDIR          *((volatile uint32_t*)0x0209C004)         // 设置输入还是输出

#endif 

四、C 代码编写

为了验证开关,我们加入之前的 led 代码,之前的 led 代码已经被封装好了,直接调用函数即可。我们的目的是通过开关控制灯的亮灭。

1、clk 模块(bsp_clk.c)

void clk_init()
{
    CCM_CCGR0 = 0xffffffff;
    CCM_CCGR1 = 0xffffffff;
    CCM_CCGR2 = 0xffffffff;
    CCM_CCGR3 = 0xffffffff;
    CCM_CCGR4 = 0xffffffff;
    CCM_CCGR5 = 0xffffffff;
    CCM_CCGR6 = 0xffffffff;
}

2、led 模块(bsp_led.c)

void led_init()
{
    /* 1、设置IO复用为GPIO1_IO03 */
    IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 0x5;

    /* 2、初始化复用引脚,设置电气属性 */
    IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 = 0x10B0;

    /* 3、初始化GPIO1 */
    GPIO1_GDIR |= (1 << 3);
}

void led_on()
{
    GPIO1_DR &= ~(1 << 3);
}

void led_off()
{
    GPIO1_DR |= (1 << 3);
}

void switch_led(uint8_t status)
{
    if (status == ON)
    {
        led_on();
    }
    else
    {
        led_off();
    }
}

2、delay 模块(bsp_delay.c)

void delay_short(volatile unsigned int n)
{
	while(n--){}
}

void delay(volatile unsigned int n)
{
	while(n--)
	{
		delay_short(0x7ff);
	}
}

3、key 模块(bsp_key.c)

void key_init()
{
    /* 1、设置IO复用为GPIO1_IO03 */
    IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B = 0x5;

    /* 2、初始化复用引脚,设置电气属性 */
    IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B = 0xF080;

    /* 3、初始化GPIO1 */
    GPIO1_GDIR &= ~(1 << 18);
}

unsigned char read_key()
{
    unsigned char ret = 1;
    if (((GPIO1_DR >> 18) & 0x01) == 0)
    {
        delay(10);
        if (((GPIO1_DR >> 18) & 0x01) == 0)
        {
            ret = 0;
        }
    }
    return ret;
}

4、main.c

int main(void)
{
    clk_init();     // 初始化时钟
    led_init();     // 初始化LED
    key_init();     // 初始化按键
    led_on();       // LED 初始为亮

    unsigned char status = OFF;
    while (1)
    {
        if (read_key() == 0)
        {
            switch_led(status);
            status = ON;
        }
    }
    
    return 0;
}

 

五、链接脚本(imx6u.lds)

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

六、Makefile 文件(测试工程的整体结构)

测试工程的结构如下:

# ################################################################
# # 指定编译器、获取源文件、指定目标文件的生成位置
# ################################################################
# 编译器
TOOLCHAIN_PATH		:= /home/pigeon/workspace/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
CC					:= $(TOOLCHAIN_PATH)/arm-linux-gnueabihf-gcc
LD					:= $(TOOLCHAIN_PATH)/arm-linux-gnueabihf-ld
OBJCOPY				:= $(TOOLCHAIN_PATH)/arm-linux-gnueabihf-objcopy
OBJDUMP				:= $(TOOLCHAIN_PATH)/arm-linux-gnueabihf-objdump
 
# 目标文件名
TARGET_NAME		:= key
OBJ_DIR			:= obj

# 引入头文件
INCLUDES		:= -Icommon -Ibsp
 
# 获取到一级子目录下的源文件
DIR1			:= project
SOURCES 		+= $(wildcard ${DIR1}/*.c ${DIR1}/*.s)

# 获取到二级子目录下的源文件
DIR2 			:= bsp
SUBDIRS			= $(shell ls $(DIR2) -l | grep ^d | awk '{print	$$9}')
SOURCES			+= $(foreach subdir,${SUBDIRS}, $(wildcard $(DIR2)/${subdir}/*.c))

# 创建 $(OBJ_DIR) 目录
$(shell \
	if test -e $(OBJ_DIR); then \
		rm -rf $(OBJ_DIR)/*; \
	else \
		mkdir -p $(OBJ_DIR); \
fi)


# 生成 .o 文件
define compile
OBJ = $(if $(findstring .c,$1), $(patsubst %.c,%.o,$1), $(patsubst %.s,%.o,$1))
NODIR_OBJ = $$(notdir $$(OBJ))
$$(shell $$(CC) -o $$(OBJ_DIR)/$$(NODIR_OBJ) -c $1 $$(INCLUDES))
OBJ_FILE	+= $$(OBJ_DIR)/$$(NODIR_OBJ)
endef

OBJ_FILE		:= 
$(foreach src_file, ${SOURCES}, $(eval $(call compile, $(src_file))))	# 遍历每一个源文件,同时生成对应的 .o 文件

# ################################################################
# # 编译生成目标文件、库文件/执行文件
# ################################################################
default:
	$(LD) -Timx6u.lds -o $(OBJ_DIR)/$(TARGET_NAME).elf $(OBJ_FILE)
	$(OBJCOPY) -O binary -S -g $(OBJ_DIR)/$(TARGET_NAME).elf $(OBJ_DIR)/$(TARGET_NAME).bin
	$(OBJDUMP) -D $(OBJ_DIR)/$(TARGET_NAME).elf > $(OBJ_DIR)/$(TARGET_NAME).dis

# ################################################################
# # 伪目标/自定义函数
# ################################################################
.PHONY:clean
clean:
	rm -rf ${OBJ_DIR}/*

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

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

相关文章

【6.13 代随_56day】 两个字符串的删除操作、编辑距离

两个字符串的删除操作、编辑距离 两个字符串的删除操作1.方法图解步骤代码 编辑距离1.方法图解步骤代码 两个字符串的删除操作 力扣连接&#xff1a;583. 两个字符串的删除操作&#xff08;中等&#xff09; 1.方法 确定递推公式 当word1[i - 1] 与 word2[j - 1]相同的时候 …

STL之list

目录 list模拟实现一. list的基本框架二. list_node类1.构造函数2.其他函数 三. 迭代器&#xff08;iterator&#xff09;1.结构2. 构造函数3. 运算符重载operator-> 四.反向迭代器1.结构2.构造函数3.运算符重载 五. list常用方法及实现1. 默认构造函数a.empty_init 2.迭代器…

8. WebGPU 平移变换

我们将开始编写与顶点缓冲区文章中的示例类似的代码&#xff0c;但这次将绘制单个 F 而不是一堆圆&#xff0c;并使用索引缓冲区来保持数据更小。 让我们在像素空间而不是裁剪空间中工作&#xff0c;就像 Canvas 2D API 我们将制作一个 F&#xff0c;将从 6 个三角形构建它 …

啥?PCB拼版对SMT组装有影响!

PCB为什么要拼版&#xff1f; 拼版主要是为了满足生产的需求&#xff0c;有些PCB板太小&#xff0c;不满足做夹具的要求&#xff0c;所以需要拼在一起进行生产。 拼版也可以提高SMT贴片的焊接效率&#xff0c;如只需要过一次SMT&#xff0c;即可完成多块PCB的焊接。 同时也可…

你知道ai绘画工具都有哪些吗?ai画图的软件分享给你

大家好&#xff01;你有没有想过&#xff0c;如果我们能有一种神奇的工具&#xff0c;可以帮助我们实现想象中的绘画作品&#xff0c;该有多好呢&#xff1f;现在&#xff0c;随着人工智能的发展&#xff0c;我们可以借助ai绘画工具来探索艺术的奇妙世界了&#xff01;不过你是…

又双叕搞事?我拿着这份“满级”的JVM笔记,拼进了阿里

JVM JVM&#xff0c;一个熟悉又陌生的名词&#xff0c;从认识Java的第一天起&#xff0c;我们就会听到这个名字&#xff0c;在参加工作的前一两年&#xff0c;面试的时候还会经常被问到JDK&#xff0c;JRE&#xff0c;JVM这三者的区别。 JVM&#xff08;Java Virtual Machine…

汽车IVI中控开发中视频相关的一些知识点

前言: 视频最早的渊源来源于电视。做汽车仪表/IVI中控,尤其是IVI信息娱乐部分,都要涉及到视频这个知识点,各种概念很多,首先需要明确一条主线,那就是SDTV标清电视->HDTV高清电视->UHDTV超高清电视的一个发展脉络,BT601/656是SDTV标清电视接口,BT1120则对应HDTV高…

ShardingSphere

一、基本概念 1、什么是ShardingSphere 1、一套开源的分布式数据库中间件解决方案 2、有三个产品&#xff1a;Sharding-JDBC和Sharding-Proxy、Sharding-Sidecar 3、定位为关系型数据库中间件&#xff0c;合理在分布式环境下使用关系型数据库操作 2、分库分表 1什么是分库…

文物和古建筑防雷综合解决方案

文物和古建筑作为珍贵的历史遗产&#xff0c;需要受到专业的防雷保护&#xff0c;以保持其完整性和安全性。本文将介绍详细的文物和古建筑防雷方案和措施&#xff0c;包括避雷针安装、接地系统建设、监测技术和定期维护等。 引言&#xff1a; 文物和古建筑承载着珍贵的历史记忆…

防雷抗浪涌插排插座推荐,同为科技(TOWE)防雷桌面PDU安全可靠

同为科技TOWE双排防雷抗浪涌桌面PDU插座 随着夏天天气越来越热&#xff0c;强对流天气增多&#xff0c;雷雨天气频发。在雷电季节&#xff0c;通常影响家用电器安全的主要原因是由于雷电感应的侵入&#xff0c;特别是对绝缘强度低、过电压耐受力差的微电子产品影响甚大。而所谓…

JVM笔记(二)

JVM内存管理 在之前&#xff0c;我们了解了JVM的大致运作原理以及相关特性&#xff0c;这一章&#xff0c;我们首先会从内存管理说起。 在传统的C/C开发中&#xff0c;我们经常通过使用申请内存的方式来创建对象或是存放某些数据&#xff0c;但是这样也带来了一些额外的问题&…

一次XxlJob调度任务重复执行的问题排查

目录 东老师的问题1. 为什么会重复执行2. 为什么时间间隔改为1min就不会重复执行** 开始排查先看下任务配置 任务第一次执行排查执行类 》JobThreadJobThread的核心逻辑1.循环消费 一个阻塞队列 不断的去消费队列中TriggerParam 这个参数2.看下TriggerParam&#xff0c;这正是我…

硬件学习 软件 Cadence day10 查看网表导入进度,钻孔保护等一些操作

1. 查看网表导入状态。 2. 放置元器件 之前 画板框 3.放置元器件 4.把导入的DXF 文件变成板框 1.首先导入DXF文件 2. 点击按钮 3. 鼠标点击需要 调整为板框的地方 3.1 其中包括边框 3.2 固定的钻孔 5.给钻孔打上保护&#xff08;防止布线的时候区域错误&#xff0c;在固定的时…

12. AbstractQueuedSynchronizer之AQS

12.1 前置知识 ● 公平锁和非公平锁 ○ 公平锁&#xff1a;锁被释放以后&#xff0c;先申请的线程先得到锁。性能较差一些&#xff0c;因为公平锁为了保证时间上的绝对顺序&#xff0c;上下文切换更频繁 ○ 非公平锁&#xff1a;锁被释放以后&#xff0c;后申请的线程可能会先获…

第58讲:Python编程中最难以理解的递归函数核心概念以及应用案例

文章目录 1.递归函数的概念2.递归函数的使用2.1.案例一2.1.1.需求描述2.1.2.使用常规的循环来实现2.1.3.使用递归函数实现 2.2.案例二2.2.1.需求描述2.2.2.使用常规的循环来实现2.2.3.使用递归函数实现 3.使用递归函数计算阶乘3.1.阶乘的概念3.2.使用递归函数实现阶乘的算法3.3…

分布式Profinet IO模块

PROFINET IO模块是一种用于工业自动化控制系统中的设备控制模块。它使用以太网技术&#xff0c;在现场设备和处理器/控制器之间提供快速、精确和可靠的数据交换。PROFINET IO模块通常是面向过程的&#xff0c;可以用于监测和控制工业过程中的各种设备和参数&#xff0c;如传感器…

Vue中使用editor.md(2):添加拖拽图片上传功能

0. 背景 在对editor.md简单使用后&#xff0c;希望添加图片拖拽或粘贴上传的功能。 简单使用参考&#xff1a;Vue中使用editor.md&#xff08;1&#xff09;&#xff1a;简单使用 1. 实现 1.1 添加粘贴监听 // 使用axios import axios from /api/indexfunction initPasteDra…

什么是Vue的插件?如编写自定义 Plugin?

什么是Vue的插件&#xff1f; 在Vue开发中&#xff0c;我们经常需要使用一些第三方库或功能性模块&#xff0c;Vue插件就是一种将这些库或模块集成到Vue应用中的方式。插件是Vue.js提供的一种机制&#xff0c;用于扩展Vue的功能。插件通常用于封装某些特定的功能&#xff0c;例…

【AI人工智能】 你如果要使用最强大的语言模型,你还要有最精美的浏览器标签页iTab (2)

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

UnityA*导航算法,通俗易懂

首先A*寻路算法分为2D算法和3D算法&#xff0c;目前它甚至不如NAVMesh算法效率高。但NAVMesh不适用于2D&#xff0c;因此2D还是要靠A*算法来进行实现。 当前就来说说2D是如何实现的。 首先2DA*算法先要将地图划分成格子分块标记成二维数组 每个格子依据x&#xff0c;y&#xf…