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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

树莓派linux驱动学习之LED控制

發布時間:2025/6/15 linux 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 树莓派linux驱动学习之LED控制 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? 前面我們編寫了hello world的程序,接下來繼續研究GPIO功能,通過GPIO來控制LED的亮滅,這在單片機中應該算是十分簡單的一個程序了,但是在Linux系統中控制GPIO沒有那么簡單,難點就在于GPIO地址的獲取,也是我一直在糾結的問題。

一、GPIO地址

? ? ? ? 我看了中嵌的嵌入式開發視頻,里面使用三星2440控制LED的亮滅,但是驅動程序中沒有寫清楚具體的底層是如何實現的,這也是我查找的重點。我首先翻閱了樹莓派CPU(bcm2835)的芯片手冊,查到了GPIO的物理地址:
? ? ? ? 但是在芯片資料的最開始,有提到芯片內部已經把上圖中的物理總線地址抽象到了面對操作系統的物理地址:

? ? ? ? 所以,我們在編寫驅動程序的時候,IO空間的起始地址是0x20000000,加上GPIO的偏移量2000000,所以GPIO的物理地址應該是從0x20200000開始的,然后在這個基礎上進行Linux系統的MMU內存虛擬化管理,銀蛇到虛擬地址上。

二、硬件平臺

? ? ? ? 我在樹莓派的擴展口的GPIO 17上接上了一個LED:

三、編寫驅動代碼

