stm8不需要專門配置GPIO口,執行初始化就可以啦!有些stm8需要打開EEPROM設置I2C(看官方文檔)。
stm8主要靠SR1和SR3狀態寄存器判斷I2C的情況(while(!XXXXX)就是出自這里),多半大家調不通!就是卡在這里(需要注意的是 寄存器有些位,只要讀寄存器就可以清除,在仿真的時候,最好不要打開寄存器頁面)。這里分軟故障和硬故障:
首先是硬故障: 一般是stm8芯片IO口壞啦,有些時候stm8能夠寫程序而且IO別的功能都是好的,單單是I2C用不起!還有就是IO上拉電壓不夠!我就遇到這樣的問題,我IO 加上邏輯分析儀后就可以調通,不加就通不了。這個也搞啦我很久。
軟故障: 一般主要是設置CR1和CR2問題,只要按照我的參考程序設置就可以!
我詳細的講講,寄存器I2c_CR2 應答使能位(位2)ack。首先是理解:官方文檔上面說的是ack應答使能,對是使能!很多人包括我自己 開始都認為是發送ack,導致每次stm8收到數據后,我們都手動在每次收到字節后加I2C_AcknowledgeConfig(I2C_ACK_CURR)無任何意義,因為在接收模式下,收到完整字節后,自動發送ack(提前是CR2 ack位使能,不需要專門CR2 ack位置1) ,都是軟件虛擬I2C用多啦!想當然啦! 還有就是使用這個ack!設置ACK都必須在接收字節前,也就是說為個在收到最后一個字節后產生一個NACK 脈沖,在讀倒數第二個數據字節之后,必須清除ack位(ack=0)!設置ack同理! 還有需要 主要的地方 如果設置 ack=0; 下次需要重新產生ack的時候!需要手動置位ack!記住在開始接收之前!如果你只有一個字節正確,后面全部是0xFF...可能就是這個問題(切記!切記!很多例子都沒有加上這句,包括風馳 的例子!! 不過 他沒有加循環! 如果他再循環一次就會出現問題。)
隨便說說仿真調試!在調試過程中,最好不要打開I2C寄存器看!因為對寄存器的讀,也會造成寄存器有些位重置!直接按Go,然后暫停。進去程序看卡在那里啦。
操作庫和寄存器編寫程序,其實沒有分別!不過為啦更好的理解,我在這里是操作寄存器!網上有人說加入中斷會對I2C產生影響,我這里沒有加中斷。希望有后來人補全!反正我這幾天運行沒有發現問題!
附錄1 主要I2C程序
- void Read_8816(u8 *pBuffer, u8 index, u8 NumByteToRead)
- {
- while(I2C->SR3 & 0x02); //等待總線空閑 檢測i2c-SR3 busy位
- //以下見stm8s中文數據手冊P251(圖96主設備發送模式發送序列圖)
- //S 起始條件
- I2C->CR2 |= 0x01; //產生起始位 CR2 start位
- //EV5:SB=1,讀SR1 然后將地址寫入DR寄存器將清除該標志。
- while(!(I2C->SR1 & 0x01)); //等待START發送完 E5
- //ADDRESS (發送模式)
- I2C->DR = 0x00; //發送MLX90615器件地址(最后一位是0,表示發送)
- while(!(I2C->SR1 & 0x02)); //等特7位器件地址發送完并且收到ack,ADDR置1
- //EV6:ADDR 在軟件讀取SR1后,對SR3寄存器讀操作 將清除改位
- I2C->SR1; //見P251 讀SR1 (實驗證明可以不要)
- I2C->SR3; //然后讀SR3 清 ADDR(等于庫函數I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))
- //DATA 發送寄存器地址
- I2C->DR = (u8)(index);
- //EV8_2 TxE=1 ,BTF=1,產生停止條件時由硬件清除。
- while(!(I2C->SR1 & 0x84)); //檢測SR1 TXE1 BTF位置(只有當stm8收到ack,TxE才會置1,其實這句相當于判斷收到ack沒有?)
- //在發送地址和清除ADDR 之后,I2C接口進入主設備接收模式。以下見stm8s中文數據手冊P252(圖97主設備接收模式接收序列圖)
- //S 重復起始條件
- I2C->CR2 |= 0x01; //產生重復起始位
- //EV5:SB=1,讀SR1 然后將地址寫入DR寄存器將清除該標志。
- while(!(I2C->SR1 & 0x01)); //等待START發送完
- //ADDRESS (接收)
- I2C->DR = 0x01; //發送MLX90615器件地址(最后一位是1,表示接收),發送完后自動發送ack(提前是CR2 ack位使能)
- //EV6:ADDR 在軟件讀取SR1后,對SR3寄存器讀操作 將清除改位
- while(!(I2C->SR1 & 0x02)); //等特7位器件地址發送完并且收到ack,ADDR置1
- I2C->SR1; //見P251 讀SR1 (實驗證明可以不要)
- I2C->SR3; //然后讀SR3 清 ADDR(等于庫函數I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED))
- //循環讀取數據
- while(NumByteToRead)
- {
- //EV7_1 :RxNE=1 ,讀DR寄存器清除該標志。設置ACK=0和STOP 請求。(在接收最后一個字節前)
- if(NumByteToRead == 1) //實驗證明在最后一個字節前后都一樣
- {
- I2C->CR2 &= ~0x04; //ack使能
- I2C->CR2 |= 0x02; //停止位產生stop
- }
- ///測試EV7 RxNE=1(收到一個字節后RxNE置1) ,判斷DR寄存器有數據
- if(I2C->SR1 & 0x40)
- {
- *pBuffer=I2C->DR;//在接收模式下,收到完整字節后,自動發送ack(提前是CR2 ack位使能,不需要專門CR2 ack位置1)
- //在風馳里面例子,在每次收到字節后加I2C_AcknowledgeConfig(I2C_ACK_CURR)無任何意義,
- pBuffer++;
- NumByteToRead--;
- }
- }
- I2C->CR2 |= 0x04;//為一下循環開始 設置 ack使能,上面 EV7_1設置ack=0發送stop后;需要手動設置ack=1使能,必要在接收數據之前
- //切記!切記!很多例子都沒有加上這句,包括風馳 的例子! 不過 他沒有加循環! 如果他在循環一次就會出現問題。CR2 ack位其實就是使能的意思!!很多人都理解成需要手動設置!
- }
復制代碼
|