IIC是多主、多從、單工IIC的串行總線,傳輸僅需兩根線,SDA(數據線)、SCL(時鍾線)
IIC空閑時SDA和SCL都處於高電平狀態(兩根線一般情況均接上拉電阻)
IIC傳輸數據的模式為每傳輸8位后,要通過一個ACK位進行相互確認。
個人認為SCL產生上升沿后,設備開始檢測SDA的電平,當SDA下降,SCL為高,表示開始工作,以此作為當前傳輸的數據,SCL的下降沿是作為SDA信息可調整的信號,在之后就能進行SDA的電平調整。
IIC有三種速率選擇:
普通模式(100kbps)
快速模式(400kbps)
高速模式(3.4Mbps)
具體選用哪種速率要看對應IIC設備數據手冊能支持的最大速率是多少,並通過更改時序中的延時時間進行切換。 IIC驅動代碼基本上通用於任何IIC設備上。實現包括IIC 的初始化(IO 口)、 IIC 開始、 IIC 結束、 ACK、 IIC讀寫等功能 IIC 的初始化(IO 口)、 IIC 開始、 IIC 結束、 ACK、 IIC讀寫等功能 。
IIC初始化代碼:
#define IIC_SCL_H HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_SET) //SCL H #define IIC_SCL_L HAL_GPIO_WritePin(GPIOC,GPIO_PIN_12,GPIO_PIN_RESET) //SCL H #define IIC_SDA_H HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_SET) //SDA_H #define IIC_SDA_L HAL_GPIO_WritePin(GPIOC,GPIO_PIN_11,GPIO_PIN_RESET) //SDA_L #define READ_SDA HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_11) //輸入SDA
上面為.h中的SDA、SCL的宏定義
void IIC_Init(void) { GPIO_InitTypeDef GPIO_Initure; __HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC時鍾 //PC11,12初始化設置 GPIO_Initure.Pin=GPIO_PIN_11|GPIO_PIN_12; GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出 GPIO_Initure.Pull=GPIO_PULLUP; //上拉 GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速 HAL_GPIO_Init(GPIOC,&GPIO_Initure); GPIO_Initure.Pin = GPIO_PIN_10; GPIO_Initure.Mode=GPIO_MODE_INPUT; GPIO_Initure.Pull=GPIO_NOPULL; GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH; //高速 HAL_GPIO_Init(GPIOC,&GPIO_Initure); IIC_SDA_H; IIC_SCL_H; delay_nms(5); }
記得初始化時把SDA和SCL拉高
IIC開始:
void IIC_Start(void) { IIC_SDA_H; IIC_SCL_H; delay_nns(5); IIC_SDA_L;//START:when CLK is high,DATA change form high to low delay_nns(5); IIC_SCL_L;//鉗住I2C總線,准備發送或接收數據 delay_nns(5); }
IIC結束:
void IIC_Stop(void) { IIC_SDA_L;//STOP:when CLK is high DATA change form low to high delay_nns(5); IIC_SCL_H; delay_nns(5); IIC_SDA_H;//發送I2C總線結束信號 delay_nns(5); }
發送ACK:
void IIC_Ack(void) { IIC_SDA_L; delay_nns(5); IIC_SCL_H; delay_nns(5); IIC_SCL_L; delay_nns(5); IIC_SDA_H; }
不發送NACK:
void IIC_NAck(void) { IIC_SDA_H; delay_nns(5); IIC_SCL_H; delay_nns(5); IIC_SCL_L; delay_nns(5); IIC_SDA_L; }
等待ACK:
uint8_t IIC_Wait_Ack(void) { uint8_t ucErrTime=0; //SDA_IN(); //SDA設置為輸入 IIC_SDA_H; delay_nns(5); IIC_SCL_H; delay_nns(5); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL_L;//時鍾輸出0 return 0; }
發送字節:
void IIC_Send_Byte(uint8_t txd) { IIC_SCL_L;//拉低時鍾開始數據傳輸 for(uint8_t i = 0;i < 8;i++) { if(txd&0x80) IIC_SDA_H; else IIC_SDA_L; txd<<=1; IIC_SCL_H; delay_nns(5); IIC_SCL_L; delay_nns(5); } // IIC_SDA_H; // IIC_SCL_H; //當去掉wait_ack時的時候添加 // delay_nns(5); //IIC_SCL_L; }
讀取字節:
uint8_t IIC_Read_Byte(unsigned char ack) { uint8_t TData=0,i; for(i=0;i<8;i++) { IIC_SCL_H; delay_nns(5); TData=TData<<1; //if(GPIOB->IDR& GPIO_IDR_IDR7) //判斷SDA是否為高 if(SDA_READ) { TData|=0x01; } IIC_SCL_L; delay_nns(5); } if(!ack) IIC_NAck(); else IIC_Ack(); // IIC_SCL_L; // delay_nns(5); // IIC_SDA_L; // delay_nns(5); //ACK // IIC_SCL_H; // delay_nns(5); // IIC_SCL_L; // delay_nns(5); // IIC_SDA_H; return TData; }
以上為IIC通用代碼,但是注意每次發完數據之后需要 wait_ACK檢測是否發送成功!
