I2C协议和实现代码

硬件原理

IIC.h代码实现


#ifndef __DRIVER_I2C_H
#define __DRIVER_I2C_H

#include "stm32f1xx_hal.h"

/*********************
 * 引脚宏定义
**********************/
#define SCL_PIN         GPIO_PIN_10
#define SDA_PIN         GPIO_PIN_11

#define SCL_PORT        GPIOF
#define SDA_PORT        GPIOF

/*********************
 * 函数宏定义
**********************/
#define SCL_H           HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 1)
#define SCL_L           HAL_GPIO_WritePin(SCL_PORT, SCL_PIN, 0)

#define SDA_H           HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 1)
#define SDA_L           HAL_GPIO_WritePin(SDA_PORT, SDA_PIN, 0)
#define SDA_IN          HAL_GPIO_ReadPin(SDA_PORT, SDA_PIN)

/*
 *  函数名:I2C_GPIO_ReInit
 *  功能描述:将模拟I2C的SCL和SDA引脚进行重新初始化
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
extern void I2C_GPIO_ReInit(void);

/*
 *  函数名:I2C_Start
 *  功能描述:模拟发出I2C的开始信号-->在SCL的高电平下,SDA的电平由高到低变化
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
extern void I2C_Start(void);

/*
 *  函数名:I2C_Stop
 *  功能描述:模拟发出I2C的停止信号-->在SCL的高电平下,SDA的电平由低到高变化
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
extern void I2C_Stop(void);

/*
 *  函数名:I2C_GetAck
 *  功能描述:模拟I2C获取从设备的响应信号-->在SCL的高电平下,从设备将SDA拉低
 *  输入参数:无
 *  输出参数:无
 *  返回值:成功得到响应返回0,否则返回-1
*/
extern int I2C_GetAck(void);

/*
 *  函数名:I2C_ACK
 *  功能描述:模拟I2C发出一个应答信号,在第九个时钟将SDA拉低
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
extern void I2C_ACK(void);

/*
 *  函数名:I2C_NACK
 *  功能描述:模拟I2C发出一个非应答信号,在第九个时钟将SDA拉高
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
extern void I2C_NACK(void);

/*
 *  函数名:I2C_WriteByte
 *  功能描述:模拟I2C发出一个字节的数据
 *  输入参数:data-->要发送出去的数据,范围0~255
 *  输出参数:无
 *  返回值:无
*/
extern void I2C_WriteByte(uint8_t data);

/*
 *  函数名:I2C_ReadByte
 *  返回值:返回读取到的数据
 *  输入参数:ack-->根据此参数判断在读到一个字节之后是否发出应答信号
 *  输出参数:无
*/
extern uint8_t I2C_ReadByte(uint8_t ack);

#endif /* __DRIVER_I2C_H */

IIC.C代码实现
#include "driver_i2c.h"

/*
 *  函数名:I2C_Delay
 *  功能描述:使用软件方式延时
 *  输入参数:t-->延时事件
 *  输出参数:无
 *  返回值:无
*/
void I2C_Delay(uint32_t t)
{
    volatile uint32_t tmp = t;
    while(tmp--);
}

/*
 *  函数名:I2C_GPIO_ReInit
 *  功能描述:将模拟I2C的SCL和SDA引脚进行重新初始化
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
void I2C_GPIO_ReInit(void)
{
    /* 1. 使用结构体定义硬件GPIO对象 */
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    
    /* 2. 将SCL和SDA的GPIO寄存器的值恢复为复位上电值 */
    HAL_GPIO_DeInit(SCL_PORT, SCL_PIN);
    HAL_GPIO_DeInit(SDA_PORT, SDA_PIN);
    
    /* 3. 使能SCL和SDA的GPIO的时钟,因为他们都是GPIOF组的,所以这里只使能GPIOF的时钟 */
    __HAL_RCC_GPIOF_CLK_ENABLE();
    
    /* 4. 设置GPIO的模式为开漏输出模式,响应速度设置为快速响应 */
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        
    /* 5. 选择要设置的GPIO引脚 */
    GPIO_InitStruct.Pin = SCL_PIN;
    
    /* 6. 调用init函数初始化GPIO */
    HAL_GPIO_Init(SCL_PORT, &GPIO_InitStruct);
    
    GPIO_InitStruct.Pin = SDA_PIN;
    HAL_GPIO_Init(SDA_PORT, &GPIO_InitStruct);
}

