【树莓派学习笔记】九、C语言寄存器操作控制GPIO

目录

  • CPU型号确定
  • 寄存器的地址问题
  • GPIO寄存器
    • GPFESLn
    • GPSETn
    • GPCLRn
  • 重要函数
    • mmap函数
    • munmap函数
  • 点灯程序

平台:树莓派3B
版本: 2021-05-07-raspios-buster-armhf


CPU型号确定

pinout

命令可知,所用的板子Soc型号为BCM2837
在这里插入图片描述

寄存器的地址问题

本节内容修改自虚拟地址/物理地址——virtual address(memory)/physical address: 树莓派 mmap example —— 风竹夜
由于官方只公开了BCM2835的芯片手册(Raspberry Pi Documentation),而我们用的板子Soc为BCM2837,因此由手册得到的地址是不准确的。但两个芯片外设上区别不大,手册仍有一定的参考价值。
手册第5页描绘了BCM2835的地址映射情况
在这里插入图片描述
其中要区分文档中的三个地址,Bus Address、Physical AddressVirtual Address
在树莓派中,借助ARM内部的MMU,CPU外设物理地址映射成了虚拟地址。
这里的 Virtual AddressPhysical Address 是通过 ARM MMU 来实现映射的(先不管cache等其他因素)。主板上外设的实际地址是 Physical Address,所以要访问 GPIO 寄存器,也就是访问 Physical Address 中从 0x20000000 开始的某处的地址, 那么就需要在代码中访问 Virtual Address 中从 0xF2000000 开始的某处的地址,由于该虚拟地址在高地址内存,因此只能在内核的代码中才能够访问到。
在这里插入图片描述
而在树莓派3B中我们可以通过

sudo cat /proc/iomem

命令获取物理地址分配情况
在这里插入图片描述
由图可知,树莓派3B GPIO 的物理起始地址为0x3f200000

GPIO寄存器

从手册第89页开始详细地描述了GPIO外设。
在这里插入图片描述

第90-91页的表格标明了和GPIO相关的寄存器的地址。
其中GPFESLn(选择引脚功能)、GPSETn(设置引脚输出高电平)和GPCLRn(设置引脚输出低电平)是控制引脚输出电平需要用到的寄存器。
虽然树莓派3B的Soc换成了BCM2837,GPIO外设的基地址有变,但手册上的偏移地址还是有参考价值的。
其中GPFESL0的偏移地址为0x00GPSET0的偏移地址为0x1CGPCLRn的偏移地址为0x28
在这里插入图片描述在这里插入图片描述

GPFESLn

由手册知
GPFESL0控制GPIO Pin 0~9;
GPFESL1控制GPIO Pin 10~19;
GPFESL2控制GPIO Pin 20~29;
GPFESL3控制GPIO Pin 30~39;
GPFESL4控制GPIO Pin 40~49;
GPFESL5控制GPIO Pin 50~59;
3位为间隔,000 为输入,001为输出
在这里插入图片描述
在这里插入图片描述

GPSETn

由手册知
GPSET0控制GPIO pin 0~31
GPSET1控制GPIO pin 32~53
在这里插入图片描述

GPCLRn

由手册知
GPCLR0控制GPIO pin 0~31
GPCLR1控制GPIO pin 32~53
在这里插入图片描述

重要函数

mmap函数

mmap将一个文件或者其它对象映射进内存。mmap操作提供了一种机制,让用户程序直接访问设备内存,这种机制,相比较在用户空间和内核空间互相拷贝数据,效率更高。

void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
start:映射区的开始地址,设置为0时表示由系统决定映射区的起始地址。
length:映射区的长度。//长度单位是 以字节为单位,不足一内存页按一内存页处理。
prot:期望的内存保护标志,不能与文件的打开模式冲突。
PROT_EXEC //页内容可以被执行;
PROT_READ //页内容可以被读取;
PROT_WRITE //页可以被写入;
PROT_NONE //页不可访问
flags:指定映射对象的类型,映射选项和映射页是否可以共享。
fd:有效的文件描述词。一般是由open()函数返回。
offset:被映射对象内容的起点。
返回值:成功:被映射区的指针。失败:MAP_FAILED[其值为(void *)-1]。

munmap函数

munmap()用来取消参数start所指的映射内存起始地址

int munmap(void *start,size_t length);
start:映射区的开始地址
length:欲取消的内存大小
返回值:成功:0;失败:-1。

点灯程序

在合适的地方编写main.c文件

