CH579M模拟IIC

玩过这款芯片的都知道,CH579M是没有硬件IIC和开漏输出的,那么只能用到推挽输出模式模拟IIC,推挽输出和开漏输出模式的输出的区别:

   

开漏输出:内部没有P-MOS管,没有办法真正内部拉高,所以需要外接一个上拉电阻,这就是为何用开漏输出模拟IIC需要外接电阻,开漏输出只能拉低。
 

推挽输出:内部有P-MOS和N-MOS管,内部可拉高拉低,用推挽输出模式模拟IIC,有一个缺点,有多个设备容易烧引脚,因为不同设备可能会在总线上同时输出不同电平,例如,两个设备一个输出高电平另一个输出低电平,导致信号线相互冲突。所以慎重使用。

在本文章中使用的是推挽输出:硬件上不需要外接电阻,我是用来和MXP6655XA陀螺仪通信的,模拟IIC仅供参考。

.h头文件

#define I2C_SCL    GPIO_Pin_9      
#define I2C_SDA    GPIO_Pin_9              
#define SCL_High() GPIOB_SetBits(I2C_SCL)   
#define SCL_LOW()  GPIOB_ResetBits(I2C_SCL)
#define SDA_High() GPIOA_SetBits(I2C_SDA)   
#define SDA_LOW()  GPIOA_ResetBits(I2C_SDA)
#define SDA_X()    GPIOA_ReadPortPin(GPIO_Pin_9)
#define SDA_OUT()  GPIOA_ModeCfg(I2C_SDA, GPIO_ModeOut_PP_5mA)
#define SDA_IN()   GPIOA_ModeCfg(I2C_SDA, GPIO_ModeIN_Floating)
#define interrupt  GPIOB_ReadPortPin(GPIO_Pin_8)
void MXC6655XA_Config();
void IIC_R_W_Config(uint8_t dir);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Send(uint8_t dat);
uint8_t IIC_Receive(uint8_t ACK);
void IIC_Ack(void);
void IIC_NAk(void);
uint8_t IIC_Wait_Ack(void);
int MXC6655XA_X(uint8_t addr,uint8_t Reg_HSB,uint8_t Reg_LSB);
int MXC6655XA_Y(uint8_t addr,uint8_t Reg_HSB,uint8_t Reg_LSB);
int MXC6655XA_Z(uint8_t addr,uint8_t Reg_HSB,uint8_t Reg_LSB);
uint8_t Write_MXC6655XA(uint8_t addr,uint8_t register1,uint8_t value);

.c文件

1:初始化时钟和数据脚

/******************************************************************************************** 
* 函数名称: MXC6655XA_Config()
* 功能说明:    初始化SCL和Data脚
* 输    入: 无
* 输    出: 无
*********************************************************************************************/
void MXC6655XA_Config()
{
    
  GPIOB_ModeCfg(GPIO_Pin_9,GPIO_ModeOut_PP_5mA);
  GPIOA_ModeCfg(GPIO_Pin_9,GPIO_ModeOut_PP_5mA);
  GPIOB_ModeCfg(GPIO_Pin_8,GPIO_ModeIN_Floating);
}

2:配置数据脚输入和输出

/******************************************************************************************** 
* 函数名称: IIC_R_W_Config()
* 功能说明:    设置I2C_SDA引脚的读或写
* 输    入: 0=读入,1=写 
* 输    出: 无
*********************************************************************************************/
void IIC_R_W_Config(uint8_t dir)
{
    if(dir)GPIOA_ModeCfg(I2C_SDA, GPIO_ModeOut_PP_5mA); //SDA推挽输出模式 
    else GPIOA_ModeCfg(I2C_SDA, GPIO_ModeIN_PU);        //SDA上拉输入模式
}

 3:起始信号

/******************************************************************************************** 
* 函数名称: IIC_Start()
* 功能说明:    产生I2C传输的Start信号
* 输    入: 无 
* 输    出: 无
*********************************************************************************************/
void IIC_Start(void)
{
    IIC_R_W_Config(1);   //SDA推挽输出
    SDA_High();              //拉高数据线
    SCL_High();              //拉高时钟线
    DelayUs(5);               //等待4.7Us以上
    SDA_LOW();            //数据拉低产生一个(时高数低)信号    
    DelayUs(5);              //等待4.7Us以上
    SCL_LOW();            //时钟拉低
}

 4:停止位

/******************************************************************************************** 
* 函数名称:    IIC_Stop()
* 功能说明:    产生I2C传输的Stop信号
* 输    入: 无 
* 输    出: 无
*********************************************************************************************/
void IIC_Stop(void)
{
    IIC_R_W_Config(1);
    SCL_LOW();             // scl = 0
    DelayUs(5);   
    SDA_LOW();             //sda=0
    DelayUs(5);
    SCL_High();             // scl = 1
    DelayUs(5);    
    SDA_High();             // sda = 1
    DelayUs(5);
}

5:发送

