MSP430F5529 DriverLib 库函数学习笔记(十二)I2C实战
目錄
- 上機實戰
- I2C給 DAC 芯片 DAC7571 寫入數字量
- DAC7571 介紹
 
- 程序分析
- 引腳復用
- I2C 初始化
- 發送一個字節
- 發送一個字
- 讀取一個字節
- 讀取多個字節
- 中斷服務函數
- 整體代碼
- main.c
- MSP430F5529_I2C.c
- MSP430F5529_I2C.h
 
 
- 實驗結果
 
- I2C 讀取 TMP421 溫度
- TMP421 簡介
- 程序摘要
- TMP421初始化
- 溫度的讀取和解算
 
- 實驗結果
 
 
平臺:Code Composer Studio 10.3.1
  MSP430F5529 LaunchPad? Development Kit
  (MSP?EXP430F5529LP)
上機實戰
I2C給 DAC 芯片 DAC7571 寫入數字量
DAC7571 介紹
DAC7571 是低功耗,單通道 12 位 DA 轉換器.DAC7571 兼容 I2C 接口,通過這兩條數據線和外部通信,時鐘的最高速度為 3.4Mbps.
 
 DAC7571 的外觀圖和引腳定義
 
 如上圖所示:
 1 腳:模擬電壓輸出腳.
 2 腳:接地.
 3 腳:電源輸入腳.
 4 腳:串行數據輸入引腳.
 5 腳:串行時鐘輸入引腳.
 6 腳:地址選擇腳.
 DAC7571 的數字信號轉換成模擬信號是通過一個放大器進行轉換,如下圖所示.
 
 DAC7571 的數字信號為無符號型數據.根據下面公式可以算出輸出電壓值和輸入量的關系.
 
 VOUT 代表輸出電壓值, VDD 為電源電壓值,D 為輸入的數字量.
 DAC7571 按照 I2C 通信規范進行通信,如下圖所示:
 
 DAC7571 通信標準模式:
 ???????首先發送開始信號,然后發送從機地址字節(最后一位為讀寫控制位),然后等待從機應答,然后發送控制位和數據高四位組成的字節,然后等待從機應答,然后發送數據低八位,然后等待應答或者不等待應答,最后發送結束信號。
 
 名詞解釋:
 A 表示應答信號,即數據線拉低。
 S 表示開始信號。
 Sr 表示重新發送開始信號。
 P 表示停止信號。
 From Master to DAC7571 表示信號是主機發送給 DAC7571。
 From DAC7571 to Master 表示信號是 DAC7571 發送給主機。
 DAC7571 的地址高 6 位由工廠燒錄進去,最后一位是通過外部引腳確定。
 地址共 7 位加上最后一個讀寫控制位構成一個字節。DAC7571 只支持寫不支持讀操作。
 DAC7571 通信高速模式:
 ???????首先發送開始信號,然后發送發送高速模式控制字,然后發送一個時鐘信號不用等待應答,然后重新發送開始信號,下面步驟和標準模式一樣。
 
 名稱解釋:
 HS-Mode Master Code 為告訴模式控制字
 數據字節介紹:如下圖所示
 
 PD1 和 PD2 是操作模式選擇,正常模式時這兩個位都是 0。
 D0-D11 為 12 位的數據位。
程序分析
引腳復用
void Init_I2C_GPIO(void) {/* Select I2C function for I2C_SDA & I2C_SDA */GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3,GPIO_PIN0 | GPIO_PIN1); }I2C 初始化
由下圖可知,DAC7571的7位地址為1 0 0 1 1 0 A0,A0接地,故A0 = 0
 則對應地址為1001100B 即0x4C
 
