一.任务要求

完成一个字符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灯设计相关推荐

  1. Linux io模型及函数调用,Linux 网络编程的5种IO模型:信号驱动IO模型

    Linux 网络编程的5种IO模型:信号驱动IO模型 背景 这一讲我们来看 信号驱动IO 模型. 介绍 情景引入: 在信号驱动IO模型中,当用户线程发起一个IO请求操作,会给对应的socket注册一个 ...

  2. Linux内核驱动如何编写?我们先从字符驱动入门开始

    几年前正式转到linux开发岗位的时候,由于项目急需编写linux驱动来控制项目采集设备(板卡),我便被安排做这一部分工作.那时候挺慌的-,在之前的一年多时间里基本都是window应用开发,对于lin ...

  3. linux 最快的,五种方式装Linux哪种最快

    mask宇 于 2012-05-20 00:46:44发表: 个人觉得硬盘的传输速率更快 所以悬着硬盘. Hoo_h 于 2012-05-20 00:18:54发表: 想尝试硬盘安装,用过光盘和U盘 ...

  4. linux系统支持游戏,3种方法让Linux系统支持游戏

    Linux操作系统一直被供奉在圣坛之上,只有程序猿.攻城狮和技术大牛才能用.但是很多菜鸟怀着敬畏的精神安装了Linux操作系统,却发现-太高端-不会用- 对此,很多人询问,在Linux上能不能玩游戏? ...

  5. linux常见功能代码,几种功能类似Linux命令汇总(示例代码)

    wc 命令用于统计文本的行数.字数.字节数,格式为"wc [参数]  文本". -l 只显示行数 -w 只显示单词数 -c  只显示字节数 例:统计当前系统中的用户个数: [[em ...

  6. linux系统进程有哪几种主要状态,Linux 进程状态详解

    目的 为了对进程从产生到消亡的整个过程进行跟踪和描述,就需要定义各种进程的各种状态并制定相应的状态转换策略,以此来控制进程的运行. 粗略分类 运行态:进程占用CPU,并在CPU上运行: 就绪态:进程已 ...

  7. linux:线程同步的5种方法

    linux:线程同步的5种方法 一.为什么要使用线程: 二.线程同步的5种方法 2.1 互斥量 2.2 读写锁 2.3 条件变量 2.4 自旋锁 2.5 屏障 一.为什么要使用线程: <1> ...

  8. 查看linux 文件创建时间,在Linux下查看文件三种时间

    原标题:在Linux下查看文件三种时间 在Linux下,文件包含三种时间属性,分别为: atime(access time):最近访问文件内容时间(Last Access Time). mtime(m ...

  9. linux系统 清屏命令,【转】linux清屏的几种方法

    在windows的DOS操作界面里面,清屏的命令是cls,那么在linux 里面的清屏命令是什么呢?下面笔者分享几种在linux下用过的清屏方法. 1.clear命令.这个命令将会刷新屏幕,本质上只是 ...

最新文章

  1. Android 的NDK的Makefile编写
  2. mysql用外键链接两个表_可能做一个MySQL外键的两个可能的表之一?
  3. 开始测试鸿蒙系统,华为打起反击战!正式测试“鸿蒙系统”,谷歌认怂,恢复华为资格...
  4. WPF ,listbox,平滑滚动的2种方式。
  5. mysql中non用什么_mysql Non-Transactional Database Only(只支持MyISAM)
  6. 按汇总分组/多维数据集
  7. python3 读取文本文件_Python3 读写文件
  8. PN序列的产生以及相关函数的计算
  9. matlab仿真ppt,Matlab系列之Simulink仿真教程.ppt
  10. 直角三角形斜边用计算机怎么算,直角三角形斜边怎么算 计算方法有哪些
  11. oppoa57升级android版本,OPPO A57刷机教程_OPPO A57升级更新官方系统包
  12. 使用YQL解决跨域请求json转jsonp问题
  13. CASCADE: Contextual Sarcasm Detection in Online Discussion Forums(2018)论文笔记
  14. 会议室可以使用全彩LED显示屏吗?
  15. Unity3D学习笔记——RigidBody(刚体)
  16. RationalDMIS 7.1 程序示例
  17. pandas用read_scv读取含英文双引号的文件
  18. 杨柳絮-Info:春天将不再漫天飞“雪”,济源治理杨柳絮在行动
  19. 。Windows 键盘快捷键
  20. 电子商务巨头阿里巴巴正考虑在复杂供应链中使用区块链

热门文章

  1. Bailian4148 生理周期【枚举+中国剩余定理】
  2. HDU2046 骨牌铺方格【递推】
  3. 《诗经》诗无邪 —— 雅篇
  4. 标准模板库 STL 使用之 —— vector 使用 tricks
  5. 【笔试/面试】SQL 经典面试题
  6. 机器学习基础(九)—— iterative optimization
  7. python抛出异常 后如何接住,Python 异常的捕获、异常的传递与主动抛出异常操作示例...
  8. cpython是什么_CPython是什么?PyPy是什么?Python和这两个东西有什么关系?
  9. 自学python顺序-要成为一名Python程序员,要学习哪些内容,学习顺序是怎样的?...
  10. python自动化办公-python自动化办公?学这些就够用了