前一段時間對stm32的i2c模組進行了除錯,今天做乙個總結。關於i2c協議的知識,這裡就不再贅述,網上有很多介紹i2c協議的文章。目前實現i2c協議的方式有兩種,一是採用gpio口來模擬i2c協議,另外一種是使用stm32自帶的i2c模組。雖說使用gpio口模擬i2c協議較為複雜,需要詳細了解i2c協議的內容,但是實現這種方式的資料也非常多,網上都有對應的原始碼實現,只需要簡單修改,就可以實現功能。而針對使用stm32自帶的i2c模組,網路上貶斥的聲音較多,說是模組本身自帶bug,容易出問題,甚至還有人說是史上最難調的i2c模組。當然了,這些問題我自己目前還沒有遇到,可能需要以後來驗證了。好了,言歸正傳,今天主要記錄一下除錯過程以及需要注意的地方。
//功能:初始化iic介面
void ssx1207_init(void)
該函式完成對i2c模組的初始化,首先要確定使用的gpio口,然後對gpio口的引數進行配置,這一部分也是引數網上的一下資料進行配置的,需要注意的是gpio_mode要配置成復用模式,gpio_otype要配置成開漏模式,如果使用別的庫可能對應的引數有差異,但基本功能應該是一樣的,需要將gpio口配置成復用開漏模式。上面只是對要使用到的gpio口的配置,還需要配置i2c的引數,這部分只需要注意一下ownaddress1即可,該引數只需要跟匯流排上的其他i2c裝置的位址不一樣就行了,是使用者自己定義的。
初始化函式記錄完成之後,下面記錄主i2c裝置對從i2c裝置寫資料的過程。
//功能:將指定數量的資料寫入到iic裝置中
//引數:
// pbuffer--要寫入的資料陣列
// numtowrite--寫入資料的個數
void ssx1207_writebytearray(u8 *pbuffer,u16 numtowrite) }
flag = i2c_getlastevent(i2c1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("ev5 sucess\r\n");
i2c_send7bitaddress(i2c1,0x50,i2c_direction_transmitter);//傳送安全晶元位址和寫命令
timeout=0x1000;
while(!i2c_checkevent(i2c1,i2c_event_master_transmitter_mode_selected))//ev6事件 }
flag = i2c_getlastevent(i2c1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("ev6 sucess\r\n");
while(numtowrite--) }
flag = i2c_getlastevent(i2c1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("ev8 sucess\r\n");
i2c_senddata(i2c1,*pbuffer);
pbuffer++;
}timeout=0x1000;
while(!i2c_checkevent(i2c1,i2c_event_master_byte_transmitted))//ev8_2事件 }
flag = i2c_getlastevent(i2c1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("ev8_2 sucess\r\n");
i2c_generatestop(i2c1,enable);//產生乙個停止訊號
}該函式是將指定數量的資料寫入到i2c從裝置中,整個流程是參照手冊的上的流程來編碼的。
//功能:從iic裝置讀取指定長度的資料
//引數:
// pbuffer:要讀取資料的存放陣列
// numtoread:讀取資料的數量
void ssx1207_readbytearray(u8 *pbuffer,u16 numtoread) }
flag = i2c_getlastevent(i2c1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("ev5 sucess!\r\n");
i2c_send7bitaddress(i2c1,0x50,i2c_direction_receiver);//傳送安全晶元位址和讀命令
timeout=0x1000;
while(!i2c_checkevent(i2c1,i2c_event_master_receiver_mode_selected))//ev6事件 }
flag = i2c_getlastevent(i2c1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("ev6 sucess!\r\n");
}while(numtoread)
if((numtoread==1)&&(numtoread_flag!=8))
timeout=0x1000;
while(!i2c_checkevent(i2c1,i2c_event_master_byte_received))//ev7事件 }
*pbuffer=i2c_receivedata(i2c1);
flag = i2c_getlastevent(i2c1);
printf("flag=%x\r\n",flag);
if(timeout!=0)
printf("ev7 sucess! *pbuffer=%02x\r\n",*pbuffer);
pbuffer++;
}printf("numtoread=%d\r\n",numtoread);
}該函式是主裝置向從i2c裝置讀取指定長度的資料。整個流程也是參考手冊的流程來實現的。
讀取資料的過程主要是注意要讀取的資料還剩三個位元組的時候cr1暫存器中ack位和stop位的變化情況,這裡所說的情況是要讀取的資料大於兩個位元組的情況。
如**中紅色標註的所示,此時倒數第三個位元組在dr暫存器中,需要將ack復位,然後讀取該位元組,但stop位不能置1(務必要注意這一點,網上有在此時就將stop位置1的,導致後續的操作失敗)。當要讀取倒數第二個位元組時,將stop位置1,如**中紫色標註的部分。另外,為了後續正常讀寫資料,需要將ack位再次置1,本次是在寫資料函式內實現的。以上是操作i2c裝置的三個重要的函式,針對測試的主函式就不再記錄了。
STM32之I2C 學習筆記
1 i2c是兩線式序列匯流排,由資料線sda和時鐘scl構成的序列匯流排,可傳送和接收資料。在cpu與被控ic之間 ic與ic之間進行雙向傳送,高速iic匯流排一般可達400kbps以上。2 iic是半雙工通訊方式,也就是說它既可以接收也可以傳送,但是由於它只有一根資料線,所以接收和傳送不能同時進行...
STM32 軟體模擬I2C
i2c的兩個引腳 scl引腳和sda引腳 需要既能輸出又能輸入,為了避免複雜的配置操作需要把該引腳配置為開漏輸出模式,該模式的說明如下圖所示 當微控制器的sda引腳配置為低電平時,sda線被拉低 當微控制器的sda引腳配置為高電平時,引腳埠為高阻態,sda線通過上拉電阻被vcc拉高。因此一定要注意在...
STM32的I2C特性及架構
軟體模擬協議 使用cpu直接控制通訊引腳 gpio 的電平,產生出符合通訊協議標準的邏輯。硬體實現協議 由stm32的i2c片上外設專門負責實現i2c通訊協議,只要配置好該外設,它就會自動根據協議要求產生通訊訊號,收發資料並快取起來,cpu只要檢測該外設的狀態和訪問資料暫存器,就能完成資料收發。這種...