第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 编程大纲

  1. I2C相关参数宏定义

  2. I2C GPIO初始化

  3. I2C协议

  4. SHT20读取数据

  5. 主函数测试

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);
	}
}

posted @ 2025-04-28 22:00  hazy1k  阅读(41)  评论(0)    收藏  举报