QT5.12通过Linux应用层使用I2C通信

I2C总线是一种使用起来非常的方便的通信总线,主要由SCL(时钟线),SDA(数据线)组成。本文主要介绍如何在LINUX应用层使用I2C总线与外设芯片通信。实现的方式主要是通过O_RDWR   IOTCL实现。

下面的程序代码是基于QT5.12的环境编写的。

写I2C设备的函数实例

 

int I2C_Dev_Write(int fd, int slave_addr, QByteArray tx_cmd_data)
{
    struct i2c_rdwr_ioctl_data work_queue;
    int ret;

    work_queue.nmsgs = 1;

    work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs * sizeof(struct i2c_msg));
    if(!work_queue.msgs)
    {
        printf("msgs memery alloc error\n");
        return -1;
    }

    if ((work_queue.msgs->buf = (unsigned char *)malloc(tx_cmd_data.length() * sizeof(unsigned char))) == NULL)
    {
        printf("buf memery alloc error...\n");
        free(work_queue.msgs);
        return -1;
    }

    work_queue.msgs->len = tx_cmd_data.length();
    work_queue.msgs->flags = 0;
    work_queue.msgs->addr = slave_addr;
    for(int i=0;i<tx_cmd_data.length();i++)
    {
        work_queue.msgs->buf[i] = tx_cmd_data.at(i)&0xff;
    }

    ret=ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
    if(ret < 0)
    {
        printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
    }

    free(work_queue.msgs->buf);
    free(work_queue.msgs);

    return  ret;
}

读I2C设备的函数实例

QByteArray I2C_Dev_Read(int fd,int slave_addr,int reg_addr,int read_data_len)
{
    struct i2c_rdwr_ioctl_data work_queue;
    QByteArray ret_byte_array;
    int ret;
    int rx_data_len;

    ret_byte_array.clear();

    work_queue.nmsgs = 1;
    work_queue.msgs = (struct i2c_msg *)malloc(work_queue.nmsgs *sizeof(struct i2c_msg));
    if(work_queue.msgs==nullptr)
    {
        printf("Memery alloc error\n");
        return ret_byte_array;
    }

    rx_data_len = read_data_len;
    work_queue.msgs->buf = (unsigned char *)malloc(rx_data_len * sizeof(unsigned char));
    if (work_queue.msgs->buf == nullptr)
    {
        printf("rx buf memery alloc error...\n");
        free(work_queue.msgs);
        return ret_byte_array;
    }

    work_queue.msgs->flags = I2C_M_RD;
    work_queue.msgs->addr = slave_addr;
    work_queue.msgs->len = rx_data_len;
    memset(work_queue.msgs->buf,0x00,rx_data_len);

    ret = ioctl(fd, I2C_RDWR, (unsigned long) &work_queue);
    if(ret < 0)
    {
        printf("Error during I2C_RDWR ioctl with error code: %d\n", ret);
    }
    else
    {
        for(int i=0;i<rx_data_len;i++)
        {
            ret_byte_array.append(work_queue.msgs->buf[i]&0xff);
        }
    }

    free(work_queue.msgs->buf);
    free(work_queue.msgs);

    return ret_byte_array;
}

上面I2C设备读写函数主要是通过 “ struct  i2c_rdwr_ioctl_data ”  结构和 “ ioctl ” 函数实现的。可以看到上面两个函数的代码十分相似,主要区别在于 “ work_queue.msgs->flags ”和 “work_queue.msgs->buf ” 的赋值,根据I2C总线的规范要求, work_queue.msgs->flags为1时表示读设备数据,I2C从设备按照SCL线的时钟信号,返回内部寄存器的数据,寄存器的起始地址位最近一次写的寄存器地址。因此在对I2C设备读数据之前,应先通过写命令重置I2C设备内部的寄存器指向,使其指向要读的起始地址。

struct  i2c_rdwr_ioctl_data 的结构和struct i2c_msg的结构

/* This is the structure as used in the I2C_RDWR ioctl call */
struct i2c_rdwr_ioctl_data {
	struct i2c_msg *msgs;	/* pointers to i2c_msgs */
	__u32 nmsgs;			/* number of i2c_msgs */
};
struct i2c_msg {
	__u16 addr;	/* slave address			*/
	__u16 flags;
#define I2C_M_TEN		0x0010	/* this is a ten bit chip address */
#define I2C_M_RD		0x0001	/* read data, from slave to master */
#define I2C_M_STOP		0x8000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NOSTART		0x4000	/* if I2C_FUNC_NOSTART */
#define I2C_M_REV_DIR_ADDR	0x2000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_IGNORE_NAK	0x1000	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_NO_RD_ACK		0x0800	/* if I2C_FUNC_PROTOCOL_MANGLING */
#define I2C_M_RECV_LEN		0x0400	/* length will be first received byte */
	__u16 len;		/* msg length				*/
	__u8 *buf;		/* pointer to msg data			*/
};

