中科银河芯陆续推出了一系列的i2c温度传感器用于满足不同应用的需求:
在这里插入图片描述
针对以上i2c传感器我编写了一个通用版本linux驱动供大家参考指导;
温度读取流程:
配置唤醒参数——>等待唤醒——>采集数据——> 进入睡眠
不同的传感器唤醒命令是不一样的,例如GXT310的唤醒命令是利用单次转换还是连续转换来进入低功耗或唤醒,如下图配置寄存器表:
在这里插入图片描述
GX21M15是通过配置寄存器第0位的睡眠标识来进行唤醒与睡眠操作:
在这里插入图片描述

因此在代码端的wakeup函数内,我们只需要配置不同的命令即可:

//*返回值,成功,返回0。失败,返回 -1
static int gxt_wakeup(void)
{
        int ret = 0;

#ifdef  SENSOR_GXT310   
        uint8_t   dat310[3] = {0x01,0x02,0x9E};//GXT310
        //报警     过温     连续转换  16位 不超时 CRC   8HZ  非单次模式
        //                  1   0        1 0 0 1   1  1   1  0
        //ALT - - FQ1 FQ0 - TM SD       EM - - TO EC CR1 CR0 OS
        //
        //  正常模式
                                        
        ret = gxt_write_cmd(gxt_i2c_client,dat310,3);
#endif

#ifdef  SENSOR_GXT21M15
        uint8_t dat21m15[2]  = {0x01,0x00};
        // B[7:5]保留 B[4:3]故障队列 OSPOL OS_COMP_INIT  SLEEP
        //  000         00            0          0        0
        //     

      ret = gxt_write_cmd(gxt_i2c_client,dat21m15,2);
#endif

        return ret;
}

读取温度数据:
中科银河的温度传感器温度数据寄存器基本上都是在00h,我们只需要读取00h 两个字节即可(有CRC也可以读3个字节把CRC读取出来进行校验)在这里插入图片描述
在这里插入图片描述

读取代码如下:

static ssize_t gxt_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{

        short gxt_result[2];
        uint8_t temp[8];
        int error;
        error = gxt_read_data(gxt_i2c_client,0,temp,3);
        gxt_result[0] = temp[0]*256+temp[1];
	 //gxt_result[1] = temp[3]*256+temp[4];	
        if(error>=0)
        {
                error = copy_to_user(buf, gxt_result, cnt);
                printk("temp = %d\n",gxt_result[0]);
        }
        else
        {
                printk("%s() i2c_read_data Failed!\n", __func__);
                return -1;
        }


        return 0;
}

温度转化
驱动程式内不做温度转化,我们只需要把16Bit的温度值传给应用层,让应用层进行浮点运算即可,例如GXT310是16位AD数据,将值转化成温度的公式为:temp = AD数据值0.0078125
在这里插入图片描述
GX75/GX21M15等是12位AD数据,我们需要将值右移4位即除16,再成温度LSB值,公式为:temp = AD数据值/16.0
0.
在这里插入图片描述
应用层转换代码如下:

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <sys/time.h>

int main(int argc, char *argv[])
{

    unsigned short data[2];
    float T,RH;
    int ret = -1 ;
    while(1)
    {
         /*打开文件*/
         int fd = open("/dev/GXT_SENSOR", O_RDWR);
        if(fd < 0)
         {
                printf("open file : %s failed !\n", argv[0]);
                return -1;
        }

    /*读取数据*/

        ret = read(fd,&data,2);
        if(ret >= 0)//读取到数据
        {
                float temp;
                printf("ret data = %d\n",data[0]);
                //计算温度数据

                //temp = data[0]/16.0*0.0625;//GXT21M15温度计算公式
                temp = data[0]*0.0078125;//GXT310计算公式

                printf("temp = %f\n\n",temp);
        }
        else
        {
                printf("read failed\n");
        }

        usleep(1000000);
        if(close(fd)<0)
        {
                printf("close file error!\n");
        }
    }
    return 0;
}

以下是真实测试结果:
在这里插入图片描述

linugx源码分享

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/i2c.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#include <asm/io.h>
#include <linux/device.h>

#include <linux/platform_device.h>


//以下型号选一个
#define  SENSOR_GXT310   
//#define  SENSOR_GXT21M15


/*------------------字符设备内容----------------------*/
#define DEV_NAME "GXT_SENSOR"
#define DEV_CNT (1)
#define DRIVER_VERSION "1.0.0"


