嵌入式linux led驱动有几种写法,嵌入式Linux字符驱动LED灯设计
一.任务要求
完成一个字符IO口驱动,在开发板上该IO口对应LED灯。该驱动程序通过控制IO口的高低电平来控制亮灭。同时要写一个应用层的测试程序,用来测试驱动程序。我的测试程序为myled_test.c,要求在shell下能够通过该测试程序来控制LED灯的亮灭。如:
./myled_test
on 表示灯全亮;
./myled_test
off 表示灯全灭;
二.流程图设计
图1.应用层访问设备的流程图
三. 字符IO口驱动程序的设计流程
1)Linux内核的模块机制
在Linux下,驱动程序都是以模块存在的,模块是向内核动态的增加功能,每个模块都包括module_init和module_exit两个函数,分别在向系统插入模块和移除模块时被调用。框架如下:
#include
#include
static int
hellomodule_init(void)
{
printk("hello word\n");
return
0;
}
static void
hellomodule_exit(void)
{
printk("goodbye word\n");
return;
}
module_init(hellomodule_init);
module_exit(hellomodule_exit);
MODULE_LICENSE("GPL");
2)Linux字符IO驱动设计
步骤如下:
1.定义描述字符IO设备的结构体
在Linux中,每个设备都有一个结构体来描述的,该结构体包含了该设备的所有信息。如下:
struct cdev
{
struct
kobject kobj;
struct module
*owner;
const struct
file_operations *ops;
struct
list_head list;
dev_t
dev;
unsigned int
count;
};
2.定义设备结构体变量
用设备结构体来定义一个变量,在内核中该变量就代表对应的设备。如下:
struct cdev
myled_cdev;
3.定义设备的操作接口函数
设备都是有一些操作的,应用程序就通过这些接口操作函数来使用驱动程序对设备的控制。如下:
static struct
file_operations led_ops={
.open =
myled_open,
.ioctl =
myled_ioctl,
.release =
myled_close,
};
4.设备的操作函数
根据设备的操作接口函数完成操作函数,如下:
int
myled_open(struct inode *inode,struct file *file)
{
int value =
0;
value =
(1<<10)|(1<<12)|(1<<16)|(1<<20);
writel(value,S3C2410_GPBCON);
value = 0x0;
writel(value,S3C2410_GPBUP);
value =
0xfffffffe;
writel(value,S3C2410_GPBDAT);
return 0;
}
int
myled_ioctl(struct inode *inode,struct file *file,unsigned int
cmd,unsigned long arg)
{
switch(cmd)
{
case
LED_ON:
writel(0x0,S3C2410_GPBDAT);
break;
case
LED_OFF:
writel(0xfffffffe,S3C2410_GPBDAT);
break;
default:
break;
}
return 0;
}
int
myled_close(struct inode *inode,struct file *file)
{
printk("bye");
return 0;
}
5.字符驱动模块的初始化和退出函数
这两个函数是模块的框架,定义如下:
static int __init
LED_INIT(void)
{
int re = 0;
int ret = 0;
myled_no =
MKDEV(MAINLEDNO,MINLEDNO);
ret =
register_chrdev_region(myled_no,1,"myled");
if(ret<0)
{
printk("cant
regist");
return
ret;
}
printk("reg
ok");
cdev_init(&myled_cdev,&led_ops);
myled_cdev.owner =
THIS_MODULE;
re =
cdev_add(&myled_cdev,myled_no,1);
if(re<0)
{
printk("add
error");
return
re;
}
printk("add
ok");
return 0;
}
static void __exit
LED_EXIT(void)
{
cdev_del(&myled_cdev);
unregister_chrdev_region(myled_no,1);
printk("exit
ok");
}
和unregister_chrdev_region> 。
最后向内核申明myled_init和myled_exit函数以及LICENSE。如下:
module_init(LED_INIT);
module_exit(LED_EXIT);
MODULE_LICENSE("GPL");
6.设备驱动的编译
Linux驱动模块的编译是通过Linux顶层下的Makefile文件来实现的,如下:
obj-m:=myled.o
KDIR=/home/neo/linux-2.6.30.9-EL-20101126
all:
make -C $(KDIR)
SUBDIRS=$(shell pwd) modules
arm-linux-gcc -o
myled_test myled_test.c
四. 字符IO驱动测试程序设计流程
为了测试IO驱动是否正常,在应用层编写一个LED灯的程序,主要完成打开,关闭功能。如下:
int main(int
argc,char **argv)
{
int
fd;
fd =
open("/dev/ledS0",0);
if(!strcmp(argv[1],"on"))
{
ioctl(fd,LED_ON);
}
else
if(!strcmp(argv[1],"off"))
{
ioctl(fd,LED_OFF);
}
return 0;
}
五. 编译及下载流程
1.动态加载
a) 将myled.c和myled_test.c用make进行编译,得到模块myled.ko和执行文件myled_test
b) 更新S3C2440的内核和文件系统。启动开发板的LINUX系统。
c) 往开发板内核中添加驱动模块
在shell下执行insmod
myled.ko
d) 创建设备文件节点
在shell下执行mknod
/dev/ledS0 c 108 0
108:主设备号
0:次设备号>
e) 将执行文件myled_test添加到开发板上,并执行:
./myled_test
on
./myled_test
off
2.静态加载
a) 打开内核源码文件包,将myled.c文件拷到driver文件夹下,打开Kconfig文件,在其中添加如下代码:
config
LINETECH_LED
bool "config
myled"
default y
help
myled driver
test
b) 同时打开Makefile文件,添加如下代码:
obj-$(CONFIG_LINETECH_LED) +=myled.o
c) 在终端输入make
menuconfig进行内核的配置,如图:
最后一个选项即为我要选得myled配置。
d)
将内核编译得到zImage,下载到开发板中,创建设备文件节点
在shell下执行mknod
/dev/ledS0 c 108 0
108:主设备号
0:次设备号>\
e)
将执行文件myled_test添加到开发板上,并执行:
./myled_test
on
./myled_test
off
三. 总结
通过这次对LINUX字符驱动LED灯的设计让我获益匪浅,该实验让我对驱动程序的设计有了大概的了解。首先,要知道驱动程序必须要有框架,即初始化和退出。然后,每个设备都有与之对应的结构体,而应用层要使用驱动程序,其中必须要有接口操作函数,特别注意下我在myled_open中将LED的寄存器进行配置,而不是在初始化函数中设置,是因为:虽然加载了模块,但是这个模块却不一定会被用到,所以在使用时才去设置。最后在初始化函数中要对cdev结构体变量进行初始化,并把该结构体注册到内核中。
概括为:应用程序在内核的字符设备数组中能够找到主设备号,根据设备号找到该设备的结构体cdev,访问结构体中的变量*ops,而*ops指向file_operation结构体,该结构体中有被应用层调用的函数。
四. 代码
//myled.c
#include
#include
#include
#include
#include
#include
#include
#define MAINLEDNO
108
#define MINLEDNO
0
#define LED_ON
0x01
#define LED_OFF
0x02
dev_t myled_no =
0;
struct cdev
myled_cdev;
````````int
myled_open(struct inode *inode,struct file *file)
{
int value =
0;
value =
(1<<10)|(1<<12)|(1<<16)|(1<<20);
writel(value,S3C2410_GPBCON);
value = 0x0;
writel(value,S3C2410_GPBUP);
value =
0xfffffffe;
writel(value,S3C2410_GPBDAT);
return 0;
}
int
myled_ioctl(struct inode *inode,struct file *file,unsigned int
cmd,unsigned long arg)
{
switch(cmd)
{
case LED_ON:
writel(0x0,S3C2410_GPBDAT);
break;
case LED_OFF:
writel(0xfffffffe,S3C2410_GPBDAT);
break;
default:
break;
}
return 0;
}
int
myled_close(struct inode *inode,struct file *file)
{
printk("bye");
return 0;
}
static struct
file_operations led_ops={
.open =
myled_open,
.ioctl =
myled_ioctl,
.release =
myled_close,
};
static int __init
LED_INIT(void)
{
int re = 0;
int ret = 0;
myled_no =
MKDEV(MAINLEDNO,MINLEDNO);
ret =
register_chrdev_region(myled_no,1,"myled");
if(ret<0)
{
printk("cant
regist");
return ret;
}
printk("reg
ok");
cdev_init(&myled_cdev,&led_ops);
myled_cdev.owner =
THIS_MODULE;
re =
cdev_add(&myled_cdev,myled_no,1);
if(re<0)
{
printk("add
error");
return re;
}
printk("add
ok");
return 0;
}
static void __exit
LED_EXIT(void)
{
cdev_del(&myled_cdev);
unregister_chrdev_region(myled_no,1);
printk("exit
ok");
}
module_init(LED_INIT);
module_exit(LED_EXIT);
MODULE_LICENSE("GPL");
//myled_test.c
#include
#include
#include
#include
#include
#define LED_ON
0x01
#define LED_OFF
0x02
int main(int
argc,char **argv)
{
int fd;
fd =
open("/dev/ledS0",0);
if(!strcmp(argv[1],"on"))
{
ioctl(fd,LED_ON);
}
else
if(!strcmp(argv[1],"off"))
{
ioctl(fd,LED_OFF);
}
return 0;
}
Makefile
obj-m:=myled.o
KDIR=/home/neo/linux-2.6.30.9-EL-20101126
all:
make -C $(KDIR)
SUBDIRS=$(shell pwd) modules
arm-linux-gcc -o
myled_test myled_test.c
嵌入式linux led驱动有几种写法,嵌入式Linux字符驱动LED灯设计相关推荐
- Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型
Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...
- Linux内核驱动如何编写?我们先从字符驱动入门开始
几年前正式转到linux开发岗位的时候,由于项目急需编写linux驱动来控制项目采集设备(板卡),我便被安排做这一部分工作.那时候挺慌的-,在之前的一年多时间里基本都是window应用开发,对于lin ...
- linux 最快的,五种方式装Linux哪种最快
mask宇 于 2012-05-20 00:46:44发表: 个人觉得硬盘的传输速率更快 所以悬着硬盘. Hoo_h 于 2012-05-20 00:18:54发表: 想尝试硬盘安装,用过光盘和U盘 ...
- linux系统支持游戏,3种方法让Linux系统支持游戏
Linux操作系统一直被供奉在圣坛之上,只有程序猿.攻城狮和技术大牛才能用.但是很多菜鸟怀着敬畏的精神安装了Linux操作系统,却发现-太高端-不会用- 对此,很多人询问,在Linux上能不能玩游戏? ...
- linux常见功能代码,几种功能类似Linux命令汇总(示例代码)
wc 命令用于统计文本的行数.字数.字节数,格式为"wc [参数] 文本". -l 只显示行数 -w 只显示单词数 -c 只显示字节数 例:统计当前系统中的用户个数: [[em ...
- linux系统进程有哪几种主要状态,Linux 进程状态详解
目的 为了对进程从产生到消亡的整个过程进行跟踪和描述,就需要定义各种进程的各种状态并制定相应的状态转换策略,以此来控制进程的运行. 粗略分类 运行态:进程占用CPU,并在CPU上运行: 就绪态:进程已 ...
- linux:线程同步的5种方法
linux:线程同步的5种方法 一.为什么要使用线程: 二.线程同步的5种方法 2.1 互斥量 2.2 读写锁 2.3 条件变量 2.4 自旋锁 2.5 屏障 一.为什么要使用线程: <1> ...
- 查看linux 文件创建时间,在Linux下查看文件三种时间
原标题:在Linux下查看文件三种时间 在Linux下,文件包含三种时间属性,分别为: atime(access time):最近访问文件内容时间(Last Access Time). mtime(m ...
- linux系统 清屏命令,【转】linux清屏的几种方法
在windows的DOS操作界面里面,清屏的命令是cls,那么在linux 里面的清屏命令是什么呢?下面笔者分享几种在linux下用过的清屏方法. 1.clear命令.这个命令将会刷新屏幕,本质上只是 ...
最新文章
- Android 的NDK的Makefile编写
- mysql用外键链接两个表_可能做一个MySQL外键的两个可能的表之一?
- 开始测试鸿蒙系统,华为打起反击战!正式测试“鸿蒙系统”,谷歌认怂,恢复华为资格...
- WPF ,listbox,平滑滚动的2种方式。
- mysql中non用什么_mysql Non-Transactional Database Only(只支持MyISAM)
- 按汇总分组/多维数据集
- python3 读取文本文件_Python3 读写文件
- PN序列的产生以及相关函数的计算
- matlab仿真ppt,Matlab系列之Simulink仿真教程.ppt
- 直角三角形斜边用计算机怎么算,直角三角形斜边怎么算 计算方法有哪些
- oppoa57升级android版本,OPPO A57刷机教程_OPPO A57升级更新官方系统包
- 使用YQL解决跨域请求json转jsonp问题
- CASCADE: Contextual Sarcasm Detection in Online Discussion Forums(2018)论文笔记
- 会议室可以使用全彩LED显示屏吗?
- Unity3D学习笔记——RigidBody(刚体)
- RationalDMIS 7.1 程序示例
- pandas用read_scv读取含英文双引号的文件
- 杨柳絮-Info:春天将不再漫天飞“雪”,济源治理杨柳絮在行动
- 。Windows 键盘快捷键
- 电子商务巨头阿里巴巴正考虑在复杂供应链中使用区块链
热门文章
- Bailian4148 生理周期【枚举+中国剩余定理】
- HDU2046 骨牌铺方格【递推】
- 《诗经》诗无邪 —— 雅篇
- 标准模板库 STL 使用之 —— vector 使用 tricks
- 【笔试/面试】SQL 经典面试题
- 机器学习基础(九)—— iterative optimization
- python抛出异常 后如何接住,Python 异常的捕获、异常的传递与主动抛出异常操作示例...
- cpython是什么_CPython是什么?PyPy是什么?Python和这两个东西有什么关系?
- 自学python顺序-要成为一名Python程序员,要学习哪些内容,学习顺序是怎样的?...
- python自动化办公-python自动化办公?学这些就够用了