基于tiny4412开发板LED灯驱动标准的read write函数写法
来源:互联网 发布:山东大学威海知乎 编辑:程序博客网 时间:2024/05/22 04:28
简介
原来曾经写过一个led灯的驱动,调用read write函数对灯的亮灭进行操作,虽然达到了控制的目的,学过系统编程的人知道,其实标准的read write函数的用法,并不是这样的,在对文件操作时,我们读取相关文件内容时,每当我们读取一部分内容时,文件内位置指针会随着移动,在进行文件内容读取时,读取内容会在当前位置读取一定数量的内容。写操作同样。当我们写一些内容到一个文件,例如将1234456789
写到new.txt
中,先写1234
,在写56789
,打开文件我们会发现,写入内容为123456789
,后写入的56789
并没有将原来写入的1234
覆盖掉(这两次写操作均是在一次文件打开中执行,关闭后重新打开会覆盖掉原来的内容)。我们写的read
write
函数,进行例如读取灯的状态时,每次读一个灯的状态,往往读取的都是第一个灯的状态,并不会随着我们读取次数的增加,而灯的位置发生变化,驱动比较笨不会进行位置偏移,或者写的并不符合标准,就这个问题将给出标准的基于led
read
write
函数的写法,实现像操作文件一样去操作灯。
驱动层read
write
函数原型
ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
我们可以看到这两个函数与我们写上层应用时,参数是不一样的,多了一个loff_t *
。这就是驱动层与应用层的区别,而我们实现驱动led
灯,像操作文件一样,这个参数至关总要。这个参数是干什么的呢?这个参数记录着当前操作位置。也就是一个文件内有123456789
内容我先读取了1234
这几项内容,假如文件没有关闭,再继续读文件会从5开始读取,并不会从1开始读取,实现这个功能就是loff_t *
的作用,它会把当前文件操作的位置记录下来,方便下次操作。
之前的reead write代码
ssize_t leddriver_read(struct file *file, char __user *usr, size_t size, loff_t *loft){ unsigned char LED_STATUE; copy_from_user(&LED_STATUE,usr,1); printk("leddriver read is %d\r\n",LED_STATUE); switch(LED_STATUE) { case 10:GPM4DAT |= (0x1<<0);break; case 11:GPM4DAT &=~(0X1<<0);break; case 20:GPM4DAT |= (0x1<<1);break; case 21:GPM4DAT &=~(0X1<<1);break; case 30:GPM4DAT |= (0x1<<2);break; case 31:GPM4DAT &=~(0X1<<2);break; case 40:GPM4DAT |= (0x1<<3);break; case 41:GPM4DAT &=~(0X1<<3);break; } return 0;}
只能传入参数控制某个灯亮
新的标准led read write函数
ssize_t leddriver_read(struct file *file, char __user *usr, size_t size, loff_t *loft){ loff_t cur_pos=*loft;//取出当前读写位置值 unsigned char led_statue[10],i,LED_NUM=4; //读取数据长度为0什么也不做 返回0 退出程序的执行 if(size<=0) { return 0; } //读取位置在末尾 无论size是多少都不能读出数据 数据有效区域越界 if(cur_pos>=LED_NUM) { return 0; } //判断size+当前位置是大于文件大小,只读取有效位的内容 if(cur_pos+size>LED_NUM) { size=LED_NUM-cur_pos; } for(i=0;i<LED_NUM;i++) { if(GPM4DAT &(1<<i)) led_statue[i]=1; else led_statue[i]=0; } if(copy_to_user(usr,&led_statue[cur_pos],size)){ printk("copy to user err\r\n"); return -EFAULT; }; //指针重新定位当前位置 *loft+=size; return size;}
ssize_t leddriver_write (struct file *file, const char __user *usr, size_t size, loff_t *loft){ loff_t cur_pos=*loft; unsigned char led_statue[10],i,LED_NUM=4; //写入数据大小为0 什么也不操作返回0退出 if(size<=0) { return 0; } //当前位置大于等于文件最大有效数据,即使写入数据也是无效,所依不进行操作 返回0退出 if(cur_pos>=LED_NUM) { return 0; } //如果当前位置加上所要读取数据的长度大于剩余有效位 只读取有效数据位的数值 if(size+cur_pos>LED_NUM) { size=LED_NUM-cur_pos; } if(copy_from_user(&led_statue[cur_pos],usr,size)) { printk("copy from user err\r\n"); return -EFAULT; } for(i=0;i<size;i++) { if(led_statue[i+cur_pos]==0) GPM4DAT &= ~(1<<(i+cur_pos)); else GPM4DAT |= (1<<(i+cur_pos)); } *loft+=size; return size;}
验证led write的app函数
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(int argc,char *argv[]){ int led_fp,i; unsigned char led_statue[4]={1,1,1,1},statue[4]={0}; led_fp = open(argv[1],O_RDWR); write(led_fp,led_statue,2); sleep(2); write(led_fp,led_statue,2); close(led_fp);}
运行这个app函数会发现,两个灯先亮,两秒之后,剩余两个灯再次亮起。实现箱操作文件那样,可以在原来的基础上进行操作的用法。
验证led read的app函数
因为lseek函数还没写,所以文件在上一步写完后会定位到,文件末尾,在进行读操作,什么也读不到。所以进行写操作后,需要将文件关闭,再次打开在进行读取验证,否则验证结果不正确。
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(int argc,char *argv[]){ int led_fp,i; unsigned char led_statue[4]={1,1,0,1},statue[4]={0}; led_fp = open(argv[1],O_RDWR); read(led_fp,statue,2); for(i=0;i<2;i++) { if(statue[i]==0) { printf("第%d个灯亮\r\n",i+1); } else { printf("第%d个灯灭\r\n",i+1); } } sleep(1); read(led_fp,statue,2); for(i=0;i<2;i++) { if(statue[i]==0) { printf("第%d个灯亮\r\n",i+1); } else { printf("第%d个灯灭\r\n",i+1); } } close(led_fp);}
运行app后会依次读取灯的状态。
总结
像操作文件一样操作led灯,就要依赖文件偏移参数。
总的驱动代码
#include<linux/kernel.h>#include<linux/module.h>#include<linux/init.h>#include<asm/io.h>#include<asm/uaccess.h>#include<linux/fs.h>#include<linux/cdev.h>#include<linux/kdev_t.h>#include<linux/slab.h>#include<linux/device.h> //增加自动创建设备头文件#include<linux/uaccess.h>//定义字符设备结构体static struct cdev *leddriver_cdev;//定义设备号(包含主次)static dev_t leddriver_num=0;//定义设备类static struct class *leddriver_class;//定义设备结构体static struct device *leddriver_device;//定义错误返回类型static int err;//定义设备名称#define LEDDRIVER_NAME "myled"#define GPM4CON_ADDR 0x110002E0 #define GPM4DAT_ADDR 0X110002E4static volatile unsigned long *gpm4con=NULL; static volatile unsigned long *gpm4dat=NULL;#define GPM4CON *gpm4con#define GPM4DAT *gpm4datssize_t leddriver_read(struct file *file, char __user *usr, size_t size, loff_t *loft){ loff_t cur_pos=*loft;//取出当前读写位置值 unsigned char led_statue[10],i,LED_NUM=4; //读取数据长度为0什么也不做 返回0 退出程序的执行 if(size<=0) { return 0; } //读取位置在末尾 无论size是多少都不能读出数据 数据有效区域越界 if(cur_pos>=LED_NUM) { return 0; } //判断size+当前位置是大于文件大小,只读取有效位的内容 if(cur_pos+size>LED_NUM) { size=LED_NUM-cur_pos; } for(i=0;i<LED_NUM;i++) { if(GPM4DAT &(1<<i)) led_statue[i]=1; else led_statue[i]=0; } if(copy_to_user(usr,&led_statue[cur_pos],size)){ printk("copy to user err\r\n"); return -EFAULT; }; //指针重新定位当前位置 *loft+=size; return size;}ssize_t leddriver_write (struct file *file, const char __user *usr, size_t size, loff_t *loft){ loff_t cur_pos=*loft; unsigned char led_statue[10],i,LED_NUM=4; //写入数据大小为0 什么也不操作返回0退出 if(size<=0) { return 0; } //当前位置大于等于文件最大有效数据,即使写入数据也是无效,所依不进行操作 返回0退出 if(cur_pos>=LED_NUM) { return 0; } //如果当前位置加上所要读取数据的长度大于剩余有效位 只读取有效数据位的数值 if(size+cur_pos>LED_NUM) { size=LED_NUM-cur_pos; } if(copy_from_user(&led_statue[cur_pos],usr,size)) { printk("copy from user err\r\n"); return -EFAULT; } for(i=0;i<size;i++) { if(led_statue[i+cur_pos]==0) GPM4DAT &= ~(1<<(i+cur_pos)); else GPM4DAT |= (1<<(i+cur_pos)); } *loft+=size; return size;}int leddriver_open (struct inode *node, struct file *file){ printk("files open is success\r\n"); return 0;}int leddriver_release (struct inode *node, struct file *file){ printk("leddriver close is success\r\n"); return 0;}//文件操作函数结构体static struct file_operations leddriver_fops={ .owner=THIS_MODULE, .open=leddriver_open, .release=leddriver_release, .read=leddriver_read, .write=leddriver_write,};static __init int ldedriver_init(void){//分配字符设备结构体,前面只是定义没有分配空间leddriver_cdev=cdev_alloc();//判断分配成功与否if(leddriver_cdev==NULL){ err=-ENOMEM; printk("leddriver alloc is err\r\n"); goto err_leddriver_alloc;}//动态分配设备号err=alloc_chrdev_region(&leddriver_num, 0, 1, LEDDRIVER_NAME);//错误判断if(err<0){ printk("alloc leddriver num is err\r\n"); goto err_alloc_chrdev_region;}//初始化结构体cdev_init(leddriver_cdev,&leddriver_fops);//驱动注册err=cdev_add(leddriver_cdev,leddriver_num,1);if(err<0){ printk("cdev add is err\r\n"); goto err_cdev_add;}//创建设备类leddriver_class=class_create(THIS_MODULE,"led_class"); err=PTR_ERR(leddriver_class); if(IS_ERR(leddriver_class)) {printk("leddriver creat class is err\r\n");goto err_class_create; }//创建设备 leddriver_device=device_create(leddriver_class,NULL, leddriver_num,NULL, "leddevice"); err=PTR_ERR(leddriver_device); if(IS_ERR(leddriver_device)) {printk("leddriver device creat is err \r\n");goto err_device_create; }//led灯寄存器配置 gpm4con=ioremap(GPM4CON_ADDR, 4); gpm4dat=ioremap(GPM4DAT_ADDR, 4); GPM4CON &= ~(0XFFFF<<0); GPM4CON |= (0x1111<<0); GPM4DAT |= (0XF<<0);printk("leddriver init is success\r\n");return 0;err_device_create:class_destroy(leddriver_class);err_class_create: cdev_del(leddriver_cdev);err_cdev_add:unregister_chrdev_region(leddriver_num, 1);err_alloc_chrdev_region:kfree(leddriver_cdev);err_leddriver_alloc:return err;}static __exit void leddriver_exit(void){ //取消映射 iounmap(gpm4con); iounmap(gpm4dat); device_destroy(leddriver_class,leddriver_num); class_destroy(leddriver_class); cdev_del(leddriver_cdev); unregister_chrdev_region(leddriver_num, 1); printk("leddriver is exit\r\n");}module_init(ldedriver_init);module_exit(leddriver_exit);MODULE_LICENSE("GPL");
- 基于tiny4412开发板LED灯驱动标准的read write函数写法
- 基于tiny4412开发板LED灯驱动标准的llseek函数写法
- tiny4412开发板LED灯驱动写法
- 基于tiny4412开发板led灯字符设备ioctl驱动写法
- Tiny4412开发板 LED灯的控制
- 基于TINY4412的Andorid开发-------简单的LED灯控制
- 基于TINY4412的Andorid开发-------简单的LED灯控制
- 基于TINY4412的Andorid开发-------简单的LED灯控制
- 基于TINY4412的Andorid开发-------简单的LED灯控制
- 基于TINY4412的Andorid开发-------简单的LED灯控制
- 基于TINY4412的Andorid开发-------简单的LED灯控制
- 基于tiny4412开发板的I2C子系统写法
- tiny4412 SDK1312B LED驱动
- 基于tiny4412按键中断驱动的poll、select函数演示
- 基于TQ2440开发的LED驱动
- 基于S3C2440开发板LED灯驱动移植
- tiny4412开发板蜂鸣器驱动
- 基于tiny4412的ts驱动简单分析
- Python入门——for
- centos7升级python3.6.1及遇到的问题
- 大学英语单词V
- 双色河内塔(c/python)
- spring的自动化装配bean
- 基于tiny4412开发板LED灯驱动标准的read write函数写法
- 从零开始学习c++之程序计算的简单应用
- zookeeper在windons下安装
- VINS mono 系统学习 二
- 二叉树遍历的非递归算法
- .WebDelegatingSubject cannot be cast to cn.itcast.bos.domain.system.User
- 开启博客生涯的第一天
- java面向对象的概念总结
- 網絡Io实现方式