/************************************************************
利用IO口模擬IIC時序,需要使用2個IO口(SDA和SCL)
?? ?SCL時鐘線只能由主器件進行控制,所以SCL引腳必須為輸出模式
SDA數據線,在主器件發送數據時,SDA引腳為輸出模式
SDA數據線,在主器件接收數據時,SDA引腳為輸入模式
************************************************************/
//配置SCL——》PB6,PB7的引腳設置
#define ?SDA_SET(n) ?(n)?(GPIO_SetBits(GPIOB,GPIO_Pin_7)):(GPIO_ResetBits(GPIOB,GPIO_Pin_7))?
#define ?SCL_SET(n) ?(n)?(GPIO_SetBits(GPIOB,GPIO_Pin_6)) : (GPIO_ResetBits(GPIOB,GPIO_Pin_6))?
#define ?SDA_READ ? ?GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7)
void IIC_SCLConfig(void)
{
//打開GPIOA時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure = {0};//定義結構體GPIO外設結構體變量
?? ??? ?GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //配置引腳
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;?
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //推挽模式
GPIO_Init(GPIOB, &GPIO_InitStructure);
}?
//配置IIC_Config初始化
void IIC_Config(void)
{
IIC_SCLConfig();
?? ?//開始期間SDA 與SCL都空閑狀態是高電平
SDA_SET(1);
SCL_SET(1);
Delay_nus(5);
}
//IIC的開始信號
void IIC_Start(void)
{
//2.確保SDA與SCL空閑處于高電平
SDA_SET(1);
SCL_SET(1);
Delay_nus(5);
//3.SDA電平拉低
SDA_SET(0);
Delay_nus(5);
//4.把SCL引腳電平拉底此時,此時準備數據
SCL_SET(0);
Delay_nus(5);
}
//IIC的發送字節 ?
//由于:開始-->發送字節-->等待應答-->發送字節所以第一步不能少
void IIC_SendByte(uint8_t Byte)
{
//2.把SCL引腳電平拉底此時,此時準備數據
SCL_SET(0);
Delay_nus(5);
//3.此時準備數據
for(uint8_t i = 0;i < 8;i++)
{
//4.判斷最高位是0或者是1
if(Byte & 0x80)
{
SDA_SET(1);
}
else
{
SDA_SET(0);
}
Byte <<= 1;
Delay_nus(5);
//5.此時SCL引腳電平拉高,從機接收數據
SCL_SET(1);
Delay_nus(5);
//6.把SCL引腳電平拉底此時,此時準備數據
SCL_SET(0);
Delay_nus(5);
}
}
//判斷是否從機應答
uint8_t IIC_SlaveACK(void)
{
uint8_t data = 0;
SDA_SET(1);//主機釋放SDA,讓從機對SDA進行控制
//2.把SCL引腳電平拉低,此時第九個脈沖的低電平,此時從機準備Bit
SCL_SET(0);
Delay_nus(5);
//3.把SCL引腳電平拉高,此時第九個脈沖高電平到來
SCL_SET(1);
Delay_nus(5);
//4.主機讀取狀態 1:表示未應答 ? 0:表示已應答
if(SDA_READ)
{
data = 1;
}
else
{
data = 0;
}
//5.把SCL引腳電平拉低,此時第九個脈沖的結束
SCL_SET(0);
Delay_nus(5);
return data;
}
//IIC讀取數據
uint8_t IIC_ReadData(void)
{
uint8_t data = 0;?
SCL_SET(0);
//主機釋放SDA,讓從機對SDA進行控制
SDA_SET(1);
//3.主機循環八次讀取數據
for(uint8_t i = 0;i < 8;i++)
{
//2.把SCL引腳拉低,此時從機準備數據
SCL_SET(0);
Delay_nus(5);
//4.把SCL電平拉高8bit,此時主機讀取bit
SCL_SET(1);
Delay_nus(5);
//5.主機讀取bit
data <<= 1;
data |= SDA_READ;
//Delay_nus(5);
}
//?? ?//6.把SCL引腳電平拉低,此時準備數據
//?? ?SCL_SET(0);
//?? ?Delay_nus(5);
return data;
}
//主機應答 ?ACK = 1 表示不應答 ? ACK = 0表示應答
void IIC_MasterACK(uint8_t Ack)
{
?? ?//2.把SCL引腳電平拉低,此時主機準備應答
SCL_SET(0);
Delay_nus(5);
//3.判斷主機是否應答 1:表示未應答 ? 0:表示已應答
if(Ack)
{
SDA_SET(1);
}
else
{
SDA_SET(0);
}
?? ?//4.把SCL引腳電平拉高,從機讀取應答
SCL_SET(1);
Delay_nus(5);
//5.把SCL引腳電平拉低
SCL_SET(0);
Delay_nus(5);
}
//停止位
void IIC_Stop(void)
{
//1.SDA配置為輸出模式
//?? ?IIC_SDAConfig(GPIO_Mode_Out_OD);
//2.確保SDA與SCL都為低電平
SDA_SET(0);
SCL_SET(0);
Delay_nus(5);
//3.SCL電平拉高
SCL_SET(1);
Delay_nus(5);
//4.SDA電平拉高
SDA_SET(1);
Delay_nus(5);
}