第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 编程大纲
-
I2C接口GPIO配置
-
I2C模式配置,编写基础函数
-
通过I2C读取SHT20传感器数据
-
主函数测试
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. 小结
- I2C 引脚配置:选择正确的引脚并设置复用功能。
- 外设时钟配置:确保启用 I2C 外设的时钟。
- 配置 I2C 控制寄存器:设置 I2C 模式、波特率和时钟源。
- 数据传输:使用
TXBUF
发送数据,确保总线空闲时再发送。
本文作者:hazy1k
本文链接:https://www.cnblogs.com/hazy1k/p/18689837
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步