IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> 树莓派控制 LED(命令行直接操作寄存器) -> 正文阅读

[系统运维]树莓派控制 LED(命令行直接操作寄存器)

想法

之前在单片机上写过很多控制 GPIO 的代码,代码比较简单,也很好理解。同样的事情到了嵌入式 Linux 上似乎变得复杂了很多。这很不符合我的预期,我认为事物应该照着简单的方向发展(俗话说,高端的食材往往采用最朴素的烹饪方法。。咳咳。。扯远了)。不过我知道,嵌入式 Linux 是为了分层、复用、扩展性强、便于移植等方面才将 LED 的驱动和应用做成了那个(diao)样子。目前我没能感受到它的强大之处,说明我的等级还不够,还需要猥琐发育,我也期待能快点悟到嵌入式 Linux 驱动的真谛。不过,单片机出身的我,还是更迫切地想知道如何才能最简单、最直接地控制 LED,先有一个简单的实现方法,再向复杂的驱动靠拢,一步步去感悟驱动的美妙。

在 51 单片机上控制一个引脚输出高低电平非常简单,只需要给相应的寄存器赋值 0 或 1 就可以了,如下

#include <reg52.h>

sbit IN=P3^0;
sbit OUT=P1^0;

void main (void)
{
	while (1)
	{
		if(IN==0)
			OUT=0;
		else
			OUT=1;
	 }
}

在 STM32 上稍微复杂点,需要配置引脚的模式(通用、复用,输入、输出,上拉、下拉),还需要配置时钟线,不过也就这几个步骤,也都看得懂,说白了就是配置几个寄存器。那么,嵌入式 Linux 不管设计得多复杂,控制 GPIO 最终应该也就是配置几个寄存器而已,所以,我就想着在嵌入式 Linux 系统中直接操作寄存器来控制 GPIO 输出高低电平,最终还真被我实现了,下面我就讲一讲我实现的思路

devmem

思路很简单:找到读写寄存器的方法、确定 GPIO 的寄存器地址、将值写入寄存器。

首先要去查嵌入式 Linux 中有没有什么命令或方法能够直接读写寄存器,找到了 devmem 这个命令,用法是这样的

# devmem
BusyBox v1.33.0 (2021-11-28 00:41:57 CST) multi-call binary.

Usage: devmem ADDRESS [WIDTH [VALUE]]

Read/write from physical address

        ADDRESS Address to act upon
        WIDTH   Width (8/16/...)
        VALUE   Data to be written

例:devmem 0x12345678 就能读出地址为 0x12345678 的寄存器中的数据。并且,看到 devmem 是 busybox 中的程序,所以后面可以阅读 busybox 源码进一步探索该命令原理。

寄存器地址

接下来就要查找控制 GPIO 需要配置哪些寄存器,这就需要阅读芯片的数据手册了。我使用的是树莓派 3B+,主芯片是 BCM2837,由于没找到 BCM2837 的 DataSheet,只找到了 BCM2835 的,不过问题不大,大体一样,不一样的地方在网上查查资料也可以知道,后面我也会提到。

首先,选定要控制的引脚,这里我选择控制 Header 的 7 引脚,对应 BCM 的 4 pin 脚。
在这里插入图片描述
控制这个引脚需要操作三个寄存器:GPFSLn(GPIO Function Select Registers,GPIO 功能选择寄存器)、GPSETn(GPIO Pin Output Set Registers,输出设置寄存器)、GPCLRn(GPIO Pin Output Clear Registers,输出清除寄存器)。再结合引脚 4,可得上述三个寄存器的地址分别为:0x7E200000(功能选择寄存器)、0x7E20001C(输出设置寄存器)、0x7E200028(输出清除寄存器)。

不过,这三个地址为总线地址,而 devmen 访问的是物理地址,所以我们需要知道这两个地址的映射(换算)关系,看下图
在这里插入图片描述
从图中可知,I/O 外设的总线起始地址为 0x7E000000,对应的物理地址为 0x3F000000(上图是 BCM2835 芯片的映射关系,我们用的是 BCM2837,所以对图片做了一点修正)。同理可得,刚才的三个寄存器映射到物理地址分别为:0x3F200000、0x3F20001C、0x3F200028。

读取

下面我们就来读取一下这三个地址中的值

# devmem 0x3f200000
0x00000000
# devmem 0x3f20001C
0x6770696F
# devmem 0x3f200028
0x6770696F

进一步的,功能选择寄存器是每个 GPIO 用 3 bits 来表示,从 000-111 分别代表 8 个不同的功能,我们用的是 4 引脚,对应 14-12bit,所以我们只需要读取 0x3f200000 寄存器的低 16bits 就可以了,可以使用下面这个命令

# devmem 0x3f200000 16
0x0000

请添加图片描述
输出设置寄存器和输出清除寄存器,每一引脚对应 1 位,我们只要关心 bit4 就可以了,也就是说我们只需要读写 1 字节就行了,

命令如下:

# devmem 0x3f20001C 8
0x6F
# devmem 0x3f200028 8
0x6F

请添加图片描述

设置

一切准备就绪,那我们就开始设置,看能不能点亮 LED

先将 4 脚配置成输出模式(14-12bit 的值为 001),命令如下:

# devmem 0x3f200000 16 0x1000

刚下完命令,LED 就亮了(因为 LED 负极接在了 4 引脚上,且引脚默认输出低电平),见下图
请添加图片描述
设置 4 引脚为高电平

# devmem 0x3f20001C 8
0x6F
# devmem 0x3f20001C 8 0x7F

LED 就灭了,见下图
请添加图片描述
再次设置 4 引脚为低电平

# devmem 0x3f200028 8
0x6F
# devmem 0x3f200028 8 0x7F

LED 又亮了

成功!

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2021-12-02 17:10:50  更:2021-12-02 17:11:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 2:16:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码