驱动开发,使用数码管显示采集的温湿度的值(取整)

1.IIC驱动层次图(同SPI)

驱动开发,使用数码管显示采集的温湿度的值(取整)_第1张图片

        前提:将核心层和总线驱动层配置进内核;

        先完成设备驱动和i2c总线驱动的绑定,让总线驱动管理到设备驱动,调用核心层API即可完成绑定,然后i2c总线驱动完成设备驱动和si7006的匹配, 最后设备驱动通过IIC控制器完成si7006设备的温湿度的采集,最后将采集的温湿度显示在数码管上;

2.代码

---head.h---头文件
#ifndef __HEAD_H__
#define __HEAD_H__

#define GET_HUM _IOR('m',1,int)  //获取湿度的功能码
#define GET_TEM _IOR('m',0,int)  //获取温度的功能码
#define GET_TH _IOR('m',2,int)//获取数码管的功能码
#endif
---si7006.c---温湿度驱动文件
#include 
#include 
#include 
#include 
#include 
#include 
#include "head.h"

unsigned int major;
struct class *cls;
struct device *dev;
struct i2c_client *client1;

// 封装函数读取温度和湿度
int read_hum_tem(char reg)
{
    // 封装传输的消息
    char r_buf[] = {reg};
    short value;
    struct i2c_msg r_msg[] = {
        [0] = {
            .addr = client1->addr,
            .flags = 0,
            .len = sizeof(r_buf),
            .buf = r_buf,
        },
        [1] = {
            .addr = client1->addr,
            .flags = 1,
            .len = 2,
            .buf = (char *)&value,
        },
    };

    // 传输消息
    int ret = i2c_transfer(client1->adapter, r_msg, 2);
    if (ret != 2)
    {
        printk("传输消息失败\n");
        return -EIO;
    }
    return value;
}

// 封装操作方法
int si7006_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long si7006_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int tem, hum;
    int ret;
    switch (cmd)
    {
    case GET_HUM: // 读取湿度
        hum = read_hum_tem(0xE5);
        ret = copy_to_user((void *)arg, &hum, 4);
        if (ret)
        {
            printk("copy_to_user err\n");
            return ret;
        }
        break;

    case GET_TEM: // 读取湿度
        tem = read_hum_tem(0xE3);
        ret = copy_to_user((void *)arg, &tem, 4);
        if (ret)
        {
            printk("copy_to_user err\n");
            return ret;
        }
        break;
    }

    return 0;
}

int si7006_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

// 定义操作方法结构体遍历并且初始化
struct file_operations fops = {
    .open = si7006_open,
    .unlocked_ioctl = si7006_ioctl,
    .release = si7006_close,
};

// 给对象分配空间并初始化
int i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
    client1 = client;
    int ret;
    // 字符设备驱动注册
    major = register_chrdev(0, "si7006", &fops);
    if (major < 0)
    {
        printk("注册字符设备驱动失败\n");
        ret = major;
        goto out1;
    }
    printk("注册字符设备驱动成功\n");

    // 设备节点的创建
    // 向上提交目录
    cls = class_create(THIS_MODULE, "si7006");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = PTR_ERR(cls);
        goto out2;
    }
    printk("向上提交目录成功\n");

    // 向上提交设备节点
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "si7006");
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点信息失败\n");
        ret = PTR_ERR(dev);
        goto out3;
    }
    printk("向上提交设备节点信息成功\n");

    return 0;

// 设备信息的获取
out3:
    class_destroy(cls);
out2:
    unregister_chrdev(major, "si7006");
out1:
    return ret;
}
int i2c_remove(struct i2c_client *client)
{
    // 设备节点的销毁
    device_destroy(cls, MKDEV(major, 0));
    // 设备信息的注销
    class_destroy(cls);
    // 字符设备驱动注销
    unregister_chrdev(major, "si7006");

    return 0;
}

// 设备树匹配构建
struct of_device_id oftable[] = {
    {
        .compatible = "hqyj,si7006",
    },
    {},
};

struct i2c_driver i2c_drv = {
    .probe = i2c_probe,
    .remove = i2c_remove,
    .driver = {
        .name = "si7006",
        .of_match_table = oftable,
    },
};

module_i2c_driver(i2c_drv);
MODULE_LICENSE("GPL");
---m74hc595.c---数码管驱动文件
#include 
#include 
#include 
#include "head.h"
unsigned int major;
struct class *cls;
struct device *dev;
struct spi_device *spi1 = NULL;
char code[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};  //数字
char which[] = {0x8,0x4,0x2,0x1};  //数码管

// 封装操作方法
int m74hc595_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

