MSP430G2553读取SHT30温湿度传感器(串口输出)程序

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并通过串口输出温湿度数据。

专注于matlab/simulink,电子电路,编程