目录
- 上机实战
- 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
/***************************************************************************//*** @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 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℃。