项目中经常会使用YK和YX功能,DI操作,简单来说就是外部输入高电平,软件检测信号就为1;外部信号输入低电平,软件检测信号就为0;依据这样的设计,我们来看一下字符驱动该如何完成。

下面介绍一种有IO控制和74HC595扩展控制DO的混合YK;

为什么要加74HC595芯片?

1、CPU的关键不够用

2、锁存作用,595是一种移位的锁存器,就是CPU程序复位后,锁存外部的状态不发送变化;比如:外部接触器断开时序有要求;

字符驱动的模型还是套用gpio系统;

1、模块的入口函数

module_init(at91_dido_init);
module_exit(at91_dido_cleanup);MODULE_DESCRIPTION ("AT91 dido DRIVER");
MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR ("Jack");
MODULE_LICENSE ("GPL");

2、创建init和cleanup函数
定义初始化信息, 定义YK YX控制的结构体

struct dido_pin
{ulong DI_YX[MAX_YX_NUMBER];/*PA0~PA7*//*PE8~PE10*/ulong pin_shcp;  //shift register clock inputulong pin_stcp;  //storage register clock inputulong pin_ds;   //serial data input
};struct St_dido
{dev_t dev_major;char di_stat[MAX_YK_NUMBER];char do_stat[MAX_YK_NUMBER];//目前为一一对应关系struct dido_pin Dido_pin;atomic_t open_count;struct mutex dido_mudex;//互斥锁struct cdev dido_dev;//struct class *dido_class;struct device *dido_device;
};

3、注册及注销驱动流程
定义YX对应的硬件管脚和595控制管脚

static int __init at91_dido_init(void)
{ int retval = -1;int inum = 0;dev_t dev_id;// 分配一个结构pdido = (struct St_dido *)kzalloc(sizeof (struct St_dido),GFP_KERNEL);if(!pdido){printk("%s:kzalloc failded from:%s\n", __func__,DIDO_DETECT_NAME);return -ENOMEM;}//init low dido pinfor( inum=0; inum < 6; inum ++ ){pdido->Dido_pin.DI_YX[inum] = AT91_PIN_PE0+inum;}pdido->Dido_pin.DI_YX[6]  = AT91_PIN_PC16;pdido->Dido_pin.DI_YX[7]  = AT91_PIN_PC21;pdido->Dido_pin.pin_shcp  = AT91_PIN_PD28;pdido->Dido_pin.pin_stcp  = AT91_PIN_PD31;pdido->Dido_pin.pin_ds   = AT91_PIN_PD19;//printk("dido_pin:green:%d\n",pwdt->wdg_pin);mutex_init(&(pdido->dido_mudex));//pwdt->open_count = ATOMIC_INIT(0);//初始化为0//分配主设备号if (dido_major) {dev_id = MKDEV(dido_major, 0);retval = register_chrdev_region(dev_id, MAX_DIDO_NB,DIDO_DETECT_NAME);} else {retval = alloc_chrdev_region(&dev_id, 0, MAX_DIDO_NB,DIDO_DETECT_NAME);dido_major = MAJOR(dev_id);}if(retval<0){printk("dido: register error!\n");goto error_malloc;}elseprintk("dido:dido_major:%d\n",dido_major); cdev_init(&(pdido->dido_dev), &at91_dido_fops);retval = cdev_add(&(pdido->dido_dev), dev_id,MAX_DIDO_NB);if(retval<0){printk("dido:cdev_add faidido!!!\n");goto error_reg;}//创建类pdido->dido_class = class_create(THIS_MODULE,DIDO_DETECT_NAME);if(!pdido->dido_class){printk("dido:class_create error!\n");goto error_cdev;}pdido->dido_device= device_create(pdido->dido_class, NULL,MKDEV(dido_major, 0),NULL, DIDO_DETECT_NAME);if(!pdido->dido_device){printk("dido:device_create error!\n");goto error_class;}for(inum=0; inum<MAX_YX_NUMBER;inum++){pdido->di_stat[inum] = 1;pdido->do_stat[inum] = 0;}return 0;error_class:class_destroy(pdido->dido_class);
error_cdev:cdev_del(&(pdido->dido_dev));
error_reg:unregister_chrdev_region(dev_id,MAX_DIDO_NB);
error_malloc:kfree(pdido);return retval;
}
static void __exit at91_dido_cleanup(void)
{ int inum = 0;dev_t dev_id;dev_id = MKDEV(dido_major,0);if(pdido->dido_device){device_destroy(pdido->dido_class,MKDEV(dido_major, 0));}if(pdido->dido_class){class_destroy(pdido->dido_class);}// del cdevcdev_del(&(pdido->dido_dev));if(dido_major){unregister_chrdev_region(dev_id,MAX_DIDO_NB);}//mutex destorymutex_destroy(&pdido->dido_mudex);for(inum=0;inum<MAX_YX_NUMBER;inum++){pdido->di_stat[inum] = 1;pdido->do_stat[inum] = 0;}//释放内存kfree(pdido);printk("dido:mod is cleanup.\n");
}

