RT-Thread在正点原子apllo上使用IIC读取AP3216

1.  AP3216在STM32IGT6的PH4、PH5上,地址为0x1E,AP3216为标准IIC器件。

2. 写操作,

    根据读写时序,传输的struct rt_i2c_msg的addr设置为0x1E,flags设置为RT_I2C_WR,数据长度len为2,buf指向长度为2的数组,第一个数据为AP3216寄存器地址,第二个为要写入寄存器的值,然后使用rt_i2c_transfer()函数就可以了。

3. 读操作

    根据时序图,读操作与写操作开始基本相同,先发送AP3216地址与读信号,发送结束后再发送要读的寄存器地址,不同的是读取要先发送一个起始start信号,然后发送AP3216地址,然后读取返回的数据。在两次发送地址之间有一个重发的start信号,但是没有stop信号,如果使用两次rt_i2c_transfe()函数,会产生一个stop,操作可能失败,方法是定义一个struct rt_i2c_msg数组,这样声明赋值:   

    struct rt_i2c_msg msgs[2];

    msgs[0].addr = AP3216C_ADDR;
    msgs[0].flags = RT_I2C_WR;
    msgs[0].buf = ®
    msgs[0].len = 1;

    msgs[1].addr = AP3216C_ADDR;
    msgs[1].flags = RT_I2C_RD;
    msgs[1].buf = buf;
    msgs[1].len = len;

    rt_i2c_transfer(bus, msgs, 2);

    中间的其实信号,在RT-Thread系统的i2c-bit-ops中定义了i2c_bit_xfer()函数,此函数定义如下:

static rt_size_t i2c_bit_xfer(struct rt_i2c_bus_device *bus,
                              struct rt_i2c_msg         msgs[],
                              rt_uint32_t               num)
{
    struct rt_i2c_msg *msg;
    struct rt_i2c_bit_ops *ops = (struct rt_i2c_bit_ops *)bus->priv;
    rt_int32_t i, ret;
    rt_uint16_t ignore_nack;

    LOG_D("send start condition");
    i2c_start(ops);
    for (i = 0; i < num; i++)
    {
        msg = &msgs[i];
        ignore_nack = msg->flags & RT_I2C_IGNORE_NACK;
        if (!(msg->flags & RT_I2C_NO_START))
        {
            if (i)
            {
                i2c_restart(ops);
            }
            ret = i2c_bit_send_address(bus, msg);
            if ((ret != RT_EOK) && !ignore_nack)
            {
                LOG_D("receive NACK from device addr 0x%02x msg %d",
                        msgs[i].addr, i);
                goto out;
            }
        }
        if (msg->flags & RT_I2C_RD)
        {
            ret = i2c_recv_bytes(bus, msg);
            if (ret >= 1)
                LOG_D("read %d byte%s", ret, ret == 1 ? "" : "s");
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_EIO;
                goto out;
            }
        }
        else
        {
            ret = i2c_send_bytes(bus, msg);
            if (ret >= 1)
                LOG_D("write %d byte%s", ret, ret == 1 ? "" : "s");
            if (ret < msg->len)
            {
                if (ret >= 0)
                    ret = -RT_ERROR;
                goto out;
            }
        }
    }
    ret = i;

out:
    LOG_D("send stop condition");
    i2c_stop(ops);

    return ret;
}

      可以看出此函数首先通过i2c_start(ops) 发送起始信号,i=0,不执行i2c_stop(ops),当i>0时便执行此代码,调用i2c_restart(ops),实现重新发送一次start信号,然后发送地址,通过flag值判断读或者写,结束后发送stop信号。如果分两次调用rt_i2c_transfer()函数,就会发送两次i2c_stop(ops)即两次stop;

4. 最后附上一个简单代码事例

#include <rtthread.h>
#include <rtdevice.h>




//0x3c = 0011 1100 >> 1 --> 0001 1110
#define AP3216_ADD		0x1E

#ifndef AP3216_I2CBUS_NAME
#define AP3216_I2CBUS_NAME			"i2c2"  /* 连接的I2C总线设备名称 */
#endif

