首页 > 其他分享 >硬件IIC的7位从机地址查询方式读写参考代码

硬件IIC的7位从机地址查询方式读写参考代码

时间:2022-12-16 10:24:51浏览次数:78  
标签:return IIC mem 读写 uint8 从机 timeout I2C

目录

本文中使用582测试,在整合先前博客中的代码的基础上,加上读写超时,加上返回值,加上16位从机寄存器地址的判断,希望读写各用一个函数就能解决硬件IIC的使用问题。

#include "CH58x_common.h"

#define TIME_OUT    10000            //用于IIC读写超时,等待n次
#define DELAY_IIC   DelayUs(5)   //用于IIC读写超时,设置一次等待的时长

#define HOST_NO_ADDR     0x66   //随便设置,对主机不影响
#define EEPROM_ADDR      0xA0   //EEPROM设备地址

uint8_t IIC_read_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_des, uint8_t len);
uint8_t IIC_write_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_src, uint8_t len);

uint8_t wData[32] = {8};            //存放即将写的数据
uint8_t rData[32] = {0};            //存放读取出的数据

uint8_t mem_writing[5] = {0x10, 0x20, 0x30, 0x40, 0x50};        //存放8位的目标内存/寄存器
uint16_t mem_writing2[2] = {0x1020, 0x2022};                //存放16位的目标内存/寄存器

const uint8_t data[5][20] = {       //随便写一些数值,每行第一个字节表示之后的字节长度
        {8,1,2,3,4,5,6,7,8},
        {5,10,48,48,77,3},
        {7,168,42,44,145,1,38,44},
        {6,4,44,145,1,16,44},
        {6,48,47,46,45,44,43},
};

int main()
{
    SetSysClock(CLK_SOURCE_PLL_80MHz);

    GPIOA_SetBits(GPIO_Pin_9);  //串口1GPIO初始化,TXD在配置推挽输出前先置位
    GPIOA_ModeCfg(GPIO_Pin_8, GPIO_ModeIN_PU);
    GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
    UART1_DefInit();                                //串口初始化

    GPIOB_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13, GPIO_ModeIN_PU);
    I2C_Init(I2C_Mode_I2C, 400000, I2C_DutyCycle_16_9, I2C_Ack_Enable, I2C_AckAddr_7bit, HOST_NO_ADDR);
    DelayMs(300);       //上电延时
    PRINT("---------Init_OK---------\n");

    while(1)
    {
        uint8_t trans_num = 0;

        for(uint8_t k=0; k<2; k++)              //16位目标内存/寄存器读写
        {
            trans_num = data[k][0] + 1;
            memcpy(wData, data[k], trans_num);
            PRINT("Writing to 0x%02x:", mem_writing2[k]);

            for(uint8_t i=0; i<trans_num; i++)
            {
                PRINT("%x ", wData[i]);
            }
            PRINT("\n");

            IIC_write_nBytes(EEPROM_ADDR, mem_writing2[k], 1, wData, trans_num);
            DelayMs(100);
            IIC_read_nBytes(EEPROM_ADDR, mem_writing2[k], 1, rData, trans_num);

            PRINT("Read  form 0x%02x:", mem_writing2[k]);
            for(uint8_t i=0; i<trans_num; i++)
            {
                PRINT("%x ", rData[i]);
                rData[i] = 0;
            }
            PRINT("\n");
            DelayMs(100);
        }

        DelayMs(500);

        for(uint8_t k=0; k<5; k++)          //16位目标内存/寄存器读写
        {
            trans_num = data[k][0] + 1;
            memcpy(wData, data[k], trans_num);
            PRINT("Writing to 0x%02x:", mem_writing[k]);

            for(uint8_t i=0; i<trans_num; i++)
            {
                PRINT("%x ", wData[i]);
            }
            PRINT("\n");

            IIC_write_nBytes(EEPROM_ADDR, mem_writing[k], 0, wData, trans_num);
            DelayMs(100);
            IIC_read_nBytes(EEPROM_ADDR, mem_writing[k], 0, rData, trans_num);

            PRINT("Read  form 0x%02x:", mem_writing[k]);
            for(uint8_t i=0; i<trans_num; i++)
            {
                PRINT("%x ", rData[i]);
                rData[i] = 0;
            }
            PRINT("\n");
            DelayMs(100);
        }

        DelayMs(1000);
    }
}

uint8_t IIC_timeout(uint16_t *p_times)      //判断读写等待过程中是否超时
{
    (*p_times)++;
    DELAY_IIC;
    if(*p_times > TIME_OUT)
    {
        return 1;
    }
    return 0;
}

