当前位置: 代码网 > 服务器>服务器>Linux > 驱动开发(应用):设计一个社区饮水机控制系统

驱动开发(应用):设计一个社区饮水机控制系统

2024年08月01日 Linux 我要评论
功能简介:1、检测终端输入数据 (有包头包尾的数据处理功能)2、本地保存用户数据(保存ID和消费金额)。3、驱动层上电红灯闪烁,当检测到应用层安装以后绿灯常亮。4、用户刷卡或扫码前(接收到应用层数据前)按键无效,提示“请先刷卡”5、接收到金额数据后,判断按键(开始、停止)6、开始灌水亮红灯,售水结束亮绿灯并且蜂鸣器响一段时间表示水停。7、无操作检测,按下停止后10s内没有其他操作则售水结束,退还剩余金额。
驱动开发相关文章:

驱动开发(一):驱动代码的基本框架

驱动开发(四):linux内核中断

驱动开发(五):linux内核定时器

驱动开发(六):应用层通过文件系统与内核层交互

目录

功能概述

详情

驱动代码

应用层代码


功能概述

模拟饮水机按键控制开始停止功能,并根据时间控制出水量 (红灯表示出水状态,绿灯表示停止状态)。应用层程序模拟刷卡或者扫码计费,如应用层(向驱动)传递数据 3 那么就表示付费3元。

详情

1、检测终端输入数据 (有包头包尾的数据处理功能)

输入格式 :包头 id 金额 包尾   

eg: (0x55 0x01 0x02 0xff)

包头:0x55

 i d:0x01

金额2元:0x02

包尾:0xff 

2、本地保存用户数据(保存id和消费金额)。

3、驱动层上电红灯闪烁,当检测到应用层安装以后绿灯常亮。

4、用户刷卡或扫码前(接收到应用层数据前)按键无效,提示“请先刷卡”

5、接收到金额数据后,判断按键(开始、停止)

6、开始灌水亮红灯,售水结束亮绿灯并且蜂鸣器响一段时间表示水停。

7、无操作检测,按下停止后10s内没有其他操作则售水结束,退还剩余金额。

驱动代码

#include <linux/init.h>
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <asm/io.h>
#include <linux/uaccess.h>

irqreturn_t handler(int irqno, void *dev);
void timer_function(unsigned long data);
void timer_function2(unsigned long data);
void timer_function3(unsigned long data);
void timer_function4(unsigned long data);
void timer_function5(unsigned long data);

#define modname "lianxi"     //驱动文件名字
unsigned int major=0;               //主设备号


#define gpiono(m, n) m * 32 + n
#define gpio_b8 (gpiono(1, 8))
#define gpio_b16 (gpiono(1, 16))
int gpiono[] = {gpio_b8, gpio_b16};
char *name[] = {"gpio_it_8", "gpio_it_16"};

#define red 0xc001a000
#define green 0xc001e000
#define blue 0xc001b000
unsigned int *red_base = null;
unsigned int *green_base = null;
unsigned int *blue_base = null;

#define beep 0xc001c000
unsigned int *beep_base = null;


struct timer_list mytimer; //按键
struct timer_list mytimer2; //扣费
struct timer_list mytimer3; //闪灯
struct timer_list mytimer4; //蜂鸣器
struct timer_list mytimer5; //无操作检测

//******************************读写操作函数**************

int copy_size = 0;
char kbuf[128] = {0};

ssize_t mycdv_read(struct file *file, char __user *ubuf, size_t len, loff_t *loff)
{
  if (len > sizeof(kbuf))    //len是用户需要的,有可能大于内核传的
    {
        len = sizeof(kbuf);    //大于的时候,有多少就给它多少
    }
    copy_size = copy_to_user(ubuf, kbuf, len);
    if (copy_size)
    {
        printk(kern_err "copy_to_user error\n");
        return copy_size;
    }

    return 0;
}

ssize_t mycdv_write(struct file *file, const char __user *ubuf, size_t len, loff_t *lo)
{
    if (len > sizeof(kbuf))
    {
        len = sizeof(kbuf);
    }

    copy_size = copy_from_user(kbuf, ubuf, len);
    if (copy_size)
    {
        printk(kern_err "copy_from_user error\n");
        return copy_size;
    }

    if( kbuf[0] != 0x55 || kbuf[3] != 0xff)                    //判断数据格式是否正确
    {
      printk(kern_err "数据格式错误,请重新输入\n");
      return 0;
    }
    kbuf[4]=0xff;
    printk(kern_err "等待灌装......\n");


      
    return 0;
}
int mycdv_open(struct inode *inode, struct file *file)
{
    printk(kern_err "mycdv open ok\n");

    del_timer(&mytimer3);          //***********停止闪烁
    *(red_base) &= ~(1 << 28);    //**关红灯
    *(green_base) |= 1 << 13;       //****开绿灯
    return 0;
}
int mycdv_release(struct inode *inode, struct file *file)
{
    printk(kern_err "mycdv release ok\n");

    *(green_base) &=~(1 << 13);    //****************关绿灯

    mytimer3.expires = jiffies + 10;          //****************再闪红灯
    mytimer3.function = timer_function3;
    mytimer3.data = 0;
    init_timer(&mytimer3);  	
    add_timer(&mytimer3);   

    return 0;
}