/******************************************************************************************** 
* 函数名称: IIC_Send()
* 功能说明: 向IIC总线发送一个字节的数据
* 输    入:    1byte data
* 输    出: 无
*********************************************************************************************/
void IIC_Send(uint8_t data)
{
    uint8_t i;
    IIC_R_W_Config(1);   //数据线推挽输出
    SCL_LOW();               //拉低时钟开始数据传输
    
    for(i=0;i<8;i++)          
    {
        if(data&0x80)SDA_High();//data每位和高位做比较HSB输出
        else SDA_LOW();
        data<<=1;
        DelayUs(5);
        SCL_High();                         //拉高时钟等待从设备读取数据
        DelayUs(5);
        SCL_LOW();                         //拉低时钟准备下一位数据
    }
}

6:读取一个字节

/******************************************************************************************** 
* 函数名称:    IIC_Receive()
* 功能说明:    从IIC总线接收一个字节的数据
* 输    入: 无
* 输    出: byte        从IIC总线上接收到得数据
* 注意事项: 无
*********************************************************************************************/
uint8_t IIC_Receive(uint8_t ACK)
{
    uint8_t i,data;
    IIC_R_W_Config(0);        //数据线设置为浮空输入    
    for(i=0;i<8;i++)
    {
        SCL_LOW();                //时钟线拉低
        DelayUs(4);
        SCL_High();                //时钟线拉告
        data<<=1;                    //数据左移
        if(SDA_X())data|=0x01; //读取数据为高时,data置高
        DelayUs(4);
    }
    
    if(!ACK)IIC_NAk();         //不应答
    else IIC_Ack();               //应答
    
    return data;

7: 应答

/************************************************************************************************ 
* 函数名称: IIC_Ack()
* 功能说明:    在应答位位置产生应答,从而继续连续传输
* 输    入: 无 
* 输    出: 无 
*************************************************************************************************/
void IIC_Ack(void)

    SCL_LOW();               //时钟拉低
    IIC_R_W_Config(1);  //数据作为推挽输出
    SDA_LOW();              //拉低数据线即给于应答
    DelayUs(4);
    SCL_High();              //时钟拉高
    DelayUs(4);
    SCL_LOW();              //时钟拉低
}

8:非应答

/********************************************************************************************* 
* 函数名称: IIC_NAk()
* 功能说明:    在应答位位置不产生应答,从而终止连续传输
* 输    入: 无 
* 输    出: 无 
**********************************************************************************************/
void IIC_NAk(void)

    SCL_LOW();
    IIC_R_W_Config(1);  //数据推挽输出
    SDA_High();              //数据线不拉低即不给于应答
    DelayUs(4); 
    SCL_High();              //时钟拉高
    DelayUs(4);
    SCL_LOW();              //时钟拉低

9: 等待应答

/*********************************************************************************************** 
* 函数名称: IIC_Wait_Ack()
* 功能说明:    检测从机应答位
* 输    入: 无 
* 输    出: uint8_t    0=ACK_OK 从机产生了应答;1=ACK_NO 从机没有产生应答
************************************************************************************************/
uint8_t IIC_Wait_Ack(void)
{    
    uint32_t i;
    IIC_R_W_Config(1);  //数据线推挽输出
    SDA_High();              //数据线拉高
    DelayUs(4);
    IIC_R_W_Config(0);  //数据线浮空输入
    SCL_High();              // 时钟线拉高
    while(SDA_X()){       //等待回应
        i++;
        if(i>1000){
            IIC_Stop();       //数据线未被拉低,即未收到应答
            return 1;          //应答超时返回1
        }
        DelayUs(3);
    }
    SCL_LOW();
    DelayUs(4);    
    return 0;                //应答成功
}

 与MXC6655XA陀螺仪通讯


/*********************************************************************************************** 
* 函数名称: MXC6655XA_X(uint8_t addr,uint8_t Reg_HSB,uint8_t Reg_LSB)
* 功能说明: X轴由范围值:-2048到+2047(以补码形式输出)
* 输    入: 
* 输    出: 得到X轴加速度输出************************************************************************************************/
int MXC6655XA_X(uint8_t addr,uint8_t Reg_HSB,uint8_t Reg_LSB)
{
    uint8_t ii = 0;
    uint8_t MSB = 0, LSB = 0;
    
    IIC_Start();                        //产生起始信号
    IIC_Send(addr);                 //发送MXC6655XA_XYZ芯片地址及读写位,0表示写
    if(IIC_Wait_Ack())              //检测MXC6655XA_XYZ是否有响应
    {
        IIC_Stop();                     //产生停止信号
        SDA_OUT();                  //将SDA引脚恢复为输出模式
        return 0;        
    }
    
    IIC_Send(Reg_HSB);        //发送寄存器地址
    IIC_Wait_Ack();                 //检测MXC6655XA_X是否有响应
    IIC_Send(addr|0x1);         //读取MXC6655XA_X陀螺仪地址数据      
    if(!IIC_Wait_Ack())MSB = IIC_Receive(1);   //非应答
    else MSB = IIC_Receive(0);    //应答
    IIC_Stop();                       //停止                
    SDA_OUT();                   //数据作为推挽输出                

    return 0;
        
}
 

驱动MXC6655XA三轴陀螺仪待更新!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值