【树莓派学习笔记】九、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 Address、Virtual Address
在树莓派中,借助ARM内部的MMU,CPU外设物理地址映射成了虚拟地址。
这里的 Virtual Address 和 Physical 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的偏移地址为0x00;GPSET0的偏移地址为0x1C;GPCLRn的偏移地址为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.tpcf.cn/news/400584.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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对…

Linux虚拟机安装应用程序提示Graphical installers are not supported by the vm

Linux安装应用程序提示Graphical installers are not supported by the vm 参考链接&#xff1a;http://www-01.ibm.com/support/docview.wss?uidswg21462180 Technote (troubleshooting) Problem(Abstract) Attempts to install IBM Security AppScan Source on Linux result…

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

最近&#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…

[转帖]鲍鹏山:我们培养了很多高学历的野蛮人

按&#xff1a;我的理解&#xff0c;鲍老师的讲演有下面五重意思&#xff1a; 1.集中精力研究有意义的问题&#xff0c;而不应该刻意掌握一些无实际意义的知识。“我之所以这么聪明&#xff0c;是因为我从来不在不必要的事情上浪费精力--尼采” 2.为了获得别人的羡慕钦佩去掌握…

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

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

粘贴复制Android复制和粘贴的实现

最近研究粘贴复制&#xff0c;稍微总结一下&#xff0c;以后继续补充&#xff1a; main.xml如下: <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:tools"http://schemas.android.com/tools"android:layout_width&quo…

【机器视觉学习笔记】生成高斯滤波器掩膜(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常量只…

1-1、article元素

示例一&#xff1a;  <article><header><h1>苹果</h1><p>发表日期&#xff1a;<time pubdate>2017/07/02</time></p></header><p><b>苹果</b>,植物类水果</p><footer><p><smal…

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

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

小坑

Ubuntu下安装WebStorm 转载于:https://www.cnblogs.com/zhanhg/p/4408650.html

通过Java代码打开浏览器,本地文件目录以及ftp站点

Desktop.getDesktop().browse(new URI(http://www.baidu.com/)); 调用本地默认浏览器打开网页 Desktop.getDesktop().browse(new File("D:\\all").toURI());打开该D:\\all所在文件目录 打开本地文件另一种方法: Desktop.getDesktop().open(new File("D:\\all&q…

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

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

(转)IOS中获取各种文件的目录路径的方法

iphone沙箱模型的有四个文件夹&#xff0c;分别是什么&#xff0c;永久数据存储一般放在什么位置&#xff0c;得到模拟器的路径的简单方式是什么.documents&#xff0c;tmp&#xff0c;app&#xff0c;Library。&#xff08;NSHomeDirectory()&#xff09;&#xff0c;手动保存…

MongoDB 空指针引用拒绝服务漏洞

漏洞版本: MongoDB 漏洞描述: Bugtraq ID:60252 CVE ID:CVE-2013-2132MongoDB是一个基于分布式文件存储的数据库。由C语言编写在解析非法DBref记录时MongoDB存在一个安全漏洞&#xff0c;允许远程攻击者利用漏洞触发一个空指针引用错误&#xff0c;可使应用程序崩溃 <* 参考…

【机器视觉学习笔记】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***** …