I2C总线标准代码
/********
起始信號,SCL=1,時鐘總線為高電平,數據總線由高電平變為低電平SDA=1-->SDA=0
void I2C_Start(void)
{
I2C_SCL_HIGH();//SCL=1
I2C_SDA_HIGH();//SDA=1? 開始都為高電平,當SDA為低電平為起始信號
I2C_DELAY();
I2C_SDA_LOW();
I2C_DELAY();
I2C_SCL_LOW();
I2C_DELAY();
}
停止信號 SCL=1,SDA=0,時鐘總線為高電平,數據總線由低電平變為高電平SDA=0-->SDA=1
void I2C_Stop(void)
{
????I2C_SDA_Low();
????I2C_SCL_High();
????I2C_Delay();
????I2C_SDA_High();
????I2C_Delay();
}
發送一個字節8位
u8 I2C_SendByte(uint8_t Byte)
{
????uint8_t i;
????for(i = 0 ; i < 8 ; i++)/* 先發送高位字節 */
????{
????????if(Byte & 0x80)
????????{
????????????I2C_SDA_High();
????????}
????????else
????????{
????????????I2C_SDA_Low();
????????}
????????I2C_Delay();
????????I2C_SCL_High();
????????I2C_Delay();
????????I2C_SCL_Low();
????????I2C_Delay();
????????if(i == 7)
????????{
????????????I2C_SDA_High();?????????????????????/* 釋放SDA總線 */
????????}
????????Byte <<= 1;?????????????????????????????/* 左移一位? */
????????I2C_Delay();
????}
}
?
//CPU從I2C總線設備上讀取一個字節(8bit數據)
u8 I2C_ReadByte(void)
{
? ? uint8_t i;
? ? uint8_t value;
?
? ? /* 先讀取最高位即bit7 */
? ? value = 0;
? ? for(i = 0 ; i < 8 ; i++)
? ? {
? ? ? ? value <<= 1;
? ? ? ? I2C_SCL_High();
? ? ? ? I2C_Delay();
? ? ? ? if(I2C_SDA_READ())
? ? ? ? {
? ? ? ? ? ? value++;
? ? ? ? }
? ? ? ? I2C_SCL_Low();
? ? ? ? I2C_Delay();
? ? }
? ? return value;
}
//CPU產生一個ACK信號
void I2C_Ack(void)
{
? ? I2C_SDA_Low();
? ? I2C_Delay();
? ? I2C_SCL_High();
? ? I2C_Delay();
? ? I2C_SCL_Low();
? ? I2C_Delay();
? ? I2C_SDA_High();
}
//CPU產生一個非ACK信號
void I2C_NoAck(void)
{
? ? I2C_SDA_High();
? ? I2C_Delay();
? ? I2C_SCL_High();
? ? I2C_Delay();
? ? I2C_SCL_Low();
? ? I2C_Delay();
}
//CPU產生一個時鐘,并讀取器件的ACK應答信號
uint8_t I2C_WaitToAck(void)
{
? ? uint8_t redata;
? ? I2C_SDA_High();
? ? I2C_Delay();
? ? I2C_SCL_High();
? ? I2C_Delay();
? ? if(I2C_SDA_READ())
? ? {
? ? ? ? redata = 1;
? ? }
? ? else
? ? {
? ? ? ? redata = 0;
? ? }
? ? I2C_SCL_Low();
? ? I2C_Delay();
? ? return redata;
}
寫數據時序圖進行分解,經分解后如下圖所示:
結合I2C總線協議的知識,我們可以知道I2C寫數據由一下10個步驟組成。?
??第一步,發送一個起始信號。?
??第二步,發送7bit從機地址,即OZ9350的地址。此處需要注意,發送數據時,無法發送7bit數據,此處發送了7bit地址+1bit讀寫選擇位,即發送7bit+r/w。最低位為1表示讀,為0表示寫。?
??第三步,產生一個ACK應答信號,此應答信號為從機器件產生的應答。?
??第四步,發送寄存器地址,8bit數據。?
??第五步,產生一個ACK應答信號,此應答信號為從機器件產生的應答。?
??第六步,發送一個數據,8bit數據。?
??第七步,產生一個ACK應答信號,此應答信號為從機器件產生的應答信號。?
??第八步,發送一個CRC校驗碼,此CRC校驗值為2、4、6步數據產生的校驗碼。?
??第九步,既可以發送一個應答信號,也可以發送一個無應答信號,均有從機器件產生。?
??第十步,發送一個停止信號。?
??接下來,按照以上十個步驟,可以寫出i2c寫數據的函數。代碼如下: ?
u8 I2C_WriteBytes(void)
{
? ? I2C_Start(); ? ? ? ? ? ? ? ? ? ?//1
? ? I2C_SendByte(Slaver_Addr | 0); ?//2
? ? I2C_WaitToAck(); ? ? ? ? ? ? ? ?//3
? ? I2C_SendByte(Reg_Addr); ? ? ? ? //4
? ? I2C_WaitToAck(); ? ? ? ? ? ? ? ?//5
? ? I2C_SendByte(data); ? ? ? ? ? ? //6
? ? I2C_WaitToAck(); ? ? ? ? ? ? ? ?//7
? ? I2C_SendByte(crc); ? ? ? ? ? ? ?//8
? ? I2C_WaitToAck(); ? ? ? ? ? ? ? ?//9
? ? I2C_Stop(); ? ? ? ? ? ? ? ? ? ? //10
}
讀數據的時序圖經分解后如下圖所示:
通過分解后的時序圖,可以看到OZ9350的讀數據由以下13個步驟組成。?
??第一步,發送一個起始信號。?
??第二步,發送7bit從機地址,即OZ9350的地址。此處需要注意,發送數據時,無法發送7bit數據,此處發送了7bit地址+1bit讀寫選擇位,即發送7bit+r/w。最低位為1表示讀,為0表示寫。?
??第三步,產生一個ACK應答信號,此應答信號為從機器件產生的應答。?
??第四步,發送寄存器地址。?
??第五步,產生一個ACK應答信號,此應答信號為從機器件產生的應答。?
??第六步,再次發送一個騎士信號。?
??第七步,發送7bit從機地址,即OZ9350的地址。此處需要注意,發送數據時,無法發送7bit數據,此處發送了7bit地址+1bit讀寫選擇位,即發送7bit+r/w。最低位為1表示讀,為0表示寫。?
??第八步,產生一個ACK應答信號,此應答信號為從機器件產生的應答。?
??第九步,讀取一個字節(8bit)的數據。?
??第十步,產生一個ACK應答信號,此應答信號為CPU產生。?
??第十一步,讀取一個CRC校驗碼。?
??第十二步,產生一個NACK信號。此無應答信號由CPU產生。?
??第十三步,產生一個停止信號。?
??接下來,由以上分析步驟,可以寫出OZ9350的I2C讀數據代碼。如下所示:
u8 I2C_ReadBytes(void)
{
? ? u8 data;
? ? u8 crc;
? ? I2C_Start(); ? ? ? ? ? ? ? ? ? ?//1
? ? I2C_SendByte(Slaver_Addr | 0); ?//2
? ? I2C_WaitToAck(); ? ? ? ? ? ? ? ?//3
? ? I2C_SendByte(Reg_Addr); ? ? ? ? //4
? ? I2C_WaitToAck(); ? ? ? ? ? ? ? ?//5
? ? I2C_Start(); ? ? ? ? ? ? ? ? ? //6
? ? I2C_SendByte(Slaver_Addr | 1); ?//7 1-讀
? ? I2C_WaitToAck(); ? ? ? ? ? ? ? ?//8
? ? data=I2C_ReadByte(); ? ? ? ? ? ?//9
? ? I2C_Ack(); ? ? ? ? ? ? ? ? ? ? ?//10
? ? crc=I2C_ReadByte(); ? ? ? ? ? ? //11
? ? I2C_NoAck(); ? ? ? ? ? ? ? ? ? ?//12
? ? I2C_Stop(); ? ? ? ? ? ? ? ? ? ? //13
}
寫:MCU在數據總線上的數據穩定之后,檢測邊沿信號(上升沿)寫數據到器件;
讀:MCU發出邊沿信號(下降沿)告訴器件發送數據,檢測到邊沿信號之后,器件改變(更新)數據,等待穩定之后MCU讀取數據
數據的寫操作:圖中演示了I2C連續寫數據,兩個字節的連續寫入,更多字節同樣
數據的讀操作:在上圖中,可以認為寫入了設備地址及寄存器地址,再次重啟總線后,發送讀命令,連續讀取兩個字節,發送NACK,發送停止信號;
?
總結
- 上一篇: Linux编程简介——VI
- 下一篇: 隐藏网页文件的后缀(IIS测试通过)!