對(duì)于MSP430的學(xué)習(xí)經(jīng)歷一個(gè)從痛苦到對(duì)430很有感情的轉(zhuǎn)變.當(dāng)然開(kāi)始學(xué)習(xí)的時(shí)候那是相當(dāng)惱火.網(wǎng)上也沒(méi)有什么很多的相關(guān)資料.就算有資料也是給不全.參考與學(xué)習(xí)都不很方便.經(jīng)過(guò)多方面的努力和找書(shū)再到對(duì)程序的仔細(xì)讀,感到非模擬的總線(xiàn)帶來(lái)的方便還是很多的. 下面就是程序和流程圖: IIC.h void Init_IIC(void); void EEPROM_ByteWrite(unsigned char nAddr,unsigned char nVal); unsigned char EEPROM_RandomRead(unsigned char nAddr); unsigned char EEPROM_CurrentAddressRead(void); void EEPROM_AckPolling(void); void Init_CLK(void); void Init_IIC_Port(void); Main.C /******************************************* IIC for AT24c16 OR AT24CXXX 系列 只要控制好IICRM IICSTP IICSTT 其硬件會(huì)自動(dòng)完成 SCL SDA的一系列時(shí)序 只要注意各個(gè)發(fā)送與接收的控制標(biāo)志位. ******************************************/ #include #include "IIC.h" volatile unsigned char Data[6]; void main(void) { //volatile unsigned char Data[6]; //停止看門(mén)狗 WDTCTL = WDTPW+WDTHOLD; //初始化端口 Init_IIC_Port(); //初始化時(shí)鐘 Init_CLK(); //I2C初始化 Init_IIC(); //置傳輸方式及控制方式 //打開(kāi)中斷 _EINT(); //寫(xiě)入數(shù)據(jù) EEPROM_ByteWrite(0x0000,0x12); //等待寫(xiě)操作完成 EEPROM_AckPolling(); //寫(xiě)入數(shù)據(jù) EEPROM_ByteWrite(0x0001,0x34); //等待寫(xiě)操作完成 EEPROM_AckPolling(); //寫(xiě)入數(shù)據(jù) EEPROM_ByteWrite(0x0002,0x56); //等待寫(xiě)操作完成 EEPROM_AckPolling(); //寫(xiě)入數(shù)據(jù) EEPROM_ByteWrite(0x0003,0x78); //等待寫(xiě)操作完成 EEPROM_AckPolling(); //寫(xiě)入數(shù)據(jù) EEPROM_ByteWrite(0x0004,0x9A); //等待寫(xiě)操作完成 EEPROM_AckPolling(); //寫(xiě)入數(shù)據(jù) EEPROM_ByteWrite(0x0005,0xBC); //等待寫(xiě)操作完成 EEPROM_AckPolling(); //讀出數(shù)據(jù),隨機(jī)讀 Data[0] = EEPROM_RandomRead(0x0000); //地址自動(dòng)加1 //讀出數(shù)據(jù),當(dāng)前地址讀 Data[1] = EEPROM_CurrentAddressRead(); //讀出數(shù)據(jù),當(dāng)前地址讀 Data[2] = EEPROM_CurrentAddressRead(); //讀出數(shù)據(jù),當(dāng)前地址讀 Data[3] = EEPROM_CurrentAddressRead(); //讀出數(shù)據(jù),當(dāng)前地址讀 Data[4] = EEPROM_CurrentAddressRead(); //讀出數(shù)據(jù),當(dāng)前地址讀 Data[5] = EEPROM_CurrentAddressRead(); } IIC.C #include #include "IIC.h" #define SLAVEADDR 0x50; int tx_count; int rx_count; unsigned char I2CBuffer[3]; void Init_IIC(void) { //將P3.1和P3.3設(shè)置為I2C管腳 P3SEL = 0x0A; //設(shè)置P3.1和P3.3管腳的方向 P3DIR &= ~0x0A; //選擇為I2C模式 U0CTL |= I2C + SYNC; //禁止I2C模塊 U0CTL &= ~I2CEN; //設(shè)置I2C為7位地址模式,不使用DMA, //字節(jié)模式,時(shí)鐘源為SMCLK, //設(shè)置成傳輸模式 I2CTCTL = I2CTRX + I2CSSEL_2; //定義從器件地址 I2CSA = SLAVEADDR; //設(shè)置本身的地址 I2COA = 0x01A5; //I2C時(shí)鐘為SMCLK / 160 I2CPSC = 159; //SCL 高電平為:5 *I2C 時(shí)鐘 I2CSCLH = 0x03; //SCL 低電平為:5 *I2C 時(shí)鐘 I2CSCLL = 0x03; //I2C 模塊有效 U0CTL |= I2CEN; tx_count = 0; rx_count = 0; } void I2CWriteInit(void) //對(duì)于AT24CXXX的寫(xiě)操作是置成主模式并置位中斷使能. { //主(Master)模式 U0CTL |= MST; //傳輸模式,R/W 為:0 I2CTCTL |= I2CTRX; //清除中斷標(biāo)志 I2CIFG &= ~TXRDYIFG; //發(fā)送中斷使能 I2CIE = TXRDYIE; } void I2CReadInit(void) { //接收模式,R/W 為:1 I2CTCTL &= ~I2CTRX; //接收中斷使能 I2CIE = RXRDYIE; } void EEPROM_ByteWrite(unsigned char nAddr, unsigned char nVal) { //等待I2C模塊完成所有操作 //在選定的地址寫(xiě)入數(shù)據(jù). while (I2CDCTL&I2CBUSY) ; //設(shè)置地址數(shù)據(jù) I2CBuffer[1] = nAddr; //設(shè)置數(shù)據(jù) I2CBuffer[0] = nVal; //設(shè)置緩沖區(qū)指針 tx_count = 1; //寫(xiě)數(shù)據(jù)初始化 I2CWriteInit(); //設(shè)置為主模式 //發(fā)送數(shù)據(jù)的長(zhǎng)度 //1個(gè)控制字節(jié),2個(gè)數(shù)據(jù)字節(jié) I2CNDAT = 2; //開(kāi)始和停止條件產(chǎn)生 //開(kāi)始I2C通信 I2CTCTL |= I2CSTT+I2CSTP; return; } unsigned char EEPROM_CurrentAddressRead(void) { //等待I2C模塊完成所有操作 while (I2CDCTL&I2CBUSY); //讀操作的初始化 I2CReadInit(); //主(Master)模式 U0CTL |= MST; //接收1個(gè)字節(jié)的數(shù)據(jù) I2CNDAT = 1; //清除中斷標(biāo)志 I2CIFG &= ~ARDYIFG; //開(kāi)始接收,產(chǎn)生重新起始和停止條件 I2CTCTL |= I2CSTT + I2CSTP; //等待傳輸完成 while ((~I2CIFG)&ARDYIFG) ; //返回?cái)?shù)據(jù) return I2CBuffer[0]; } unsigned char EEPROM_RandomRead(unsigned char nAddr) { //等待I2C模塊完成所有操作 while (I2CDCTL&I2CBUSY); //設(shè)置地址 I2CBuffer[0] = nAddr; //設(shè)置緩沖區(qū)指針 tx_count = 0; //寫(xiě)操作初始化 I2CWriteInit(); //傳輸數(shù)據(jù)長(zhǎng)度 //1個(gè)控制字節(jié)和一個(gè)地址數(shù)據(jù) I2CNDAT = 1; //清除中斷標(biāo)志 I2CIFG &= ~ARDYIFG; //起始條件產(chǎn)生 I2CTCTL |= I2CSTT; //等待傳輸完成 while ((~I2CIFG)&ARDYIFG); //讀操作初始化 I2CReadInit(); //接收一個(gè)字節(jié)的數(shù)據(jù) I2CNDAT = 1; //清除中斷標(biāo)志 I2CIFG &= ~ARDYIFG; //開(kāi)始接收,產(chǎn)生重新起始和停止條件 I2CTCTL |= I2CSTT + I2CSTP; //等待傳輸完成 while ((~I2CIFG)&ARDYIFG); //返回?cái)?shù)據(jù) return I2CBuffer[0]; } void EEPROM_AckPolling(void) { unsigned int count; //等待I2C模塊完成所有操作 while (I2CDCTL&I2CBUSY); count=0; //清除I2CEN位 U0CTL &= ~I2CEN; I2CTCTL |= I2CRM; //使能I2C模塊 U0CTL |= I2CEN; //設(shè)置NACKIFG標(biāo)志 I2CIFG = NACKIFG; while (NACKIFG & I2CIFG) { //清除中斷標(biāo)志 I2CIFG=0x00; //主(Master)模式 U0CTL |= MST; //設(shè)置傳輸模式 I2CTCTL |= I2CTRX; //產(chǎn)生起始條件 I2CTCTL |= I2CSTT; //等待I2CSTT被清除 while (I2CTCTL & I2CSTT) ; //產(chǎn)生停止條件 I2CTCTL |= I2CSTP; //等待停止條件復(fù)位 while (I2CDCTL & I2CBUSY) ; count = count + 1; } //清除I2CEN位 U0CTL &= ~I2CEN; I2CTCTL &= ~I2CRM; //使能I2C U0CTL |= I2CEN; return; } #if __VER__ < 200 interrupt [USART0TX_VECTOR] void ISR_I2C(void) #else #pragma vector=USART0TX_VECTOR __interrupt void ISR_I2C(void) #endif //上面的程序其實(shí)只要編寫(xiě) : //#pragma vector=USART0TX_VECTOR __interrupt void ISR_I2C(void)就行. { switch (I2CIV) { case I2CIV_AL: { //仲裁中斷 break; } case I2CIV_NACK: { //NACK中斷 break; } case I2CIV_OA: { //自己地址中斷 break; } case I2CIV_ARDY: { //訪問(wèn)準(zhǔn)備好中斷 break; } case I2CIV_RXRDY: { //接收準(zhǔn)備好中斷 I2CBuffer[0]=I2CDRB; break; } case I2CIV_TXRDY: { //發(fā)送準(zhǔn)備好中斷 I2CDRB = I2CBuffer[tx_count]; tx_count = tx_count - 1; if (tx_count < 0) { //禁止發(fā)送中斷 I2CIE &= ~TXRDYIE; } break; } case I2CIV_GC: { //一般調(diào)用中斷 break; } case I2CIV_STT: { //起始條件中斷 break; } } } void Init_IIC_Port(void) { //初始化端口寄存器 與IIC口無(wú)關(guān)的PX口關(guān)閉以便于對(duì)編寫(xiě)系統(tǒng)板的綜合程序. //P1DIR = 0xFF; //P2DIR = 0xFF; P3DIR = 0xF5; //P4DIR = 0xFF; P5DIR = 0x7F; //P6DIR = 0xFF; //P4OUT = 0X11; //P5OUT &= 0XF0; P3SEL|=BIT1+BIT3; //在這里如果設(shè)置成 } void Init_CLK(void) { unsigned int i; //將寄存器的內(nèi)容清零 //XT2震蕩器開(kāi)啟 //LFTX1工作在低頻模式 //ACLK的分頻因子為1 BCSCTL1 = 0X00; do { // 清除OSCFault標(biāo)志 IFG1 &= ~OFIFG; for (i = 0x20; i > 0; i--); } while ((IFG1 & OFIFG) == OFIFG); // 如果OSCFault =1 //open XT2, LFTX2 選擇低頻率 BCSCTL1 &= ~(XT2OFF + XTS); //BCSCTL1=0X00 功能一樣 //DCO Rsel=7(Freq=3200k/25攝氏度) BCSCTL1 |= RSEL0 + RSEL1 + RSEL2; BCSCTL1 |= 0x07; //MCLK的時(shí)鐘源為T(mén)X2CLK,分頻因子為1 BCSCTL2 += SELM1; //SMCLK的時(shí)鐘源為T(mén)X2CLK,分頻因子為1 BCSCTL2 += SELS; } //對(duì)于系統(tǒng)時(shí)鐘的選擇關(guān)系到整個(gè)程序運(yùn)行穩(wěn)定性. 看到很多賣(mài)開(kāi)發(fā)板的人將IIC硬件寫(xiě)上去后再去搞個(gè)模擬的IIC總線(xiàn)程序. 感覺(jué)到有點(diǎn)說(shuō)不出的感覺(jué). 其實(shí)430的IIC不是專(zhuān)用來(lái)外擴(kuò)展FLASH的,而是用來(lái)和一些特殊的電路連接,實(shí)現(xiàn)功能. 對(duì)于MSP430147~149 15X 16X 的芯片內(nèi)部有48~60K的Flash了還有必要來(lái)個(gè)模擬的IIC總線(xiàn)時(shí)序么.裝個(gè)UCOS都可以了.開(kāi)發(fā)板要做的事情就是如何做好非模擬IIC程序的設(shè)計(jì).更不是為了和C1搞比拼搶占市場(chǎng). 上面的程序是經(jīng)過(guò)MSP430F1611的測(cè)試.程序的大部分來(lái)自 |