/***************************************
 * 从从机的某寄存器起始,连续读取n个字节的数据
 * 参数:addr 从机地址
 *      mem 内存/寄存器地址
 *      men_16 是否为16位内存/寄存器地址
 *      p_des 目的地址指针
 *      len 读取长度
 * 返回值:0:正常
 *      1~7:卡在第n步
 *      0xFF:卡在连续读的过程中
 */

uint8_t IIC_read_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_des, uint8_t len)
{
    uint16_t i_timeout = 0;

//主机通知从机要读取它的哪块内存
    while(I2C_GetFlagStatus(I2C_FLAG_BUSY))                            //IIC主机判忙
    {
        if(IIC_timeout(&i_timeout))
            return 1;
        else i_timeout = 0;
    }

    I2C_GenerateSTART(ENABLE);                                          //起始信号
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT))                //判断BUSY, MSL and SB flags
    {
        if(IIC_timeout(&i_timeout))
            return 2;
        else i_timeout = 0;
    }

    I2C_Send7bitAddress(addr, I2C_Direction_Transmitter);               //发送器件地址+最低位0表示为“写”
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))  //判断BUSY, MSL, ADDR, TXE and TRA flags
    {
        if(IIC_timeout(&i_timeout))
            return 3;
        else i_timeout = 0;
    }

    if(mem_16)
    {
        I2C_SendData((uint8_t)(mem>>8));                                    //发送内存地址的高8位

        while(!I2C_GetFlagStatus(I2C_FLAG_TXE))                             //获取TxE的状态    数据寄存器为空标志位,可以向其中写数据
        {
            if(IIC_timeout(&i_timeout))
                return 4;
            else i_timeout = 0;
        }
    }

    I2C_SendData((uint8_t)mem);                                         //发送内存地址的低8位
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED))           //判断TRA, BUSY, MSL, TXE and BTF flags
    {
        if(IIC_timeout(&i_timeout))
            return 5;
        else i_timeout = 0;
    }

//直接产生一个重起始信号即可开始读的过程
    I2C_GenerateSTART(ENABLE);                                          //重起始信号
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT))                //判断BUSY, MSL and SB flags
    {
        if(IIC_timeout(&i_timeout))
            return 6;
        else i_timeout = 0;
    }

    I2C_Send7bitAddress(addr, I2C_Direction_Receiver);                  //发送地址+最低位1表示为“读”
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))     //判断BUSY, MSL and ADDR flags
    {
        if(IIC_timeout(&i_timeout))
            return 7;
        else i_timeout = 0;
    }

    I2C_GenerateSTOP(DISABLE);                                          
    //关闭停止信号使能(某些情况下可能会在此清除PE,这一行可以去掉)

    for(uint8_t i=0; i<len; i++)
    {
        if(i == len-1)
        I2C_AcknowledgeConfig(DISABLE);         
        //清除ACK位(某些情况下可能会在此清除PE,这一行可以去掉,但是逻辑分析仪抓时序,会多接收一个字节数据)
        //主设备为了能在收到最后一个字节后产生一个NACK信号,必须在读取倒数第二个字节之后(倒数第二个RxNE 事件之后)清除ACK位(ACK=0)

        while(!I2C_GetFlagStatus(I2C_FLAG_RXNE))                        //获取RxEN的状态,等待收到数据
        {
            if(IIC_timeout(&i_timeout))
                return 0xff;
            else i_timeout = 0;
        }

        *(p_des+i) = I2C_ReceiveData();                                   //获得从机的寄存器中的数据
    }

    I2C_GenerateSTOP(ENABLE);                                           //使能停止信号
    I2C_AcknowledgeConfig(ENABLE);                                      //传输完毕,再次打开ACK使能

    return 0;
}

/***************************************
 * 向从机某寄内存地址起始,连续写入n个字节的数据
 * 参数:addr 从机地址
 *      mem 寄存器地址
 *      men_16 是否为16位内存/寄存器地址
 *      p_src 源地址指针
 *      len 读取长度
 * 返回值:0:正常
 *      1~5:卡在第n步
 *      0xFF:卡在连续写的过程中
 */
