欢迎光临散文网 会员登陆 & 注册

I2C软件模拟(记录)

2023-08-06 19:35 作者:昵称问你的昵称是什么  | 我要投稿

//MYI2C.C

#include "myi2c.h"

/*
1:将我们定义的SCL和SDA对应的引脚初始化为开漏输出模式
2:根据I2C协议规定需将SCL和SDA置高电平

*/
void MyI2C_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructurt;
    GPIO_InitStructurt.GPIO_Mode = GPIO_Mode_Out_OD;//输入时先置1为高阻态,然后即可读取输入数据寄存器即可获取输入的数据
    GPIO_InitStructurt.GPIO_Pin = SCL_PIN | SDA_PIN;
    GPIO_InitStructurt.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(I2C_PORT,&GPIO_InitStructurt);
    
    GPIO_SetBits(I2C_PORT,SCL_PIN | SDA_PIN);
}

//写SCL引脚
void MyI2C_W_SCL(uint8_t BitValue)
{
    GPIO_WriteBit(I2C_PORT,SCL_PIN,(BitAction)BitValue);//使用宏定义引脚,
    Delay_us(10);
}

//写SDA引脚
void MyI2C_W_SDA(uint8_t BitValue)
{
    GPIO_WriteBit(I2C_PORT,SDA_PIN,(BitAction)BitValue);
    Delay_us(10);
}

//读SDA引脚
uint8_t MyI2C_R_SDA(void)
{
    uint8_t BitValue;//将读取的数据通过该变量返回
    BitValue = GPIO_ReadInputDataBit(I2C_PORT,SDA_PIN);//获取该引脚此时处于什么电平
    Delay_us(10);
    return BitValue;
}

//起始条件时序
void MyI2C_Start(void)
{
    //先释放SDA,SCL(输出高电平)
    MyI2C_W_SDA(1);//先放SDA在前有助于该函数兼容起始条件和重复起始条件
    MyI2C_W_SCL(1);
    //起始条件时序
    MyI2C_W_SDA(0);
    MyI2C_W_SCL(0);
}

//停止条件时序
void MyI2C_Stop(void)
{
    //确保SDA能产生上升沿,需先拉低SDA
    MyI2C_W_SDA(0);
    //SDA,SCL回归默认高电平
    MyI2C_W_SCL(1);
    MyI2C_W_SDA(1);
}

//发送一个字节Byte。除终止条件时SCL以高电平结束外,
//其它所有的时序单元结束都应该保证以低电平结束,
//作用是方便各个时序单元的拼接。每放完一位后,应
//应先释放SCL,再拉低SCL
void MyI2C_SendByte(uint8_t Byte)
{
    uint8_t i;
    for(i=0;i<8;i++)
    {
        MyI2C_W_SDA(Byte & (0x80 >>i));//取BYTE的每一位,读函数会判断输入的每一位,有1则1,无1则0
        MyI2C_W_SCL(1);//驱动时钟走一个脉冲,让从机读刚写入的位
        MyI2C_W_SCL(0);
    }
}

//接收一个字节时序。SCL低电平,主机释放SDA,从机把数据
//放到SDA上,主机释放SCL,SCL变为高电平,主机开始接收数据
uint8_t MyI2C_ReceiveByte(void)
{
    uint8_t i,Byte = 0x00;//接收到的数据
    MyI2C_W_SDA(1);//释放SDA
    for(i=0;i<8;i++)
    {
        MyI2C_W_SCL(1);//释放SCL,让从机先别发数据,读数据
        if(MyI2C_R_SDA()==1)
        {
            Byte |= (0x80>>i);
        }
        MyI2C_W_SCL(0);//让从机放数据到SDA上
    }
    return Byte;
}

//发送应答,进函数时,SCL为低电平
void MyI2C_SendACK(uint8_t ACKbit)
{
    MyI2C_W_SDA(ACKbit);
    MyI2C_W_SCL(1);//从机读
    MyI2C_W_SCL(0);
}

//接收应答,进函数时,SCL为低电平
uint8_t MyI2C_ReceiveACK(void)
{
    uint8_t ACKbit;
    MyI2C_W_SDA(1);//释放SDA
    MyI2C_W_SCL(1);//主机读
    ACKbit = MyI2C_R_SDA();//ACKbit=0为有从机应答
    MyI2C_W_SCL(0);//进入下一个时序
    return ACKbit;
}

//MYI2C.H

#ifndef __MYI2C_H
#define __MYI2C_H

#include "Device/Include/stm32f10x.h"   // Device header
#include "Delay.h"
//使用宏定义方便后续使用其它引脚模拟时方便代码的修改
#define I2C_PORT GPIOB
#define SCL_PIN GPIO_Pin_10
#define SDA_PIN GPIO_Pin_11
void MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendACK(uint8_t ACKbit);
uint8_t MyI2C_ReceiveACK(void);
#endif

//以上代码都是跟着江协大老师写的,我只是加了点不知其所以然的注释,发上这里来是为了以后好找回。

I2C软件模拟(记录)的评论 (共 条)

分享到微博请遵守国家法律