7.1.I2C 基礎知識
I2C(Inter-Integrated Circuit)總線是一種由Philips公司開發的兩線式串行總線,用于內部IC控制的具有多端控制能力的雙線雙向串行數據總線系統,能夠用于替代標準的并行總線,連接各種集成 電路和功能模塊。I2C器件能夠減少電路間的連接,減少電路板的尺寸,降低硬件成本并提高系統的可靠性。I2C總線傳輸模式具有向下兼容性,傳輸速率標準模式下可達100kbps,快速模式下可 達400kbps,高速模式下可達3.4Mbps。
為了清楚起見,在此對I2C通信中關于設備的基本概念進行簡要講解。
① 發送設備:發送數據到總線上的設備。
② 接收設備:從總線上接收數據的設備。
④ 從設備:被主設備尋址的設備。
多主:多個主設備可以嘗試在不破壞信息的前提下同時控制線。
同步:同步兩個或更多設備之間的時鐘信號的過程。
仲裁:如果超過一個主設備同時試圖控制總線,只有一個主設備被允許,且獲勝主設備的信息不被破壞。
(1)I2C設備連接原理 I2C設備連接示意圖如設備連接示意圖所示。I2C總線是由數據線SDA和時鐘線SCL構成的串行總線,可發送和接收數據。在GD32 MCU與被控IC(集成電路)之間、IC與IC之間進行雙向傳送,最高傳送速率1Mbps。各種設備均并聯在總線上,兩條總線都被上拉電阻上拉到VCC,所有設備地位對等,都可作為主機或從機,就像電話機一樣只要撥通各自的號碼就能正常工作,所以,每個設備都有唯一的地址。在信息的傳輸過程中,I2C總線上并接的每個設備既是主設備(或從設備),又是發送設備(或接收設備),這取決于它所要完成的功能。每個設備都可以把總線接地拉低,卻不允許把總線電平直接連到VCC上置高。把總線電平拉低稱為占用總線,總線電平為高等待被拉低則稱為總線被釋放。
I2C 設備連接示意圖

由于SDA和SCL均為雙向I/O線,都是開漏極端(輸出1時,為高阻狀態),因此I2C總線上的所有設備的SDA和SCL引腳都要外接上拉電阻。
(2)I2C數據通信協議
I2C數據通信時序圖如I2C數據通信時序圖所示。下面首先介紹起始位和停止位,起始位和停止位都是由主設備產生的,如圖中虛線所示。當SCL時鐘線為高電平時,SDA數據線上由高到低的跳變,產生一個開始信號,即起始位。當SCL時鐘線為高電平時,SDA數據線上由低到高的跳變,將產生一個停止信號,即停止位。起始位之后,總線被認為忙,即有數據在傳輸,傳輸的第一個字節,即7位從地址和R/ ̄W 位。當R/ ̄W位為0時,主機向從機發送數據;當R/ ̄W位為1時,主機接收來自從機的數據。在每個字節后的第九個SCL時鐘上,接收機發送ACK位。停止位之后,總線被認為閑,空閑狀態時,SDA和SCL都是高電平。
注意:當SCL位為高電平時,SDA的數據必須保持穩定,否則,由于起始位和停止位的電氣邊沿特性,SDA上數據發生改變將被識別為起始位或停止位。所以,只有當SCL為低電平時才允許SDA上的數據改變。
I2C 數據通信時序圖

I2C總線上每位數據傳輸的示意圖

(3)I2C的尋址方式 GD32 MCU的I2C模塊支持7位和10位兩種尋址模式,7位尋址模式最多尋址128個設備,10位尋址模式最多尋址1024個設備。I2C總線理論上可以允許的最大設備數是以總線上所有器件的電容總和不超過400pF為限(其中,包括連線本身的電容和其連接端的引出等效電容),總線上所有器件要依靠SDA發送的地址信號尋址,不需要片選信號。
① 7位尋址模式
如圖下圖所示為7位地址方式下的I2C數據傳輸格式,第一個字節由7位從地址和R/ ̄W讀/寫位組成。不論總線上傳送的是地址還是數據信息,每個字節傳輸完畢,接收設備都會發送響應位(ACK)。地址類信息傳輸之后是數據信息,直到接收到停止信息。
7 位尋址模式數據格式

