树莓派linux驱动学习之LED控制
前面我们编写了hello world的程序,接下来继续研究GPIO功能,通过GPIO来控制LED的亮灭,这在单片机中应该算是十分简单的一个程序了,但是在Linux系统中控制GPIO没有那么简单,难点就在于GPIO地址的获取,也是我一直在纠结的问题。
一、GPIO地址
二、硬件平台
三、编写驱动代码
- #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");
硬件相关操作:
- #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;
- }
应用测试程序:
- #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控制相关推荐
- linux uart寄存器 代替 printk,Linux驱动学习之设备树(设备树下的LED驱动实验),...
Linux驱动学习之设备树(设备树下的LED驱动实验), 概念 Linux内核从3.x开始引入设备树的概念,用于实现驱动代码与设备信息相分离.相当于从驱动代码分离出来的配置文件,比如串口的波特率通过设 ...
- Linux驱动学习--USB接口wifi/BT芯片开发之BT开发(BlueDroid框架)
目录 一.引言 二.整体框架分析(结合实际芯片分析) 三.内核中的相关配置 四.厂家驱动分析 五.蓝牙BlueDroid协议 一.引言 之前我们简单分析过BlueDroid框架,今天来结合源码,挑重点 ...
- IMX6ULL嵌入式Linux驱动学习笔记(二)
IMX6ULL嵌入式Linux驱动学习 一.字符设备驱动 二.驱动模块的加载与卸载 三.字符设备的注册与注销 四.设备号 五.file_operations的具体实现 六.字符设备驱动框架 七.编写应 ...
- Linux 驱动学习笔记 - beep(九)
Linux 驱动学习笔记 - beep(九) 本系列均为正点原子 Linux 驱动的学习笔记, 以便加深笔者记忆.如读者想进一步学习,可以到正点原子官网中下载资料进行学习. 添加 pinctrl 节点 ...
- 讯为4412开发板Linux驱动学习笔记
驱动理论专题一 Linux驱动程序的基本认识 有了内存管理单元,就有虚拟地址,物理地址. 驱动理论专题二 学会查看原理图 以LED2为示例 通过原理图查看到KP_COL0,赋予高电平则能点亮LED2, ...
- Linux驱动学习笔记
驱动学习笔记 1.字符设备驱动 Linux 驱动有两种运行方式 第一种就是将驱动编译进 Linux 内核中,这样当 Linux 内核启 动的时候就会自动运行驱动程序. 第二种就是将驱动编译成模块(Li ...
- (学习)linux驱动学习知识积累(一)
一.基础知识扫盲 1.dev_t结构体 在内核中,dev_t结构体用来保存设备编号信息,在linux/type.h中定义,是一个32位的数,12位表示主设备号+20位的次设备号 int MAJOR(d ...
- Linux驱动学习之什么是驱动?
一.什么是驱动? 1: 驱动一词的字面意思 2: 物理上的驱动 3: 硬件中的驱动 4: linux内核驱动.软件层面上的驱动广义上是指:这一段代码操作了硬件去动,所以这一段代码就叫硬件的驱动程序. ...
- Linux驱动学习(一):什么是Linux驱动
文章目录 前言 一.设备驱动简介 二.模块的编译和加载 总结 前言 一.设备驱动简介 驱动程序在 Linux 内核里扮演着特殊的角色. 它们是截然不同的"黑盒子", 使硬件的特殊的 ...
最新文章
- 使用git上传代码到github
- 文献记录(part91)--A boundary method for outlier detection based on support vector domain description
- mysql cookbook
- Qt 第二章 创建对话框--快速设计对话框(2)
- C语言 找出任意两整数之间的素数以及他们的和
- excel删除行 uipath_工作再忙,也要学会这10个最经典的Excel小技巧
- 1个app的完整测试用例_同你分享1个完整的聚类分析案例
- 互联网日报 | 8月3日 星期二 | 陌陌宣布更名为“Hello”集团;国家电网升至世界500强第二位;比亚迪总市值超8300亿...
- mysql正则mybatis中用法_SQL正则表达式及mybatis中使用正则表达式
- 微信僵尸粉删除工具 WeTool v4.0.7.0 免费版
- 【Week 8 作业 B】猫猫向前冲
- 详解 ARM PMU (Performance Monitoring Unit)
- openresty ngx_lua重定向
- 远程粒子计数器助力药企环境监测 为洁净卫生护航
- Andorid微信刷脸支付使用过程解析
- go语言学习-- chan与goroutine
- 可以测试流放之路伤害的软件,测试平台及细节一览 - 《流放之路》国服硬件需求测试:低配也能续写ARPG传奇 - 超能网...
- CVE-2020-14364:QEMU USB模块越界读写漏洞通告
- Mac回收站清空还能恢复吗?2个方法快速找回废纸篓清空文件
- 省级面板数据(2000-2019)八:人民生活篇(城乡人均收入、支出、耐消品、住房)(stata版)
热门文章
- 【Android 事件分发】ItemTouchHelper 源码分析 ( OnItemTouchListener 事件监听器源码分析 )
- 【嵌入式开发】ARM 芯片简介 (ARM芯片类型 | ARM处理器工作模式 | ARM 寄存器 | ARM 寻址)
- issubclass和isinstance 反射 内置方法(魔术方法)
- Autodesk布道GIS新理念
- Java(CS)请求分流
- windows下定时利用bat脚本实现ftp上传和下载
- statspack系列8
- ThinkPad E440 加内存后导致开不了机
- UpdatePanel 后台注册脚本失效
- MySQL数据导入oracle