long m74hc595_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int i,ret;
    unsigned int num;
    char buf[2];  //存储数字和哪一个数码管

    ret = copy_from_user(&num,(void *)arg,4);
    if(ret)
    {
        printk("copy_from_user fail\n");
        return -EIO;
    }

    if(cmd == GET_TH)
    {
        for(i=0; i<4; i++)
        {
            buf[1] = code[num%10];  //1234
            buf[0] = which[i];
            spi_write(spi1, buf, sizeof(buf));
            num /= 10;
        }
    }

    return 0;
}

int m74hc595_close(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

// 定义操作方法结构体遍历并且初始化
struct file_operations fops = {
    .open = m74hc595_open,
    .unlocked_ioctl = m74hc595_ioctl,
    .release = m74hc595_close,
};

int m74hc595_probe(struct spi_device *spi)
{
    spi1 = spi;
    int ret;
    // 字符设备驱动注册
    major = register_chrdev(0, "m74hc595", &fops);
    if (major < 0)
    {
        printk("注册字符设备驱动失败\n");
        ret = major;
        goto out1;
    }
    printk("注册字符设备驱动成功\n");

    // 设备节点的创建
    // 向上提交目录
    cls = class_create(THIS_MODULE, "m74hc595");
    if (IS_ERR(cls))
    {
        printk("向上提交目录失败\n");
        ret = PTR_ERR(cls);
        goto out2;
    }
    printk("向上提交目录成功\n");

    // 向上提交设备节点
    dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "m74hc595");
    if (IS_ERR(dev))
    {
        printk("向上提交设备节点信息失败\n");
        ret = PTR_ERR(dev);
        goto out3;
    }
    printk("向上提交设备节点信息成功\n");

    return 0;
out3:
    class_destroy(cls);
out2:
    unregister_chrdev(major, "m74hc595");
out1:
    return ret;
}
int m74hc595_remove(struct spi_device *spi)
{
    // 设备节点的销毁
    device_destroy(cls, MKDEV(major, 0));
    // 设备信息的注销
    class_destroy(cls);
    // 字符设备驱动注销
    unregister_chrdev(major, "m74hc595");

    printk("%s:%d\n", __FILE__, __LINE__);
    return 0;
}

// 设备树匹配表
struct of_device_id of_table[] = {
    {.compatible = "hqyj,m74hc595"},
    {},
};
// 定义SPI对象并且初始化
struct spi_driver m74hc595 = {
    .probe = m74hc595_probe,
    .remove = m74hc595_remove,
    .driver = {
        .name = "m74hc595",
        .of_match_table = of_table,
    },
};
// 一键注册宏
module_spi_driver(m74hc595);
MODULE_LICENSE("GPL");
---test.c---测试文件
#include "head.h"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int value = 0;

void *temhum_handle(void *arg) // arg = &fd
{
    while (1)
    {
        ioctl(*((int *)arg), GET_TH, &value); // 将温湿度传递给数码管
        //printf("%d\n",*((int *)arg));
    }
    pthread_exit(NULL);
}

int main(int argc, const char *argv[])
{
    int tem, hum;
    float tem1, hum1;
    int fd1 = open("/dev/si7006", O_RDWR);
    if (fd1 < 0)
    {
        printf("设备文件打开失败\n");
        exit(-1);
    }
    int fd2 = open("/dev/m74hc595", O_RDWR);
    if (fd2 < 0)
    {
        printf("设备文件打开失败\n");
        exit(-1);
    }

    // 采用多线程
    pthread_t tid;
    if (pthread_create(&tid, NULL, temhum_handle, (void *)&fd2) != 0)
    {
        fprintf(stderr, "pthread_create fail__%d__\n", __LINE__);
        return -1;
    }
    pthread_detach(tid);

    while (1)
    {
        ioctl(fd1, GET_HUM, &hum);
        ioctl(fd1, GET_TEM, &tem);
        // 大小端转换
        hum = ntohs(hum);
        tem = ntohs(tem);
        // 计算数据
        hum1 = 125.0 * hum / 65536 - 6;
        tem1 = 175.72 * tem / 65536 - 46.85;

        printf("tem = %f,hum = %f\n", tem1, hum1);
        value = (int)tem1 * 100 + (int)hum1;

        sleep(1);
    }
    pthread_join(tid, NULL);

    return 0;
}

3.测试现象

驱动开发,使用数码管显示采集的温湿度的值(取整)_第2张图片

驱动开发,使用数码管显示采集的温湿度的值(取整)_第3张图片

驱动开发,使用数码管显示采集的温湿度的值(取整)_第4张图片

你可能感兴趣的:(驱动开发,驱动开发,c语言,stm32)