<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 關(guān)于MSP硬件I2C講解

          關(guān)于MSP硬件I2C講解

          作者: 時間:2016-11-21 來源:網(wǎng)絡(luò) 收藏

          0.前言

          對于大多數(shù)單片機(jī)來說,I2C成了一個老大難問題。從51時代開始,軟件模擬I2C成了主流,甚至到ARMCortex M3大行其道的今天,軟件模擬I2C依然是使用最廣的方法。雖然軟件模擬可以解決所有的問題,但是總感覺沒有充分發(fā)揮MCU內(nèi)部的硬件資源。查閱了所有關(guān)于MSP430F5系列的圖書,沒有關(guān)于硬件I2C的應(yīng)用代碼,自己通過調(diào)試摸索,把經(jīng)驗(yàn)總結(jié)之后和大家分享,希望大家喜歡。同時,I2C的使用可以分為等待法和中斷法,從理解的角度來說等待法思路清晰易于上手,從功耗的角度出發(fā),中斷法可以靈活的進(jìn)入低功耗模式,但是不易理解。本文先從等待法入手。

          本文引用地址:http://www.ex-cimer.com/article/201611/319192.htm

          MSP430F5系列的硬件I2C使用大致會有以下問題:

          【I2C地址設(shè)定】一般情況下I2C的7位地址被寫成了8位長度,最低位無效。例如AT24C02的I2C地址為0xA0,其實(shí)真正的7位地址為0x50。而MSP430正是需要填入這7位地址0x50。

          【I2C停止位發(fā)送】在I2C讀操作過程中,讀取最后一個字節(jié)之后MCU應(yīng)向從機(jī)發(fā)送無應(yīng)答,MSP430F5系列的MCU發(fā)送無應(yīng)答的操作將自動完成,這就以為在讀取最后一個字節(jié)內(nèi)容時,應(yīng)先操作停止位相關(guān)寄存器。

          【I2C起始位發(fā)送】如果仔細(xì)分析MSP430F5參考手冊,將會發(fā)現(xiàn)讀操作和寫操作發(fā)送I2C起始位時略有不同。寫操作時需要先向TXBUF中寫入數(shù)據(jù),之后才可以等待TXSTT標(biāo)志位變?yōu)?,而讀操作和寫操作稍有不同。

          【AT24C02操作時序圖】

          1.初始化設(shè)置

          1.1代碼實(shí)現(xiàn)

          1. voiducb0_config(void)
          2. {
          3. P3SEL&=~BIT2;//P3.2@UCB0SCL
          4. P3DIR|=BIT2;
          5. P3OUT|=BIT2;
          6. //輸出9個時鐘以恢復(fù)I2C總線狀態(tài)
          7. for(uint8_ti=0;i<9;i++)
          8. {
          9. P3OUT|=BIT2;
          10. __delay_cycles(8000);
          11. P3OUT&=~BIT2;
          12. __delay_cycles(8000);
          13. }
          14. P3SEL|=(BIT1+BIT2);//P3.1@UCB0SDAP3.2@UCB0SCL
          15. //P3.1@ISP.1P3.2@ISP.5
          16. UCB0CTL1|=UCSWRST;
          17. UCB0CTL0=UCMST+UCMODE_3+UCSYNC;//I2C主機(jī)模式
          18. UCB0CTL1|=UCSSEL_2;//選擇SMCLK
          19. UCB0BR0=40;
          20. UCB0BR1=0;
          21. UCB0CTL0&=~UCSLA10;//7位地址模式
          22. UCB0I2CSA=EEPROM_ADDRESS;//EEPROM地址
          23. UCB0CTL1&=~UCSWRST;
          24. }

          1.2代碼分析

          I2C從設(shè)備的地址一般有以下通俗說法——7位地址,寫地址(寫控制字)和讀地址(讀控制字)。1個I2C通信的控制字節(jié)(I2C啟動之后傳送的第一個字節(jié))由7位I2C地址和1位讀寫標(biāo)志位組成,7位I2C地址即7位地址,若讀寫標(biāo)志位為讀標(biāo)志(讀寫標(biāo)志位置位)加上7位I2C地址便組成了讀地址(讀控制字),若讀寫標(biāo)志位為寫標(biāo)志(讀寫標(biāo)志位清零)加上7位地址便組成了寫地址(寫控制字)。例如AT24C02的I2C7位地址為0x50,讀地址(讀控制字)為0xA1,寫地址(寫控制字)為0xA1。

          在MSP430F5系列中,I2CSA地址寄存器應(yīng)寫入7位地址,參照上面的例子應(yīng)寫入0X50。至于I2C讀寫位的控制由CTL1寄存器完成,用戶無需干預(yù)。

          在I2C設(shè)置開始之前,可以先通過SCL端口發(fā)送9個時鐘信號,該時鐘信號可以是I2C從機(jī)芯片從一種錯誤的通信狀態(tài)恢復(fù),雖然這9個時鐘信號不起眼但是對于調(diào)試過程來說非常有用。例如在調(diào)試過程中,錯誤的發(fā)送了停止位,若再次啟動調(diào)試則I2C從設(shè)備仍處于一種錯誤的狀態(tài),這9個時鐘信號可以把I2C從設(shè)備從錯誤的狀態(tài)“拉”回來。

          2.寫單個字節(jié)

          向I2C從設(shè)備寫入單個字節(jié)應(yīng)該是最為簡單的一個操作,因?yàn)樗械目刂茩?quán)都在主機(jī)手中。寫單個字節(jié)實(shí)際包括了2個重要部分,一個便是寫寄存器地址,另一個便是寫寄存器內(nèi)容。對于AT24C02而言,存儲內(nèi)容的字節(jié)長度為一個字節(jié),而對于容量更大的EEPROM而言,存儲地址可為兩個字節(jié)。

          2.1 代碼實(shí)現(xiàn)

          1. uint8_teeprom_writebyte(uint8_tword_addr,uint8_tword_value)
          2. {
          3. while(UCB0CTL1&UCTXSTP);
          4. UCB0CTL1|=UCTR;//寫模式
          5. UCB0CTL1|=UCTXSTT;//發(fā)送啟動位
          6. UCB0TXBUF=word_addr;//發(fā)送字節(jié)地址
          7. //等待UCTXIFG=1與UCTXSTT=0同時變化等待一個標(biāo)志位即可
          8. while(!(UCB0IFG&UCTXIFG))
          9. {
          10. if(UCB0IFG&UCNACKIFG)//若無應(yīng)答UCNACKIFG=1
          11. {
          12. return1;
          13. }
          14. }
          15. UCB0TXBUF=word_value;//發(fā)送字節(jié)內(nèi)容
          16. while(!(UCB0IFG&UCTXIFG));//等待UCTXIFG=1
          17. UCB0CTL1|=UCTXSTP;
          18. while(UCB0CTL1&UCTXSTP);//等待發(fā)送完成
          19. return0;
          20. }

          2.2 代碼分析

          關(guān)于代碼出口的說明,關(guān)于I2C的讀寫函數(shù),若返回值為0說明所有的操作正常,若返回值為非0說明操作有誤,例如1代表從機(jī)無應(yīng)答。這種組合方式可能與各位的編程習(xí)慣有出入,一般認(rèn)為返回1表示操作成功,而返回0表示操作失敗。這種方式的問題便是無法有效的表達(dá)錯誤原因,因?yàn)?ldquo;0”只有一個,而非“0”卻有很多。

          寫單個字節(jié)可以劃分為——從機(jī)寫地址發(fā)送、寄存器地址發(fā)送、寄存器內(nèi)容發(fā)送。寄存器地址的發(fā)送由MSP430自動完成,這和軟件模擬的操作有所區(qū)別。請勿發(fā)送I2C從機(jī)地址,若操作AT24C02發(fā)送需要寫入的存儲字節(jié)的首地址即可。

          在單字節(jié)和多字節(jié)寫操作過程中,尤其要注意UCTXSTT標(biāo)志位的變化位置。UCTXSTT標(biāo)志位會在從機(jī)接收完寫控制字節(jié)或讀控制字節(jié)之后變化,但是在寫控制字節(jié)發(fā)送之后,必須先填充TXBUF,再嘗試等待STT標(biāo)志位復(fù)位,此時STT標(biāo)志位和TXIFG標(biāo)志位會同時變化。若從機(jī)沒有應(yīng)答,那么NACK標(biāo)志位也會發(fā)生變化。再次強(qiáng)調(diào)需要先填充TXBUF,在等待STT標(biāo)志位復(fù)位。以下代碼將導(dǎo)致程序一直停留在while(UCB0IFG & UCTXSTT)處,具體的原因可查看MSP430參考手冊。

          1. while(UCB0CTL1&UCTXSTP);
          2. UCB0CTL1|=UCTR;//寫模式
          3. UCB0CTL1|=UCTXSTT;//發(fā)送啟動位
          4. //等待UCTXSTT=0同時變化,但是很遺憾該變化不會發(fā)送
          5. while(UCB0IFG&UCTXSTT);
          6. UCB0TXBUF=word_addr;//發(fā)送字節(jié)地址

          3.寫多個字節(jié)

          3.1代碼實(shí)現(xiàn)

          1. uint8_teeprom_writepage(uint8_tword_addr,uint8_t*pword_buf,uint8_tlen)
          2. {
          3. while(UCB0CTL1&UCTXSTP);
          4. UCB0CTL1|=UCTR;//寫模式
          5. UCB0CTL1|=UCTXSTT;//發(fā)送啟動位
          6. UCB0TXBUF=word_addr;//發(fā)送字節(jié)地址
          7. //等待UCTXIFG=1與UCTXSTT=0同時變化等待一個標(biāo)志位即可
          8. while(!(UCB0IFG&UCTXIFG))
          9. {
          10. if(UCB0IFG&UCNACKIFG)//若無應(yīng)答UCNACKIFG=1
          11. {
          12. return1;
          13. }
          14. }
          15. for(uint8_ti=0;i
          16. {
          17. UCB0TXBUF=*pword_buf++;//發(fā)送寄存器內(nèi)容
          18. while(!(UCB0IFG&UCTXIFG));//等待UCTXIFG=1
          19. }
          20. UCB0CTL1|=UCTXSTP;
          21. while(UCB0CTL1&UCTXSTP);//等待發(fā)送完成
          22. return0;
          23. }

          3.2 代碼分析

          多字節(jié)寫函數(shù)和單字節(jié)寫函數(shù)相似,不做過多的解釋。

          4.讀單個字節(jié)

          單字節(jié)讀函數(shù)是4中讀寫函數(shù)中最為復(fù)雜的,復(fù)雜的原因在于讀最后一個字節(jié)之前就需要操作UCTXSTP標(biāo)志位。

          4.1 代碼實(shí)現(xiàn)

          1. uint8_teeprom_readbyte(uint8_tword_addr,uint8_t*pword_value)
          2. {
          3. UCB0CTL1|=UCTR;//寫模式
          4. UCB0CTL1|=UCTXSTT;//發(fā)送啟動位和寫控制字節(jié)
          5. UCB0TXBUF=word_addr;//發(fā)送字節(jié)地址,必須要先填充TXBUF
          6. //等待UCTXIFG=1與UCTXSTT=0同時變化等待一個標(biāo)志位即可
          7. while(!(UCB0IFG&UCTXIFG))
          8. {
          9. if(UCB0IFG&UCNACKIFG)//若無應(yīng)答UCNACKIFG=1
          10. {
          11. return1;
          12. }
          13. }
          14. UCB0CTL1&=~UCTR;//讀模式
          15. UCB0CTL1|=UCTXSTT;//發(fā)送啟動位和讀控制字節(jié)
          16. while(UCB0CTL1&UCTXSTT);//等待UCTXSTT=0
          17. //若無應(yīng)答UCNACKIFG=1
          18. UCB0CTL1|=UCTXSTP;//先發(fā)送停止位
          19. while(!(UCB0IFG&UCRXIFG));//讀取字節(jié)內(nèi)容
          20. *pword_value=UCB0RXBUF;//讀取BUF寄存器在發(fā)送停止位之后
          21. while(UCB0CTL1&UCTXSTP);
          22. return0;
          23. }

          4.2代碼分析

          這段代碼給人一個錯覺,MSP430先發(fā)送了停止位,然后再讀取了一個字節(jié)內(nèi)容。其實(shí)實(shí)際情況并不是這樣的。I2C讀操作時,主機(jī)讀取最后一個字節(jié)內(nèi)容之后,應(yīng)向從機(jī)發(fā)送無應(yīng)答NACK(無應(yīng)答區(qū)別于應(yīng)答),之后主機(jī)發(fā)送停止位。MSP430為了完成這一組合動作,要求用戶提前操作UCTXSTP標(biāo)志位,在讀取RXBUF之后做出發(fā)送NACK和I2C停止位的“組合動作”。

          1. while(!(UCB0IFG&UCRXIFG));
          2. *pword_value=UCB0RXBUF;//讀取BUF寄存器在發(fā)送停止位之后
          3. UCB0CTL1|=UCTXSTP;//發(fā)送停止位

          以上代碼可能導(dǎo)致后續(xù)的I2C操作無法進(jìn)行。

          5.讀多個字節(jié)

          5.1代碼實(shí)現(xiàn)

          1. uint8_teeprom_readpage(uint8_tword_addr,uint8_t*pword_buf,uint8_tlen)
          2. {
          3. while(UCB0CTL1&UCTXSTP);
          4. UCB0CTL1|=UCTR;//寫模式
          5. UCB0CTL1|=UCTXSTT;//發(fā)送啟動位和寫控制字節(jié)
          6. UCB0TXBUF=word_addr;//發(fā)送字節(jié)地址
          7. //等待UCTXIFG=1與UCTXSTT=0同時變化等待一個標(biāo)志位即可
          8. while(!(UCB0IFG&UCTXIFG))
          9. {
          10. if(UCB0IFG&UCNACKIFG)//若無應(yīng)答UCNACKIFG=1
          11. {
          12. return1;
          13. }
          14. }
          15. UCB0CTL1&=~UCTR;//讀模式
          16. UCB0CTL1|=UCTXSTT;//發(fā)送啟動位和讀控制字節(jié)
          17. while(UCB0CTL1&UCTXSTT);//等待UCTXSTT=0
          18. //若無應(yīng)答UCNACKIFG=1
          19. for(uint8_ti=0;i
          20. {
          21. while(!(UCB0IFG&UCRXIFG));//讀取字節(jié)內(nèi)容,不包括最后一個字節(jié)內(nèi)容
          22. *pword_buf++=UCB0RXBUF;
          23. }
          24. UCB0CTL1|=UCTXSTP;//在接收最后一個字節(jié)之前發(fā)送停止位
          25. while(!(UCB0IFG&UCRXIFG));//讀取最后一個字節(jié)內(nèi)容
          26. *pword_buf=UCB0RXBUF;
          27. while(UCB0CTL1&UCTXSTP);
          28. return0;
          29. }

          5.2代碼分析

          讀單個字節(jié)和寫單個字節(jié)相似。唯一需要注意的是,寫操作需要先填充TXBUF,而讀操作不存在這個問題。試想一下,I2C寫操作時必定會向I2C從機(jī)寫入一個字節(jié)內(nèi)容,所以先填充TXBUF也是合情合理的事情,填充TXBUF之后MSP430會進(jìn)行一連串的動作——發(fā)送I2C起始位、I2C讀控制器和寫入從機(jī)的第一個字節(jié)。

          6 單元測試

          單元測試分為兩個部分。單字節(jié)寫函數(shù)和單字節(jié)讀函數(shù)分為一組,先使用單字節(jié)邪惡函數(shù)向某地址寫入某內(nèi)容,在使用單字節(jié)讀函數(shù)讀出某內(nèi)容,如果寫入的參數(shù)和讀出的內(nèi)容相同,則測試通過。多字節(jié)寫函數(shù)和多字節(jié)度函數(shù)分為一組,測試過程相似,不同的是寫入的內(nèi)容從一個變?yōu)榱诉B續(xù)8個。請注意AT24C02的頁大小為8,若從頁首地址開始,最大的寫字節(jié)個數(shù)為8。

          另外,EEPROM寫操作之后需要有10ms的延時,否則將無法進(jìn)行寫操作和讀操作。具體請查看AT24C02數(shù)據(jù)手冊。

          6.1 測試代碼

          1. voideeprom_config()
          2. {
          3. #ifDEBUF_EEPROM_I2C
          4. uint8_ttest_byte1=0x0B;
          5. uint8_ttest_byte2=0x01;
          6. /*
          7. step1向地址0x00寫入某個值,例如0x0B
          8. 然后讀出地址0x00結(jié)果,判斷該值是否為0x0B
          9. */
          10. eeprom_writebyte(0x00,test_byte1);
          11. delay_ms(10);
          12. eeprom_readbyte(0x00,&test_byte2);
          13. assert_param(test_byte1==test_byte2);
          14. if(test_byte1==test_byte2)
          15. {
          16. printf("ByteReadandByteWriteTestPassrn");
          17. }
          18. /*
          19. step2以地址0x08作為起始地址,連續(xù)寫入8個字節(jié)數(shù)據(jù)
          20. 再連續(xù)從該起始地址讀取8字節(jié)內(nèi)容,比較寫入和讀出字節(jié)內(nèi)容
          21. 成功的條件為寫入和讀取字節(jié)內(nèi)容相同
          22. */
          23. uint8_ttest_buf1[8]={1,2,3,4,5,6,7,8};
          24. uint8_ttest_buf2[8]={0,0,0,0,0,0,0,0};
          25. eeprom_writepage(0x08,test_buf1,8);
          26. delay_ms(10);
          27. eeprom_readpage(0x08,test_buf2,8);
          28. assert_param(memcmp(test_buf1,test_buf2,8)==0);
          29. if(!memcmp(test_buf1,test_buf2,8))
          30. {
          31. printf("PageReadandPageWriteTestPass!rn");
          32. }
          33. #endif
          34. }

          6.2 測試結(jié)果



          關(guān)鍵詞: MSP硬件I2

          評論


          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();