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

驱动开发相关文章:

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

驱动开发(二):创建字符设备驱动

驱动开发(三):内核层控制硬件层

驱动开发(四):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;
}

  • 20
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STM32智能饮水机是一种利用STM32微控制器技术来实现的智能化饮水机。该产品结合了先进的微控制技术和人工智能算法,具有以下特点: 1. 高效节能:STM32微控制器具有优异的功耗控制能力,可以有效减少设备运行时的能耗,并且确保设备在待机状态时也能保持低能耗。这样不仅为用户节省了能源开支,也对环境保护起到积极作用。 2. 智能化控制:饮水机内部搭载了先进的人工智能算法,可以根据用户的健康需求和饮用习惯,智能调节饮水机的水温、水量和水质。用户可以通过手机APP或者设备面板进行设置,实现个性化的饮水需求。 3. 安全可靠:STM32微控制器具有丰富的安全保护机制,可以确保饮水机在工作过程中不会出现意外故障和安全隐患。例如,通过温度保护、过流保护等功能,保证了设备的安全运行。 4. 数据监控与分析:饮水机内置传感器可以实时监测水温、水质和水量等参数,并将数据传输给STM32微控制器进行分析和处理。用户可以通过手机APP或者设备面板查看相关数据,并根据数据分析结果调整饮水机的工作状态。 5. 人性化设计:STM32智能饮水机外观简洁美观,操作简单方便。设备内部采用可拆卸式设计,方便用户进行清洁和维护。同时,设备还具备自动冲洗和自动消毒功能,保证用水的卫生安全。 综上所述,STM32智能饮水机通过STM32微控制器技术的应用,实现了高效节能、智能化控制、安全可靠、数据监控与分析、人性化设计等多种功能,为用户提供了一种更加智能、健康、方便的饮水体验。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值