/*
 *  函数名:I2C_Start
 *  功能描述:模拟发出I2C的开始信号-->在SCL的高电平下,SDA的电平由高到低变化
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
void I2C_Start(void)
{
    SCL_H;
    SDA_H;
    I2C_Delay(100);
    SDA_L;
    I2C_Delay(100);
}

/*
 *  函数名:I2C_Stop
 *  功能描述:模拟发出I2C的停止信号-->在SCL的高电平下,SDA的电平由低到高变化
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
void I2C_Stop(void)
{
    SDA_L;
    SCL_H;
    I2C_Delay(100);
    SDA_H;
    I2C_Delay(100);
}

/*
 *  函数名:I2C_GetAck
 *  功能描述:模拟I2C获取从设备的响应信号-->在SCL的高电平下,从设备将SDA拉低
 *  输入参数:无
 *  输出参数:无
 *  返回值:成功得到响应返回0,否则返回-1
*/
int I2C_GetAck(void)
{
    int i = 0;
    SCL_L;
    SDA_H;
    I2C_Delay(100);
    SCL_H;
    while(SDA_IN != 0)
    {
        i++;
        if(i == 100)
        {
            SCL_L;
            return -1;
        }
        I2C_Delay(10);
    }
    SCL_L;
    return 0;
}

/*
 *  函数名:I2C_ACK
 *  功能描述:模拟I2C发出一个应答信号,在第九个时钟将SDA拉低
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
void I2C_ACK(void)
{
    SCL_L;
    SDA_L;
    I2C_Delay(100);
    SCL_H;
    I2C_Delay(100);
}

/*
 *  函数名:I2C_NACK
 *  功能描述:模拟I2C发出一个非应答信号,在第九个时钟将SDA拉高
 *  输入参数:无
 *  输出参数:无
 *  返回值:无
*/
void I2C_NACK(void)
{
    SCL_L;
    SDA_H;
    I2C_Delay(100);
    SCL_H;
    I2C_Delay(100);
}

/*
 *  函数名:I2C_WriteByte
 *  功能描述:模拟I2C发出一个字节的数据
 *  输入参数:data-->要发送出去的数据,范围0~255
 *  输出参数:无
 *  返回值:无
*/
void I2C_WriteByte(uint8_t data)
{
    uint8_t i = 0;
    for(i=0; i<8; i++)
    {
        SCL_L;
        I2C_Delay(100);
        if(data & 0x80)
        {
            SDA_H;
        }
        else
        {
            SDA_L;
        }
        data <<= 1; // 发出1bit数据后,要更新数据,将data的次高位移位到最高位
        SCL_H;
        I2C_Delay(100);
    }
    I2C_GetAck();
}

/*
 *  函数名:I2C_ReadByte
 *  返回值:返回读取到的数据
 *  输入参数:ack-->根据此参数判断在读到一个字节之后是否发出应答信号
 *  输出参数:无
*/
uint8_t I2C_ReadByte(uint8_t ack)
{
    uint8_t i = 0;
    uint8_t data = 0;
    
    SDA_H;
    for(i=0; i<8; i++)
    {
        SCL_L;
        I2C_Delay(100);
        SCL_H;
        I2C_Delay(100);
        data <<= 1; // 更新数据前,要将上一次数据左移1位用来保存接下来的这一位数据
        if(SDA_IN == 1)    
        {                 
            data++;
        }
        else
        {
            data = data;
        }
    }
    
    // 根据ack决定是否发出应答
    if(ack == 0)
    {
        I2C_ACK();
    }
    else if(ack == 1)
    {
        I2C_NACK();
    }
    
    return data;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值