树莓派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驱动学习之hello world
最近想学习一下linux驱动,看了一些书和教学视频,大概了解了一下,不过要想深入,肯定需要实践.手上有几块linux的板子,最终选择了树莓派作为我的实验平台,资料比较丰富,接口也比较简单. 程序员的入 ...
- linux 驱动学习笔记01--Linux 内核的编译
由于用的学习材料是<linux设备驱动开发详解(第二版)>,所以linux驱动学习笔记大部分文字描述来自于这本书,学习笔记系列用于自己学习理解的一种查阅和复习方式. #make confi ...
- linux驱动学习(二) Makefile高级【转】
转自:http://blog.csdn.net/ghostyu/article/details/6866863 版权声明:本文为博主原创文章,未经博主允许不得转载. 在我前一篇写的[ linux驱动学 ...
- 超简单易用的 “在 pcduino 开发板上写 Linux 驱动控制板载 LED 的闪烁”
版权声明:本文为博主原创文章,未经博主同意不得转载.转载联系 QQ 30952589,加好友请注明来意. https://blog.csdn.net/sleks/article/details/251 ...
- Linux驱动开发之LED驱动
首先讲下字符设备控制技术 : 大部分驱动程序除了需要提供读写设备的能力外,还需要具备控制设备的能力.比如: 改变波特率. 在用户空间,使用ioctl系统调用来控制设备,原型如下:int ioctl(i ...
- Linux驱动学习之常用的模块操作命令
1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...
- Linux驱动学习之什么是驱动?
一.什么是驱动? 1: 驱动一词的字面意思 2: 物理上的驱动 3: 硬件中的驱动 4: linux内核驱动.软件层面上的驱动广义上是指:这一段代码操作了硬件去动,所以这一段代码就叫硬件的驱动程序. ...
- Linux驱动学习步骤(转载)
1. 学会写简单的makefile 2. 编一应用程序,可以用makefile跑起来 3. 学会写驱动的makefile 4. 写一简单char驱动,makefile编译通过,可以insmod, ls ...
- linux驱动学习之Input输入子系统
以前,看过国嵌关于input子系统的视频课程,说实话,我看完后脑子里很乱,给我的印象好像是input子系统驱动是一个全新的驱动架构,疑惑相当多.前几天在网上,看到有很多人介绍韦东山老师的linux驱动 ...
随机推荐
- Android中Sqlite数据库进行增删改查
今天这篇文章写Sqlite数据库,通过一个小案例来完整讲一下数据库常见的CRUD操作. 先对知识点总结: SQLite数据库 轻量级关系型数据库 创建数据库需要使用的api:SQLiteOpenHel ...
- Android简易实战教程--第四十四话《ScrollView和HorizontalScrollView简单使用》
一.ScrollView 由于手机屏幕的高度有限,当普通布局放不下现实和的内容时,ScrollView视图(滚动视图)就会派上用场,因为数据可以往下滚动显示. 二.HorizontalScrollVi ...
- RxJava(二) map操作符用法详解
欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/51531348 本文出自:[余志强的博客] 1 map操作符的作用 R ...
- CSDN 支持Markdown写文章了!
开源中国等其他技术博客很早就支持markdown格式写文章了,今天发现csdn竟然也可以了,不仅支持而且可以在线预览,本地导入导出,远程导入. 这些对于程序员写东西都非常好用,不用总是花时间来排版了. ...
- 在自己笔记本电脑上如何访问虚拟机的内容、包括可以使用ssh、访问tomcat、访问nginx
1.给自己的电脑设置一个回环网卡,关于如何配置回环网卡,可以百度搜索一下 设置好后的状态如下: 并把回环网卡的ipv4的值设置成192.168.1.1 配置如下: 2.将vmware中的"虚 ...
- Java多线程模型
谈到Java多线程就涉及到多线程的模型及Java线程与底层操作系统之间的关系.正如我们熟知,现代机器可以分为硬件和软件两大块,如图2-5-1-1,硬件是基础,软件提供实现不同功能的手段.而且软件可以分 ...
- Dynamics CRM2013 停用默认公共视图
CRM视图中一般只会有一个默认公共视图,如果你不想用已有的默认视图只需新建个视图再指定默认,然后将原有视图停用即可,但我碰到了个另类的问题,即在一个实体下同时存在两个默认视图而且无法停用. 如下图中的 ...
- jvm java虚拟机 新生代的配置
1.1.1.1. -Xmn参数 参数-Xmn1m可以用于设置新生代的大小.设置一个较大的新生代会影响老生代的大小,因为这两者的总和是一定的,这个系统参数对于系统性能以及GC行为有很大的影响,新生代一般 ...
- Android对话框AlertDialog-android学习之旅(四十二)
对话框简介 android提供了丰富的对话框支持,支持四种如下的对话框. AlertDialog简介 介绍上面六个方法的代码示例 setMessage() <?xml version=" ...
- 2015-2016机器人操作系统(ROS)及其应用暑期学校资料汇总 ROS Summer School 持续更新
综合信息:2015 2016 课程资料:2015 2016 其他重要机器人.ROS相关学习活动 知乎关于ROS的话题 1 ROS的开发流程?http://www.zhihu.com/qu ...