
前提:将核心层和总线驱动层配置进内核;
先完成设备驱动和i2c总线驱动的绑定,让总线驱动管理到设备驱动,调用核心层API即可完成绑定,然后i2c总线驱动完成设备驱动和si7006的匹配, 最后设备驱动通过IIC控制器完成si7006设备的温湿度的采集,最后将采集的温湿度显示在数码管上;
- #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
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/i2c.h>
- #include <linux/fs.h>
- #include <linux/uaccess.h>
- #include <linux/device.h>
- #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");
- #include <linux/init.h>
- #include <linux/module.h>
- #include <linux/spi/spi.h>
- #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");
- #include "head.h"
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/ioctl.h>
- #include <arpa/inet.h>
- #include <pthread.h>
-
- 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;
- }