uint8_t IIC_write_nBytes(uint8_t addr, uint16_t mem, uint8_t mem_16, uint8_t *p_src, uint8_t len)
{
    uint16_t i_timeout = 0;
//主机通知从机要写它的哪块内存
    while(I2C_GetFlagStatus(I2C_FLAG_BUSY))                             //IIC主机判忙
    {
        if(IIC_timeout(&i_timeout))
            return 1;
        else i_timeout = 0;
    }

    I2C_GenerateSTART(ENABLE);                                          //起始信号
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_MODE_SELECT))                //判断BUSY, MSL and SB flags
    {
        if(IIC_timeout(&i_timeout))
            return 2;
        else i_timeout = 0;
    }

    I2C_Send7bitAddress(addr, I2C_Direction_Transmitter);               //发送地址+最低位0表示为“写”
    while(!I2C_CheckEvent(I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) //判断BUSY, MSL, ADDR, TXE and TRA flags
    {
        if(IIC_timeout(&i_timeout))
            return 3;
        else i_timeout = 0;
    }

    if(mem_16)
    {
        I2C_SendData((uint8_t)(mem>>8));                                    //发送内存地址的高8位

        while(!I2C_GetFlagStatus(I2C_FLAG_TXE))                             //获取TxE的状态    数据寄存器为空标志位,可以向其中写数据
        {
            if(IIC_timeout(&i_timeout))
                return 4;
            else i_timeout = 0;
        }
    }

    I2C_SendData((uint8_t)mem);                                         //发送内存地址的低8位

//ACK之后直接写入数据
    for(uint8_t i=0; i<len; i++)
    {
        while(!I2C_GetFlagStatus(I2C_FLAG_TXE))                         //获取TxE的状态    数据寄存器为空标志位,可以向其中写数据
        {
            if(IIC_timeout(&i_timeout))
                return 0xff;
            else i_timeout = 0;
        }
        I2C_SendData(*(p_src+i));                                         //发送数据
    }

    while(!I2C_CheckEvent(I2C_EVENT_MASTER_BYTE_TRANSMITTED))           //判断TRA, BUSY, MSL, TXE and BTF flags
    {
        if(IIC_timeout(&i_timeout))
            return 5;
        else i_timeout = 0;
    }

    I2C_GenerateSTOP(ENABLE);                                           //停止信号

    return 0;
}

标签:return,IIC,mem,读写,uint8,从机,timeout,I2C
From: https://www.cnblogs.com/JayWellsBlog/p/16986611.html

相关文章

  • uniapp本地文件读写操作
    说明主要是封装官方文档里面的官方文档地址:https://www.html5plus.org/doc/zh_cn/io.html创建或打开文件//fileName目录路径dirEntry之前打开过的目录(没有则不填写......
  • Python14 文件读写和编码&OS、path模块的使用
    编码文件读写操作#作者:咸瑜file=open("text.txt","r",encoding="utf-8")print(file.readlines())#['姓名:咸瑜\n','年龄:18\n','籍贯:广东·惠州']file.clo......
  • 硬件IIC调试问题排查
    目录沁恒蓝牙系列芯片中目前只有CH582/583以及208包含有硬件IIC外设,本文均使用582进行测试,其他沁恒芯片也可以参考本文排查。先进行“常规”检查,检查相关引脚的焊接、线......
  • 基于Sharding-Jdbc 实现的读写分离实现
    1.pom文件依赖<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.2.2.RELEASE</version......
  • 分库分表、读写分离
    总览1、MySQL分库分表2、MySQL读写分离&主从同步 什么是分表数据角度:数据会分开存储水平分表。结构没有变 字段角度(设计问题):字段分开。10个字段5个字段。垂直分......
  • IIC协议驱动设计
    FPGA零基础学习:IIC协议驱动设计本系列将带来FPGA的系统性学习,从最基本的数字电路基础开始,最详细操作步骤,最直白的言语描述,手把手的“傻瓜式”讲解,让电子、信息、通信类专......
  • 【java-01】springboot利用sharding jdbc实现读写分离
    写在开头打算把自己的java后端学习过程分享给大家,也方便之后自己回顾。从这里开始~目前在学习黑马的瑞吉外卖新手入门项目,这篇随笔记录的是项目优化之一读写分离先列出......
  • Linux libxls和xlslib读写Excel文档【转】
    转自:https://www.joxrays.com/linux-xls/这里要讨论的是两款开源库libxls和xlslib,前者用与读Excel,后者用于写.所以可以在Linux或Windows上使用libxls(读Excel......
  • Centos7 查看磁盘i/o, 定位占用i/o读写高的进程
     Centos7查看磁盘i/o,定位占用i/o读写高的进程概要:1、iostat用法2、先用iostat查看磁盘io是否读写负载很高3、找出使用io高的进程的工具iotop4、lsof查......
  • ARMv7-A Coprocessor概要以及读写
     关键词:MRC/MCR/MRRC/MCRR、CP14、CP15等等。1.ARMv7-ACoprocessor介绍ARMv7-A支持16个Coprocessor,分别是:(A2.9Coprocessorsupport)CP15-SystemControl。CP14-D......