static struct rt_i2c_bus_device *ap3216_i2c_bus=RT_NULL;


static rt_err_t ap_write(rt_uint8_t addr, rt_uint8_t cmd)
{
	rt_uint8_t buf[2];
	struct rt_i2c_msg msgs;
	
	buf[0] 		= addr;
	buf[1]		= cmd;
	msgs.addr  	= AP3216_ADD;
	msgs.flags 	= RT_I2C_WR;
	msgs.buf	= buf;
	msgs.len	= 2;
	
	if(rt_i2c_transfer(ap3216_i2c_bus, &msgs, 1) != 1)
	{
		rt_kprintf("error when send %d %d", addr, cmd);
		return -RT_ERROR;
	}else{
		return RT_EOK;
	}
	
}

static rt_err_t ap_read(rt_uint8_t addr, rt_uint8_t *rtnum)
{
	struct rt_i2c_msg msgs[2];
	msgs[0].addr 	= msgs[1].addr \
					= AP3216_ADD;
	msgs[0].flags	= RT_I2C_WR;
	msgs[0].buf		= &addr;
	msgs[0].len		= 1;
	
	msgs[1].flags	= RT_I2C_RD;
	msgs[1].buf		= rtnum;
	msgs[1].len		= 1;
	
	if(rt_i2c_transfer(ap3216_i2c_bus, msgs, 2) != 2)
	{
		rt_kprintf("read failed regesiter %d", addr);
		return -RT_ERROR;
	}else{
		return RT_EOK;
	}
}

static rt_err_t ap3216_init(void)
{
	rt_uint8_t tmp;
	if(ap_write(0x00, 0x03) != RT_EOK)
	{
		rt_kprintf("init first failed\n");
		return -RT_ERROR;
	}else
	{
		rt_thread_mdelay(50);
		ap_read(0x00, &tmp);
	}
	
	if(tmp == 0x03)
		return RT_EOK;
	else{
		rt_kprintf("init second failed\n");
		return -RT_ERROR;
	}
}


static void i2c_ap3216_app(int argc, char *argv[])
{
    char name[RT_NAME_MAX];
	rt_uint8_t cnt;
	rt_uint8_t buf[6];
	rt_uint16_t ir, als, ps;
	
    if (argc == 2)
    {
        rt_strncpy(name, argv[1], RT_NAME_MAX);
    }
    else
    {
        rt_strncpy(name, AP3216_I2CBUS_NAME, RT_NAME_MAX);
    }
	
	
	/* 查找I2C总线设备,获取I2C总线设备句柄 */
    ap3216_i2c_bus = (struct rt_i2c_bus_device *)rt_device_find(name);

    if(ap3216_i2c_bus == RT_NULL)
    {
        rt_kprintf("can't find %s device!\n", name);
    }else{
		rt_kprintf("find i2c2\n");
	}
	ap3216_init();
	
	while(1){
		for(cnt = 0; cnt < 6; cnt++){
			ap_read(0x0A+cnt, buf+cnt);
		}

		if(buf[0]&0X80)ir=0;						//IR_OF位为1,则数据无效
		else ir=((rt_uint16_t)buf[1]<<2)|(buf[0]&0X03); 	//读取IR传感器的数据  
		als=((rt_uint16_t)buf[3]<<8)|buf[2];				//读取ALS传感器的数据   
		if(buf[4]&0x40)ps=0;    					//IR_OF位为1,则数据无效
		else ps=((rt_uint16_t)(buf[5]&0X3F)<<4)|(buf[4]&0X0F); //读取PS传感器的数据   
		rt_kprintf("%d\t",ir);
		rt_kprintf("%d\t",als);
		rt_kprintf("%d\t\n",ps);
		rt_thread_mdelay(500);
	}
}



/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(i2c_ap3216_app, i2c ap3216 app);
发布了4 篇原创文章 · 获赞 6 · 访问量 477

猜你喜欢

转载自blog.csdn.net/qq_38784061/article/details/104341239