打印
[软件资料]

分享个自己写的硬件IIC通讯方法

[复制链接]
1517|20
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 yuyy1989 于 2023-6-7 15:01 编辑

鉴于官方库的IIC方法有数组越界的问题,并且不太满足我的使用需求,自己重写了一下,有需要的可以参考一下,已经和DHTC12通信测试过


#include "yuyy_hard_iic.h"
#include "cw32f030_gpio.h"
#include "cw32f030_rcc.h"
#include "cw32f030_i2c.h"

#define YUYY_HARD_IIC(x) x==2?CW_I2C2:CW_I2C1

void yuyy_hard_iic_init(void)
{
    __RCC_GPIOB_CLK_ENABLE();
    __RCC_I2C1_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStructure;
    PB10_AFx_I2C1SCL();
    PB11_AFx_I2C1SDA();
    GPIO_InitStructure.Pins = GPIO_PIN_10 | GPIO_PIN_11;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD; //
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_Init(CW_GPIOB, &GPIO_InitStructure);
   
    I2C_InitTypeDef I2C_InitStruct;
    I2C_InitStruct.I2C_BaudEn = ENABLE;
    I2C_InitStruct.I2C_Baud = 9;  //100K=(8000000/(8*(1+9))
    I2C_InitStruct.I2C_FLT = ENABLE;
    I2C_InitStruct.I2C_AA = DISABLE;
    I2C1_DeInit();
    I2C_Master_Init(CW_I2C1,&I2C_InitStruct);//初始化模块
    I2C_Cmd(CW_I2C1,ENABLE);  //模块使能
}

uint8_t yuyy_hard_iic_sendregaddr(uint8_t iicx,uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen)
{
    uint8_t err = 0,u8State,retry = 0,sendlen = 0;
    I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
    while(1)
    {
        while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
        u8State = I2C_GetState(YUYY_HARD_IIC(iicx));
        switch(u8State)
        {
            case 0x08:   //发送完START信号
            case 0x10:   //发送完重复起始信号
                I2C_GenerateSTART(YUYY_HARD_IIC(iicx), DISABLE);
                I2C_Send7bitAddress(YUYY_HARD_IIC(iicx), (devaddr<<1),I2C_Direction_Transmitter);   //发送从机地址
                break;
            case 0x18:   //发送完SLA+W信号
            case 0x28:   //发送完1字节数据:发送EEPROM中memory地址也会产生,发送后面的数据也会产生
                if(sendlen < regaddrlen)
                {
                    if(sendlen == 0 && regaddrlen == 2)
                        I2C_SendData(YUYY_HARD_IIC(iicx),(regaddr>>8)&0xFF);
                    else
                        I2C_SendData(YUYY_HARD_IIC(iicx),regaddr&0xFF);
                }
                sendlen++;
                break;
            case 0x20:   //发送完SLA+W后从机返回NACK
            case 0x38:   //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
                if(retry < 3)
                {
                    sendlen = 0;
                    I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
                }
                else
                    err = 1;
                retry++;
                break;
            case 0x30:   //发送完一个数据字节后从机返回NACK
                err = 1;
                break;
            default:
                err = 1;
                break;
        }
        if(err > 0 || sendlen == regaddrlen)
        {
            if(err > 0)
                        {
                I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
                        }
                I2C_ClearIrq(YUYY_HARD_IIC(iicx));
            break;
        }
        I2C_ClearIrq(YUYY_HARD_IIC(iicx));
    }
    return err;
}

uint8_t yuyy_hard_iic_senddatas(uint8_t iicx,uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen,uint8_t *datas,uint8_t datalen)
{
        uint8_t err = 0,u8State = 0,sendlen = 0;
    err = yuyy_hard_iic_sendregaddr(iicx,devaddr,regaddr,regaddrlen);
    if(err == 0)
        {
                while(1)
        {
            while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
            u8State = I2C_GetState(YUYY_HARD_IIC(iicx));
            switch(u8State)
            {
                case 0x18:   //发送完SLA+W信号
                case 0x28:   //发送完1字节数据:发送EEPROM中memory地址也会产生,发送后面的数据也会产生
                    if(sendlen < datalen)
                    {
                        I2C_SendData(YUYY_HARD_IIC(iicx),datas[sendlen]);
                    }
                    sendlen++;
                    break;
                case 0x20:   //发送完SLA+W后从机返回NACK
                case 0x38:   //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
                    err = 1;
                    break;
                case 0x30:   //发送完一个数据字节后从机返回NACK
                    err = 1;
                    break;
                default:
                    err = 1;
                    break;
            }
            if(err > 0 || sendlen > datalen)
            {
                I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
                I2C_ClearIrq(YUYY_HARD_IIC(iicx));
                break;
            }
            I2C_ClearIrq(YUYY_HARD_IIC(iicx));
        }
        }
    return err;
}
uint8_t yuyy_hard_iic_readdatas(uint8_t iicx,uint8_t devaddr,uint16_t regaddr,uint8_t regaddrlen,uint8_t *datas,uint8_t datalen)
{
        uint8_t err = 0,u8State = 0,retry = 0,i = 0;
    if(regaddrlen > 0)
    {
        err = yuyy_hard_iic_sendregaddr(iicx,devaddr,regaddr,regaddrlen);
        while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
        I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
        I2C_ClearIrq(YUYY_HARD_IIC(iicx));
    }
    if(err == 0)
    {
        I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
        while(1)
        {
            while(0 == I2C_GetIrq(YUYY_HARD_IIC(iicx)));
            u8State = I2C_GetState(YUYY_HARD_IIC(iicx));
            switch(u8State)
            {
                case 0x28:
                    I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
                    break;
                case 0x08:   //发送完START信号
                case 0x10:   //发送完重复起始信号
                    I2C_GenerateSTART(YUYY_HARD_IIC(iicx), DISABLE);
                    I2C_Send7bitAddress(YUYY_HARD_IIC(iicx), (devaddr<<1),I2C_Direction_Receiver);   //发送从机地址+R字节
                case 0x40:   //发送完SLA+R信号,开始接收数据
                    if(datalen>1)
                        I2C_AcknowledgeConfig(YUYY_HARD_IIC(iicx),ENABLE);
                    break;
                case 0x50:   //接收完一字节数据,在接收最后1字节数据之前设置AA=0;
                    datas[i++] = I2C_ReceiveData(YUYY_HARD_IIC(iicx));
                    if(i==datalen-1)
                        I2C_AcknowledgeConfig(YUYY_HARD_IIC(iicx),DISABLE);
                    break;
                case 0x58:   //接收到一个数据字节,且NACK已回复
                    datas[i++] = I2C_ReceiveData(YUYY_HARD_IIC(iicx));
                    break;
                case 0x38:   //主机在发送 SLA+W 阶段或者发送数据阶段丢失仲裁  或者  主机在发送 SLA+R 阶段或者回应 NACK 阶段丢失仲裁
                    //I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
                    err = 1;
                    break;
                case 0x48:   //发送完SLA+R后从机返回NACK
                    if(retry < 3)
                    {
                        I2C_GenerateSTART(YUYY_HARD_IIC(iicx), ENABLE);
                    }
                    else
                        err = 2;
                    retry++;
                    break;
                default:
                    err = u8State;
                    break;
            }
            if(i==datalen || err > 0)
            {
                I2C_GenerateSTOP(YUYY_HARD_IIC(iicx), ENABLE);
                I2C_ClearIrq(YUYY_HARD_IIC(iicx));
                break;
            }
            I2C_ClearIrq(YUYY_HARD_IIC(iicx));
        }
    }
    return err;
}