② 10位尋址模式
如下圖所示為10位地址方式下的I2C數據傳輸格式。第一個字節由二進制位11110、從地址的最高兩位及R/ ̄W讀/寫控制位組成。第一個字節傳輸完畢后是ACK響應位。第二個字節就是10位從地址的低8位,后面是響應位和數據。
10 位尋址模式數據格式

③ 二次發送從地址模式(重復產生起始條件)
主機可以在不停止數據傳輸的情況下,通過產生重復的起始條件,改變SDA上數據流的方向,這稱為RESTART。再次發送起始信號后,需重新發送從地址和R/ ̄W讀/寫控制位。重新產生起始條件數據傳輸格式如圖所示。

7.2.GD32 I2C 外設原理簡介
因篇幅有限,本文無法詳細介紹GD32所有系列I2C外設接口,下面以GD32F30x為列,著重介紹下GD32F30x的I2C外設簡介和結構框圖,后介紹下各個系列的差異。
GD32 I2C 主要特性
GD32F30X系列I2C 接口模塊實現了 I2C 協議的標速模式,快速模式以及快速+ 模式,具備CRC 計算和校驗功能、支持 SMBus(系統管理總線) 和 PMBus(電源管理總線),此外還支持多主機 I2C 總線架構。 I2C 接口模塊也支持 DMA 模式,可有效減輕 CPU 的負擔。
GD32 MCU I2C模塊主要特性描述如下:
? 并行總線至 I2C 總線協議的轉換及接口;
? 同一接口既可實現主機功能又可實現從機功能;
? 主從機之間的雙向數據傳輸;
? 支持 7 位和 10 位的地址模式和廣播尋址;
? 支持 I2C 多主機模式;
? 支持標速(最高 100 KHz),快速(最高 400 KHz) 和快速+ 模式(最高 1MHz);
? 從機模式下可配置的 SCL 主動拉低;
? 支持 DMA 模式;
? 兼容 SMBus 2.0 和 PMBus;
? 兩個中斷:字節成功發送中斷和錯誤事件中斷;
? 可選擇的 PEC(報文錯誤校驗) 生成和校驗;
I2C 結構框圖介紹
I2C內部結構框圖如下圖所示,該結構框圖可分為五個部分:
1、用于產生I2C通信時序;
2、用于收發I2C數據,當有數據需要發送時,會首先將數據填充到數據寄存器,然后數據被自動移位到移位寄存器,通過SDA引腳發送出去,當有數據需要接受時,首先會根據SCL選擇的時鐘邊沿在移位寄存器中鎖存SDA數據,當數據接受到后,數據被移到數據緩沖寄存器,并置位接受緩沖區非空標志;
3、用于收發數據CRC計算;
4、用于I2C模塊控制及相關標志位查詢;
5、系統通過APB總線對I2C數據寄存器及控制寄存器進行操作。

各系列 I2C 功能差異
GD32各系列MCU有關IIC功能差異如各系列I2C功能差異表所示。

7.3.硬件連接說明
如AT24C02C EEPROM IIC接口參考電路圖所示,AT24C02C為IIC接口的EEPROM,該電路圖為其典型參考電路,其中5腳為I2C SDA引腳,6腳為I2C SCL引腳,I2C總線需要通過4.7K歐姆電阻上拉。

