在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            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)驗總結(jié)之后和大家分享,希望大家喜歡。同時,I2C的使用可以分為等待法和中斷法,從理解的角度來說等待法思路清晰易于上手,從功耗的角度出發(fā),中斷法可以靈活的進(jìn)入低功耗模式,但是不易理解。本文先從等待法入手。

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

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

            【I2C地址設(shè)定】一般情況下I2C的7位地址被寫成了8位長度,最低位無效。例如AT24C02的I2C地址為0xA0,其實真正的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代碼實現(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);//[email protected]@UCB0SCL
            15. //[email protected]@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)該是最為簡單的一個操作,因為所有的控制權(quán)都在主機(jī)手中。寫單個字節(jié)實際包括了2個重要部分,一個便是寫寄存器地址,另一個便是寫寄存器內(nèi)容。對于AT24C02而言,存儲內(nèi)容的字節(jié)長度為一個字節(jié),而對于容量更大的EEPROM而言,存儲地址可為兩個字節(jié)。

            2.1 代碼實現(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á)錯誤原因,因為“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代碼實現(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 代碼實現(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)容。其實實際情況并不是這樣的。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代碼實現(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)閉