打印
[PIC®/AVR®/dsPIC®产品]

【CuriosityNano测评报告】06.I2C通讯实验(结束篇)

[复制链接]
1829|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
#申请原创#

    在之前多天实验的基础上,今天通过将地址数据添加到要写入的数据之前的办法,实现了多字节数据写入,可以不用之前的通过循环逐个写入的笨办法。至此,PIC18F16Q40核心板的硬件I2C测试全部达到了目的,尽管使用了一些比较牵强附会的办法,如通过预先将双字节地址数据交换来解决高低字节地址错位、通过将地址信息添加到要写入的数据之前、重构数组的办法实现多字节数据的连续写入等。
    之所以本次执著地测试硬件I2C通讯,是因为以前的屡次测试均没有取得过成功,每次都是半途而废改用模拟I2C。相对而言,模拟I2C看得见、摸得着,动用起来更得心应手。而硬件I2C则因为不熟悉各种参数如何设置,也看不明白数据手册,只能凭着一知半解揣摩各个参数的应用。这次花费了一周时间,通过逻辑分析仪抓取时序,有针对性地尝试变更各个参数并观察实际结果,总算基本完成了测试计划,尽管有些代码或参数设置可能是多余的,代码也肯定有优化空间,但I2C通讯的测试将暂告一段落。
    本次分别测试了8位寄存器地址和16位寄存器地址的器件,单个字节和多个字节的读写操作,共计8种操作方式。除了8位地址的单字节读写操作和多字节读操作使用的是范例中现成的函数外,其他8位地址的多字节写、16位地址的单字节和多字节的读写操作都自己改写的函数。
    下面是这8个函数列表:
uint8_t  I2C1_Read1ByteRegister(i2c1_address_t address, uint8_t reg);                                //8位地址单字节读
void I2C1_Write1ByteRegister(i2c1_address_t address, uint8_t reg, uint8_t data);                  //8位地址单字节写
void I2C1_ReadDataBlock(i2c1_address_t address, uint8_t reg, uint8_t *data, size_t len);       //8位地址多字节读
void I2C_8addrBuffWrite(i2c1_address_t address, uint8_t reg, uint8_t *data, uint8_t len);       //8位地址多字节写
uint8_t I2C_16addr_ByteRead(i2c1_address_t address, uint16_t reg);                                   //16位地址单字节读
void I2C_16addr_BuffRead(i2c1_address_t address,uint16_t reg,uint8_t *data,uint8_t len);     //16位地址多字节读
void I2C_16addr_ByteWrite(i2c1_address_t address,uint16_t reg,uint8_t data);                      //16位地址单字节写
void I2C_16addr_BuffWrite(i2c1_address_t address, uint16_t reg, uint8_t *data, uint8_t len);  //16位地址多字节写


    这是我自己改写的5个操作函数代码:
void I2C_8addrBuffWrite(i2c1_address_t address, uint8_t reg, uint8_t *data, uint8_t len)
{
    uint8_t i,Buffer[20];
    Buffer[0] = reg;
    for(i=1; i<(len+1); i++){
        Buffer[i] = data[i-1];
    }
    i = i + 1;
   
    while(!I2C1_Open(address));             // sit here until we get the bus..
    I2C1_SetBuffer(Buffer,i);
    I2C1_SetAddressNackCallback(NULL,NULL); //NACK polling?
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close());       // sit here until finished.
}

uint8_t I2C_16addr_ByteRead(i2c1_address_t address, uint16_t reg)
{
    uint8_t dat = 0x00;
    uint16_t addr = reg<<8 | reg>>8;
   
    while(!I2C1_Open(address));                                                  // 打开I2C设备.
    I2C1_SetDataCompleteCallback(rd1RegCompleteHandler,&dat); // 传递数据指针
    I2C1_SetBuffer(&addr,2);                                                       // 指定数据地址
    I2C1_SetAddressNackCallback(NULL,NULL);                             // 等待应答
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close());                                       // 等待操作结束
   
    return dat;
}

void I2C_16addr_BuffRead(i2c1_address_t address,uint16_t reg,uint8_t *data,uint8_t len)
{
    uint16_t addr;
   
    addr = reg<<8 | reg>>8;
   
    i2c1_buffer_t bufferBlock; // result is little endian
    bufferBlock.data = data;
    bufferBlock.len = len;

    while(!I2C1_Open(address)); // sit here until we get the bus..
    I2C1_SetDataCompleteCallback(rdBlkRegCompleteHandler,&bufferBlock);
    I2C1_SetBuffer(&addr,2);
    I2C1_SetAddressNackCallback(NULL,NULL); //NACK polling?
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close()); // sit here until finished.
   
}