在struct i2c_msg的结构中len成员的值为要读(或者写)的数据长度, 当flags成员的值为1时, *buf成员用于保存读到的数据;当时flags成员为0时,*buf成员中的数据为要写到I2C设备的数据。在写I2C设备时,*buf成员的第0个字节即buf[0]为要写入的寄存器地址,从buf[1]才是要写入的数据;addr成员为I2C设备的通信地址(7bit),“ ioctl ” 函数会对I2C设备地址左移并或上读写标记位。

基于Max44009数字光亮度传感器的读写实例

static unsigned char gy_49_tx_cmd01[8]={0x01,0x00};  //禁用中断
static unsigned char gy_49_tx_cmd02[8]={0x02,0x80};  //初始化芯片为自动模式

void MAX44009::Init(char dev_name[], U8 addr)
{
    m_addr=addr;    // 设备的I2C通信地址
    m_fd=I2C_Dev_Open(dev_name); //打开I2C设备,m_fd为文件描述符,后面读写操作时会用到
    if(m_fd==-1)
    {
        printf("MAX44009 Open I2C Bus Error\n");
    }
}

double MAX44009::Read_LUX(void)
{
    int value_e,value_m,ret;
    double ret_value;

    I2CWrite(m_addr,0x02,&gy_49_tx_cmd02[1],1);  

    for(int i=0;i<8;i++)  //依次读取芯片内部8个寄存器的数据
    {
        I2CWrite(m_addr,(U8)(i&0xff),nullptr,0);  //发送写命令,目的在于重置芯片内部的寄存器指针
        ret=I2CRead(m_addr,(U8)(i&0xff),&m_reg_map[i],1);//发送读命令,读取一个寄存器的数据
    }

    value_e=m_reg_map[LUX_HIGH_REG_ADDR]>>4;  //计算光亮度
    value_m=m_reg_map[LUX_HIGH_REG_ADDR];
    value_m<<=4;
    value_m|=(m_reg_map[LUX_LOW_REG_ADDR]&0x0f);

    ret_value=pow(2,value_e)*value_m+0.045;

    return  ret_value;

}

void MAX44009::I2CWrite(U8 addr,U8 reg_addr,U8 buf[],U8 len) //类中的写方法
{
    int tx_len;
    unsigned char tx_buf[128];

    tx_buf[0]=reg_addr;
    if(len>0)
    {
        for(int i=0;i<len;i++)
        {
            tx_buf[i+1]=buf[i];
        }
    }
    tx_len=len+1;

    I2C_Dev_Write(m_fd,addr,tx_buf,tx_len);
}

int MAX44009::I2CRead(U8 addr, U8 reg_addr, U8 rbuf[], U8 rlen) //类中的读方法
{
    int ret;

    ret=I2C_Dev_Read(m_fd,addr,reg_addr,rbuf,rlen);

    return ret;
}

运行结果

root@orangepione:~# ./test_i2c_app 
Read LUX From MAX44009
LUX=21.045000  //打开手电筒照射Max44009之前
LUX=22.045000
LUX=78.045000
LUX=75.045000
LUX=862.045000
LUX=6060032.045000  //打开手电筒照射Max44009之后
LUX=6057984.045000
LUX=6047744.045000
LUX=6864.045000
LUX=55.045000    //关闭手电筒之后
LUX=46.045000
LUX=28.045000

从上面的运行结果可以看出,MAX44009芯片对于外部环境的光源亮度还是很敏感的。做个简单的环境检测方面的应用是绰绰有余的。

 

  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
要在Linux使用ODBC库,需要进行以下步骤: 1. 安装ODBC驱动程序 首先需要安装ODBC驱动程序,比如unixODBC或者FreeTDS等。可以通过包管理器进行安装,比如Ubuntu可以使用以下命令安装: ``` sudo apt-get install unixodbc unixodbc-dev ``` 2. 安装ODBC插件 QT提供了ODBC插件,需要先编译安装。下载QT源代码,进入源代码目录,执行以下命令: ``` cd qtbase/src/plugins/sqldrivers/odbc qmake odbc.pro make sudo make install ``` 3. 配置ODBC数据源 使用ODBC需要先在系统中配置ODBC数据源。可以通过ODBC配置文件/etc/odbc.ini和/etc/odbcinst.ini进行配置。在odbc.ini中添加数据源,比如: ``` [mydsn] Driver = FreeTDS Description = My database Servername = myserver Database = mydatabase ``` 在odbcinst.ini中添加驱动程序信息,比如: ``` [FreeTDS] Description = FreeTDS ODBC driver Driver = /usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.so Setup = /usr/lib/x86_64-linux-gnu/odbc/libtdsS.so ``` 4. 在QT项目中使用ODBC 在QT项目中使用ODBC需要在.pro文件中添加以下内容: ``` QT += sql QT += core-private QT += network-private LIBS += -lodbc ``` 然后在代码中使用QSqlDatabase连接ODBC数据源: ``` QSqlDatabase db = QSqlDatabase::addDatabase("QODBC"); db.setDatabaseName("mydsn"); if (db.open()) { // 连接成功 } else { // 连接失败 } ``` 以上是在Linux使用QT5.12连接ODBC的基本步骤,具体的ODBC驱动程序和数据源配置可能会有所不同,需要根据实际情况进行调整。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值