struct semaphore sem; //互斥锁,只能有一个打开
static dev_t gxt_devno;      //定义字符设备的设备号
static struct cdev gxt_chr_dev;          //定义字符设备结构体chr_dev
struct class *class_gxt;                         //保存创建的类
struct device *device_gxt;                       // 保存创建的设备
struct device_node *gxt_device_node;    //设备树节点结构体

/*------------------IIC设备内容----------------------*/
struct i2c_client *gxt_i2c_client = NULL; //保存gxt设备对应的i2c_client结构体,匹配成功后由.prob函数带回。

/*
        //CRC校验
static u8 CRC_Check(unsigned char *check_data, unsigned char num, unsigned 
char check_crc)

{
    uint8_t bit;        // bit mask
    uint8_t crc = 0xFF; // calculated checksum
    uint8_t byteCtr;    // byte counter

 // calculates 8-Bit checksum with given polynomial x8+x5+x4+1
    for(byteCtr = 0; byteCtr < num; byteCtr++)
    {
        crc ^= (*(check_data+byteCtr));
        //crc校验,最高位是1就^0x31
        for(bit = 8; bit > 0; --bit)
        {
            if(crc & 0x80)
                crc = (crc << 1) ^ 0x31;
            else
                crc = (crc << 1);
        }
    }
    if(crc==check_crc)
        return 1;
    else
        return 0;
}
*/

static int gxt_write_cmd(struct i2c_client *client, uint8_t *dat ,uint8_t datlen)
{

        int error = 0;
        int i;
        uint8_t  write_data[8];
        struct i2c_msg send_msg; //要发送的数据结构体
        if(datlen>8)
        {
                printk(KERN_DEBUG "\n i2c write_cmd datlen error \n");
                return -1;
        }

        for(i=0;i<datlen;i++)
                write_data[i] = *(dat+i);

        send_msg.addr = client->addr; //iic 总线上的地址
        send_msg.flags = 0;              //标记为发送数据
        send_msg.buf = write_data;       //写入的首地址
        send_msg.len = datlen;               //reg长度

        error = i2c_transfer(client->adapter, &send_msg, 1);
        if (error != 1)
        {
                printk(KERN_DEBUG "\n i2c_transfer error \n");
                return -1;
        }

        return 0;
}



static int gxt_read_data(struct i2c_client *client, u8 addr, uint8_t *dat, u32 length)

{

        int error = 0;
        uint8_t address_data = addr;
        struct i2c_msg msg[2];
        msg[0].addr = client->addr;
        msg[0].flags = 0;
        msg[0].buf = &address_data;
        msg[0].len = 1;

        msg[1].addr = client->addr;
        msg[1].flags = I2C_M_RD;//读数据
        msg[1].buf = dat;
        msg[1].len = length;

        error = i2c_transfer(client->adapter, msg, 2);

        if (error != 2)
        {
                printk(KERN_DEBUG "\n i2c_read error \n");
                return -1;
        }

        return 0;

}


//*返回值,成功,返回0。失败,返回 -1
static int gxt_wakeup(void)
{
        int ret = 0;

#ifdef  SENSOR_GXT310   
        uint8_t   dat310[3] = {0x01,0x02,0x9E};//GXT310
        //报警     过温     连续转换  16位 不超时 CRC   8HZ  非单次模式
        //                  1   0        1 0 0 1   1  1   1  0
        //ALT - - FQ1 FQ0 - TM SD       EM - - TO EC CR1 CR0 OS
        //
        //  正常模式
                                        
        ret = gxt_write_cmd(gxt_i2c_client,dat310,3);
#endif

#ifdef  SENSOR_GXT21M15
        uint8_t dat21m15[2]  = {0x01,0x00};
        // B[7:5]保留 B[4:3]故障队列 OSPOL OS_COMP_INIT  SLEEP
        //  000         00            0          0        0
        //     

      ret = gxt_write_cmd(gxt_i2c_client,dat21m15,2);
#endif

        return ret;
}

static int gxt_sleep(void)
{
        int ret = 0;
	
#ifdef  SENSOR_GXT310   	 
        uint8_t dat310[3] = {0x01,0x02,0x99};//单次模式       
        ret = gxt_write_cmd(gxt_i2c_client,dat310,3);
#endif

#ifdef  SENSOR_GXT21M15
      uint8_t dat21m15[2] = {0x01,0x01};//睡眠模式
      ret = gxt_write_cmd(gxt_i2c_client,dat21m15,2);
#endif

        return ret;
}

static int gxt_reset(void)
{
        int ret = 0;
        //部分sensor不支持复位指令
        //
        return ret;
}

