一、USCI I2C 驅動介紹
對於MSP430G2553,硬件I2C由外設USCI(Universal Serial Communication Interface)提供。USCI又分為USCI_A和USCI_B,其中USCI_A支持UART/IrDA/LIN/SPI通訊,USCI_B支持I2C/SPI通訊。MSP430G2553帶有一個USCI_A和一個USCI_B,硬件I2C對應的管腳為P1.6(UCB0SCL)和P1.7(UCB0SDA)。
由於Launchpad上P1.6連接到了LED2,因此在使用硬件I2C時,務必要將LED2對應的跳線取下,否則總線無法正常工作。
在官方MSP430x2xx Family User's Guide中,已對USCI_B的I2C模式進行的詳細的介紹。了解這些信息,由於排查I2C通訊中可能遇到的問題。然而,本着不重復發明輪子的想法,TI已經提供了詳細的I2C驅動代碼和使用范例,正常開發只要增加TI的代碼文件並稍作更改,直接調用TI提供的函數即可。
幾個可參考的官方USCI I2C驅動資料/范例有:
Application Report, Using the USCI I2C Master, SLAA382A
—— 重點推薦。
Application Report, Using the USCI I2C Slave, SLAA383
—— 重點推薦。
—— 包含了CRC的計算方法,驅動代碼增加了對I2C器件響應超時異常的判斷。
Application Report, Using the MSP430 Launchpad as a Standalone I2C Host for Audio Products, SLAA605A
—— 除了USCI I2C,還包含了GPIO I2C的驅動代碼。
Application Report, Interfacing an EEPROM via I2C Using the MSP430, SLAA208A
—— 驅動封裝了操作EEPROM的I2C函數。
二、USCI I2C Master 驅動
I2C驅動使用SLAA382A提供的USCI I2C Master Library(without DMA support),將其中的TI_USCI_I2C_master.c代碼device specific header修改#include相關頭文件為:
#include "io430.h"
(IAR的project option中已選擇器件為G2553)
在TI_USCI_I2C_receiveinit()和TI_USCI_I2C_transmitinit()函數中修改對應的管腳,將P3SEL |= SDA_PIN + SCL_PIN; 注釋掉,增加:
P1SEL |= SDA_PIN + SCL_PIN;
P1SEL2|= SDA_PIN + SCL_PIN;
修改TI_USCI_I2C_master.h中SDA_PIN和SCL_PIN的定義:
#define SDA_PIN BIT7 #define SCL_PIN BIT6
這樣,硬件I2C驅動部分就大功告成了。剩下的就是調用驅動代碼中的函數,完成與外部器件的通訊功能。
三、使用示例——MSP430G2553讀取溫濕度傳感器Si7021
Si7021芯片的介紹可參考之前一篇文章。
Si7021模塊從淘寶購買,原來以為板子自帶I2C上拉電阻的,后來才發現模塊的上拉電阻並沒有焊接到VDD上,還需要自己把背面三個焊點焊在一起才行。
以下代碼每隔2s測量一次溫濕度,並通過串口打印結果。printf()函數的使用可參考之前另一篇文章。

