打印
[STM32F1]

软件模拟IIC通讯

[复制链接]
347|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kkzz|  楼主 | 2023-11-14 12:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式


void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
uint8_t MyI2C_R_SDA(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
void MyI2C_SendBuffer(uint8_t *Buffer, uint32_t len);
void MyI2C_RecvBuffer(uint8_t I2C_Slave_Addr, uint8_t AR_Addr, uint8_t *Buffer, uint32_t len);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);


 


// 需要替换的函数
GPIO_WriteBit();         // 引脚电平写入函数
GPIO_ReadInputDataBit(); // 读引脚电平函数
Delay_us(10);            // 延迟函数
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 拉高拉低SCL
* @param {uint8_t} BitValue 0/1
* [url=home.php?mod=space&uid=266161]@return[/url] {*}
*/
void MyI2C_W_SCL(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
    Delay_us(10);
}
/**
* @brief : 拉高拉低SDA
* @param {uint8_t} BitValue 0/1
* @return {*}
*/
void MyI2C_W_SDA(uint8_t BitValue)
{
    GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
    Delay_us(10);
}
/**
* @brief : 读SDA电平
* @return {*}
*/
uint8_t MyI2C_R_SDA(void)
{
    uint8_t BitValue;
    BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
    Delay_us(10);
    return BitValue;
}

void MyI2C_Init(void)
{
    /*使能外设时钟*/
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    /*结构体配置IIC引脚*/
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); // 拉高引脚电平
}

/********************************************************************************************************************************************
修改上面的函数就行下面的都是封装好的
IIC通讯原则 发送起始信号 发送一个字节 接收应答标志 发送下一个字节 接收应答标志 发送停止标志
*******************************************************************************************************************************************/

/**
* @brief 发送开始标志
* @return {*}
*/
void MyI2C_Start(void)
{
    MyI2C_W_SDA(1);
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(0);
    MyI2C_W_SCL(0);
}
/**
* @brief 发送停止标志
* @return {*}
*/
void MyI2C_Stop(void)
{
    /*SCL高电平期间SDA由低变高*/
    MyI2C_W_SDA(0);
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(1);
}

/**
* @brief  起始位后SCL为低 可以放数据在SDA上,随后拉高SCL从机读取主机发送的数据,主机在拉低SCL进入下一位的发送
* @param {uint8_t} Byte
* @return {*}
*/
void MyI2C_SendByte(uint8_t Byte)
{
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
        MyI2C_W_SDA(Byte & (0x80 >> i));
        MyI2C_W_SCL(1);
        MyI2C_W_SCL(0);
    }
}
/**
* @brief  发送buffer
* @param {uint8_t} Byte
* @return {*}
*/
void MyI2C_SendBuffer(uint8_t *Buffer, uint32_t len)
{
    MyI2C_Start();
    for (int i = 0; i < len; i++)
    {
        MyI2C_SendByte(Buffer[i]);
        MyI2C_ReceiveAck();
    }
    MyI2C_Stop();
}
/**
* @brief : 接收指定从机寄存器地址的buffer
* @param {uint8_t} I2C_Slave_Addr 从机地址
* @param {uint8_t} AR_Addr  寄存器地址
* @param {uint8_t} *Buffer  数据
* @param {uint32_t} len  数据长度
* @return {*}
*/
void MyI2C_RecvBuffer(uint8_t I2C_Slave_Addr, uint8_t AR_Addr, uint8_t *Buffer, uint32_t len)
{

    MyI2C_Start();

    MyI2C_SendByte(I2C_Slave_Addr);
    MyI2C_ReceiveAck();
    MyI2C_SendByte(AR_Addr);
    MyI2C_ReceiveAck();

    MyI2C_Start();
    MyI2C_SendByte(I2C_Slave_Addr | 0x01);
    MyI2C_ReceiveAck();
    for (int i = 0; i < len; i++)
    {
        Buffer[i] = MyI2C_ReceiveByte();
        if (i == len - 1)
        {
            MyI2C_SendAck(1);
        }
        else
        {
            MyI2C_SendAck(0);
        }
    }

    MyI2C_Stop();
}

/**
* @brief  主机先拉高SDA是释放总线的意思,SCL此时为低 ,从机可以 放数据在SDA上,随后主机拉高SCL读取SDA的值在拉低SCL进入下一个周期
* @param {uint8_t} Byte
* @return {*}
*/
uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i, Byte = 0x00;
    MyI2C_W_SDA(1);
    for (i = 0; i < 8; i++)
    {
        MyI2C_W_SCL(1);
        if (MyI2C_R_SDA() == 1)
        {
            Byte |= (0x80 >> i);
        }
        MyI2C_W_SCL(0);
    }
    return Byte;
}
/**
* @brief  发送应答位
* @param {uint8_t} Byte 0应带继续接收,1不应答
* @return {*}
*/
void MyI2C_SendAck(uint8_t AckBit)
{
    MyI2C_W_SDA(AckBit);
    MyI2C_W_SCL(1);
    MyI2C_W_SCL(0);
}
/**
* @brief  发送应答位
* @param {uint8_t} Byte 0应带继续接收,1不应答
* @return {*}
*/
uint8_t MyI2C_ReceiveAck(void)
{
    uint8_t AckBit;
    MyI2C_W_SDA(1);
    MyI2C_W_SCL(1);
    AckBit = MyI2C_R_SDA();
    MyI2C_W_SCL(0);
    return AckBit;
}


使用特权

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

本版积分规则

315

主题

10660

帖子

13

粉丝