nano main.c
#include <stdio.h>
#include <sys/mman.h>   //mmap、munmap函数的定义
#include <fcntl.h>      //open函数的定义
#include <unistd.h>     //close函数的定义
#include <stdint.h>     //uint8_t、uint32_t等类型的定义
#include <unistd.h>     //sleep函数的定义#define GPIO_BASE_Physical_Address  0x3f200000#define GPFSEL0_Offs    0x00  
#define GPSET0_Offs     0x1C
#define GPCLR0_Offs     0x28 int main(int argc, char *argv[])
{int fd;uint8_t Pin = 3;fd = open("/dev/gpiomem", O_RDWR);if (fd == -1)   //只有root用户才能读取/dev/mem, 故本实验选择读取/dev/gpiomem,以实现普通用户控制GPIO{printf("open Error!\n");return -1;}void *GPIO_BASE = mmap(0, sysconf(_SC_PAGESIZE), PROT_READ | PROT_WRITE, MAP_SHARED , fd, GPIO_BASE_Physical_Address);close(fd);if(GPIO_BASE == MAP_FAILED){printf("mmap Error!\n");return -1;}volatile uint32_t * GPFSEL0 = (uint32_t *)(GPIO_BASE + GPFSEL0_Offs);volatile uint32_t * GPSET0 = (uint32_t *)(GPIO_BASE + GPSET0_Offs);volatile uint32_t * GPCLR0 = (uint32_t *)(GPIO_BASE + GPCLR0_Offs);*GPFSEL0 = (*GPFSEL0 & ~((uint32_t)7 << (3 * Pin))) | ((uint32_t)1) << (3 * Pin); //设置Pin 3为输出模式for(uint8_t i = 0; i < 10; ++i)             //反转Pin 3 i次{*GPCLR0 = ((uint32_t)1) << Pin;   sleep(1);*GPSET0 = ((uint32_t)1) << Pin;     sleep(1);}*GPFSEL0 = *GPFSEL0 & ~((uint32_t)7 << (3 * Pin));  //设置Pin 3为输入模式if(munmap(GPIO_BASE, sysconf(_SC_PAGESIZE)) == -1){printf("munmap Error!\n");return -1;}GPIO_BASE = MAP_FAILED;GPFSEL0 = MAP_FAILED;GPSET0 = MAP_FAILED;GPCLR0 = MAP_FAILED;return 0;
}

其中sysconf(_SC_PAGESIZE)为页的长度,相关知识见yaaangmin大佬的视频:深入理解计算机系统20:内存 - 多级页表、虚拟地址、物理地址

编写Makefile文件

nano Makefile

注意Makefile里的缩进为Tab而不是空格

main: main.ogcc -o main main.o
main.o: main.cgcc -c main.c
clean:rm *.orm main
clear:rm *.orm main

在这里插入图片描述
编译并测试

make
./main

可见Pin 3 脚所连LED闪烁(Pin 3脚已事先接好LED和限流电阻下拉至GND)

此编号对应

gpio readall

命令下的BCM编号
在这里插入图片描述

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

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

相关文章

bzoj2527

首先环可以变成链来处理&#xff0c;对于l>r的情况就是修改区间[1,r],[l,mx]然后不难想到整体二分&#xff0c;二分答案k,然后算1~k场流星雨对国家的贡献然后判定将国家划分变成子问题解决&#xff0c;没什么难的终于不是tle&#xff0c;poi良心了一把 1 type wayrecord2 …

第17章:图像分割提取

第17章&#xff1a;图像分割提取一、用分水岭算法实现图像分割提取&#xff1a;1. 算法原理&#xff1a;2. 相关函数介绍&#xff1a;(1) 形态学函数回顾&#xff1a;(2) 距离变换函数distanceTransform&#xff1a;(3) 确定未知区域&#xff1a;(4) 函数connectedComponents对…

[转]可伸缩系统的架构经验

最近&#xff0c;阅读了Will Larson的文章Introduction to Architecting System for Scale&#xff0c;感觉很有价值。作者分享了他在Yahoo!与Digg收获的设计可伸缩系统的架构经验。在我过往的架构经验中&#xff0c;由于主要参与开发企业软件系统&#xff0c;这种面向企业内部…

【Linux技巧】cmake、make命令多线程编译,大大提高编译速度

目录获取最大可用线程数自动以最大线程数编译makecmake效果系统&#xff1a;Debian 获取最大可用线程数 nprocnproc命令可返回当前可用的最大线程数 树莓派3B (BCM2837)&#xff1a;4 RK3399 Pro&#xff1a;6 自动以最大线程数编译 make sudo make -j $(nproc)cmake su…

redis学习(九)——数据持久化

一、概述 Redis的强大性能很大程度上都是因为所有数据都是存储在内存中的&#xff0c;然而当Redis重启后&#xff0c;所有存储在内存中的数据将会丢失&#xff0c;在很多情况下是无法容忍这样的事情的。所以&#xff0c;我们需要将内存中的数据持久化&#xff01;典型的需要持久…

【机器视觉学习笔记】生成高斯滤波器掩膜(C++)

目录原理二维高斯分布生成高斯掩膜&#xff08;小数形式&#xff09;源码及效果平台&#xff1a;Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 本文算法摘自高斯滤波(GaussianFilter)原理及C实现 —— 小武~~ 原理 高斯滤波和均值滤波一样&#xff0c;都是利用一个掩膜…

第18章:视频处理

第18章&#xff1a;视频处理一、VideoCapture类&#xff1a;1. VideoCapture类中相关方法介绍&#xff1a;(1) 初始化&#xff1a;(2) 初始化判断方法&#xff1a;(3) 捕获帧&#xff1a;(4) 释放&#xff1a;(5) 属性设置&#xff1a;(6) 捕获多摄像头(视频文件)数据&#xff…