7.4.軟件配置說明
本小節講解I2C_Example下的I2C0主機歷程,本例程講解IIC作為主機情況下對從機的讀寫,并引入超時恢復機制。
IIC 初始化配置
IIC初始化配置代碼如代碼清單I2C初始化配置所示,首先進行GPIO初始化,然后對IIC外設進行初始化。注意本例程僅講解IIC0的外設引腳及模塊初始化,若其他IIC模塊可參考修改。
void I2C_init(uint32_t I2Cx) { GPIO_Configuration_I2C(I2Cx); i2c_clock_config(I2Cx, 400000, I2C_DTCY_2); /* I2C address configure */ i2c_mode_addr_config(I2Cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0); /* enable acknowledge */ i2c_ack_config(I2Cx, I2C_ACK_DISABLE); /* enable I2Cx */ i2c_enable(I2Cx); }
時鐘及 GPIO 引腳配置
時鐘及GPIO引腳配置如代碼清單I2C時鐘及GPIO引腳配置所示,在例程中PB6、PB7引腳需要配置為復用開漏模式。
void GPIO_Configuration_I2C(uint32_t I2Cx) { uint32_t GPIO_SDA; uint32_t GPIO_SCL; uint32_t GPIO_Pin_SDA,GPIO_Pin_SCL; rcu_periph_reset_enable(RCU_I2C0RST); rcu_periph_reset_disable(RCU_I2C0RST); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X /* enable GPIOB clock */ rcu_periph_clock_enable(RCU_GPIOB); /* enable I2C0 clock */ rcu_periph_clock_enable(RCU_I2C0); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X rcu_periph_clock_enable(RCU_AF); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #endif GPIO_SCL=GPIOB; GPIO_Pin_SCL=GPIO_PIN_6; GPIO_SDA=GPIOB; GPIO_Pin_SDA=GPIO_PIN_7; #endif /* Reset I2C1 IP */ // I2C_DeInit(I2Cx); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X /* I2C0 GPIO ports */ /* connect PB6 to I2C0_SCL */ gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); /* connect PB7 to I2C0_SDA */ gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #if defined GD32F1X0 || GD32F3X0 || GD32E23X /* I2C GPIO ports */ /* connect I2C_SCL_GPIO_PIN to I2C_SCL */ gpio_af_set(GPIO_SCL, GPIO_AF_1, GPIO_Pin_SCL); /* connect I2C_SDA_GPIO_PIN to I2C_SDA */ gpio_af_set(GPIO_SDA, GPIO_AF_1, GPIO_Pin_SDA); #elif defined GD32F4XX gpio_af_set(GPIO_SCL, GPIO_AF_4, GPIO_Pin_SCL); gpio_af_set(GPIO_SDA, GPIO_AF_4, GPIO_Pin_SDA); #endif gpio_mode_set(GPIO_SCL, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SCL); gpio_output_options_set(GPIO_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); gpio_mode_set(GPIO_SDA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SDA); gpio_output_options_set(GPIO_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #endif }
I2C 多字節寫操作
I2C多字節寫操作如代碼清單IIC寫多字節操作所示,該函數接口實現IIC外設對IIC從機的多字節寫操作。
/*! \brief I2Cx Write NBytes \param[in] i2c_periph : I2Cx(x=0,1) \param[in] addr : slave address \param[in] start_Addr : reg \param[in] number_Bytes: number to Write \param[in] ADDR_Length : number of the addr */ I2C_Status I2Cx_Write_NBytes(uint32_t I2Cx,uint8_t driver_Addr, uint16_t start_Addr, uint8_t number_Bytes, uint8_t *write_Buffer,uint8_t ADDR_Length) { uint32_t I2C_Timeout = I2C_SHORT_TIMEOUT; i2c_ack_config(I2Cx,I2C_ACK_ENABLE); while(i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_start_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND); I2C_Timeout = I2C_SHORT_TIMEOUT; while(SET != i2c_flag_get( I2Cx , I2C_FLAG_TBE )) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_enable(I2Cx); if(ADDR_Length)//á?×??úμ??· { i2c_data_transmit(I2Cx, (uint8_t)((start_Addr & 0xFF00) >> 8)); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_data_transmit(I2Cx, (uint8_t)(start_Addr & 0x00FF)); } else { i2c_data_transmit(I2Cx, start_Addr); } I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } while(number_Bytes) { i2c_data_transmit(I2Cx, *write_Buffer); I2C_Timeout = I2C_SHORT_TIMEOUT; //while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED))//5 // while(!i2c_flag_get(I2Cx, I2C_BTC))// while(!i2c_flag_get(I2Cx, I2C_FLAG_TBE)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* point to the next location where the byte read will be saved */ write_Buffer++; /* decrement the read bytes counter */ number_Bytes--; } // while(!i2c_flag_get(I2C1, I2C_BTC)) // { // if((I2C_Timeout--) == 0) // { // Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); // return I2C_FAIL; // } // } /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while (I2C_CTL0(I2Cx) & 0x0200) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_ack_config(I2Cx,I2C_ACK_ENABLE); return I2C_OK; }
IIC 多字節讀操作
IIC多字節讀操作如代碼清單IIC多字節讀操作所示,該函數接口可實現對IIC從機的多字節讀功能。
I2C_Status I2Cx_Read_NBytes(uint32_t I2Cx,uint8_t driver_Addr, uint16_t start_Addr, uint8_t number_Bytes, uint8_t *read_Buffer,uint8_t ADDR_Length) { uint32_t I2C_Timeout = I2C_SHORT_TIMEOUT; i2c_ack_config(I2Cx,I2C_ACK_ENABLE); while(i2c_flag_get(I2Cx, I2C_FLAG_I2CBSY)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } if(number_Bytes==2) { i2c_ackpos_config(I2Cx,I2C_ACKPOS_NEXT); } i2c_start_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_master_addressing(I2Cx, driver_Addr, I2C_TRANSMITTER); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* clear the ADDSEND bit */ i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND); I2C_Timeout = I2C_SHORT_TIMEOUT; while(SET != i2c_flag_get( I2Cx , I2C_FLAG_TBE )) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_enable(I2Cx); if(ADDR_Length)//á?×??úμ??· { i2c_data_transmit(I2Cx, (uint8_t)((start_Addr & 0xFF00) >> 8)); I2C_Timeout = I2C_SHORT_TIMEOUT; //while(!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTING)) while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_data_transmit(I2Cx, (uint8_t)(start_Addr & 0x00FF)); } else { i2c_data_transmit(I2Cx, start_Addr); } I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_start_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_SBSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } i2c_master_addressing(I2Cx, driver_Addr, I2C_RECEIVER); I2C_Timeout = I2C_SHORT_TIMEOUT; if(number_Bytes<3) { i2c_ack_config(I2Cx,I2C_ACK_DISABLE); } while(!i2c_flag_get(I2Cx, I2C_FLAG_ADDSEND)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* clear the ADDSEND bit */ i2c_flag_clear(I2Cx,I2C_FLAG_ADDSEND); if(number_Bytes==1) { i2c_stop_on_bus(I2Cx); } while(number_Bytes) { if(3 == number_Bytes){ /* wait until BTC bit is set */ I2C_Timeout = I2C_LONG_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* disable acknowledge */ /* disable acknowledge */ i2c_ack_config(I2Cx,I2C_ACK_DISABLE); } if(2 == number_Bytes){ /* wait until BTC bit is set */ I2C_Timeout = I2C_LONG_TIMEOUT; while(!i2c_flag_get(I2Cx, I2C_FLAG_BTC)) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* send a stop condition to I2C bus */ i2c_stop_on_bus(I2Cx); I2C_Timeout = I2C_SHORT_TIMEOUT; while (I2C_CTL0(I2Cx) & 0x0200) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } } /* wait until the RBNE bit is set and clear it */ if(i2c_flag_get(I2Cx, I2C_FLAG_RBNE)){ /* read a byte from the EEPROM */ *read_Buffer = i2c_data_receive(I2Cx); /* point to the next location where the byte read will be saved */ read_Buffer++; /* decrement the read bytes counter */ number_Bytes--; } } while(I2C_CTL0(I2Cx)&0x0200) { if((I2C_Timeout--) == 0) { Resume_IIC(I2C_LONG_TIMEOUT,I2Cx); return I2C_FAIL; } } /* enable acknowledge */ i2c_ack_config(I2Cx,I2C_ACK_ENABLE); i2c_ackpos_config(I2Cx,I2C_ACKPOS_CURRENT); return I2C_OK; }
IIC 超時恢復機制
IIC超時恢復機制實現如代碼清單IIC超時恢復機制所示。
uint32_t I2C_Timeout; void Delay_I2C(uint32_t i) { while(i--); } void Resume_IIC(uint32_t Timeout,uint32_t I2Cx ) { uint32_t GPIO_SDA; uint32_t GPIO_SCL; uint32_t GPIO_Pin_SDA,GPIO_Pin_SCL; #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X || GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X /* enable GPIOB clock */ rcu_periph_clock_enable(RCU_GPIOB); /* enable I2C0 clock */ rcu_periph_clock_enable(RCU_I2C0); #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X rcu_periph_clock_enable(RCU_AF); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #endif #endif GPIO_SCL=GPIOB; GPIO_Pin_SCL=GPIO_PIN_6; GPIO_SDA=GPIOB; GPIO_Pin_SDA=GPIO_PIN_7; do{ #if defined GD32F10X_HD || GD32F30X_HD || GD32F20X_CL || GD32E10X /* I2C0 GPIO ports */ /* connect PB6 to I2C0_SCL */ gpio_init(GPIO_SCL, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); /* connect PB7 to I2C0_SDA */ gpio_init(GPIO_SDA, GPIO_MODE_AF_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #elif defined GD32F1X0 || GD32F4XX || GD32F3X0 || GD32E23X #if defined GD32F1X0 || GD32F3X0 || GD32E23X /* I2C GPIO ports */ /* connect I2C_SCL_GPIO_PIN to I2C_SCL */ gpio_af_set(GPIO_SCL, GPIO_AF_1, GPIO_Pin_SCL); /* connect I2C_SDA_GPIO_PIN to I2C_SDA */ gpio_af_set(GPIO_SDA, GPIO_AF_1, GPIO_Pin_SDA); #elif defined GD32F4XX gpio_af_set(GPIO_SCL, GPIO_AF_4, GPIO_Pin_SCL); gpio_af_set(GPIO_SDA, GPIO_AF_4, GPIO_Pin_SDA); #endif gpio_mode_set(GPIO_SCL, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SCL); gpio_output_options_set(GPIO_SCL, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SCL); gpio_mode_set(GPIO_SDA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_Pin_SDA); gpio_output_options_set(GPIO_SDA, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_Pin_SDA); #endif gpio_bit_reset(GPIO_SCL, GPIO_Pin_SCL); Delay_I2C(20); gpio_bit_reset(GPIO_SDA, GPIO_Pin_SDA); Delay_I2C(20); gpio_bit_set(GPIO_SCL, GPIO_Pin_SCL); Delay_I2C(20); gpio_bit_set(GPIO_SDA, GPIO_Pin_SDA); Delay_I2C(20); if(Timeout-- == 0) return; }while((!gpio_input_bit_get(GPIO_SDA, GPIO_Pin_SDA))&(!gpio_input_bit_get(GPIO_SCL, GPIO_Pin_SCL))); I2C_init(I2Cx); }
主函數說明
本例程主函數如代碼清單I2C例程主函數所示。
int main(void) { I2C_init(I2C0); I2Cx_Write_NBytes(I2C0,0xA0, 0,8, Write_Buf,0); I2Cx_Read_NBytes(I2C0,0xA0, 0,8, Read_Buf,0); while (1) { }
7.5.I2C 使用注意事項
1、I2C總線需要上拉;
2、I2C引腳需要配置為復用開漏模式;
3、若采用查詢方式進行I2C數據傳輸,有可能會由于總線干擾,導致I2C卡死,可以在查詢方式上增加超時機制,如果超時重配IIC恢復總線通信(注意重配IIC時,建議先將I2C模塊Deinit,然后 在調用Init函數進行初始化)。
4、若采用軟件模擬IIC的方式,在移植過程中出現問題,可能是由于代碼執行效率的問題,可以排查軟件延遲時間和其他芯片上的軟件延遲時間是否相同,可以通過調整軟件延遲時間進行測試;或者有可能是由于初始化配置IO端口的時候可能會引入干擾,可以先配置IO口輸出高,然后再配置為推挽或開漏模式。
-
單片機
+關注
關注
6043文章
44619瀏覽量
638467 -
mcu
+關注
關注
146文章
17317瀏覽量
352618 -
嵌入式
+關注
關注
5092文章
19177瀏覽量
307632 -
I2C
+關注
關注
28文章
1495瀏覽量
124540 -
GD32
+關注
關注
7文章
413瀏覽量
24467
發布評論請先 登錄
相關推薦
GD32 MCU 入門教程】GD32 MCU 常見外設介紹(12)FMC 模塊介紹

GD32 MCU移植
兆易創新GD32 MCU選型手冊,適用于GD32全系列MCU
【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(1)使用Keil開發GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(2)使用 IAR 開發 GD32

【GD32 MCU 入門教程】一、GD32 MCU 開發環境搭建(3)使用 Embedded Builder 開發 GD32

【GD32 MCU 入門教程】二、GD32 MCU 燒錄說明(1)ISP 燒錄

【GD32 MCU 入門教程】GD32 MCU 常見外設介紹(14)RTC 模塊介紹

【GD32 MCU入門教程】GD32 MCU GPIO 結構與使用注意事項

評論