發送一個字節
/* write a byte to specific register, cannot called in interrupt context */ void writeByte(uint8_t byte) {while (USCI_B_I2C_isBusBusy(I2C_USCI_BASE));USCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);// Initiate start and send first characteri2c_buf[0] = byte;i2c_buf_cur = 1;i2c_buf_len = 1;USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_BASE, i2c_buf[0]);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }發送一個字
/* write a byte to specific register, cannot called in interrupt context */while (USCI_B_I2C_isBusBusy(I2C_USCI_BASE));USCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);// Initiate start and send first characteri2c_buf[0] = word >> 8;i2c_buf[1] = (uint8_t)word;i2c_buf_cur = 1;i2c_buf_len = 2;USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_BASE, i2c_buf[0]);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }讀取一個字節
/* read some byte from specific register, cannot called in interrupt context */ void readByte(uint8_t RegAddr, uint8_t* b) {// send addressUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);i2c_buf_cur = 1;i2c_buf_len = 1;USCI_B_I2C_masterSendSingleByte(I2C_USCI_BASE, RegAddr);// receiveUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_RECEIVE_MODE);i2c_rx_buf = b;i2c_rx_buf_len = 1;USCI_B_I2C_masterReceiveSingleStart(I2C_USCI_BASE);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }讀取多個字節
void readBytes(uint8_t RegAddr, uint8_t length, uint8_t* data) {// send addressUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);i2c_buf_cur = 1;i2c_buf_len = 1;USCI_B_I2C_masterSendSingleByte(I2C_USCI_BASE, RegAddr);// receiveUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_RECEIVE_MODE);i2c_rx_buf = data;i2c_rx_buf_len = length;USCI_B_I2C_masterReceiveMultiByteStart(I2C_USCI_BASE);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }中斷服務函數
#pragma vector = I2C_USCI_VECTOR __interrupt void USCI_B0_ISR(void) {switch (__even_in_range(I2C_USCI_IV, 12)){case USCI_I2C_UCTXIFG:if (i2c_buf_cur < i2c_buf_len){USCI_B_I2C_masterSendMultiByteNext( I2C_USCI_BASE, i2c_buf[i2c_buf_cur]);i2c_buf_cur++;}else{USCI_B_I2C_masterSendMultiByteStop(I2C_USCI_BASE);//Clear master interrupt statusUSCI_B_I2C_clearInterrupt(I2C_USCI_BASE,USCI_B_I2C_TRANSMIT_INTERRUPT);__bic_SR_register_on_exit(LPM0_bits);}break;case USCI_I2C_UCRXIFG:i2c_rx_buf_len--;if(i2c_rx_buf_len){if(i2c_rx_buf_len== 1){//Initiate end of reception -> Receive byte with NAK*i2c_rx_buf++ = USCI_B_I2C_masterReceiveMultiByteFinish( I2C_USCI_BASE);}else{//Keep receiving one byte at a time*i2c_rx_buf++ = USCI_B_I2C_masterReceiveMultiByteNext( I2C_USCI_BASE);}}else{//Receive last byte*i2c_rx_buf= USCI_B_I2C_masterReceiveMultiByteNext(I2C_USCI_BASE);__bic_SR_register_on_exit(LPM0_bits);}break;} }整體代碼
main.c
#include "driverlib.h" #include "MSP430F5529_I2C.h"#define MCLK_IN_HZ 25000000#define delay_us(x) __delay_cycles((MCLK_IN_HZ/1000000*(x))) #define delay_ms(x) __delay_cycles((MCLK_IN_HZ/1000*(x)))void SystemClock_Init(void) {PMM_setVCore(PMM_CORE_LEVEL_3); //高主頻工作需要較高的核心電壓//XT1引腳復用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);//起振XT1UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);//XT2引腳復用GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);//起振XT2UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);//XT2作為FLL參考時鐘,先8分頻,再50倍頻 4MHz / 8 * 50 = 25MHzUCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);UCS_initFLLSettle(25000, 50);//XT1作為ACLK時鐘源 = 32768HzUCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作為MCLK時鐘源 = 25MHzUCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//DCOCLK作為SMCLK時鐘源 = 25MHzUCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);//設置外部時鐘源的頻率,使得在調用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK時可得到正確值UCS_setExternalClockSource(32768, 4000000); }int main(void) {unsigned int i;WDT_A_hold(WDT_A_BASE);SystemClock_Init();Init_I2C_GPIO();I2C_init();writeWord((uint16_t)(2*4096/3.3 + 0.5));__bis_SR_register(GIE);while(1){} }MSP430F5529_I2C.c
#include "driverlib.h"#define I2C_USCI_BASE USCI_B0_BASE #define I2C_USCI_VECTOR USCI_B0_VECTOR #define I2C_USCI_IV UCB0IV#define I2C_BUF_LENGTH 32 static char i2c_buf[I2C_BUF_LENGTH]; static uint8_t i2c_buf_len = 0; static uint8_t i2c_buf_cur = 0;static uint8_t *i2c_rx_buf = 0; static uint8_t i2c_rx_buf_len = 0;void Init_I2C_GPIO(void) {/* Select I2C function for I2C_SCL & I2C_SDA */GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P3,GPIO_PIN0 | GPIO_PIN1); }/***************************************************************************//*** @brief Configures I2C* @param none* @return none******************************************************************************/void I2C_init(void) {/* I2C Master Configuration Parameter */USCI_B_I2C_initMasterParam i2cConfig ={USCI_B_I2C_CLOCKSOURCE_SMCLK,UCS_getSMCLK(),USCI_B_I2C_SET_DATA_RATE_100KBPS};/* Initialize USCI_B0 and I2C Master to communicate with slave devices*/USCI_B_I2C_initMaster(I2C_USCI_BASE, &i2cConfig);/* Enable I2C Module to start operations */USCI_B_I2C_enable(I2C_USCI_BASE);// Specify slave addressUSCI_B_I2C_setSlaveAddress(I2C_USCI_BASE, 0x4C);USCI_B_I2C_clearInterrupt(I2C_USCI_BASE, USCI_B_I2C_RECEIVE_INTERRUPT);USCI_B_I2C_enableInterrupt(I2C_USCI_BASE, USCI_B_I2C_RECEIVE_INTERRUPT);USCI_B_I2C_clearInterrupt(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT);USCI_B_I2C_enableInterrupt(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_INTERRUPT);return; }/* write a byte to specific register, cannot called in interrupt context */ void writeByte(uint8_t byte) {while (USCI_B_I2C_isBusBusy(I2C_USCI_BASE));USCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);// Initiate start and send first characteri2c_buf[0] = byte;i2c_buf_cur = 1;i2c_buf_len = 1;USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_BASE, i2c_buf[0]);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }/* write a word to specific register, cannot called in interrupt context */ void writeWord(uint16_t word) {while (USCI_B_I2C_isBusBusy(I2C_USCI_BASE));USCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);// Initiate start and send first characteri2c_buf[0] = (word >> 8) & 0x0f;i2c_buf[1] = (uint8_t)word;i2c_buf_cur = 1;i2c_buf_len = 2;USCI_B_I2C_masterSendMultiByteStart(I2C_USCI_BASE, i2c_buf[0]);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }///* set/clear some bit to specific register, cannot called in interrupt context */ //void writeBit(uint8_t regAddr, uint8_t bitNum, uint8_t data) //{ // uint8_t b = 0; // readByte(regAddr, &b); // delay_ms(2); // b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum)); // writeByte(regAddr, b); //}/* read some byte from specific register, cannot called in interrupt context */ void readByte(uint8_t RegAddr, uint8_t* b) {// send addressUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);i2c_buf_cur = 1;i2c_buf_len = 1;USCI_B_I2C_masterSendSingleByte(I2C_USCI_BASE, RegAddr);// receiveUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_RECEIVE_MODE);i2c_rx_buf = b;i2c_rx_buf_len = 1;USCI_B_I2C_masterReceiveSingleStart(I2C_USCI_BASE);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }void readBytes(uint8_t RegAddr, uint8_t length, uint8_t* data) {// send addressUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_TRANSMIT_MODE);i2c_buf_cur = 1;i2c_buf_len = 1;USCI_B_I2C_masterSendSingleByte(I2C_USCI_BASE, RegAddr);// receiveUSCI_B_I2C_setMode(I2C_USCI_BASE, USCI_B_I2C_RECEIVE_MODE);i2c_rx_buf = data;i2c_rx_buf_len = length;USCI_B_I2C_masterReceiveMultiByteStart(I2C_USCI_BASE);// wait for end__bis_SR_register(GIE + LPM0_bits);__no_operation(); }#pragma vector = I2C_USCI_VECTOR __interrupt void USCI_B0_ISR(void) {switch (__even_in_range(I2C_USCI_IV, 12)){case USCI_I2C_UCTXIFG:if (i2c_buf_cur < i2c_buf_len){USCI_B_I2C_masterSendMultiByteNext( I2C_USCI_BASE, i2c_buf[i2c_buf_cur]);i2c_buf_cur++;}else{USCI_B_I2C_masterSendMultiByteStop(I2C_USCI_BASE);//Clear master interrupt statusUSCI_B_I2C_clearInterrupt(I2C_USCI_BASE,USCI_B_I2C_TRANSMIT_INTERRUPT);__bic_SR_register_on_exit(LPM0_bits);}break;case USCI_I2C_UCRXIFG:i2c_rx_buf_len--;if(i2c_rx_buf_len){if(i2c_rx_buf_len== 1){//Initiate end of reception -> Receive byte with NAK*i2c_rx_buf++ = USCI_B_I2C_masterReceiveMultiByteFinish( I2C_USCI_BASE);}else{//Keep receiving one byte at a time*i2c_rx_buf++ = USCI_B_I2C_masterReceiveMultiByteNext( I2C_USCI_BASE);}}else{//Receive last byte*i2c_rx_buf= USCI_B_I2C_masterReceiveMultiByteNext(I2C_USCI_BASE);__bic_SR_register_on_exit(LPM0_bits);}break;} }MSP430F5529_I2C.h
#ifndef MSP430F5529_I2C_H_ #define MSP430F5529_I2C_H_void Init_I2C_GPIO(void); void I2C_init(void); void writeByte(uint8_t byte); void writeWord(uint16_t word); void readByte(uint8_t RegAddr, uint8_t* b); void readBytes(uint8_t RegAddr, uint8_t length, uint8_t* data);#endif /* MSP430F5529_I2C_H_ */實驗結果
我們的目標電壓是2V 由
 
 得所發數據為(uint16_t)(2*4096/3.3 + 0.5) = 2482D = 9B2,即分為兩幀發送,第一幀為0x09 ,第二幀為 0xB2,所發的第一個數據0x98由7位地址1001100B ( 0x4c )和讀寫位構成8位數據 10011000B, 即0x98
 
 測得輸出電壓為1.9866V,誤差0.67%
 
I2C 讀取 TMP421 溫度
TMP421 簡介
TMP421 是一款遠程溫度傳感器控制芯片,內置一本地溫度傳感器,與 I2C 和 SMBus 串行總線兼容,實現遠程控制。如下圖所示,通過 DXP、DXN 連接一個三極管或二極管組成一個遠程溫度傳感器,遠程溫度傳感器最大精度為±1℃;本地溫度傳感器最大精度為±1.5℃。本次實驗是通過 I2C 來控制 TMP421 的溫度采集的,將格式設為擴展二進制,溫度檢測范圍為-64 ~ 191℃。通過配置 TMP421 的配置寄存器來初始化,然后通過讀取它的本地溫度寄存器和遠程溫度寄存器來獲取溫度數據。
 
 TMP421 可以測量本地溫度(芯片的溫度),還可以測量遠程溫度——用兩根等長導線連接一個 PNP 型三極管 C9012(TO-92)即可,三極管端的溫度即為遠程溫度。在口袋板上我們可以用2pin 杜邦線分別連接芯片的DXN與 DXP端(口袋板右側擴展插針P3.6 與P3.7),杜邦線的另一頭連接 C9012 三級管的基極+集電極(b+c)與發射極(e 極),即:DXN(P3.6)連接 b 和 c,DXP(P3.7)連接 e,這種用法實際是把三極管當做一個二極管來用。
 
 ?????????C9012 三極管管腳定義
 
程序摘要
和DAC的程序類似,不過地址改為TMP421的地址
USCI_B_I2C_setSlaveAddress(I2C_USCI_BASE, 0x2A);TMP421初始化
writeWord((uint16_t)0x0904);writeWord((uint16_t)0x2103);writeWord((uint16_t)0x0B07);溫度的讀取和解算
float Temp = 0;while(1){readByte(0x00, &a1);a1 -= 64;readByte(0x10, &a2);a2 = a2 >> 4;a2 = (a2 * 625)/100;Temp = a1 + a2/100.;delay_ms(2);}實驗結果
 讀得當前本地溫度為31.93℃。
 
總結
以上是生活随笔為你收集整理的MSP430F5529 DriverLib 库函数学习笔记(十二)I2C实战的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        