人若无名 便可潜心练剑.|

hazy1k

园龄:7个月粉丝:14关注:0

🔖TI
2025-01-24 17:19阅读: 17评论: 0推荐: 0

第12章 I2C-湿温度传感器

第十二章 I2C-湿温度传感器

1. 硬件设计

1.1 I2C简介

I2C总线通常使用两种电压电平,即高电平(VH)和低电平(VL)。高电平为2.5V至5.5V,低电平为0V至0.3V;这些电压电平范围是根据I2C规范确定的。I2C总线有不同的传输速率可选,包括标准模式(100 kbps)、快速模式(400 kbps)以及高速模式。传输速率的选择取决于应用的需求和设备的支持能力。为避免信号冲突,微处理器(MCU)必须只能驱动SDA和 SCL在低电平,即开漏输出。设置为开漏模式主要是为了保护器件和防止干扰。

  • 防止干扰:多个器件共享同一条数据线(SDA)和同一条时钟线(SCL),如果采用推挽输出模式,多个器件的输出将会叠加在数据线上,造成信号干扰,严重时会损坏器件或导致通信错误。而采用开漏输出模式,则各个器件的输出只有拉低数据线的部分,不会干扰彼此,从而提高了总线的可靠性和抗干扰能力。

  • 防止短路:在开漏输出模式下,由于器件的输出只有拉低数据线的部分,如果两个或多个器件同时输出,也不会造成短路。而如果采用推挽输出模式,两个或多个器件同时输出时,可能会形成短路。比如主设备输出高电平,从设备输出低电平。

  • 因设置为开漏模式,需要连接一个外部的上拉电阻(例如:10k)将信号提拉至高电平。故I2C总线中的SDA(数据线)和SCL(时钟线)通常都连接了上拉电阻,以确保逻辑高电平的稳定性。上拉电阻的阻值通常在2.2kΩ至10kΩ之间,具体取决于总线的电容负载和通信距离。

I2C总线的最大线缆长度和传输容量受到一定限制。在标准模式下,最大线缆长度大约在1米左右,而在快速模式下,最大线缆长度约为0.3米。此外,线缆上的总线容量也会对传输速率产生影响。

1.1.1 I2C通信流程

I2C通信流程按照以下步骤进行:

  • 主控向总线发送开始信号。
  • 主控将要通信的设备地址和读写位(R/W)发送到总线上。
  • 设备接收到地址后发送应答信号,主控接收到应答信号后发送数据或继续发送地址。
  • 设备接收到数据后发送应答信号,主控接收到应答信号后可以继续发送数据或者停止通信。
  • 主控向总线发送停止信号。

1.1.2 I2C基本参数

速率: I2C总线有标准模式(100 kbit/s)和快速模式(400 kbit/s)两种传输模式,还有更快的扩展模式和高速模式可供选择。

器件地址: 每个设备都有唯一的7位或10位地址,可以通过地址选择来确定与谁进行通信。

总线状态: I2C总线有五种状态,分别是空闲状态、起始信号、结束信号、响应信号、数据传输。

数据格式: I2C总线有两种数据格式,标准格式和快速格式。标准格式是8位数据字节加上1位ack/nack(应答/非应答)位,快速格式允许两个字节同时传输。

由于SCL和SDA线是双向的,它们也可能会由于外部原因(比如线路中的电容等)出现电平误差,而从而导致通信出错。因此,在IIC总线中,通常使用上拉电阻来保证信号线在空闲状态下的电平为高电平。

1.2 MSPM0G的硬件I2C

MSPM0G系列的I2C支持主从模式,有7位地址位可以设置,支持 100kbps、400kbps、1Mbps 的 I2C 标准传输速率,并支持 SMBUS。 无论是主机或者从机,发送和接收都有独立的8个字节FIFO。MSPM0 I2C 具有 8 字节 FIFO,对于控制器和目标模式会生成独立的中断,并支持 DMA。

1.3 SHT20简介

SHT20是一种数字式温湿度传感器,它采用电容式测量技术,具有高准确度和稳定性,并采用标准的I2C数字接口进行通信。SHT20的测量范围涵盖了温度-40到+125°C和相对湿度0到100%RH。它广泛应用于空气质量监测、气象监测、恒温恒湿控制、食品贮藏等领域。