void I2C_16addr_ByteWrite(i2c1_address_t address,uint16_t reg,uint8_t data)
{
    uint8_t Buffer[3];
    Buffer[0] = reg>>8;
    Buffer[1] = reg;
    Buffer[2] = data;

    while(!I2C1_Open(address));                       // 打开I2C器件
    I2C1_SetBuffer(Buffer,3);                            // 写入3个字节数据(地址2+数据1)
    I2C1_SetAddressNackCallback(NULL,NULL);  // NACK polling?
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close());            // 等待写操作完成
   
}


void I2C_16addr_BuffWrite(i2c1_address_t address, uint16_t reg, uint8_t *data, uint8_t len)
{
    uint8_t i,Buffer[20];
    Buffer[0] = reg>>8;                                // 地址高字节
    Buffer[1] = reg;                                      // 地址低字节
    for(i=2; i<(len+2); i++){
        Buffer[i] = data[i-2];                           // 将要写入的数据依次排列在数组后面
    }
    i = len + 2;
   
    while(!I2C1_Open(address));                   // 打开I2C器件
    I2C1_SetBuffer(Buffer,i);                         // 写入多个字节数据
    I2C1_SetAddressNackCallback(NULL,NULL); // NACK polling?
    I2C1_MasterWrite();
    while(I2C1_BUSY == I2C1_Close());         // 等待写操作完成
}



    下面是测试成功抓取的时序图:
    这是AT24C32EEPROM的16位地址多字节读取的时序:


    这是读完多字节之后紧接着再读单个字节的时序,可以看出两次操作之间的间隔虽短,但不影响读操作进行:


    这是16位地址多字节写操作的时序:


    写完多字节数据之后,紧接着又进行写入单个字节的操作,但这两个操作之间必须间隔一定时间,否则后面的写操作不能正常完成:


    下图中可以完整看出两个写操作的过程:


    最后是本次测试过程中的照片:


使用特权

评论回复
沙发
CoolSilicon| | 2021-6-8 16:26 | 只看该作者
使用MCC生成的I2C代码,是直接可以用..不用自己去配置那么费劲啦.

另外, 赞一个楼主!!!少见的使用逻辑分析仪来做I2C的,专业!!

使用特权

评论回复
板凳
单片小菜| | 2021-6-8 16:28 | 只看该作者
楼主太赞了,细致入微,很棒。

使用特权

评论回复
地板
便携手到老| | 2021-6-8 17:31 | 只看该作者
这个**确实不错的。

使用特权

评论回复
5
huquanz711| | 2021-6-8 18:35 | 只看该作者
测试夹具不错

使用特权

评论回复
6
hu9jj|  楼主 | 2021-6-9 08:51 | 只看该作者
CoolSilicon 发表于 2021-6-8 16:26
使用MCC生成的I2C代码,是直接可以用..不用自己去配置那么费劲啦.

另外, 赞一个楼主!!!少见的使用逻辑分析 ...

逻辑分析仪是个有力的工具,否则看不见、摸不着,还不知道问题出在哪里。

使用特权

评论回复
7
hu9jj|  楼主 | 2021-6-9 08:52 | 只看该作者
单片小菜 发表于 2021-6-8 16:28
楼主太赞了,细致入微,很棒。

谢谢称赞!

使用特权

评论回复
8
hu9jj|  楼主 | 2021-6-9 08:52 | 只看该作者
便携手到老 发表于 2021-6-8 17:31
这个**确实不错的。

谢谢夸奖!仅仅是测试过程的一个小结而已。

使用特权

评论回复
9
lcczg| | 2021-6-9 10:22 | 只看该作者
很棒的调试。

使用特权

评论回复
10
自己造声卡| | 2021-6-9 12:32 | 只看该作者
逻辑分析仪吗?还是什么?

使用特权

评论回复
11
dql2015| | 2021-6-9 13:17 | 只看该作者
不错不错,逻辑分析仪不错

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:Microchip
简介:让我们来为您提供帮助。我们可提供各种资源来帮助您解决一切问题。是否需要与我们的客户支持团队联系?您可以通过电话、在线聊天功能或电子邮件与他们联系。

151

主题

1059

帖子

11

粉丝