应用层si7006.c
#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 "head.h"
int main(int argc,char const *argv[])
{
int tem,hum;
float tem1,hum1;
int fd = open("/dev/si7006",O_RDWR);
if(fd < 0)
{
printf("设备文件打开失败\n");
exit(-1);
}
while(1)
{
//获取数据
ioctl(fd,GET_HUM,&hum);
ioctl(fd,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);
sleep(1);
}
return 0;
}
驱动层myiic.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/device.h>
#include "head.h"
unsigned int major;
struct class *cls;
struct device *dev;
struct i2c_client *client1;
// 读取温湿度的函数
int i2c_read_hum_tem(char reg)
{
short value;
char r_buf[] = {reg};
int ret;
// 封装消息
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,
},
};
// 将消息传送
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, ret;
switch (cmd)
{
case GET_HUM: // 读取湿度
// 读取湿度的逻辑
hum = i2c_read_hum_tem(0XE5);
ret = copy_to_user((void *)arg, &hum, 4);
if (ret < 0)
{
printk("向用户拷贝数据失败\n");
return ret;
}
break;
case GET_TEM: // 读取温度
// 读取温度的逻辑
tem = i2c_read_hum_tem(0XE3);
ret = copy_to_user((void *)arg, &tem, 4);
if (ret < 0)
{
printk("向用户拷贝数据失败\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;
// 字符设备驱动的注册
major = register_chrdev(0, "si7006", &fops);
if (major < 0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功\n");
// 自动创建设备节点
cls = class_create(THIS_MODULE, "si7006");
if (IS_ERR(cls))
{
printk("向上提交目录失败\n");
return -PTR_ERR(cls);
}
printk("向上提交目录成功\n");
// 向上提交设备节点
dev = device_create(cls, NULL, MKDEV(major, 0), NULL, "si7006");
if (IS_ERR(dev))
{
printk("向上提交节点信息失败\n");
return -PTR_ERR(dev);
}
printk("向上提交节点信息成功\n");
// 硬件信息的获取
return 0;
}
// remove 和设备信息分离时执行
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 = "vivi,si7006",
},
{
},
};
// 分配iic驱动对象并初始化
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");
在根节点外添加设备树
*********添加************
在stm32mp157a-fsmp1a.dts文件的根节点外部,添加如下内容:
&i2c1 {
pinctrl-names = "default", "sleep";//关于pinctrl的一个列表,"default"表示默认工作模式
//"sleep"表示低功耗模式
pinctrl-0 = <&i2c1_pins_b>;//-0表示pinctrl-name列表中第一个值default
pinctrl-1 = <&i2c1_sleep_pins_b>;
//在stm32mp15-pinctrl.dtsi文件中存在内核添加的各种用于管脚复用的节点,i2c1_pins_a就是其中之一
i2c-scl-rising-time-ns = <100>;
i2c-scl-falling-time-ns = <7>;
status = "okay";
/delete-property/dmas; //删除不必要的属性
/delete-property/dma-names;
si7006@40{ //添加SI7006的从机节点
compatible="hqyj,si7006";
reg=<0X40>;
};
};
效果演示