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