C++的常量折叠(一)

前言 前几天女票问了我一个阿里的面试题&#xff0c;是有关C语言的const常量的&#xff0c;其实她一提出来我就知道考察的点了&#xff1a;肯定是const常量的内存不是分配在read-only的存储区的&#xff0c;const常量的内存分配区是很普通的栈或者全局区域。也就是说const常量只…

【机器视觉学习笔记】二值图像和灰度图像的膨胀、腐蚀、开运算、闭运算算法(C++)

目录二值图像原理腐蚀结构的原点设置在结构内部情况举例结构的原点设置在结构的外部情况举例膨胀结构的原点设置在结构的内部情况举例结构的原点设置在结构的外部情况举例开闭运算完整源码效果原图腐蚀运算膨胀运算开运算闭运算灰度图像原理腐蚀膨胀开闭运算完整源码效果原图腐…

【机器视觉学习笔记】二值图像连通区域提取算法(C++)

目录原理二值图像连通区域&#xff08;Connected Component&#xff09;连通区域分析&#xff08;Connected Component Analysis,Connected Component Labeling&#xff09;算法&#xff1a;Two-Pass&#xff08;两遍扫描法&#xff09;思路&#xff1a;Two-Pass算法的简单步骤…

【机器视觉学习笔记】Harris 角点检测算法(C++)

目录原理算法步骤优缺点源码效果原图输出平台&#xff1a;Windows 10 20H2 Visual Studio 2015 OpenCV 4.5.3 本文摘自2、Harris角点检测算法 —— 诺亚方舟369 原理 Harris算子是对Moravec算子的改进&#xff0c;包括&#xff1a; &#xff08;1&#xff09;Harris算子用…

剖析ASSERT函数

2019独角兽企业重金招聘Python工程师标准>>> &#xfeff;&#xfeff; 搜集与总结了assert函数的用法&#xff0c;记于此&#xff0c;以备后续与查找使用&#xff1a; ****身在Windows的世界&#xff0c;但还是深爱着我的它---Linux****I love Linux forever***** …

MSP430G2553 移植 Contiki RTOS 实时操作系统

目录新建工程移植过程关于时间多任务示例main.c内存使用情况效果平台&#xff1a;Code Composer Studio 10.4.0 MSP-EXP430G2 LaunchPad 试验板 MSP430G2553 LaunchPad™ Development Kit (MSP‑EXP430G2ET) contiki下载&#xff1a;contiki-os Github 本文参考自二、Contiki…

Raphael JS 矢量客户端开源框架

之前有基于svg进行矢量绘制&#xff0c;当时是自己写的一些js类库&#xff0c;最近项目中需要&#xff0c;对Raphael做了一些了解&#xff0c;总体不错。 Raphael可以对浏览器的兼容做的不错&#xff0c;基于IE的会自动使用vml进行绘制&#xff0c;其他浏览器基于svg进行绘制&a…

mac os x10.8下如何使用git与github

2019独角兽企业重金招聘Python工程师标准>>> 1、准备工作&#xff1a; 下载安装git客户端 http://code.google.com/p/git-osx-installer/downloads/list?can3(安装了git客户端&#xff0c;命令行中才有git命令) 注册github账号 https://github.com/ -->Pricing …

使用 VS 附加到进程 调试发布的网站

适用场景&#xff1a;调试已发布的网站。 1、把项目 bin 目录下的 pdb 文件复制到服务器上相应网站的 bin 目录下。 2、把VS的调试工具中的 x64 文件夹复制到服务器任意位置。 3、服务器中打开调试工具&#xff0c;并配置端口&#xff08;注意端口是否可用&#xff09;。 4、在…

Github git 命令下载加速

目录手动输入法批处理文件系统&#xff1a;Windows 10 20H2 手动输入法 在要下载到的目录按住shift右键 选择在此处打开Powershell窗口 如要下载的仓库地址&#xff1a; 通常的git命令下载&#xff1a; git clone https://github.com/apache/incubator-nuttx.gitCNPMJS.ORG…

MySql 自动更新时间为当前时间

字段类型 : timestamp默认值 : CURRENT_TIMESTAMP如果是创建时间&#xff0c;则下面的“根据当前时间戳更新”不勾选。转载于:https://blog.51cto.com/9625815/1630767

ZKP Mathematical Building Blocks (2)

MIT IAP 2023 Modern Zero Knowledge Cryptography课程笔记 Lecture 3: Mathematical Building Blocks (Yufei Zhao) Fiat Shamir heuristic Turn an interactive proof to a non-interactive proofP can simulate V whenever V picks a random valueP can simulate V’s ran…

【AVR ASF4库函数学习笔记】一、使用Microchip Studio图形化配置工程

目录新建工程配置点灯效果平台&#xff1a;Microchip Studio (原Atmel Studio 7) 欣世纪 DMAVR-L Atmega 128A - AU 新建工程 选择所用的芯片后点击CREATE NEW PROJECT创建工程 配置 设置CPU 根据所用晶振设置频率 点灯示例&#xff1a; D7由PE7控制&#xff0c;低电平点…