const struct file_operations fops=
{
   .read = mycdv_read,
   .write = mycdv_write,
   .open = mycdv_open,
   .release = mycdv_release,
};

struct class *cls;
struct device *dev;

int ret;
int i;


//入口  申请资源
static int __init hello_init(void)
{
  //***********************  创建字符设备*************

    major = register_chrdev(major, modname, &fops);       //注册字符设备
    if(major<0)
	{
 		printk(kern_err "register chrdev error\n");
		return major;
	}

    cls = class_create(this_module, modname);    //创建一个class类型的对象,向用户空间提交目录信息(内核目录的创建)
    if(is_err(cls))
    {
        return ptr_err(cls);
    }

    dev = device_create(cls, null,mkdev(major,0), null,modname );    //向用户空间提交文件信息
    if(is_err(dev ))
  {
    return ptr_err(dev);
  }
  //****************************初始化定时器***************

    mytimer.expires = jiffies + 10;
    mytimer.function = timer_function;
    mytimer.data = 0;
    init_timer(&mytimer);  //内核帮你填充你未填充的对象	
    add_timer(&mytimer);    //开启一次定时器

    mytimer3.expires = jiffies + 10;
    mytimer3.function = timer_function3;
    mytimer3.data = 0;
    init_timer(&mytimer3);  //内核帮你填充你未填充的对象	
    add_timer(&mytimer3);    //开启一次定时器

      mytimer4.expires = jiffies + 10;
      mytimer4.function = timer_function4;
      mytimer4.data = 0;
      init_timer(&mytimer4);  	
      add_timer(&mytimer4);  


    //***************************开启按键中断************

      for (i = 0; i < sizeof(gpiono) / sizeof(int); i++)
    {
        ret = request_irq(gpio_to_irq(gpiono[i]), handler, irqf_trigger_falling, name[i], null);
        if (ret != 0)
        {
            printk(kern_err "%s request irq err\n", name[i]);
            return ret;
        }
    }

  //***************************初始化led、蜂鸣器******

    red_base = ioremap(red, 40);              //关闭红灯
    if (null == red_base)
    {
        printk("red ioremap err\n");
    }
    *(red_base) &= ~(1 << 28);
    *(red_base + 1) |= 1 << 28;
    *(red_base + 9) &= ~(3 << 24);

    blue_base = ioremap(blue,40);    //关闭蓝灯
    if (null == blue_base)
    {
        printk("blue ioremap err\n");
    }
    *(blue_base) &= ~(1<<12);
    *(blue_base+1) |= 1<<12;
    *(blue_base+8) |= 2<<24;

    green_base = ioremap(green, 40);   //关绿灯
    if (null == green_base)
    {
        printk("green ioremap err\n");
    }
    *(green_base) &=~(1 << 13);
    *(green_base + 1) |= 1 << 13;
    *(green_base + 8) &= ~(3 << 26);

    beep_base = ioremap(beep,40);  //关蜂鸣器
    if (null == beep_base)
    {
        printk("beep ioremap err\n");
    }
    *(beep_base)  &= ~ (1<<14) ;
    *(beep_base+1) |= 1<<14;
    *(beep_base+8) |= 1<<28;

    return 0;
}

//出口  释放资源
static void __exit hello_exit(void)
{
  //********************还原led、蜂鸣器************

  *(red_base) |= (1 << 28);
  *(green_base) |= 1<<13;
  *(blue_base) |=(1<<12);
  *(beep_base)  &= ~ (1<<14) ;
  iounmap(red_base);
  iounmap(green_base);
   iounmap(blue_base);
  iounmap(beep_base);

//*********************关闭按键、定时器中断***********

  for (i = 0; i < sizeof(gpiono) / sizeof(int); i++)
    {
        free_irq(gpio_to_irq(gpiono[i]), null);
    }

  del_timer(&mytimer);
  del_timer(&mytimer2);
  del_timer(&mytimer3);
  del_timer(&mytimer4);
  del_timer(&mytimer5);


  //*******************************注销字符设备*****************
    device_destroy(cls, mkdev(major, 0));         
    class_destroy(cls);                                                 
    unregister_chrdev(major, modname);         

}

