STM8L的硬件I2C支持100KHz~400KHz的讀寫速度,作為主設備使用時,不需要配置IO,開啟I2C硬件后,對應的IO會自動啟用復用功能。本文選取24C02作為I2C從設備,STM8L作為主設備,進行I2C讀寫功能測試。
STM8L作為I2C主設備時,官方的數據手冊給出的配置流程如下圖:

詳細配置I2C為主設備的流程如下:
①打開I2C外設時鐘
②I2C輸入時鐘頻率大小選擇
③配置時鐘控制寄存器
④配置上升沿時間寄存器
⑤開啟I2C功能
STM8L的I2C默認為從設備,當發送一個START信號后,自動從從模式轉成主模式.
STM8L的I2C的實現寫一字節的描述如下:
①CR2寄存器中的START位被置位后,發送一個起始信號,SR1中的SB被硬件置位.讀取SR1寄存器,清除該標志位.
②向DR寄存器寫入從設備地址,SR1中的ADDR會被硬件置位,通過讀SR1,然后再讀SR3,清除該標志位.
③DR寄存器為空后,將從設備寄存器地址寫入DR
④DR寄存器為空后,將從要寫入的數據寫入DR
STM8L讀取一字節數據,這里不在贅述.
注意:I2C的時鐘頻率為2M以下時,根據數據手冊,在檢測到SB,ADDR,BTF,這些標志位后,必須在其后插入5個NOP再清除標志位.

STM8S中文文檔中,對此描述如下.