1 // msp430G2553 i2c bus <-> Si7021 humidity & temperature sensor 2 // pullup resistors for SDA & SCL lines: 10kOhm 3 // jumper for LED2 should be removed, or I2C bus won't work. 4 5 #include "io430.h" 6 #include "TI_USCI_I2C_master.h" 7 8 #define SI7021_ADDRESS 0x40 9 #define MEASURE_RH_HOLD 0xE5 10 #define MEASURE_RH_NO_HOLD 0xF5 11 #define READ_T_FROM_PRE_RH_MEASUREMENT 0xE0 12 13 #define RXD BIT1 //P1.1 14 #define TXD BIT2 //P1.2 15 16 unsigned char array[1] = {0}; 17 unsigned char store[3] = {0, 0, 0}; 18 unsigned int outHumi = 0; 19 float valueHumi = 0.0; 20 int outTemp = 0; 21 float valueTemp = 0.0; 22 23 // functions for printf() 24 void sendByte(unsigned char); 25 void printf(char *, ...); 26 void initUART(void); 27 void printf_f(float); 28 29 void main( void ) 30 { 31 // Stop watchdog timer to prevent time out reset 32 WDTCTL = WDTPW + WDTHOLD; 33 34 // DCO setup 35 BCSCTL1 = CALBC1_1MHZ; 36 DCOCTL = CALDCO_1MHZ; 37 38 // UART setup 39 initUART(); 40 41 __enable_interrupt(); 42 43 while(1) 44 { 45 TI_USCI_I2C_transmitinit(SI7021_ADDRESS, 10); // init transmitting with USCI 46 // scl clock: f(BRCLK)/10; BRCLK <- SMCLK 47 while(TI_USCI_I2C_notready()); // wait for bus to be free 48 49 array[0] = MEASURE_RH_NO_HOLD; 50 TI_USCI_I2C_transmit(1, array); 51 while(TI_USCI_I2C_notready()); 52 53 __delay_cycles(25000); //delay 25ms 54 55 // get the humidity result 56 TI_USCI_I2C_receiveinit(SI7021_ADDRESS, 10); 57 while(TI_USCI_I2C_notready()); 58 59 TI_USCI_I2C_receive(3,store); 60 while(TI_USCI_I2C_notready()); 61 62 outHumi = (store[0]<<8) | store[1]; 63 valueHumi = 125.0*outHumi/65536 - 6; 64 65 //printf("heX %x\r\n", outHumi); 66 //printf("heX %x\r\n", (unsigned int)store[2]); 67 //printf("Integer %i\r\n", (int)valueHumi); 68 printf_f(valueHumi); 69 printf(" %%RH "); 70 71 72 // get temperature from previous RH measurement 73 TI_USCI_I2C_transmitinit(SI7021_ADDRESS, 10); 74 while(TI_USCI_I2C_notready()); 75 array[0] = READ_T_FROM_PRE_RH_MEASUREMENT; 76 TI_USCI_I2C_transmit(1, array); 77 while(TI_USCI_I2C_notready()); 78 79 TI_USCI_I2C_receiveinit(SI7021_ADDRESS, 10); // init receiving with USCI 80 while(TI_USCI_I2C_notready()); // wait for bus to be free 81 TI_USCI_I2C_receive(2,store); 82 while(TI_USCI_I2C_notready()); 83 84 outTemp = (store[0]<<8) | store[1]; 85 valueTemp = 175.72*outTemp/65536 - 46.85; 86 87 //printf("heX %x\r\n", outTemp); 88 //printf("Integer %i\r\n", (int)valueTemp); 89 printf_f(valueTemp); 90 printf(" `C\r\n"); 91 92 __delay_cycles(2000000); //delay 2s 93 } 94 } 95 96 void initUART(void) { 97 //config P1.1 RXD, P1.2 TXD 98 P1SEL |= TXD + RXD; 99 P1SEL2 |= TXD + RXD; 100 101 //reset UCA0, to be configured 102 UCA0CTL1 = UCSWRST; 103 //config 104 UCA0CTL1 |= UCSSEL_2; //SMCLK 105 UCA0BR0 = 104; 106 UCA0BR1 = 0;//1MHz baut rate = 9600 107 UCA0MCTL = UCBRS0; // Modulation UCBRSx = 1 108 //make UCA0 out of reset 109 UCA0CTL1 &= ~UCSWRST; 110 } 111 112 void sendByte(unsigned char byte ) 113 { 114 while (!(IFG2&UCA0TXIFG)); // USCI_A0 TX buffer ready? 115 UCA0TXBUF = byte; // TX -> RXed character 116 } 117 118 void printf_f(float fnumber) 119 { 120 int ipart = (int)fnumber; // integer part 121 int fpart = (int)((fnumber - ipart)*100); //fractional part, 2 decimal places 122 123 printf("%i.", ipart); 124 125 if(fpart<0) 126 { 127 fpart = -fpart; 128 } 129 if(fpart<10) 130 { 131 printf("0"); 132 } 133 printf("%i", fpart); 134 }
程序輸出結果如圖所示。