Alkaitu:STM32的IO模拟I2C

发布时间 2023-04-08 20:01:41作者: 在下彦祖
#include "user_i2c.h"
#include "stm32f10x.h"
#include "user_config.h"


/*移植需改动三处*/

/***************************************************************/
/*i2c的IO脚位宏定义,移植改动第一处,如增加按格式加即可*/
/***************************************************************/
#define SCL1_SET_1       GPIO_SetBits(GPIOB, GPIO_Pin_6)
#define SCL1_SET_0       GPIO_ResetBits(GPIOB, GPIO_Pin_6)

#define SDA1_SET_1       GPIO_SetBits(GPIOB, GPIO_Pin_7)
#define SDA1_SET_0       GPIO_ResetBits(GPIOB, GPIO_Pin_7)
#define SDA1_READ_BIT    GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7)
/***************************************************************/


/***************************************************************/
/*i2c数量和延迟时间设置,移植改动第二处,可增加数量和调节时间*/
/***************************************************************/
#define I2C_DELAY_TIME 50
#define I2C_NUM_ALL 1
/***************************************************************/


/***************************************************************/
/*i2c的IO脚位初始化,移植改动第三处*/
/***************************************************************/
void user_i2c_init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    
    GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
}
/***************************************************************/


/**********************************************************************************************/
/*i2c的SCL引脚电平设置*/
/**********************************************************************************************/
void user_set_scl(unsigned char i2c_id,unsigned char bit_value)
{
    switch(i2c_id)                                                            //设定那一组模拟IO
    {
        case 1:if(bit_value != 0){SCL1_SET_1;user_delay_us(I2C_DELAY_TIME);}
                 else{SCL1_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        
        #if I2C_NUM_ALL > 1
        case 2:if(bit_value != 0){SCL2_SET_1;user_delay_us(I2C_DELAY_TIME);}
                 else{SCL2_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        #endif
        
        #if I2C_NUM_ALL > 2
        case 3:if(bit_value != 0){SCL3_SET_1;user_delay_us(I2C_DELAY_TIME);}
                 else{SCL3_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        #endif
        
        #if I2C_NUM_ALL > 3
        case 4:if(bit_value != 0){SCL4_SET_1;user_delay_us(I2C_DELAY_TIME);}
                 else{SCL4_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        #endif
        
        #if I2C_NUM_ALL > 4
        case 5:if(bit_value != 0){SCL5_SET_1;user_delay_us(I2C_DELAY_TIME);}
                 else{SCL5_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
    #endif                     
    }
}
/**********************************************************************************************/


/**********************************************************************************************/
/*i2c的SDA引脚电平设置*/
/**********************************************************************************************/
void user_set_sda(unsigned char i2c_id,unsigned char bit_value)
{
    switch(i2c_id)
    {
        case 1: if(bit_value != 0){SDA1_SET_1;user_delay_us(I2C_DELAY_TIME);}
                  else{SDA1_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        
        #if I2C_NUM_ALL > 1
        case 2: if(bit_value != 0){SDA2_SET_1;user_delay_us(I2C_DELAY_TIME);}
                  else{SDA2_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        #endif
        
        #if I2C_NUM_ALL > 2
        case 3: if(bit_value != 0){SDA3_SET_1;user_delay_us(I2C_DELAY_TIME);}
                  else{SDA3_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        #endif
        
        #if I2C_NUM_ALL > 3
        case 4: if(bit_value != 0){SDA4_SET_1;user_delay_us(I2C_DELAY_TIME);}
                  else{SDA4_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
        #endif
        
        #if I2C_NUM_ALL > 4
        case 5: if(bit_value != 0){SDA5_SET_1;user_delay_us(I2C_DELAY_TIME);}
                  else{SDA5_SET_0;user_delay_us(I2C_DELAY_TIME);};break;
    #endif                     
    }
}
/**********************************************************************************************/


/**********************************************************************************************/
/*i2c的读取SDA引脚电平*/
/**********************************************************************************************/
unsigned char user_read_sda(unsigned char i2c_id)
{
    unsigned char bit_value;
    switch(i2c_id)
    {
        case 1: bit_value = SDA1_READ_BIT;user_delay_us(I2C_DELAY_TIME);
                break;
        
        #if I2C_NUM_ALL > 1
        case 2: bit_value = SDA2_READ_BIT;user_delay_us(I2C_DELAY_TIME);
                break;
        #endif
        
        #if I2C_NUM_ALL > 2
        case 3: bit_value = SDA3_READ_BIT;user_delay_us(I2C_DELAY_TIME);
                break;
        #endif
        
        #if I2C_NUM_ALL > 3
        case 4: bit_value = SDA4_READ_BIT;user_delay_us(I2C_DELAY_TIME);
                break;
        #endif
        
        #if I2C_NUM_ALL > 4
        case 5: bit_value = SDA5_READ_BIT;user_delay_us(I2C_DELAY_TIME);
                break;
    #endif                     
    }
    return bit_value;
}
/*********************************************************************************************/


/***************************************************************/
/*i2c起始信号*/
/***************************************************************/
void user_i2c_start(unsigned char i2c_id)
{
    user_set_sda(i2c_id,1);
    user_set_scl(i2c_id,1);
    user_set_sda(i2c_id,0);
    user_set_scl(i2c_id,0);
}
/***************************************************************/


/***************************************************************/
/*i2c停止信号*/
/***************************************************************/
void user_i2c_stop(unsigned char i2c_id)
{
    user_set_sda(i2c_id,0);
    user_set_scl(i2c_id,1);
    user_set_sda(i2c_id,1);
}
/***************************************************************/


/***************************************************************/
/*i2c发送一个字节*/
/***************************************************************/
void user_i2c_send_byte(unsigned char i2c_id,unsigned char byte)
{
    unsigned char i;
    for (i = 0; i < 8; i ++)
    {
        if((byte & (0x80 >> i)) != 0)     //高位先行
        {
          user_set_sda(i2c_id,1);            
        }
        else
        {
          user_set_sda(i2c_id,0); 
        }
      user_set_scl(i2c_id,1);
        user_set_scl(i2c_id,0);
    }
}
/***************************************************************/


/***************************************************************/
/*i2c接收一个字节*/
/***************************************************************/
unsigned char user_i2c_receive_byte(unsigned char i2c_id)
{
    unsigned char i,byte = 0x00;
    user_set_sda(i2c_id,1);
    for(i = 0; i < 8; i ++)
    {
        user_set_scl(i2c_id,1);
        if(user_read_sda(i2c_id) != 0)
        {
          byte |= (0x80 >> i);
        }
        else
        {
          byte &= (~(0x80 >> i));
        }
        user_set_scl(i2c_id,0);
    }
    return byte;
}
/***************************************************************/


/********************************************************************/
/*i2c发送应答信号ack*/
/********************************************************************/
void user_i2c_send_ack(unsigned char i2c_id,unsigned char ack_bit)
{
    user_set_sda(i2c_id,ack_bit);
    user_set_scl(i2c_id,1);
    user_set_scl(i2c_id,0);
}
/********************************************************************/


/***************************************************************/
/*i2c接收应答信号ack*/
/***************************************************************/
unsigned char user_i2c_receive_ack(unsigned char i2c_id)
{
    unsigned char ackbit;
    user_set_sda(i2c_id,1);
    user_set_scl(i2c_id,1);
    ackbit = user_read_sda(i2c_id);
    user_set_scl(i2c_id,0);
    return ackbit;
}
/***************************************************************/


/***********************************************************************************************************************************/
/*指定地址读,七位寻址,最后一位:1 读数据, 0 写数据,  重要:发送一定要给应答,接收也要给应答*/
/***********************************************************************************************************************************/
unsigned char user_i2c_read_reg(unsigned char i2c_id,unsigned char device_address,unsigned char reg_address)
{
    unsigned char i2c_receive_byte_data;
    
    user_i2c_start(i2c_id);                               //发送起始信号
    
    user_i2c_send_byte(i2c_id,device_address);            //发送寻址从设备地址
    user_i2c_receive_ack(i2c_id);                         //接收应答信号
    
    user_i2c_send_byte(i2c_id,reg_address);               //发送寻址从设备的寄存器地址
    user_i2c_receive_ack(i2c_id);                         //接收应答信号
    
    user_i2c_start(i2c_id);                               //发起始信号,此时写操作改成读操作,在当前寄存器地址操作 
    
    user_i2c_send_byte(i2c_id,(device_address | 0x01));   //发送寻址从设备地址,从设备地址最后一位设置成1,设置成读数据
    user_i2c_receive_ack(i2c_id);                         //接收应答信号
    
    i2c_receive_byte_data = user_i2c_receive_byte(i2c_id);   //接收从设备发送的数据
    user_i2c_send_ack(i2c_id,1);                             //发送非应答信号,结束接收
    
    user_i2c_stop(i2c_id);                                   //发送停止信号
    
    return i2c_receive_byte_data;                            //返回接收一个字节数据
}
/***********************************************************************************************************************************/


/***********************************************************************************************************************************/
/*指定地址写,七位寻址,最后一位:1 读数据, 0 写数据*/
/***********************************************************************************************************************************/
void user_i2c_write_reg(unsigned char i2c_id,unsigned char device_address,unsigned char reg_address,unsigned char data)
{
  user_i2c_start(i2c_id);
    
    user_i2c_send_byte(i2c_id,device_address);
    user_i2c_receive_ack(i2c_id);
    
    user_i2c_send_byte(i2c_id,reg_address);
    user_i2c_receive_ack(i2c_id);
    
    /**/
    user_i2c_send_byte(i2c_id,data);                                 
    user_i2c_receive_ack(i2c_id);
    
    user_i2c_stop(i2c_id);
}
/************************************************************************************************************************/



/*******************************************************************************************/
/*测试从设备寻址响应*/
/*******************************************************************************************/
unsigned char user_i2c_test_ack(unsigned char i2c_id,unsigned char device_address)
{
    unsigned char i2c_receive_ack;
    
    user_i2c_start(i2c_id);
    
    user_i2c_send_byte(i2c_id,device_address);
    i2c_receive_ack = user_i2c_receive_ack(i2c_id);
    
    user_i2c_stop(i2c_id);
    
    return i2c_receive_ack;
}
/******************************************************************************************/
#ifndef _user_i2c_h_
#define _user_i2c_h_



/*头文件移植无需改动*/

/******************************************************************************************/
/*i2c引脚初始化函数,移植需在.C文件改动*/
/******************************************************************************************/

void user_i2c_init(void);

/******************************************************************************************/


/******************************************************************************************/
/*移植无需改动,函数实现I2C的脚位电平设置,无需改动*/
/******************************************************************************************/

void user_set_scl(unsigned char i2c_id,unsigned char bit_value); /*i2c的SCL引脚电平设置*/
void user_set_sda(unsigned char i2c_id,unsigned char bit_value); /*i2c的SDA引脚电平设置*/
unsigned char user_read_sda(unsigned char i2c_id);               /*i2c的读取SDA引脚电平*/

/*******************************************************************************************/



/*******************************************************************************************/
/*移植无需改动,函数实现I2C的时序,无需改动*/
/********************************************************************************************/

void user_i2c_start(unsigned char i2c_id);                             /*i2c起始信号*/
void user_i2c_stop(unsigned char i2c_id);                              /*i2c停止信号*/

void user_i2c_send_byte(unsigned char i2c_id,unsigned char byte);      /*i2c发送一个字节*/
unsigned char user_i2c_receive_ack(unsigned char i2c_id);              /*i2c接收应答信号ack*/

void user_i2c_send_ack(unsigned char i2c_id,unsigned char ack_bit);    /*i2c发送应答信号ack*/
unsigned char user_i2c_receive_byte(unsigned char i2c_id);             /*i2c接收一个字节*/

/*********************************************************************************************/



/***********************************************************************************************************************/
/*实际IO模拟主要引用这三个函数,无需改动*/
/************************************************************************************************************************/

/*指定地址读*/ 
unsigned char user_i2c_read_reg(unsigned char i2c_id,unsigned char device_address,unsigned char reg_address);          


/*指定地址写*/
void user_i2c_write_reg(unsigned char i2c_id,unsigned char device_address,unsigned char reg_address,unsigned char data); 


/*测试从设备寻址响应*/
unsigned char user_i2c_test_ack(unsigned char i2c_id,unsigned char device_address);                                     

/*************************************************************************************************************************/


#endif