SHT20温湿度传感器的相关参数,见下图:

2. 软件设计

2.1 编程大纲

  1. I2C接口GPIO配置

  2. I2C模式配置,编写基础函数

  3. 通过I2C读取SHT20传感器数据

  4. 主函数测试

2.2 代码分析

2.2.1 I2C GPIO配置

/* I2C GPIO配置 */
#define I2C_PORT GPIOA
#define I2C_SCL_PIN DL_GPIO_PIN_0
#define I2C_SCL_IOMUX IOMUX_PINCM1
#define I2C_SDA_PIN DL_GPIO_PIN_1
#define I2C_SDA_IOMUX IOMUX_PINCM2

void I2C_GPIO_Init(void)
{
    // 初始化数字输出引脚
    DL_GPIO_initDigitalOutput(I2C_SCL_IOMUX);
    DL_GPIO_initDigitalOutput(I2C_SDA_IOMUX);
    DL_GPIO_setPins(I2C_PORT, I2C_SCL_PIN|I2C_SDA_PIN); // 拉高I2C总线
    DL_GPIO_enableOutput(I2C_PORT, I2C_SCL_PIN|I2C_SDA_PIN); // 使能I2C总线输出
}

2.2.2 I2C初始化

2.2.2.1 相关参数宏定义
/* I2C模式配置 */
// 设置SDA输出模式
#define I2C_SDA_OUT() {DL_GPIO_initDigitalOutput(I2C_SDA_IOMUX); \
                       DL_GPIO_setPins(I2C_PORT, I2C_SDA_PIN); \
                       DL_GPIO_enableOutput(I2C_PORT, I2C_SDA_PIN);}
// 设置SDA输入模式
#define I2C_SDA_IN()  {DL_GPIO_initDigitalInput(I2C_SDA_IOMUX);}
// 获取SDA的电平,并判断高低电平
#define I2C_SDA_GET() (((DL_GPIO_readPins(I2C_PORT, I2C_SDA_PIN)&I2C_SDA_PIN)>0)?1:0)
// 设置SDA的电平
#define SDA(x) ((x)?(DL_GPIO_setPins(I2C_PORT, I2C_SDA_PIN)):(DL_GPIO_clearPins(I2C_PORT, I2C_SDA_PIN))) 
// 设置SCL的电平
#define SCL(x) ((x)?(DL_GPIO_setPins(I2C_PORT, I2C_SCL_PIN)):(DL_GPIO_clearPins(I2C_PORT, I2C_SCL_PIN))) 
2.2.2.2 I2C产生起始信号

起始信号:SCL在高电平的状态下,SDA的电平由高转低,表示开始一次通信。

void I2C_Start(void) // 产生I2C起始信号
{
    I2C_SDA_OUT();
    SCL(0);
    SDA(1);
    SCL(1);
    SDA(0);
    SCL(0);
}
2.2.2.3 I2C产生停止信号

SCL在高电平的状态下,SDA的电平由低转高,表示结束这次通信。主设备在发送停止信号后不能再向从设备发送任何数据,除非再次发送起始信号。

void I2C_Stop(void) // 产生I2C停止信号
{
    I2C_SDA_OUT();
    SCL(0);
    SDA(0);
    SCL(1);
    SDA(1);
}
2.2.2.4 I2C产生ACK/NACK

I2C还提供了一种称为“ACK/NACK”(应答/非应答)的确认机制。如果一个设备接收到数据,它将通过在SDA线上拉低电平来发送一个应答信号以通知发送方数据已被接收。相反,如果数据被损坏或未接收,接收设备将发送非应答信号。(在SDA上保持高电平)。