module_init(hello_init);    //入口
module_exit(hello_exit);    //出口
module_license("gpl");      //许可证



//*****************按键中断处理函数***********

irqreturn_t handler(int irqno, void *dev)
{
    mod_timer(&mytimer,jiffies + 30);
    return irq_handled;
}

//*****************定时器中断处理函数********

void timer_function(unsigned long data)          //***********检测按键
{
    int b8 = gpio_get_value(gpio_b8);
    int b16 = gpio_get_value(gpio_b16);

    if (b8 == 0)     //****************暂停按键按下
    {
      if(kbuf[4]!=0xff)
      {
        printk(kern_err "请先刷卡缴费\n");
        return;
      }
      printk(kern_err "暂停\n");

       *(green_base) |=1 << 13;    //****************开绿灯
      *(red_base) &= ~(1 << 28);//********关红灯

      mytimer5.expires = jiffies + 10000;                //****开启无操作检测10s
      mytimer5.function = timer_function5;
      mytimer5.data = 0;
      init_timer(&mytimer5);  	
      add_timer(&mytimer5); 
      
      del_timer(&mytimer2);
    }
    if (b16 == 0)              //*****************开始按键按下
    {
      if(kbuf[4]!=0xff)
      {
        printk(kern_err "请先刷卡缴费\n");
        return;
      }
      printk(kern_err "开始\n");
      del_timer(&mytimer5);   //**********关闭无操作检测

      *(green_base) &=~(1 << 13);    //****************关绿灯
      *(red_base) |= 1 << 28;  //********开红灯


      printk(kern_err "当前余额:%d\n",kbuf[2]);

      mytimer2.expires = jiffies + 1000;
      mytimer2.function = timer_function2;
      mytimer2.data = 0;
      init_timer(&mytimer2);  //内核帮你填充你未填充的对象	
      add_timer(&mytimer2);    //开启一次定时器
    }
}

void timer_function2(unsigned long data) //***********按秒扣费
{
    if(kbuf[2]==0)
  {
      del_timer(&mytimer2);
      printk(kern_err "灌水结束\n");

     *(green_base) |=1 << 13;    //****************开绿灯
      *(red_base) &= ~(1 << 28);  //********关红灯

      kbuf[4]=0x00;  //**********结束标志

      *(beep_base)  |= 1<<14 ;//******开蜂鸣器
      mod_timer(&mytimer4,jiffies + 1000);//*****1s后关闭

      return;
  }
  kbuf[2]=kbuf[2]-1;
  printk(kern_err "当前余额:%d\n",kbuf[2]);

  mod_timer(&mytimer2,jiffies + 1000);
}
int led_flag=0;
void timer_function3(unsigned long data) //***********闪红灯 0.3s
{
  led_flag++;
  if(led_flag==2)
    led_flag=0;
  if(led_flag==0)
    *(red_base) &= ~(1 << 28);
  if(led_flag==1)
    *(red_base) |= 1 << 28;
  mod_timer(&mytimer3,jiffies + 300);
}

void timer_function4(unsigned long data) //***********关蜂鸣器
{
  *(beep_base)  &= ~ (1<<14) ;
}

void timer_function5(unsigned long data) //***********长时间无操作
{
  printk(kern_err "售水结束,余额:%d\n",kbuf[2]);
  kbuf[4]=0x00;
}

应用层代码

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>

char buf[128]={0};
char history[128]={0};
int main(int argc, char const *argv[])
{
    int fd;
    int fd_history;
    fd = open("/dev/lianxi",o_rdwr);   //打开驱动文件
    if(fd<0)
    {
        perror("open err");
        return -1;
    }

    fd_history = open("history.txt",o_wronly | o_append | o_creat ,0777 );   //打开历史记录文件
    if(fd_history<0)
    {
        perror("open err");
        return -1;
    }
    int old,new;
    while (1)
    {
        printf("请输入id和金额     eg:(0x55 0x01 0x02 0xff) 表示包头 0x55 id 0x01 金额 2元0x02  包尾 0xff)\n");
        scanf("%x %x %x %x",&buf[0],&buf[1],&buf[2],&buf[3]);
        old=buf[2];
        write(fd,buf,sizeof(buf));   //向驱动写入数据
        memset(buf,0,sizeof(buf));    
        do{
            read(fd,buf,sizeof(buf));    //等待售水结束
        }while (buf[4]!=0x00);
        new=buf[2];
        sprintf(history,"id:0x%02hx    consumption: %d\n",buf[1],old-new);  //拼接历史记消息,写入history.txt
        write(fd_history, history, strlen(history));
        
    }
    
    close(fd_history);
    close(fd);
    return 0;
}

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com