前提:将核心层和总线驱动层配置进内核;
先完成设备驱动和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
#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");
#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");
#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;
}