PC6 PC7模拟SCL SDA
GPIO输出模式下最好设置为开漏输出。
sda输入模式下设置为上拉输入。
代码如下:
#if I2C_MODE == USER_SW_I2C
// PC6 scl PC7 sda
#define SWI2C1_SCL_PORT GPIOC
#define SWI2C1_SCL_PIN GPIO_PIN_6
#define SWI2C1_SCL_HIGH GPIO_WriteBit(SWI2C1_SCL_PORT,SWI2C1_SCL_PIN,1u)
#define SWI2C1_SCL_LOW GPIO_WriteBit(SWI2C1_SCL_PORT,SWI2C1_SCL_PIN,0u)
#define SWI2C1_SDA_PORT GPIOC
#define SWI2C1_SDA_PIN GPIO_PIN_7
#define SWI2C1_SDA_HIGH GPIO_WriteBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN,1u)
#define SWI2C1_SDA_LOW GPIO_WriteBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN,0u)
#define SWI2C1_SDA_READ GPIO_ReadInDataBit(SWI2C1_SDA_PORT,SWI2C1_SDA_PIN)
#define BIT0 0x01
#define BIT7 0x80
#endif
void BOARD_I2C1_Init(void)
{
GPIO_Init_Type gpio_init;
gpio_init.Pins = SWI2C1_SCL_PIN;
gpio_init.PinMode = GPIO_PinMode_Out_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(SWI2C1_SCL_PORT, &gpio_init);
GPIO_PinAFConf(SWI2C1_SCL_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */
/* PC7 - I2C1_SDA. */
gpio_init.Pins = SWI2C1_SDA_PIN;
gpio_init.PinMode = GPIO_PinMode_Out_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(SWI2C1_SDA_PORT, &gpio_init);
GPIO_PinAFConf(SWI2C1_SDA_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */
SWI2C1_SDA_HIGH;
SWI2C1_SCL_HIGH;
}
//gpio 模式切换函数
static void SwI2c_Sda_Config_Output_mode(void)
{
GPIO_Init_Type gpio_init;
/* PC7 - I2C1_SDA. */
gpio_init.Pins = SWI2C1_SDA_PIN;
gpio_init.PinMode = GPIO_PinMode_Out_OpenDrain;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(SWI2C1_SDA_PORT, &gpio_init);
GPIO_PinAFConf(SWI2C1_SDA_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */
SWI2C1_SDA_HIGH;
}
static void SwI2c_Sda_Config_Input_mode(void)
{
GPIO_Init_Type gpio_init;
/* PC7 - I2C1_SDA. */
gpio_init.Pins = SWI2C1_SDA_PIN;
gpio_init.PinMode = GPIO_PinMode_In_PullUp;
gpio_init.Speed = GPIO_Speed_50MHz;
GPIO_Init(SWI2C1_SDA_PORT, &gpio_init);
GPIO_PinAFConf(SWI2C1_SDA_PORT, gpio_init.Pins, GPIO_AF_15); /* disable the alternative functions. */
}
void app_swdelay_us(uint32_t us)
{
for (uint32_t j = 0u; j < (CLOCK_SYS_FREQ / 1000000u); j++)
{
__NOP();
}
}
static void SwI2c_Delay_Us(int32_t us)
{
app_swdelay_us(us);
}
void SwI2c_Start(void)
{
SWI2C1_SCL_LOW; // 先使SCL = 0, 为SDA上的电平改变做准备
SwI2c_Delay_Us(2);
SWI2C1_SDA_HIGH; // SDA = 1
SwI2c_Sda_Config_Output_mode(); // sda OD 初始化输出1,
SWI2C1_SDA_HIGH; // SDA = 1, 此时SDA的电平变化对通讯双方没有影响
SwI2c_Delay_Us(2);
SWI2C1_SCL_HIGH; // SCL = 1
SwI2c_Delay_Us(2);
SWI2C1_SDA_LOW; // SDA=0,产生下降沿,启动IIC通讯
SwI2c_Delay_Us(2);
SWI2C1_SCL_LOW; // SCL=0,为SDA上的电平改变做准备
SwI2c_Delay_Us(2);
}
void SwI2c_Stop(void) //停止信号
{
SWI2C1_SCL_LOW ; // 先使SCL = 0, 为SDA上的电平改变做准备
SwI2c_Delay_Us(2);
SWI2C1_SDA_HIGH; // SDA = 1
SwI2c_Sda_Config_Output_mode(); // sda OD 初始化输出1,
SWI2C1_SDA_HIGH;
SwI2c_Delay_Us(2);
SWI2C1_SDA_LOW; // SDA=0,此时SDA的电平变化对通讯双方没有影响
SwI2c_Delay_Us(2);
SWI2C1_SCL_HIGH; // SCL=1
SwI2c_Delay_Us(2);
SWI2C1_SDA_HIGH; // SDA=1,结束IIC通讯
SwI2c_Delay_Us(2); // SDA在结束后维持在高电平,如果有干扰脉冲产生而使得SDA
// 变低,则干扰过后会恢复高电平. 此时SCL如果因干扰而处于
return;
}
uint8_t SwI2c_Wait_Ack(void) //等待应答信号:0-应答;1-非应答
{
uint8_t uc_time = 0;
SwI2c_Sda_Config_Input_mode(); //SDA定义为输入
SWI2C1_SDA_HIGH;
SwI2c_Delay_Us(1);
SWI2C1_SCL_HIGH;
SwI2c_Delay_Us(1);
while (SWI2C1_SDA_READ)
{
uc_time++;
if (uc_time > 250)
{
SwI2c_Stop();
return 1;
}
}
SWI2C1_SCL_LOW;
return 0;
}
void SwI2c_Ack(void) //产生 ACK 应答
{
SWI2C1_SDA_HIGH; // SDA = 1
SwI2c_Sda_Config_Output_mode(); // sda OD 初始化输出1,
SWI2C1_SDA_HIGH; // SDA输出高电平
SWI2C1_SDA_LOW; // 清SDA="0",CPU发低电平确认信号,
SwI2c_Delay_Us(2);
SWI2C1_SCL_HIGH; // 置SCL="1", 产生上升沿,发送一位确认数据
SwI2c_Delay_Us(2);
SWI2C1_SCL_LOW; // 清SCL="0",为SDA上的电平改变做准备
return;
}
void Swi2c_No_Ack(void) //产生 NACK 非应答
{
SWI2C1_SDA_HIGH; // SDA = 1
SwI2c_Sda_Config_Output_mode(); // sda OD 初始化输出1,
SWI2C1_SDA_HIGH; // 置SDA=1, CPU发"高电平非应答确认"信号
SwI2c_Delay_Us(2);
SWI2C1_SCL_HIGH; // 置SCL="1", 产生上升沿,发送一位确认数据
SwI2c_Delay_Us(2);
SWI2C1_SCL_LOW; // 清SCL="0",为SDA上的电平改变做准备
return;
}
//IIC 发送一个字节
bool SwI2c_Write_Byte(uint8_t data)
{
uint8_t m; // SDA = 1
SwI2c_Sda_Config_Output_mode(); // sda OD 初始化输出1,
for (m = 0; m < 8; m++)
{
SWI2C1_SCL_LOW; // SCL=0,为SDA上的电平改变做准备
SwI2c_Delay_Us(2);
if (data & BIT7) // 由最高位开始发送
{
SWI2C1_SDA_HIGH;
}
else
{
SWI2C1_SDA_LOW;
}
SwI2c_Delay_Us(2);
SWI2C1_SCL_HIGH; // SCL="1",产生上升沿,发送一位数据
SwI2c_Delay_Us(2);
data <<= 1;
}
SWI2C1_SCL_LOW; // 清SCL="0",产生下降沿, 器件使SDA="0"
SwI2c_Delay_Us(2);
SwI2c_Sda_Config_Input_mode(); // SDA改为输入,准备接收确认应答
SWI2C1_SCL_HIGH; // SCL="1",让CPU在此期间读取SDA上的信号
for (m = 0; m < 8; m++)
{
SwI2c_Delay_Us(2);
if (SWI2C1_SDA_READ == 0)
{
SWI2C1_SCL_LOW; // 清SCL="0",为SDA上的电平改变做准备
SwI2c_Delay_Us(2);
return true; // 收到正确的低电平应答
}
}
SWI2C1_SCL_LOW; // 清SCL="0",为SDA上的电平改变做准备
return false;
}
//只写地址
uint8_t Write_Device_Addr(uint8_t addr)
{
uint8_t read_ack = 0;
SwI2c_Start();
read_ack = SwI2c_Write_Byte(addr);
SwI2c_Stop();
return(read_ack);
}
//读一个字节
uint8_t SwI2c_Read_Byte()
{
uint8_t m, data;
SwI2c_Sda_Config_Input_mode(); // SDA改为输入,准备接收数据
data = 0;
for (m = 0; m < 8; m++)
{
SWI2C1_SCL_LOW; // SCL="0",产生下降沿, 器件串出一位数据
SwI2c_Delay_Us(2);
SWI2C1_SCL_HIGH; // 置SCL="1", 让CPU在此期间读取SDA上的信号
SwI2c_Delay_Us(2);
data <<= 1;
if (SWI2C1_SDA_READ)
{
data |= BIT0;
}
else
{
data &= (~BIT0);
}
}
SWI2C1_SCL_LOW; // 清SCL="0",为SDA上的电平改变做准备
return data;
}
//在总线上搜寻挂载的器件地址
void SwI2c_Search_Device_Addr(void)
{
uint8_t result = 0;
uint8_t j = 0;
for(j = 0;j < 128; j++)
{
if((j % 16) == 0)
{
printf("\r\n");
}
result = Write_Device_Addr(j << 1);
if(result == true)
{
printf(" %X ",j << 1);//%X 十六进制输出,大写;%x 小写
}
else
{
printf(" -- ");
}
}
printf("\r\n");
}
bool SwI2c_Device_Write_Data(uint8_t device_addr,uint8_t *reg_addr,
uint16_t reg_len,const uint8_t *buf,uint8_t len)
{
SwI2c_Start();
SwI2c_Write_Byte(device_addr);
while (reg_len != 0)
{
if (SwI2c_Write_Byte(*reg_addr++) == false) // 发送一字节数据
{
SwI2c_Stop();
return false;
}
reg_len--;
}
while (len != 0)
{
if (SwI2c_Write_Byte( *buf++) == false) // 发送一字节数据
{
SwI2c_Stop();
return false;
}
len--;
}
SwI2c_Stop();
return true;
}
uint8_t SwI2c_Device_Read_Data(uint8_t device_addr,uint8_t *reg_addr,
uint16_t reg_len, uint8_t *buf,uint8_t len)
{
SwI2c_Start();
SwI2c_Write_Byte(device_addr);
while (reg_len != 0)
{
if (SwI2c_Write_Byte(*reg_addr++) == false) // 发送一字节数据
{
SwI2c_Stop();
return false;
}
reg_len--;
}
SwI2c_Start();
SwI2c_Write_Byte(device_addr + 1);
while (1)
{
*buf++ = SwI2c_Read_Byte(); // 接收一字节
len--;
if (0 == len)
{
break;
}
SwI2c_Ack(); // 未读完,CPU发低电平确认应答信号,以便读取下8位数据
}
Swi2c_No_Ack(); // 已读完所有的数据,CPU发"高电平非应答确认"信号
SwI2c_Stop();
return true;
}
SwI2c_Search_Device_Addr();
SwI2c_Device_Read_Data(0xC4,®,1,&id,1);
printf("get msa311 partid == 0x%02x\r\n",id);
代码下载