? ? ? ? 一般的設備驅動我們需要設置主設備號和次設備號,在編寫應用程序的時候還要生成設備文件,比較麻煩。Linux針對像LED這樣的操作,有一種設備叫做混雜設備:是一種特殊的字符設備,雜設備早已經存在,是為了給開發者一個較為簡單的操作方式,因為不用再重新申請一個設備號了(misc就是混雜設備的意思)。 ? ? ? ? 驅動代碼: [cpp]?view plaincopy
  • #include?<linux/miscdevice.h>??
  • #include?<linux/delay.h>??
  • #include?<asm/irq.h>??
  • #include?<linux/kernel.h>??
  • #include?<linux/module.h>??
  • #include?<linux/init.h>??
  • #include?<linux/mm.h>??
  • #include?<linux/fs.h>??
  • #include?<linux/types.h>??
  • #include?<linux/delay.h>??
  • #include?<linux/moduleparam.h>??
  • #include?<linux/slab.h>??
  • #include?<linux/errno.h>??
  • #include?<linux/ioctl.h>??
  • #include?<linux/cdev.h>??
  • #include?<linux/string.h>??
  • #include?<linux/list.h>??
  • #include?<linux/pci.h>??
  • #include?<asm/uaccess.h>??
  • #include?<asm/atomic.h>??
  • #include?<asm/unistd.h>??
  • #include?<asm/io.h>??
  • #include?<asm/uaccess.h>??
  • #include?<linux/ioport.h>??
  • ??
  • #include?"bcm2835.h"??
  • ??
  • //?Blinks?on?RPi?Plug?P1?pin?11?(which?is?GPIO?pin?17)??
  • #define?PIN?RPI_GPIO_P1_11??
  • ??
  • int?open_state?=?0;?????????//文件打開狀態??
  • ??
  • static?int?leds_open(struct?inode?*inode,?struct?file?*filp)??
  • {??
  • ????if(open_state?==?0)????
  • ????{????
  • ????????open_state?=??1;????
  • ????????printk("Open?file?suc!\n");????
  • ????????return?0;????
  • ????}????
  • ????else????
  • ????{????
  • ????????printk("The?file?has?opened!\n");????
  • ????????return?-1;????
  • ????}????
  • }??
  • ??
  • static?int?leds_ioctl(struct?file*filp,?unsigned?int?cmd,?unsigned?long?arg)??
  • {??
  • ????switch(cmd)????
  • ????{????
  • ????????case?0:????
  • ????????????bcm2835_gpio_clr(PIN);??
  • ????????????printk("LED?OFF!\n");??
  • ????????????break;????
  • ????????case?1:????
  • ????????????bcm2835_gpio_set(PIN);??
  • ????????????printk("LED?ON!\n");??
  • ????????????break;????
  • ??
  • ????????default:????
  • ????????????return-EINVAL;????
  • ????}????
  • ??
  • ????return?0;??
  • }??
  • ??
  • static?int?leds_release(struct?inode?*inode,?struct?file?*filp)??
  • {??
  • ????if(open_state?==?1)????
  • ????{????
  • ????????open_state?=??0;????
  • ????????printk("close?file?suc!\n");????
  • ????????return?0;????
  • ????}????
  • ????else????
  • ????{????
  • ????????printk("The?file?has?closed!\n");????
  • ????????return?-1;????
  • ????}????
  • }??
  • ??
  • static?const?struct?file_operations?leds_fops?=?{??
  • ????.owner?=?THIS_MODULE,??
  • ????.open?=?leds_open,??
  • ????.unlocked_ioctl?=?leds_ioctl,??
  • ????.release?=?leds_release,??
  • };??
  • ??
  • static?struct?miscdevice?misc?=?{??
  • ????.minor?=MISC_DYNAMIC_MINOR,??
  • ????.name?="my_leds",??
  • ????.fops?=&leds_fops,??
  • };??
  • ??
  • ??
  • static?int?__init?leds_init(void)??
  • {??
  • ????int?ret;??
  • ??
  • ????//注冊混雜設備??
  • ????ret?=misc_register(&misc);??
  • ??
  • ????//配置功能選擇寄存器為輸出??
  • ????bcm2835_gpio_fsel(PIN,?BCM2835_GPIO_FSEL_OUTP);??
  • ??
  • ????//設置輸出電平為高電平,LED亮??
  • ????bcm2835_gpio_set(PIN);??
  • ??
  • ????printk("ledsinit.\n");??
  • ????return?ret;??
  • }??
  • ??
  • static?void?leds_exit(void)??
  • {??
  • ????//LED滅??
  • ????bcm2835_gpio_clr(PIN);??
  • ??
  • ????misc_deregister(&misc);??????????
  • ??
  • ????printk("leds_exit\n");??
  • }??
  • ??
  • module_init(leds_init);??
  • module_exit(leds_exit);??
  • ??
  • MODULE_AUTHOR("Hu?Chunxu");??
  • MODULE_LICENSE("GPL");??
  • ? ? 硬件相關操作: [cpp]?view plaincopy
  • #include?<linux/miscdevice.h>??
  • #include?<linux/delay.h>??
  • #include?<asm/irq.h>??
  • #include?<linux/kernel.h>??
  • #include?<linux/module.h>??
  • #include?<linux/init.h>??
  • #include?<linux/mm.h>??
  • #include?<linux/fs.h>??
  • #include?<linux/types.h>??
  • #include?<linux/delay.h>??
  • #include?<linux/moduleparam.h>??
  • #include?<linux/slab.h>??
  • #include?<linux/errno.h>??
  • #include?<linux/ioctl.h>??
  • #include?<linux/cdev.h>??
  • #include?<linux/string.h>??
  • #include?<linux/list.h>??
  • #include?<linux/pci.h>??
  • #include?<asm/uaccess.h>??
  • #include?<asm/atomic.h>??
  • #include?<asm/unistd.h>??
  • #include?<asm/io.h>??
  • #include?<asm/uaccess.h>??
  • #include?<linux/ioport.h>??
  • ??
  • #include?"bcm2835.h"??
  • ??
  • int?bcm2835_gpio_fsel(uint8_t?pin,?uint8_t?mode)??
  • {??
  • ????//初始化GPIOB功能選擇寄存器的物理地址??
  • ????volatile?uint32_t?*?bcm2835_gpio?=?(volatile?uint32_t?*)ioremap(BCM2835_GPIO_BASE,?16);??
  • ????volatile?uint32_t?*?bcm2835_gpio_fsel?=?bcm2835_gpio?+?BCM2835_GPFSEL0/4?+?(pin/10);??
  • ????uint8_t???shift?=?(pin?%?10)?*?3;??
  • ????uint32_t??value?=?mode?<<?shift;??
  • ????*bcm2835_gpio_fsel?=?*bcm2835_gpio_fsel?|?value;??
  • ??
  • ????printk("fsel?address:?0x%lx?:?%x\n",?bcm2835_gpio_fsel,?*bcm2835_gpio_fsel);??
  • ??
  • ????return?0;??
  • }??
  • ??
  • int?bcm2835_gpio_set(uint8_t?pin)??
  • {??
  • ????//GPIO輸出功能物理地址??
  • ????volatile?uint32_t?*?bcm2835_gpio?=?(volatile?uint32_t?*)ioremap(BCM2835_GPIO_BASE,?16);??
  • ????volatile?uint32_t?*?bcm2835_gpio_set?=?bcm2835_gpio?+?BCM2835_GPSET0/4?+?pin/32;??
  • ????uint8_t???shift?=?pin?%?32;??
  • ????uint32_t??value?=?1?<<?shift;??
  • ????*bcm2835_gpio_set?=?*bcm2835_gpio_set?|?value;??
  • ??
  • ????printk("set?address:??0x%lx?:?%x\n",?bcm2835_gpio_set,?*bcm2835_gpio_set);??
  • ??
  • ????return?0;??
  • }??
  • ??
  • int?bcm2835_gpio_clr(uint8_t?pin)??
  • {??
  • ???//GPIO清除功能物理地址??
  • ????volatile?uint32_t?*?bcm2835_gpio?=?(volatile?uint32_t?*)ioremap(BCM2835_GPIO_BASE,?16);??
  • ????volatile?uint32_t?*?bcm2835_gpio_clr?=?bcm2835_gpio?+?BCM2835_GPCLR0/4?+?pin/32;??
  • ????uint8_t???shift?=?pin?%?32;??
  • ????uint32_t??value?=?1?<<?shift;??
  • ????*bcm2835_gpio_clr?=?*bcm2835_gpio_clr?|?value;??
  • ??????
  • ????printk("clr?address:??0x%lx?:?%x\n",?bcm2835_gpio_clr,?*bcm2835_gpio_clr);??
  • ??
  • ????return?0;??
  • }??

  • ? ? ? ? 應用測試程序: [cpp]?view plaincopy
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • #include?<unistd.h>??
  • #include?<sys/ioctl.h>??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????int?on;??
  • ????int?fd;??
  • ????if?(argc?!=?2?||?sscanf(argv[1],"%d",?&on)?!=?1?||on?<?0?||?on?>?1?)?{??
  • ????????fprintf(stderr,?"Usage:%s?0|1\n",argv[0]);??
  • ????????exit(1);??
  • ????}??
  • ????fd?=?open("/dev/my_leds",?0);??
  • ????if?(fd?<?0)?{??
  • ????????perror("open?device?leds");??
  • ????????exit(1);??
  • ????}??
  • ????/*通過ioctl來控制燈的亮、滅*/??
  • ????if(on){??
  • ????????printf("turn?on?leds!\n");??
  • ????????ioctl(fd,?1);??
  • ????}??
  • ????else?{??
  • ????????printf("turn?off?leds!\n");??
  • ????????ioctl(fd,?0);??
  • ????}??
  • ????close(fd);??
  • ????return?0;??
  • }??

  • ? ? ? 分別編譯,插入模塊,然后運行測試程序,可以控制LED的亮滅了。

    ----------------------------------------------------------------

    歡迎大家轉載我的文章。

    總結

    以上是生活随笔為你收集整理的树莓派linux驱动学习之LED控制的全部內容,希望文章能夠幫你解決所遇到的問題。

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