/*字符设备操作函数集,open函数实现*/
static int gxt_open(struct inode *inode, struct file *filp)
{

        int ret;
         /*上锁*/
        down(&sem);
        printk("\n gxt device open \n");
        ret = gxt_wakeup();//唤醒传感器

        mdelay(1);

        return ret;
}


static ssize_t gxt_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
{

        short gxt_result[2];
        uint8_t temp[8];
        int error;
        error = gxt_read_data(gxt_i2c_client,0,temp,3);
        gxt_result[0] = temp[0]*256+temp[1];
	 //gxt_result[1] = temp[3]*256+temp[4];	
        if(error>=0)
        {
                error = copy_to_user(buf, gxt_result, cnt);
                printk("temp = %d\n",gxt_result[0]);
        }
        else
        {
                printk("%s() i2c_read_data Failed!\n", __func__);
                return -1;
        }


        return 0;
}


/*字符设备操作函数集,.release函数实现*/
static int gxt_release(struct inode *inode, struct file *filp)
{

        printk("\n gxt release \n");
        /*向gxt sensor 发送睡眠命令,进入关机状态*/
        gxt_sleep();

         /*释放锁*/
        up(&sem);

        return 0;
}

/*字符设备操作函数集*/
static struct file_operations gxt_chr_dev_fops =
        {
                .owner = THIS_MODULE,
                .open = gxt_open,
                .read = gxt_read,
                .release = gxt_release,
};

/*----------------平台驱动函数集-----------------*/
static int gxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
{

        int ret = -1; //保存错误状态码
        sema_init(&sem,1);
        printk(KERN_EMERG "\t  match successed  \n");
        /*---------------------注册 字符设备部分-----------------*/

        //采用动态分配的方式,获取设备编号,次设备号为0,
        //设备名称为GXT_SENSOR,可通过命令cat  /proc/devices查看
        //DEV_CNT为1,当前只申请一个设备编号
        ret = alloc_chrdev_region(&gxt_devno, 0, DEV_CNT, DEV_NAME);
        if (ret < 0)
        {
                printk("fail to alloc gxt_devno\n");
                goto alloc_err;
        }

        //关联字符设备结构体cdev与文件操作结构体file_operations
        gxt_chr_dev.owner = THIS_MODULE;
        cdev_init(&gxt_chr_dev, &gxt_chr_dev_fops);

        // 添加设备至cdev_map散列表中
        ret = cdev_add(&gxt_chr_dev, gxt_devno, DEV_CNT);
        if (ret < 0)
        {
                printk("fail to add cdev\n");
                goto add_err;
        }

        /*创建类 */
        class_gxt = class_create(THIS_MODULE, DEV_NAME);

        /*创建设备 DEV_NAME 指定设备名,*/
        device_gxt = device_create(class_gxt, NULL, gxt_devno, NULL, DEV_NAME);
        gxt_i2c_client = client;
        return 0;

add_err:
        // 添加设备失败时,需要注销设备号
        unregister_chrdev_region(gxt_devno, DEV_CNT);
        printk("\n error! \n");
alloc_err:

        return -1;
}


static int gxt_remove(struct i2c_client *client)
{
        /*删除设备*/
        device_destroy(class_gxt, gxt_devno);     //清除设备
        class_destroy(class_gxt);                       //清除类
        cdev_del(&gxt_chr_dev);                 //清除设备号
        unregister_chrdev_region(gxt_devno, DEV_CNT); //取消注册字符设备
        return 0;
}



/*定义ID 匹配表*/
static const struct i2c_device_id gxt_device_id[] = {
        {"gxcas,gxt_sensor", 0},
        {}};

/*定义设备树匹配表*/
static const struct of_device_id gxt_of_match_table[] = {
        {.compatible = "gxcas,gxt_sensor"},
        {/* sentinel */}};

/*定义i2c总线设备结构体*/
struct i2c_driver gxt_driver = {
        .probe = gxt_probe,
        .remove = gxt_remove,
        .id_table = gxt_device_id,
        .driver = {
                .name = "gxcas,gxt",
                .owner = THIS_MODULE,
                .of_match_table = gxt_of_match_table,
        },
};

/*
*驱动初始化函数
*/
static int __init gxt_driver_init(void)
{
        int ret;
        pr_info("gxt_driver_init\n");
        ret = i2c_add_driver(&gxt_driver);
        gxt_reset();

        return ret;
}

/*
*驱动注销函数
*/
static void __exit gxt_driver_exit(void)
{
        pr_info("gxt_driver_exit\n");
        i2c_del_driver(&gxt_driver);
}

module_init(gxt_driver_init);
module_exit(gxt_driver_exit);

MODULE_LICENSE("GPL");



Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