4、595驱动

static int set_74hc595_shiftreg( struct St_dido *pdido, unsigned char index, int data )
{int i = 0;int tmpdata = 0;//获取原DO值同步到变量中for ( i = 0; i < 8; i ++ ){if ( pdido->do_stat[i] ){tmpdata |= (0x01 << i);}else{tmpdata &= ~(0x01 << i);}}printk(" tmpdata=0x%x\n",tmpdata);//操作移位寄存器for ( i = 0; i < 8; i ++ ) {if ( (tmpdata & 0x80) == 0x80 ){gpio_set_value(pdido->Dido_pin.pin_ds, 1);}else{gpio_set_value(pdido->Dido_pin.pin_ds, 0);}tmpdata = tmpdata << 1;gpio_set_value(pdido->Dido_pin.pin_shcp, 0);ndelay(200);gpio_set_value(pdido->Dido_pin.pin_shcp, 1);ndelay(200);}gpio_set_value(pdido->Dido_pin.pin_stcp, 0);ndelay(200);gpio_set_value(pdido->Dido_pin.pin_stcp, 1);ndelay(200);return 0;
}

5、驱动的操作方法

static struct file_operations at91_dido_fops={ .owner      = THIS_MODULE, .llseek     = NULL,.read       = NULL,.write      = NULL,.unlocked_ioctl      = at91_dido_ioctl, .open       = at91_dido_open, .release    = at91_dido_close,
};

6、控制方法实现函数