void I2C_Send_Ack(uint8_t ack) // 主机发送应答信号
{
    I2C_SDA_OUT();
    SCL(0);
    SDA(0);
    if(!ack)
    {
        SDA(0); // 应答为0,主机发送ACK
    }
    else
    {
        SDA(1); // 应答为1,主机发送NAK
    }
    SCL(1);
    SCL(0);
    SDA(1);
} 
2.2.2.5 等待从机应答
uint8_t I2C_Wait_Ack(void) // 等待从机应答
{
    uint8_t ack = 0;
    uint8_t flag = 10;
    I2C_SDA_IN();
    SDA(1);
    SCL(1);
    while((I2C_SDA_GET() == 1) && (flag)) // 等待从机应答
    {
        flag--;
    }
    if(flag <= 0)
    {
        I2C_Stop(); // 超时,产生停止信号
        return 1;
    }
    else
    {
        SCL(0);
        I2C_SDA_OUT();
    }
    return ack;
}
2.2.2.5 I2C读写一个字节
void I2C_Write_Byte(uint8_t data) // 主机向从机发送数据
{
    uint8_t i;
    I2C_SDA_OUT();
    SCL(0);
    for(i = 0; i < 8; i++)
    {
        SDA((data&0x80) >> 7); // 发送数据位
        SCL(1);
        SCL(0);
        data <<= 1; // 左移一位
    }
}

uint8_t I2C_Read_Byte(void) // 从机读取数据
{
    uint8_t i, read_data = 0;
    I2C_SDA_IN();
    for(i = 0; i < 8; i++)
    {
        SCL(0);
        SCL(1);
        read_data <<= 1; // 左移一位
        if(I2C_SDA_GET())
        {
            read_data|=1; // 读取数据位
        }
    }
    return read_data;
}

2.2.3 读取SHT20传感器数据

SHT20温湿度传感器的I2C地址为0x80。I2C地址是一个用于在总线上识别设备的7位地址。对于SHT20传感器,其地址的最高7位已经预设为固定值0b1000_000(0b代表二进制)。最低一位用于标识读操作或写操作,读操作为1,写操作为0。因此,SHT20的I2C地址在写操作时可以表示为0b1000_0000(0x80),读操作时表示为0b1000_0001(0x81)。

// SHT20 读取湿温度
// 函数参数regaddr:寄存器地址
// 0xf3测量温度,0xf5测量湿度
uint16_t SHT20_Read(uint8_t regaddr)
{
    uint16_t data_h = 0;
    uint16_t data_l = 0;
    uint16_t temp = 0;
    I2C_Start();
    I2C_Write_Byte(0x80|0);
    if (I2C_Wait_Ack() == 1)
    {
        printf("error -1\r\n");
    }
    I2C_Write_Byte(regaddr);
    if (I2C_Wait_Ack() == 1)
    {
         printf("error -2\r\n");
    }
    do {
        I2C_Start();
        I2C_Write_Byte(0x80 | 1);
    } while (I2C_Wait_Ack() == 1);
    data_h = I2C_Read_Byte();
    I2C_Send_Ack(0);
    data_l = I2C_Read_Byte();
    I2C_Send_Ack(1);
    I2C_Stop();
    if (regaddr == 0xf3)
    {
        temp = ((data_h << 8)|data_h) / 65536.0 * 175.72 - 46.85;
    }
    if (regaddr == 0xf5)
    {
        temp = ((data_h << 8)|data_l) / 65536.0 * 125.0 - 6;
    }
    return temp;
}

2.2.4 主函数测试

#include <ti_msp_dl_config.h>
#include "SysTick.h"
#include "Uart.h"
#include "SHT20.h"

#define T_ADDR 0xf3 // SHT20温度地址
#define PH_ADDR 0xf5 // SHT20湿度地址

int main(void)
{
    SYSCFG_DL_init();
    UART_0_init();
    I2C_GPIO_Init();
    SysTick_Init();
    NVIC_ClearPendingIRQ(UART_IRQN);
    NVIC_EnableIRQ(UART_IRQN);
    while (1)
    {
        uint32_t TEMP = SHT20_Read(T_ADDR) * 100;
        uint32_t PH = SHT20_Read(PH_ADDR) * 100;
        printf("Temperature: %d.%d C\n", TEMP / 100, TEMP % 100);
        printf("Humidity: %d.%d %%\n", PH / 100, PH % 100);
        delay_ms(1000);
    }
}

3. 小结

  1. I2C 引脚配置:选择正确的引脚并设置复用功能。
  2. 外设时钟配置:确保启用 I2C 外设的时钟。
  3. 配置 I2C 控制寄存器:设置 I2C 模式、波特率和时钟源。
  4. 数据传输:使用 TXBUF 发送数据,确保总线空闲时再发送。

本文作者:hazy1k

本文链接:https://www.cnblogs.com/hazy1k/p/18689837

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   hazy1k  阅读(17)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起