platform tree架构下i2c应用实例(HS3003)

目录

概述

[1 探究platform tree下的i2c](#1 探究platform tree下的i2c)

[1.1 platform tree下的i2c驱动](#1.1 platform tree下的i2c驱动)

[1.2 查看i2c总线下的设备](#1.2 查看i2c总线下的设备)

[1.3 使用命令读写设备寄存器](#1.3 使用命令读写设备寄存器)

[2 认识HS3003](#2 认识HS3003)

[2.1 HS3003特性](#2.1 HS3003特性)

[2.2 HS3003寄存器](#2.2 HS3003寄存器)

[2.2.1 温湿度数据寄存器](#2.2.1 温湿度数据寄存器)

[2.2.2 参数寄存器](#2.2.2 参数寄存器)

[2.2.3 一个参数配置Demo](#2.2.3 一个参数配置Demo)

[2.3 温湿度值转换](#2.3 温湿度值转换)

[2.4 HS3003应用电路](#2.4 HS3003应用电路)

[2.4.1 PIN引脚定义](#2.4.1 PIN引脚定义)

[2.4.2 sensor 应用电路](#2.4.2 sensor 应用电路)

[3 驱动程序实现](#3 驱动程序实现)

[4 测试程序实现](#4 测试程序实现)

[5 编译和验证](#5 编译和验证)

[6 波形分析](#6 波形分析)


概述

本文主要介绍platform tree架构下i2c驱动的使用方法,并介绍如何使用i2c-tools来探测总线上的设备信息。然后详细介绍HS3003的芯片的使用方法,并使用i2c驱动接口,实现该芯片的驱动程序,然后再板卡上测试验证该程序,并通过逻辑分析仪查看这个读写过程的波形。

1 探究platform tree下的i2c

1.1 platform tree下的i2c驱动

启动板卡,查询/dev/下驱动情况 , 使用命令:

bash 复制代码
ls /dev/  -l

执行命名后,可列出该目录下所有的驱动信息,找出i2c驱动,如下:

由上图可得,板卡driver下,由两个i2c接口,分别为i2c-0和i2c-1

1.2 查看i2c总线下的设备

i2c总线上可以挂载多个device,其要求在同一条总线上,每个设备的地址必须唯一性。如果两个设备的地址一样,会出现时序混乱。

下面通过命令来探测一下i2c总线下的设备情况

1) 查看i2c-0下设备情况

使用命令

bash 复制代码
 i2cdetect -a 0

执行该命令后,列出设备地址信息: 该总线下有两个设备,其地址分别为:0x1a和0x1e

2) 查看i2c-1下设备情况

使用命令

bash 复制代码
i2cdetect -a 1

执行该命令后,列出设备地址信息: 该总线下有三个设备,其地址分别为:0x40,0x44,和0x44

1.3 使用命令读写设备寄存器

使用 i2c-tools 工具包提供了一些非常方便的工具来对系统的 I2C 总线进行调试。下面以HS3003为例,使用i2c-tools工具来操作其内部的寄存器。

1)查看设备地址0x44下所有的寄存器信息

复制代码
i2cdump  -f -y 1 0x44

2) 读取寄存器的值

复制代码
i2cget -f -y 1 0x44 0x06

3)写寄存器的值

i2cset -f -y 1 0x44 0xA0 0x10 0x40

2 认识HS3003

2.1 HS3003特性

HS3003是瑞萨公司出品的一款高精度温湿度传感器,下面看看其主要参数:

2.2 HS3003寄存器

HS3003采用标准的I2C通信方式,对其寄存器的操作必须遵循标准的I2C时序。现在分析如何操作其寄存器,读取数据。

2.2.1 温湿度数据寄存器

温湿度数据寄存器的数据位定义如下,其主要由四个字节组成一个32bit数据, bit-0 和 bit-1为Mask,其主要用来标记当前数据是否有效(mask =0 数据有效), 温度数据(低16 bit ): bit-2 ~ bit ~ 15

湿度数据( 高16 bit): bit-8 ~ bit 13

采样温湿度数据间隔时间根据配置的ADC精度来选取,精度要求越高,采样所需要的时间就越长。那么读取数据时,需要等待的时间就越长。

2.2.2 参数寄存器

精度参数如下:

参数寄存器列表

如何配置参数呢?芯片手册给了四个步骤

2.2.3 一个参数配置Demo

下面给一个各一个配置参数的范例,配置humidity 的采集精度为12bit, 那么参数设定如下:

bit-10: 0

bit-11: 1

cpp 复制代码
typedef struct
{
   unsigned short res1          : 10;
   unsigned short tempdata      : 2;
   unsigned short res2          : 4;
} stru_para_bit;

typedef struct{
   union
   {
      unsigned short data;
      stru_para_bit para_bit;
   };
}stru_para;


int hs300x_init(void)
{
    int ret;
    unsigned char   buff[4];
    stru_para para;
    
    // step-1 write data from 0x06
    buff[0] = 0x06;
    buff[1] = 0;
    buff[2] = 0;
    ret = write(fd, buff, 3);
    if( ret < 0 )
    {
        printf("read temper cmd to hs3003 register failure.\n");
        return -1;
    }
    
    // step -2: read reg - 0x81
    buff[0] = 0x81;
    ret = write(fd, buff, 1);
    if( ret < 0 )
    {
        printf("read cmd to hs3003 register failure. \r\n");
        return -1;
    }
    
    ret = read(fd, buff, 2);
    if( ret < 0 )
    {
        printf("write cmd to hs3003 register failure.\n");
        return -1;
    }
    printf(" read reg: 0x81 - data0 = %02x data1 = %02x \r\n",buff[0],buff[1]);
    
    //step -3:  write data from 0x46
    para.data = buff[0]<<8 | buff[1];
    para.para_bit.tempdata = 1; 
    buff[0] = 0x46;
    buff[1] = (unsigned char)para.data;
    buff[2] = (unsigned char)(para.data>>8);
    
    ret = write(fd, buff, 3);
    if( ret < 0 )
    {
        printf("write cmd to hs3003 register failure. \r\n");
        return -1;
    }
    printf("write reg: 0x46 - data0 = %02x data1 = %02x \r\n",buff[0],buff[1]);
    
    return 0;
}

2.3 温湿度值转换

datasheet中给的转换公式如下:

下面看看在程序中如何实现温湿度值转换的

首先定义一个数据结构

cpp 复制代码
typedef struct
{
   unsigned int mask          : 2;
   unsigned int tempdata      : 14;
   unsigned int humidydata    : 14;
   unsigned int res           : 2;
} Datafetch_bit;

typedef struct{
   union
   {
      unsigned int data;
      Datafetch_bit fetch_bit;
   };
   float tempval;
   float humival;
}hs300x_data;

从温湿度的数据寄存器中读取出来有四个分别为8bit的数据, 将该数据拼成一个32bit的数据,在赋值给data, 上述数据结构会自动解析该数据。通过mask位判断数据是否有效。

cpp 复制代码
    phs300x_data->data = ((buff[0] << 24U) |(buff[1] << 16U) |(buff[2] << 8U)|(buff[3]));
    if( phs300x_data->fetch_bit.mask == HS300X_DATA_VALID){
        // get temperature value 
        val = phs300x_data->fetch_bit.tempdata;
        phs300x_data->tempval = (double)val/(double)(HS300X_DATA_FACTOR) * 165.0 - 40;

        printf(" - TM(C): %.2f \r\n", phs300x_data->tempval);

        // get humidity value 
        val = phs300x_data->fetch_bit.humidydata;
        phs300x_data->humival = (double)val/(double)(HS300X_DATA_FACTOR) * 100.0;
        
        printf(" - HM(\%): %.2f \r\n", phs300x_data->humival);
    }

2.4 HS3003应用电路

2.4.1 PIN引脚定义

传感器封装

pin引脚

2.4.2 sensor 应用电路

下面是传感器模块的实际应用电路:

3 驱动程序实现

编写驱动程序代码:

cpp 复制代码
/***************************************************************
Copyright  2024-2029. All rights reserved.
文件名     : drv_hs3003.c
作者       : tangmingfei2013@126.com
版本       : V1.0
描述       : hs3003驱动程序
其他       : 无
日志       : 初版V1.0 2024/02/01

***************************************************************/
#include <sys/types.h>
#include <sys/stat.h>
#include <linux/types.h>
#include <linux/i2c-dev.h>
#include <linux/i2c.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <linux/fs.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <time.h>

/* hs3003 i2c address */
#define HS300X_ADDR                          (0x44U)

#define HS300X_DATA_VALID                    (0x00U)
#define HS300X_DATA_STALE                    (0x01U)
#define HS300X_STATUS_MASK                   (0xC0000000U)
#define HS300X_STATUS_POS                    (30U)

#define HS300X_DATA_MASK                     (0x3FFFFFFCU)
#define HS300X_HUMI_DATA_MASK                (0x3FFF0000U)
#define HS300X_HUMI_DATA_POS                 (16U)
#define HS300X_TEMP_DATA_MASK                (0x0000FFFCU)
#define HS300X_TEMP_DATA_POS                 (2U)

#define HS300X_REG_R_TRG                     0X06
#define HS300X_REG_W_TRG                     0X46

/* calculation formula, 2^14 - 1 */
#define HS300X_DATA_FACTOR                   (16383U)

#define DEV_FILE                              "/dev/i2c-1"

typedef struct
{
   unsigned int mask          : 2;
   unsigned int tempdata      : 14;
   unsigned int humidydata    : 14;
   unsigned int res           : 2;
} Datafetch_bit;

typedef struct{
   union
   {
      unsigned int data;
      Datafetch_bit fetch_bit;
   };
   float tempval;
   float humival;
}hs300x_data;

typedef struct
{
   unsigned short res1          : 10;
   unsigned short tempdata      : 2;
   unsigned short res2          : 4;
} stru_para_bit;

typedef struct{
   union
   {
      unsigned short data;
      stru_para_bit para_bit;
   };
}stru_para;

static int fd = -1;


static int hs300x_drv_init(void)
{
    fd = open(DEV_FILE, O_RDWR);
    if( fd < 0 )
    {
        close( fd );
        printf("%s %s i2c device open failure: %s\n", __FILE__, __FUNCTION__, strerror(errno));
        return -1;
    }

    ioctl(fd, I2C_TENBIT, 0);
    ioctl(fd, I2C_SLAVE, HS300X_ADDR);
    
    printf("init hs3003!\r\n");
    return fd;
}

int hs300x_init(void)
{
    int ret;
    unsigned char   buff[4];
    stru_para para;
    
    hs300x_drv_init();
    
    // step-1 write data from 0x06
    buff[0] = 0x06;
    buff[1] = 0;
    buff[2] = 0;
    ret = write(fd, buff, 3);
    if( ret < 0 )
    {
        printf("read temper cmd to hs3003 register failure.\n");
        return -1;
    }
    
    // step -2: read reg - 0x81
    buff[0] = 0x81;
    ret = write(fd, buff, 1);
    if( ret < 0 )
    {
        printf("read cmd to hs3003 register failure. \r\n");
        return -1;
    }
    
    ret = read(fd, buff, 2);
    if( ret < 0 )
    {
        printf("write cmd to hs3003 register failure.\n");
        return -1;
    }
    printf(" read reg: 0x81 - data0 = %02x data1 = %02x \r\n",buff[0],buff[1]);
    
    //step -3:  write data from 0x46
    para.data = buff[0]<<8 | buff[1];
    para.para_bit.tempdata = 1; 
    buff[0] = 0x46;
    buff[1] = (unsigned char)para.data;
    buff[2] = (unsigned char)(para.data>>8);
    
    ret = write(fd, buff, 3);
    if( ret < 0 )
    {
        printf("write cmd to hs3003 register failure. \r\n");
        return -1;
    }
    printf("write reg: 0x46 - data0 = %02x data1 = %02x \r\n",buff[0],buff[1]);
    
    return 0;
}

int hs300x_read_value(hs300x_data *phs300x_data)
{
    int ret;
    unsigned char buff[4];
    unsigned int val;
    stru_para para;

    // write data to 0xa0
    para.data = 0;
    buff[0] = 0xa0;
    buff[1] = (unsigned char)para.data;
    buff[2] = (unsigned char)(para.data>>8);
    ret = write(fd, buff, 3);
    if( ret < 0 )
    {
        printf("write cmd to hs3003 register failure.\n");
        return -1;
    }
    sleep(1);
    
    ret = read(fd, buff, 4);
    if( ret < 0 )
    {
        printf("get the hs3003 value failure.\n");
        return -1;
    }
    printf(" - data0 = %02x data1 = %02x data3 = %02x data4 = %02x \r\n",buff[0],buff[1],buff[2],buff[3]);
    
    phs300x_data->data = ((buff[0] << 24U) |(buff[1] << 16U) |(buff[2] << 8U)|(buff[3]));
    if( phs300x_data->fetch_bit.mask == HS300X_DATA_VALID){
        // get temperature value 
        val = phs300x_data->fetch_bit.tempdata;
        phs300x_data->tempval = (double)val/(double)(HS300X_DATA_FACTOR) * 165.0 - 40;

        printf(" - TM(C): %.2f \r\n", phs300x_data->tempval);

        // get humidity value 
        val = phs300x_data->fetch_bit.humidydata;
        phs300x_data->humival = (double)val/(double)(HS300X_DATA_FACTOR) * 100.0;
        
        printf(" - HM(\%): %.2f \r\n", phs300x_data->humival);
    }
    
    return 0;
}

4 测试程序实现

编写测试程序来验证该驱动程序

cpp 复制代码
int main(void)
{
    hs300x_data stru_hs300x;
    int count_run = 10000;
    int set;

    set = hs300x_init();
    if( set < 0){
        printf("initial hs3003 failure.\r\n");
        return -1;
    }

    while( count_run > 0){
        set = hs300x_read_value( &stru_hs300x );
        if(set != -1)
        {
            //printf( "\r\n lux:  %d ", temper);
        }
        else{
            printf("read isl19035 failure. \r\n");
        }
        count_run--;
        sleep(1);
    }
    
    return 0;
}

5 编译和验证

编写Makefile ,编译测试代码,并将其copy到共享目录下,方便在板卡中运行该App

python 复制代码
CFLAGS= -Wall -O2
CC=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc
STRIP=/home/ctools/gcc-linaro-4.9.4-arm-linux-gnueabihf/bin/arm-linux-gnueabihf-strip


dev_13_hs3003: dev_13_hs3003.o
	$(CC) $(CFLAGS) -o dev_13_hs3003 dev_13_hs3003.o
	$(STRIP) -s dev_13_hs3003

clean:
	rm -f dev_13_hs3003 dev_13_hs3003.o

编译代码

运行App, 测试程序能正确地读取温度和湿度值。

6 波形分析

1)触发数据转换命令

2)读数据波形

3) 逻辑分析仪解析到的数据列表

相关推荐
不是三毛没有半4 分钟前
Centos 7 安装wget
linux
?crying32 分钟前
蓝队基础1 -- 企业信息架构与安全基础
安全·架构
叫我龙翔34 分钟前
【计网】实现reactor反应堆模型 --- 多线程方案优化 ,OTOL方案
linux·运维·网络
mit6.82436 分钟前
[Docker#9] 存储卷 | Volume、Bind、Tmpfs | -v/mount | MySQL 灾难恢复 | 问题
linux·运维·docker·容器·架构
WangYaolove13141 小时前
请解释Python中的装饰器是什么?如何使用它们?
linux·数据库·python
7yewh1 小时前
嵌入式硬件实战提升篇(一)-泰山派RK3566制作多功能小手机
linux·arm开发·驱动开发·嵌入式硬件·物联网·智能手机·硬件架构
YRr YRr2 小时前
ubuntu ros 解决建完图后 保存的地图非常小的问题
linux·运维·ubuntu
脸ル粉嘟嘟2 小时前
常用命令之Linux&Oracle&Hive&Python
linux·hive·oracle
Wils0nEdwards2 小时前
Leetcode 整数转罗马数字
linux·python·leetcode
@晓凡3 小时前
STM32编程遇到的问题随笔【一】
stm32·单片机·嵌入式硬件