IIC(Inter-Integrated Circuit) 总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接
微控制器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和接收数据。
在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。
IIC 总线在传送数据过程中共有三种类型信号, 分别是:开始信号、结束信号和应答
信号。
这些信号中,起始信号是必需的,结束信号和应答信号,都可以不要。IIC 总线时序图如
图所示:
为驱动实验室自研基于 DAC60502 的双通道电流输出模块,使用 EMIO 模拟 IIC 实现。
问:为啥不用硬件 IIC
答:就想用模拟的嘿嘿嘿
用软件模拟 IIC,最大的好处就是方便移植,同一个代码兼容所有 MCU,任何一个微控制器
只要有 IO 口,就可以很快的移植过去,而且不需要特定的 IO 口。
/*** Copyright (c) 2022-2023,HelloAlpha* * Change Logs:* Date Author Notes*/
#include "iic_io.h"extern XGpioPs GpioPs;void SCL_OUT(void)
{XGpioPs_SetDirectionPin(&GpioPs, SCL_PIN, GPIO_MODEL_OUTPUT);XGpioPs_SetOutputEnablePin(&GpioPs, SCL_PIN, GPIO_OUTPUT_ENABLE);
}void SCL_HIGH(void)
{XGpioPs_WritePin(&GpioPs, SCL_PIN, GPIO_SET);
}void SCL_LOW(void)
{XGpioPs_WritePin(&GpioPs, SCL_PIN, GPIO_RESET);
}void SDA_IN(void)
{XGpioPs_SetDirectionPin(&GpioPs, SDA_PIN, GPIO_MODEL_INPUT);
}uint32_t SDA_READ(void)
{return XGpioPs_ReadPin(&GpioPs, SDA_PIN);
}void SDA_OUT(void)
{XGpioPs_SetDirectionPin(&GpioPs, SDA_PIN, GPIO_MODEL_OUTPUT);XGpioPs_SetOutputEnablePin(&GpioPs, SDA_PIN, GPIO_OUTPUT_ENABLE);
}void SDA_HIGH(void)
{XGpioPs_WritePin(&GpioPs, SDA_PIN, GPIO_SET);
}void SDA_LOW(void)
{XGpioPs_WritePin(&GpioPs, SDA_PIN, GPIO_RESET);
}int IIC_Init(void)
{SCL_OUT();SCL_HIGH();SDA_OUT();SDA_HIGH();return 0;
}
/*** Copyright (c) 2022-2023,HelloAlpha** Change Logs:* Date Author Notes*/
#ifndef __IIC_IO_H__
#define __IIC_IO_H__#include "xgpiops.h"#define SCL_PIN 54
#define SDA_PIN 55#define GPIO_RESET 0
#define GPIO_SET 1#define GPIO_MODEL_INPUT 0
#define GPIO_MODEL_OUTPUT 1#define GPIO_OUTPUT_DISABLE 0
#define GPIO_OUTPUT_ENABLE 1void SCL_OUT(void);
void SCL_HIGH(void);
void SCL_LOW(void);void SDA_IN(void);
uint32_t SDA_READ(void);void SDA_OUT(void);
void SDA_HIGH(void);
void SDA_LOW(void);int IIC_Init(void);#endif
/*** Copyright (c) 2022-2023,HelloAlpha** Change Logs:* Date Author Notes*/
#include "iic_ctrl.h"
#include "sleep.h"#define I2C_DELAY(...) usleep(__VA_ARGS__)void IIC_Start(void)
{SDA_OUT();SDA_HIGH();SCL_HIGH();I2C_DELAY(4);SDA_LOW();I2C_DELAY(4);SCL_LOW();I2C_DELAY(2);
}void IIC_Stop(void)
{SDA_OUT();SCL_LOW();SDA_LOW();I2C_DELAY(4);SCL_HIGH();SDA_HIGH();I2C_DELAY(4);
}// 1,接收应答失败
// 0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{uint8_t ucErrTime=0;SDA_OUT();SDA_HIGH();I2C_DELAY(1);SCL_HIGH();I2C_DELAY(1);SDA_IN();while(SDA_READ()){ucErrTime++;if(ucErrTime > 250){IIC_Stop();return 1;}}SCL_LOW();return 0;
}//产生ACK应答
void IIC_Ack(void)
{SCL_LOW();SDA_OUT();SDA_LOW();I2C_DELAY(2);SCL_HIGH();I2C_DELAY(2);SCL_LOW();
}
//不产生ACK应答
void IIC_NAck(void)
{SCL_LOW();SDA_OUT();SDA_HIGH();I2C_DELAY(2);SCL_HIGH();I2C_DELAY(2);SCL_LOW();
} void IIC_Write_Byte(uint8_t data)
{uint8_t i = 0;SDA_OUT();SCL_LOW();for(i=0; i<8; i++){if(data & 0x80 )SDA_HIGH();elseSDA_LOW();data <<= 1;I2C_DELAY(2);SCL_HIGH();I2C_DELAY(2);SCL_LOW();I2C_DELAY(2);}
}// ack = 1,发送 ACK
// ack = 0,发送 nACK
uint8_t IIC_Read_Byte(uint8_t ack)
{uint8_t i = 0, data = 0;SDA_IN();for(i = 0; i < 8; i++){SCL_LOW();I2C_DELAY(2);SCL_HIGH();data <<= 1;if(SDA_READ())data++;I2C_DELAY(1);}if(!ack)IIC_NAck();elseIIC_Ack();return data;
}void IIC_Write_UINT16(uint8_t dev_addr, uint8_t wr_addr, uint16_t data)
{IIC_Start();IIC_Write_Byte(dev_addr);IIC_Wait_Ack(); IIC_Write_Byte(wr_addr);IIC_Wait_Ack(); IIC_Write_Byte(data >> 8);IIC_Wait_Ack(); IIC_Write_Byte(data & 0xFF);IIC_Wait_Ack(); IIC_Stop();I2C_DELAY(800);
}uint16_t IIC_Read_UINT16(uint8_t dev_addr, uint8_t rd_addr)
{uint16_t data;IIC_Start();IIC_Write_Byte(dev_addr);IIC_Wait_Ack();IIC_Write_Byte(rd_addr);IIC_Wait_Ack(); IIC_Start(); IIC_Write_Byte(dev_addr + 1);IIC_Wait_Ack();data = IIC_Read_Byte(1);data = (data <<8 ) + IIC_Read_Byte(0);IIC_Stop();return data;
}
/*** Copyright (c) 2022-2023,HelloAlpha** Change Logs:* Date Author Notes*/
#ifndef __I2C_CTRL_H__
#define __I2C_CTRL_H__#include "iic_io.h"void IIC_Start(void);
void IIC_Stop(void);
uint8_t IIC_Wait_Ack(void);
void IIC_Ack(void);
void IIC_NAck(void);
void IIC_Write_Byte(uint8_t value );
uint8_t IIC_Read_Byte(uint8_t addr);
void IIC_Write_UINT16(uint8_t dev_addr, uint8_t wr_addr, uint16_t data);
uint16_t IIC_Read_UINT16(uint8_t dev_addr, uint8_t rd_addr);#endif