第11章 I2C协议
第十一章 I2C协议
1. I2C协议介绍
IIC(Inter-Integrated Circuit)协议也称为I2C总线,是一种串行通信协议,通常用于连接低速外设。它由Philips(现在的NXP Semiconductors)公司于1980年代初开发,现在已经成为一个标准。IIC总线只需要两条数据线,分别是串行数据线(SDA)和串行时钟线(SCL),这使得它成为一种非常简单的接口。它适用基于芯片的通信,例如连接传感器、存储器或数字信号处理器等。
在IIC协议中,总线上有一个主设备和多个从设备。主设备掌控着总线上的通信过程,负责发起、控制、停止通信。而从设备则需要等待主设备的请求,接收或发送数据。主设备和从设备之间的数据交换采用帧格式,每个帧通常包含地址、数据和控制信息。主设备根据从设备的地址来选中要通信的设备,从设备则根据控制信息进行相应的操作。IIC协议可以支持多个从设备连接到同一个主设备,为系统设计提供了更大的灵活性。
MSPM0L系列的I2C支持主从模式,有7位地址位可以设置,支持 100kbps、400kbps、1Mbps 的 I2C 标准传输速率,并支持 SMBUS。 无论是主机或者从机,发送和接收都有独立的8个字节FIFO。MSPM0 I2C 具有 8 字节 FIFO,对于控制器和目标模式会生成独立的中断,并支持 DMA。
2. SHT20介绍
SHT20是一种数字式温湿度传感器,它采用电容式测量技术,具有高准确度和稳定性,并采用标准的I2C数字接口进行通信。SHT20的测量范围涵盖了温度-40到+125°C和相对湿度0到100%RH。它广泛应用于空气质量监测、气象监测、恒温恒湿控制、食品贮藏等领域。
SHT20温湿度传感器的相关参数,见下图:
3. 软件设计
3.1 编程大纲
-
I2C相关参数宏定义
-
I2C GPIO初始化
-
I2C协议
-
SHT20读取数据
-
主函数测试
3.2 代码分析
3.2.1 I2C宏定义
// 设置SDA输出模式
#define 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 SDA_IN() { DL_GPIO_initDigitalInput(I2C_SDA_IOMUX); }
// 读取SDA电平
#define SDA_GET() (((DL_GPIO_readPins(I2C_PORT,I2C_SDA_PIN) & I2C_SDA_PIN) > 0) ? 1 : 0)
// SDA与SCL电平控制
#define SDA(x) ((x) ? (DL_GPIO_setPins(I2C_PORT,I2C_SDA_PIN)) : (DL_GPIO_clearPins(I2C_PORT,I2C_SDA_PIN)))
#define SCL(x) ((x) ? (DL_GPIO_setPins(I2C_PORT,I2C_SCL_PIN)) : (DL_GPIO_clearPins(I2C_PORT,I2C_SCL_PIN)))
3.2.2 I2C GPIO初始化
void I2C_GPIO_Init(void)
{
DL_GPIO_initDigitalOutput(I2C_SCL_IOMUX);
DL_GPIO_initDigitalOutput(I2C_SDA_IOMUX);
DL_GPIO_setPins(GPIOA, I2C_SCL_PIN|I2C_SDA_PIN);
DL_GPIO_enableOutput(GPIOA, I2C_SCL_PIN|I2C_SDA_PIN);
}
3.2.3 I2C协议
void IIC_Start(void)
{
SDA_OUT();
SCL(0);
SDA(1);
SCL(1);
SDA(0);
SCL(0);
}
void IIC_Stop(void)
{
SDA_OUT();
SCL(0);
SDA(0);
SCL(1);
SDA(1);
}
void IIC_Send_Ack(uint8_t ack)
{
SDA_OUT();
SCL(0);
SDA(0);
if(!ack) SDA(0);
else SDA(1);
SCL(1);
SCL(0);
SDA(1);
}
uint8_t IIC_Wait_Ack(void)
{
char ack = 0;
unsigned char ack_flag = 10;
SDA_IN();
SDA(1);
SCL(1);
while((SDA_GET()==1) && (ack_flag))
{
ack_flag--;
}
if(ack_flag <= 0)
{
IIC_Stop();
return 1;
}
else
{
SCL(0);
SDA_OUT();
}
return ack;
}
void IIC_Write(uint8_t data)
{
int i = 0;
SDA_OUT();
SCL(0);
for(i = 0; i < 8; i++)
{
SDA( (data & 0x80) >> 7);
data<<=1;
SCL(1);
SCL(0);
}
}
uint8_t IIC_Read(void)
{
unsigned char i,receive = 0;
SDA_IN();
for(i=0;i<8;i++ )
{
SCL(0);
SCL(1);
receive<<=1;
if( SDA_GET() )
{
receive|=1;
}
}
return receive;
}
3.2.4 SHT20读取数据
float SHT20_Read(uint8_t regaddr)
{
unsigned char data_H = 0;
unsigned char data_L = 0;
float temp = 0;
IIC_Start();
IIC_Write(0x80|0);
if( IIC_Wait_Ack() == 1 ) printf("error -1\r\n");
IIC_Write(regaddr);
if( IIC_Wait_Ack() == 1 ) printf("error -2\r\n");
do{
IIC_Start();
IIC_Write(0x80|1);
}while( IIC_Wait_Ack() == 1 );
data_H = IIC_Read();
IIC_Send_Ack(0);
data_L = IIC_Read();
IIC_Send_Ack(1);
IIC_Stop();
if( regaddr == 0xf3 )
{
temp = ((data_H<<8)|data_L) / 65536.0 * 175.72 - 46.85;
}
if( regaddr == 0xf5 )
{
temp = ((data_H<<8)|data_L) / 65536.0 * 125.0 - 6;
}
return temp;
}
3.2.5 主函数测试
#include "ti_msp_dl_config.h"
#include <stdio.h>
#include "LED.h"
#include "SYSTICK.h"
#include "UART.h"
#include "SHT20.h"
#define T_ADDR 0xf3 // 温度
#define PH_ADDR 0xf5 // 湿度
int main(void)
{
SYSCFG_DL_init();
LED_Init();
SysTick_init();
SYSCFG_DL_UART_0_init();
I2C_GPIO_Init();
NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN);
NVIC_EnableIRQ(UART_0_INST_INT_IRQN);
printf("SHT20 Start\r\n");
while (1)
{
uint32_t TEMP = SHT20_Read(T_ADDR) * 100;
uint32_t PH = SHT20_Read(PH_ADDR) * 100;
printf("温度 = %d.%02d °c\r\n", TEMP/100,TEMP%100);
printf("湿度 = %d.%02d %%RH\r\n", PH/100,PH%100);
printf("\n");
delay_ms(1000);
}
}