static long at91_dido_ioctl(struct file *filp, unsigned int cmd, unsigned long args)
{ int ret = 0;int didex = 0;char stat_buff[22]={0};unsigned char do_index = 0xff;struct St_dido*pdido;pdido = (struct St_dido *)filp->private_data;//检查命令的有效性if ((_IOC_TYPE(cmd) != DIDO_MAGIC_NB) || (_IOC_NR(cmd) > DIDOE_IOC_MAXNR)){printk("%s:CMD error\n",__func__);return -EINVAL;} //printk("at91_dido_ioctl!!\n");//判断空间是否可访问if(_IOC_DIR(cmd) & _IOC_READ){if(!access_ok(VERIFY_WRITE,(void *)args,_IOC_SIZE(cmd)))return -EFAULT;} else if(_IOC_DIR(cmd) & _IOC_WRITE){if(!access_ok(VERIFY_READ,(void *)args,_IOC_SIZE(cmd)))return -EFAULT;ret = __get_user(do_index, (__u8 __user *)args);if(ret)return -EFAULT;else if((do_index>MAX_YK_NUMBER) || (do_index<=0))return -EINVAL;do_index--;
//    printk("do_index:%d\n",do_index);} //互斥锁if(mutex_lock_interruptible(&(pdido->dido_mudex))){return -ERESTARTSYS;} switch(cmd) {case DIDO_DO_OUTPUT_HIGH:// 放入等待队列 pdido->do_stat[do_index] = 1;set_74hc595_shiftreg( pdido, do_index, 1 );break;case DIDO_DO_OUTPUT_LOW:// 放入等待队列pdido->do_stat[do_index] = 0;set_74hc595_shiftreg( pdido, do_index, 0 );break;case DIDO_GET_STATUSE:for(didex = 0; didex < MAX_YX_NUMBER; didex ++){pdido->di_stat[didex] = gpio_get_value(pdido->Dido_pin.DI_YX[didex]);}memcpy(stat_buff,pdido->do_stat,MAX_YK_NUMBER);memcpy(stat_buff+MAX_YK_NUMBER,pdido->di_stat,MAX_YX_NUMBER);if (__copy_to_user((void __user *)args,stat_buff,sizeof(stat_buff))){mutex_unlock(&(pdido->dido_mudex));return -EFAULT;}break;default:printk("outage:error cmd %d.\n", cmd);mutex_unlock(&(pdido->dido_mudex));return -EINVAL;}mutex_unlock(&(pdido->dido_mudex));return ret;}

更多linux知识点推荐:

[Linux字符驱动] LED点灯试验

[Linux 驱动]模块加载RTX8025驱动

[linux kernel] 内核下RX8025对接系统时钟

[linux kernel]内核启动阶段控制IO口时序输出

[职场吐槽]如何缓解焦虑

[linux kernel] 内核下ksz8081驱动调试

[linux kernel] 内核下ksz9031驱动调试

[linux kernel]内核图形化裁剪配置

[linux kernel]内核移植过程记录

[linux kernel] 内核启动流程梳理

[linux 底层]u-boot EMMC驱动

[linux 底层]u-boot图形化裁剪配置

[Linux 底层]U-boot ksz9031网络驱动调试

[Linux 底层]U-boot调试命令使用技巧

[Linux 底层]U-boot编译移植

[Linux 底层]U-boot烧录脚本介绍SecureCRT

[Linux 底层]bootstrap移植裁剪及编译

[Linux 底层] 平台软件分层介绍

[Linux 驱动] RS485测试程序编写

[Linux 驱动] CAN测试程序编写

推荐阅读:

芯片手册解读 | Linux底层 | 职场吐槽 | C语言视频

关注微信公众号,回复“YK字符驱动”,下载源代码。

[Linux字符驱动] DIDO 74HC595实现遥控遥信功能相关推荐

  1. Linux字符驱动开发学习总结

    linux驱动编写(虚拟字符设备编写) 昨天我们说了一些简单模块编写方法,但是终归没有涉及到设备的编写内容,今天我们就可以了解一下相关方面的内容,并且用一个实例来说明在linux上面设备是如何编写的. ...

  2. 嵌入式linux led驱动有几种写法,嵌入式Linux字符驱动LED灯设计

    一.任务要求 完成一个字符IO口驱动,在开发板上该IO口对应LED灯.该驱动程序通过控制IO口的高低电平来控制亮灭.同时要写一个应用层的测试程序,用来测试驱动程序.我的测试程序为myled_test. ...

  3. Linux字符驱动开发

    Linux字符驱动简介 字符设备驱动简介 举个栗子 file_operations 结构体 字符设备驱动开发步骤 驱动模块的加载和卸载 字符设备的注册和注销 添加 LICENSE 和作者信息 Linu ...

  4. 关于linux字符驱动中read函数filp->f_pos 和 loff_t *ppos的关系

    在学习linux 字符驱动的时候会有这样的困惑 比如我们实现一个字符驱动的读函数,如下 static ssize_t globalmem_read(struct file *filp, char __ ...

  5. linux字符驱动之点亮LED

    上一节中,我们讲解了如何自动创建设备节点,这一节我们在上一节的基础上,实现点亮LED. 上一节文章链接:https://blog.csdn.net/qq_37659294/article/detail ...

  6. linux字符驱动之概念介绍

    一.字符驱动框架 问:应用程序open.read.write如何找到驱动程序的open.read.write函数? 答:应用程序的open.read.write是在C库里面实现的,它里面通过swi v ...

  7. Linux字符驱动设备开发

    一.基础知识 参考博客:18 linux字符设备驱动之设备号_jklinux的博客-CSDN博客 创建设备驱动的目的,通常是让用户程序来调用.一般我们使用字符设备文件来提供接口,使用户进程可以访问操作 ...

  8. Linux字符驱动中动态分配设备号与动态生成设备节点

    在编写Linux内核驱动程序的时候,如果不动态生成设备号的话,需要自己手动分配设备号,有可能你分配的设备号会与已有设备号相同而产生冲突.因此推荐自动分配设备号.使用下面的函数: int alloc_c ...

  9. linux 字符驱动阻塞型 等待队列

    2019独角兽企业重金招聘Python工程师标准>>> 内核等待队列 等待队列 在linux驱动程序设计中,可以使用等待队列来实现进程的阻塞,等待队列可看作保存进程的容器,在阻塞进程 ...

最新文章

  1. 【pytorch】nn.conv2d的使用
  2. 源码 反码 补码详解(为什么计算机存储数值为补码形式?)
  3. ElasticSearch 实践过程中遇到的几个小问题
  4. java虚拟机采用UTF-16编码格式对字符进行编码
  5. 文件名为空linux,文件系统:隐匿在Linux背后的机制
  6. micropython编程软件下载_MicroPython可视化拼插编辑器:让硬件编程更智能!
  7. 'C'is not a valid file-based resource name character: File-based resource names must contain onl解决方法
  8. 批量图片缩小工具,JPG|PNG|BMP图片缩小工具
  9. 一天看10000张黄图,鉴黄师的苦!!!
  10. jpeg 与 png 图片格式的区别
  11. PanDownload——最新修订版复活了。60MB/s,附下载地址
  12. 小米2A com.android.phone,104.android 简单的检查小米手机系统和华为手机系统是否打开通话自动录音功能,跳转通话录音页面...
  13. mysql koa2的分页查询_koa2 快速实现注册、登录+分页(一)
  14. 【POJ C++题目】魔兽世界之一:备战
  15. 如何查询会议的接受率及年论文数
  16. AOV和AOE之间的区别和联系
  17. SWOT分析和PEST分析
  18. 麦克利兰的成就动机理论(转)
  19. 计算机二级vf上机题库,计算机二级VF上机题库
  20. c语言fclose什么作用,fclose()的源码是什么?那位高人能指点一下?解决思路

热门文章

  1. 网络带宽和速度的关系
  2. Tomcat配置与调优
  3. Unity3d 周分享(13期 2019.3.23 )
  4. MySQL数据库实现主主同步
  5. 计算机图文混合排版教学设计,《WORD图文混排》教学设计
  6. 【配送路径规划】基于matlab蚁群算法求解配送路径最短问题【含Matlab源码 2222期】
  7. 公众号改名了,聊聊我的思考
  8. 线性泛函分析之对偶基
  9. Python 多线程实例
  10. BUUCTF-[HCTF 2018]admin1