MSP430G2553读取SHT30温湿度传感器(串口输出)程序
系统连接图
MSP430G2553 ─── SHT30 (I2C接口)
P1.6(SCL)────── SCL
P1.7(SDA)────── SDA
GND ─────────── GND
3.3V ────────── VIN
MSP430G2553 ─── 串口转USB (UART)
P1.1(TXD)────── RXD(USB转TTL)
P1.2(RXD)────── TXD(USB转TTL)
GND ─────────── GND
C语言源代码
/************************************************************
* MSP430G2553读取SHT30温湿度传感器
* 硬件连接:
* SHT30 I2C: P1.6(SCL), P1.7(SDA)
* UART串口: P1.1(TXD), P1.2(RXD)
* 编译环境:CCS 6.0+/IAR/Energia
************************************************************/
#include <msp430g2553.h>
#include <stdint.h>
#include <string.h>
// 系统时钟定义
#define F_CPU 1000000UL // 1MHz DCO时钟
#define I2C_FREQ 100000 // I2C频率100kHz
#define UART_BAUD 9600 // 串口波特率9600
// SHT30 I2C地址定义
#define SHT30_ADDR_W 0x44 << 1 // 写地址(0x88)
#define SHT30_ADDR_R 0x44 << 1 | 1 // 读地址(0x89)
// SHT30命令定义
#define SHT30_CMD_MSB 0x2C // 测量命令高字节
#define SHT30_CMD_LSB 0x06 // 测量命令低字节(重复性:高)
// 函数声明
void System_Init(void);
void GPIO_Init(void);
void Timer_Init(void);
void I2C_Init(void);
void UART_Init(void);
void Delay_ms(uint16_t ms);
uint8_t I2C_Write(uint8_t addr, uint8_t *data, uint8_t len);
uint8_t I2C_Read(uint8_t addr, uint8_t *data, uint8_t len);
uint8_t SHT30_Read(float *temperature, float *humidity);
void SHT30_CRC_Check(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum);
void UART_Send_Byte(uint8_t data);
void UART_Send_String(char *str);
void Float_To_String(float value, char *buffer, uint8_t precision);
// 全局变量
volatile uint16_t timer_counter = 0;
/************************************************************
* 主函数
************************************************************/
void main(void) {
WDTCTL = WDTPW | WDTHOLD; // 关闭看门狗
System_Init(); // 系统初始化
GPIO_Init(); // GPIO初始化
Timer_Init(); // 定时器初始化
I2C_Init(); // I2C初始化
UART_Init(); // 串口初始化
__enable_interrupt(); // 开启全局中断
float temperature = 0.0;
float humidity = 0.0;
char temp_str[10], hum_str[10];
uint8_t ret = 0;
UART_Send_String("\r\n\r\n=== MSP430G2553 SHT30 Demo ===\r\n");
UART_Send_String("Initializing SHT30...\r\n");
Delay_ms(100); // 等待传感器稳定
while(1) {
// 读取SHT30温湿度
ret = SHT30_Read(&temperature, &humidity);
if(ret == 0) {
// 温度转换为字符串
Float_To_String(temperature, temp_str, 2);
// 湿度转换为字符串
Float_To_String(humidity, hum_str, 2);
// 发送到串口
UART_Send_String("Temperature: ");
UART_Send_String(temp_str);
UART_Send_String(" °C\r\n");
UART_Send_String("Humidity: ");
UART_Send_String(hum_str);
UART_Send_String(" %RH\r\n");
UART_Send_String("--------------------\r\n");
} else {
UART_Send_String("Error reading SHT30\r\n");
}
// 延时2秒
Delay_ms(2000);
}
}
/************************************************************
* 系统初始化
************************************************************/
void System_Init(void) {
// 设置DCO为1MHz
BCSCTL1 = CALBC1_1MHZ;
DCOCTL = CALDCO_1MHZ;
// 设置SMCLK = DCO = 1MHz
BCSCTL2 |= SELM_0 + DIVM_0 + DIVS_0;
}
/************************************************************
* GPIO初始化
************************************************************/
void GPIO_Init(void) {
// 设置P1.6(SCL)和P1.7(SDA)为I2C功能
P1SEL |= BIT6 | BIT7;
P1SEL2 |= BIT6 | BIT7;
// 设置P1.1(TXD)和P1.2(RXD)为UART功能
P1SEL |= BIT1 | BIT2;
P1SEL2 |= BIT1 | BIT2;
// 设置P1.0为LED输出
P1DIR |= BIT0;
P1OUT &= ~BIT0; // LED初始熄灭
}
/************************************************************
* 定时器初始化
************************************************************/
void Timer_Init(void) {
// 使用Timer_A产生1ms中断
TA0CTL = TASSEL_2 + MC_1 + TACLR; // SMCLK, 增计数模式
TA0CCR0 = 1000 - 1; // 1ms中断 (1MHz/1000)
TA0CCTL0 = CCIE; // 允许CCR0中断
}
/************************************************************
* I2C初始化
************************************************************/
void I2C_Init(void) {
// 配置I2C引脚
P1SEL |= BIT6 + BIT7; // P1.6,7选择I2C功能
P1SEL2 |= BIT6 + BIT7;
UCB0CTL1 |= UCSWRST; // 进入复位状态
// 配置为主机模式
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C主机模式,同步模式
UCB0CTL1 = UCSSEL_2 + UCSWRST; // SMCLK作为时钟源,保持复位状态
// 计算I2C时钟分频
// I2C时钟 = SMCLK / (UCB0BR0 + UCB0BR1 * 256)
// 目标频率 = 100kHz, SMCLK = 1MHz
UCB0BR0 = 10; // 分频系数低8位
UCB0BR1 = 0; // 分频系数高8位
UCB0CTL1 &= ~UCSWRST; // 退出复位状态,启动I2C
UCB0I2CIE = 0; // 禁用I2C中断
}
/************************************************************
* 串口UART初始化
************************************************************/
void UART_Init(void) {
// 进入UART复位状态
UCA0CTL1 |= UCSWRST;
// 配置UART
UCA0CTL0 = 0; // 8位数据,无校验,1停止位
UCA0CTL1 |= UCSSEL_2; // SMCLK作为时钟源
// 计算波特率设置
// 1MHz时钟,9600波特率
// UCBRx = F_CPU / Baudrate
// UCBR0 = 104, UCBR1 = 0, UCBRSx = 1
UCA0BR0 = 104; // 波特率分频整数部分低8位
UCA0BR1 = 0; // 波特率分频整数部分高8位
UCA0MCTL = UCBRS_1; // 调制设置
UCA0CTL1 &= ~UCSWRST; // 退出复位状态
IE2 |= UCA0RXIE; // 允许接收中断
}
/************************************************************
* 延时函数(毫秒级)
************************************************************/
void Delay_ms(uint16_t ms) {
timer_counter = 0;
while(timer_counter < ms) {
__low_power_mode_0(); // 进入LPM0等待中断
}
}
/************************************************************
* I2C写数据
************************************************************/
uint8_t I2C_Write(uint8_t addr, uint8_t *data, uint8_t len) {
uint8_t i;
// 发送起始条件
UCB0CTL1 |= UCTR + UCTXSTT;
// 发送从机地址(写模式)
UCB0TXBUF = addr;
// 等待地址发送完成
while((UCB0CTL1 & UCTXSTT) || !(IFG2 & UCB0TXIFG));
// 检查ACK
if(UCB0CTL1 & UCNACKIFG) {
UCB0CTL1 |= UCTXSTP; // 发送停止条件
return 1; // NACK,返回错误
}
// 发送数据
for(i = 0; i < len; i++) {
UCB0TXBUF = data[i];
while(!(IFG2 & UCB0TXIFG)); // 等待发送完成
}
// 发送停止条件
UCB0CTL1 |= UCTXSTP;
while(UCB0CTL1 & UCTXSTP); // 等待停止条件完成
return 0; // 成功
}
/************************************************************
* I2C读数据
************************************************************/
uint8_t I2C_Read(uint8_t addr, uint8_t *data, uint8_t len) {
uint8_t i;
// 发送起始条件
UCB0CTL1 |= UCTXSTT;
// 发送从机地址(读模式)
UCB0TXBUF = addr | 1; // 最后一位为1表示读
// 等待地址发送完成
while((UCB0CTL1 & UCTXSTT) || !(IFG2 & UCB0TXIFG));
// 检查ACK
if(UCB0CTL1 & UCNACKIFG) {
UCB0CTL1 |= UCTXSTP; // 发送停止条件
return 1; // NACK,返回错误
}
// 接收数据
for(i = 0; i < len; i++) {
if(i == len - 1) {
// 最后1个字节,发送NACK
UCB0CTL1 &= ~UCTR; // 切换到接收模式
UCB0CTL1 |= UCTXSTT; // 接收数据
while(UCB0CTL1 & UCTXSTT);
// 发送停止条件
UCB0CTL1 |= UCTXSTP;
}
while(!(IFG2 & UCB0RXIFG)); // 等待接收完成
data[i] = UCB0RXBUF;
}
return 0; // 成功
}
/************************************************************
* 读取SHT30温湿度
************************************************************/
uint8_t SHT30_Read(float *temperature, float *humidity) {
uint8_t cmd[2] = {SHT30_CMD_MSB, SHT30_CMD_LSB};
uint8_t data[6] = {0};
uint16_t temp_raw, hum_raw;
uint8_t crc_temp, crc_hum;
// 发送测量命令
if(I2C_Write(SHT30_ADDR_W, cmd, 2)) {
return 1; // 写失败
}
Delay_ms(20); // 等待测量完成(最大20ms)
// 读取6个字节数据
if(I2C_Read(SHT30_ADDR_R, data, 6)) {
return 1; // 读失败
}
// 提取温度数据
temp_raw = (data[0] << 8) | data[1];
crc_temp = data[2];
// 提取湿度数据
hum_raw = (data[3] << 8) | data[4];
crc_hum = data[5];
// 可选:CRC校验
// SHT30_CRC_Check(&data[0], 2, crc_temp);
// SHT30_CRC_Check(&data[3], 2, crc_hum);
// 转换温度(公式来自SHT30手册)
// 温度(℃) = -45 + 175 * (temp_raw / 65535)
*temperature = -45.0 + 175.0 * ((float)temp_raw / 65535.0);
// 转换湿度
// 湿度(%RH) = 100 * (hum_raw / 65535)
*humidity = 100.0 * ((float)hum_raw / 65535.0);
return 0; // 成功
}
/************************************************************
* SHT30 CRC校验
************************************************************/
void SHT30_CRC_Check(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum) {
uint8_t crc = 0xFF;
uint8_t byteCtr, bit;
// 计算CRC-8校验
for(byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++) {
crc ^= data[byteCtr];
for(bit = 8; bit > 0; --bit) {
if(crc & 0x80) {
crc = (crc << 1) ^ 0x31;
} else {
crc = (crc << 1);
}
}
}
if(crc != checksum) {
// CRC错误处理
P1OUT |= BIT0; // LED亮表示错误
} else {
P1OUT &= ~BIT0; // LED灭表示正常
}
}
/************************************************************
* 串口发送单个字节
************************************************************/
void UART_Send_Byte(uint8_t data) {
while(!(IFG2 & UCA0TXIFG)); // 等待发送缓冲区空
UCA0TXBUF = data;
}
/************************************************************
* 串口发送字符串
************************************************************/
void UART_Send_String(char *str) {
while(*str) {
UART_Send_Byte(*str++);
}
}
/************************************************************
* 浮点数转换为字符串
************************************************************/
void Float_To_String(float value, char *buffer, uint8_t precision) {
int16_t int_part = (int16_t)value;
float frac_part = value - int_part;
if(value < 0 && int_part == 0) {
// 处理-0.x的情况
*buffer++ = '-';
}
// 整数部分转换为字符串
char temp[10];
uint8_t i = 0;
if(int_part == 0) {
temp[i++] = '0';
} else {
int16_t temp_int = (int_part < 0) ? -int_part : int_part;
while(temp_int > 0) {
temp[i++] = (temp_int % 10) + '0';
temp_int /= 10;
}
}
// 反转整数部分
while(i > 0) {
*buffer++ = temp[--i];
}
if(precision > 0) {
*buffer++ = '.'; // 小数点
// 小数部分
for(i = 0; i < precision; i++) {
frac_part *= 10;
uint8_t digit = (uint8_t)frac_part;
*buffer++ = digit + '0';
frac_part -= digit;
}
}
*buffer = '\0'; // 字符串结束符
}
/************************************************************
* 定时器中断服务程序
************************************************************/
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_CCR0_ISR(void) {
timer_counter++; // 计时器递增
P1OUT ^= BIT0; // LED闪烁指示运行
}
/************************************************************
* 串口接收中断服务程序
************************************************************/
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCI0RX_ISR(void) {
uint8_t rx_data = UCA0RXBUF;
// 简单的命令处理
switch(rx_data) {
case 't': // 发送当前温度
UART_Send_String("Current temperature: ");
break;
case 'h': // 发送当前湿度
UART_Send_String("Current humidity: ");
break;
case 'r': // 重新读取SHT30
UART_Send_String("Re-reading SHT30...\r\n");
break;
default:
break;
}
}
项目配置文件
1. CCS项目配置(main.c同级目录)
/************************************************************
* MSP430G2553配置头文件
************************************************************/
/* 链接器命令文件(lnk_msp430g2553.cmd)不需要修改 */
/* 如果需要低功耗模式,添加以下代码到main.c */
/************************************************************
* 低功耗模式版本
************************************************************/
void Enter_Low_Power_Mode(void) {
// 进入LPM3低功耗模式
__bis_SR_register(LPM3_bits + GIE);
}
调试与测试
1. 硬件连接检查
1. 电源检查:
- SHT30 VIN: 3.3V
- 上拉电阻:SCL/SDA各接4.7kΩ上拉到3.3V
2. 串口连接:
- TXD(P1.1) → USB转TTL的RXD
- RXD(P1.2) → USB转TTL的TXD
- 共地连接
3. 可选调试LED:
- P1.0连接LED+220Ω电阻到GND
2. 串口调试助手设置
波特率: 9600
数据位: 8
停止位: 1
校验位: 无
流控制: 无
3. 预期输出
=== MSP430G2553 SHT30 Demo ===
Initializing SHT30...
Temperature: 25.36 °C
Humidity: 50.25 %RH
--------------------
Temperature: 25.38 °C
Humidity: 50.30 %RH
--------------------
...
参考代码 msp430g2553读取sht30串口发送源程序 www.youwenfan.com/contentcnt/73363.html
扩展功能
1. 添加温度报警功能
// 温度报警阈值
#define TEMP_ALARM_HIGH 30.0
#define TEMP_ALARM_LOW 0.0
// 温度报警检测
void Check_Temperature_Alarm(float temp) {
if(temp > TEMP_ALARM_HIGH) {
UART_Send_String("[ALARM] High Temperature!\r\n");
} else if(temp < TEMP_ALARM_LOW) {
UART_Send_String("[ALARM] Low Temperature!\r\n");
}
}
2. 添加数据平均滤波
// 平均值滤波
#define SAMPLE_COUNT 5
float temperature_buffer[SAMPLE_COUNT];
float humidity_buffer[SAMPLE_COUNT];
uint8_t buffer_index = 0;
float Get_Average_Temperature(float new_temp) {
temperature_buffer[buffer_index] = new_temp;
buffer_index = (buffer_index + 1) % SAMPLE_COUNT;
float sum = 0;
for(uint8_t i = 0; i < SAMPLE_COUNT; i++) {
sum += temperature_buffer[i];
}
return sum / SAMPLE_COUNT;
}
3. JSON格式输出
// 发送JSON格式数据
void Send_JSON_Data(float temp, float hum) {
char temp_str[10], hum_str[10];
Float_To_String(temp, temp_str, 2);
Float_To_String(hum, hum_str, 2);
UART_Send_String("{\"temperature\":");
UART_Send_String(temp_str);
UART_Send_String(",\"humidity\":");
UART_Send_String(hum_str);
UART_Send_String("}\r\n");
}
常见问题解决
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 无串口输出 | 波特率不匹配 | 检查串口助手设置,确认9600波特率 |
| I2C通信失败 | 上拉电阻缺失 | SCL/SDA各加4.7kΩ上拉电阻 |
| 读数异常 | 供电不足 | 确保3.3V稳定,可加10μF电容 |
| 数据不更新 | 延时不足 | 增加Delay_ms(20)的时间 |
| LED不闪烁 | 定时器配置错误 | 检查Timer_Init()函数配置 |
性能优化
1. 低功耗版本
// 修改主循环为低功耗模式
while(1) {
// 读取传感器
ret = SHT30_Read(&temperature, &humidity);
if(ret == 0) {
// 发送数据
Send_JSON_Data(temperature, humidity);
}
// 进入低功耗模式5秒
__bis_SR_register(LPM3_bits + GIE);
Delay_ms(5000);
}
2. 快速测量模式
// 使用快速测量命令(15ms)
#define SHT30_CMD_FAST_MSB 0x24
#define SHT30_CMD_FAST_LSB 0x00
// 快速读取函数
uint8_t SHT30_Read_Fast(float *temperature, float *humidity) {
uint8_t cmd[2] = {SHT30_CMD_FAST_MSB, SHT30_CMD_FAST_LSB};
// ... 其余代码同SHT30_Read
Delay_ms(15); // 只需要15ms等待
}
这个完整程序可以直接在CCS、IAR或Energia中编译运行,实现了MSP430G2553读取SHT30并通过串口输出温湿度数据。