使用特权

评论回复
沙发
bestwell| | 2023-6-10 14:00 | 只看该作者
硬件II2C和软件I2C有什么区别

使用特权

评论回复
板凳
uptown| | 2023-6-10 15:36 | 只看该作者
设备其地址如何定义?               

使用特权

评论回复
地板
beacherblack| | 2023-6-10 15:42 | 只看该作者
使用单片机自带的IIC模块或外接IIC芯片,连接到需要进行通讯的从设备。在程序中初始化IIC模块,并设置时钟速率、总线地址等参数。

使用特权

评论回复
5
sesefadou| | 2023-6-10 15:57 | 只看该作者
需要考虑其他因素,如数据缓冲区的大小、中断处理函数的编写等。

使用特权

评论回复
6
kmzuaz| | 2023-6-10 16:09 | 只看该作者
硬件I2C能与软件I2C一起用一个I2C通道么

使用特权

评论回复
7
macpherson| | 2023-6-10 16:32 | 只看该作者
常见的串行通信协议,可以实现在多个设备之间进行高效稳定的数据传输。

使用特权

评论回复
8
tabmone| | 2023-6-10 16:43 | 只看该作者
硬件i2c缺陷解决方法               

使用特权

评论回复
9
bartonalfred| | 2023-6-10 16:51 | 只看该作者
在进行硬件IIC通信时,需要确保主设备和从设备在速率、地址等参数设置相同

使用特权

评论回复
10
sheflynn| | 2023-6-10 17:43 | 只看该作者
硬件IIC通讯是一种基于I2C总线的通信方式,可以实现单片机与多个设备之间的数据交换。

使用特权

评论回复
11
51xlf| | 2023-6-10 17:50 | 只看该作者
两个单片机用IIC通讯,从机的函数要怎么写

使用特权

评论回复
12
yuyy1989|  楼主 | 2023-6-10 19:18 | 只看该作者
51xlf 发表于 2023-6-10 17:50
两个单片机用IIC通讯,从机的函数要怎么写

官方有作为从机的例程的

使用特权

评论回复
13
chenqianqian| | 2023-6-11 19:24 | 只看该作者
硬件IIC就是调用官方接口函数

使用特权

评论回复
14
OKAKAKO| | 2023-6-11 21:09 | 只看该作者
IIC通讯改写其实就是对于收发数据进行更多的存储和转换,自带的库函数需要自己进行转换

使用特权

评论回复
15
小夏天的大西瓜| | 2023-6-16 16:28 | 只看该作者
模拟I2C一般是用GPIO管脚,用软件控制管脚状态以模拟I2C通信波形。
硬件I2C对应芯片上的I2C外设,有相应I2C驱动电路,其所使用的I2C管脚也是专用。

使用特权

评论回复
16
lulugl| | 2023-6-21 08:23 | 只看该作者
我最近在学习I2C的用法,感觉官方的示例,好象不是很好用,感谢分享。

使用特权

评论回复
17
lulugl| | 2023-6-21 08:25 | 只看该作者
可以分享一下你的整个工程,我学习一下吗?或者发我邮箱。

使用特权

评论回复
18
nawu| | 2023-7-4 16:00 | 只看该作者
官方的iic在进行什么操作的时候有越界的可能呢

使用特权

评论回复
19
tpgf| | 2023-7-4 16:49 | 只看该作者
自己写的iic通讯 其最大通讯速率受限于什么呢

使用特权

评论回复
20
gwsan| | 2023-7-4 17:07 | 只看该作者
tpgf 发表于 2023-7-4 16:49
自己写的iic通讯 其最大通讯速率受限于什么呢

我觉得一个是主频 一个是io的反应速度

使用特权

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

本版积分规则

149

主题

708

帖子

7

粉丝