- /*硬件連接*/
- // PC0<--->SDA PC1---->SCL
- /****************************************************************************************
- *開發環境:IAR for stm8 v6.5.3
- *硬件平臺:STM8L-DISCOVERY
- *功能說明:通過硬件I2C等待的方法,實現對24C02寄存器的讀寫,借助IAR軟件的調試功能,查看變量的數值
- *作 者:茗風
- ****************************************************************************************/
- #include"iostm8l152c6.h"
- #include"stdbool.h"
- #include"stdint.h"
- #define _5NOPS asm("nop");asm("nop");asm("nop");asm("nop"); asm("nop")//用于I2C讀寫延時
- /******************************************************************************************************
- * 名 稱:void delay_10ms(uint8_t x_ms)
- * 功 能:延時10ms
- * 入口參數:無
- * 出口參數:無
- * 說 明:
- * 范 例:無
- ******************************************************************************************************/
- void delay_100ms(void)
- {
- uint8_t i,j;
- for(i=0;i<255;i++)//2*255個指令周期
- for(j=0;j<255;j++);//2*255個指令周期
- // delay_10ms共消耗 x_ms*2*255+2*x_ms個指令周期
- // 255*2*255+2*255=130610us=130ms
- // 此延時函數,延時時間為130ms
- // 16M/8/2=1M 一個指令周期為1us
- }
- /******************************************************************************************************
- * 名 稱: uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
- * 功 能:從I2C從設備中讀取一字節的數據
- * 入口參數:address:讀取數據的寄存器地址
- * 出口參數:返回一個從I2C從設備指定地址讀到的數據
- * 說 明:
- * 范 例:無
- ******************************************************************************************************/
- uint8_t I2C_ReadOneByteDataFromSlave(uint8_t address)
- {
- volatile uint8_t t;
-
- //----------I2C起始信號--------------
- I2C1_CR2_START=1;//產生一個起始條件
- while(!(I2C1_SR1_SB==1));//讀SR1寄存器,清除SB標志位
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //-------發送寫I2C從器件地址---------
- I2C1_DR=0xA0;//發送從設備地址
- while(!(I2C1_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- if(I2C1_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位
- // 0: Data bytes received
- // 1: Data bytes transmitted
-
- //-----寫I2C從器件寄存器地址--------
- I2C1_DR=address;
- while(!(I2C1_SR1_BTF==1));//等待地址發送完成
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //--------I2C重復起始信號-----------
- I2C1_CR2_START=1;//重復產生一個起始條件
- while(!(I2C1_SR1_SB==1));//讀SR1寄存器,清除SB標志位
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //-------發送讀I2C從器件地址---------
- I2C1_DR=0xA1;//發送從設備地址
- while(!(I2C1_SR1_ADDR==1));//讀SR1寄存器,清除ADDR標志位
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- if(I2C1_SR3_TRA==1)return 1;//讀SR3寄存器,清除ADDR標志位
- while(!(I2C1_SR1_RXNE==1));//等待地址發送完成
-
- //-------------停止信號-------------
- I2C1_CR2_STOP=1;
-
- //-------------讀取數據-------------
- t=I2C1_DR;
-
- return t;
- }
- /******************************************************************************************************
- * 名 稱:void I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
- * 功 能:寫入一字節的數據到I2C設備中
- * 入口參數:address:寫入的數據存儲地址 dat:待寫入的數據
- * 出口參數:無
- * 說 明: 通過MSTM8L硬件寫入I2C設備一個字節的數據
- * 范 例:無
- ******************************************************************************************************/
- uint8_t I2C_WriteOneByteDataToSlave(uint8_t address,uint8_t dat)
- {
- volatile uint8_t t;
- //----------I2C起始信號--------------
- I2C1_CR2_START=1;//產生一個起始條件
- while(!(I2C1_SR1_SB==1));
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- I2C1_DR=0xA0;
-
- //--------寫I2C從器件地址-----------
- while(!(I2C1_SR1_ADDR==1));
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
- if(I2C1_SR3_TRA==0)return 1;//讀SR3寄存器,清除ADDR標志位
-
- //-----寫I2C從器件寄存器地址--------
- while(!(I2C1_SR1_TXE==1));
- I2C1_DR=address;
-
- //-------寫I2C數據到寄存器中--------
- while(!(I2C1_SR1_TXE==1));
- I2C1_DR=dat;
- while(!(I2C1_SR1_TXE==1));
- while(!(I2C1_SR1_BTF==1));
- _5NOPS;//根據數據手冊,檢測到標志位后,需插入5個NOP進行延時
-
- //-------------停止信號-------------
- I2C1_CR2_STOP=1;
- return 0;
- }
- /******************************************************************************************************
- * 名 稱: IIC_init()
- * 功 能:初始化IIC
- * 入口參數:無
- * 出口參數:無
- * 說 明:PC0--SDA PC1--SCL
- * 范 例:無
- ******************************************************************************************************/
- void I2C_Init(void)
- {
- //----打開IIC外設時鐘----
- CLK_PCKENR1_PCKEN13=1;//
- I2C1_CR1_PE=0;
-
- //----I2C輸入時鐘頻率選擇----
- I2C1_FREQR_FREQ=0x02;//2MHz
- /* The allowed range is between 1 MHz and 16 MHz
- 000000: not allowed
- 000001: 1 MHz
- 000010: 2 MHz
- ...
- 010000: 16 MHz */
-
- //----配置時鐘控制寄存器----
- I2C1_CCRH_F_S=0; //Standard mode I2C
- I2C1_CCRL=10; //SCK低電平時間配置
- //I2C的SCK時鐘設置為100KHz,則SCK周期為10us
- //因為I2C1_FREQR_FREQ=0x02,即I2C輸入時鐘頻率為2M,周期為0.5us
- //CCR=10時,SCK的低電平時間為tlow=10*0.5us=5us,SCk高電平時間為thigh=10*0.5us=5us
- //所以CCR=10時,SCK輸出頻率為100KHz
-
- //----配置上升時間寄存器----
- I2C1_TRISER_TRISE=3;//in standard mode, the maximum allowed SCL rise time is 1000 ns.
- //1 us / 0.5 us = 2 + 1
- I2C1_CR1_PE=1;//
-
- }
- void main(void)
- {
- static uint8_t tmp=0;
- I2C_Init();
- // asm("rim"); //enable interrupts
- I2C_WriteOneByteDataToSlave(0x02,0x84);
- delay_100ms();
- tmp=I2C_ReadOneByteDataFromSlave(0x02);
- asm("nop");
- while(1)
- {
- asm("wfi");
- }
- }
復制代碼
|