日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2023/12/9 编程问答 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【树莓派学习笔记】九、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編號

總結

以上是生活随笔為你收集整理的【树莓派学习笔记】九、C语言寄存器操作控制GPIO的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。