单片机中的I2C通信编程实战

紫色星空下的梦 2023-08-30 ⋅ 14 阅读

引言

I2C(Inter-Integrated Circuit)是一种常用于连接微控制器和外设的串行通信协议。在单片机的开发过程中,掌握I2C通信编程技巧是非常重要的。本文将以一个具体的示例来介绍如何使用I2C通信协议在单片机中进行数据传输。

示例介绍

我们将使用STM32F4系列微控制器,并且通过I2C总线与一个温湿度传感器(例如DHT11)进行通信。我们的目标是读取传感器测量到的温度和湿度值,并将其显示在LCD屏幕上。

I2C通信配置

首先,我们需要对单片机的I2C通信进行配置。以下是一些常用的配置参数:

  • 发送和接收字节的速度:可以通过设置I2C频率来控制。
  • I2C总线地址:每个设备都有一个唯一的地址,用于在总线上识别设备。
  • 发送和接收字节的字长:可以设置为8位或16位。
  • I2C时钟频率:可以通过设置I2C_CR2寄存器中的CLK频率字段来控制。

I2C通信流程

下面是使用I2C通信进行数据传输的基本流程:

  1. 初始化I2C总线和配置参数。
  2. 发送启动信号(START)到总线上。
  3. 发送设备地址和读/写模式。
  4. 如果是写操作,发送数据到设备。
  5. 如果是读操作,接收设备发送的数据。
  6. 发送停止信号(STOP)到总线上。

示例代码

以下是一个示例代码,展示了如何使用I2C通信从DHT11传感器读取温度和湿度值,并显示在LCD屏幕上。

#include <stdio.h>
#include <stm32f4xx.h>

// 定义I2C总线地址和设备地址
#define I2C_ADDRESS 0x27
#define DHT11_ADDRESS 0x5C

// 初始化I2C总线
void I2C_Init() {
  // 配置GPIO引脚作为I2C功能
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_Init(GPIOB, &GPIO_InitStruct);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_I2C1);
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_I2C1);

  // 配置I2C参数
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
  I2C_InitTypeDef I2C_InitStruct;
  I2C_InitStruct.I2C_ClockSpeed = 100000; // 设置I2C速度为100kHz
  I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStruct.I2C_OwnAddress1 = I2C_ADDRESS;
  I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_Init(I2C1, &I2C_InitStruct);

  I2C_Cmd(I2C1, ENABLE);
}

// 从DHT11读取温度和湿度值
void DHT11_ReadData(uint8_t* temperature, uint8_t* humidity) {
  // 发送启动信号
  I2C_GenerateSTART(I2C1, ENABLE);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}

  // 发送设备地址和读模式
  I2C_Send7bitAddress(I2C1, DHT11_ADDRESS, I2C_Direction_Transmitter);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) {}

  // 发送数据
  I2C_SendData(I2C1, 0x00);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) {}

  // 发送停止信号
  I2C_GenerateSTOP(I2C1, ENABLE);
  
  // 延时一段时间

  // 发送启动信号
  I2C_GenerateSTART(I2C1, ENABLE);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) {}

  // 发送设备地址和读模式
  I2C_Send7bitAddress(I2C1, DHT11_ADDRESS, I2C_Direction_Receiver);
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {}

  // 接收数据
  while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) {
    *temperature = I2C_ReceiveData(I2C1);
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) {}
    *humidity = I2C_ReceiveData(I2C1);
  }

  // 发送停止信号
  I2C_GenerateSTOP(I2C1, ENABLE);
}

int main() {
  // 初始化LCD屏幕
  LCD_Init();
  LCD_Clear();

  // 初始化I2C总线
  I2C_Init();

  uint8_t temperature, humidity;
  while (1) {
    // 从DHT11传感器读取温度和湿度值
    DHT11_ReadData(&temperature, &humidity);

    // 在LCD屏幕上显示温度和湿度值
    char temp_text[16];
    char hum_text[16];
    sprintf(temp_text, "Temp: %dC", temperature);
    sprintf(hum_text, "Humidity: %d%%", humidity);
    LCD_SetCursorPosition(0, 0);
    LCD_WriteString(temp_text);
    LCD_SetCursorPosition(1, 0);
    LCD_WriteString(hum_text);

    // 延时一段时间
    Delay(1000);
  }
}

总结

通过这个示例,我们展示了如何使用I2C通信协议在单片机中进行数据传输。通过逐步配置I2C总线和实现通信流程,我们可以与外部设备进行数据交换,并将其显示在LCD屏幕上。希望这个示例能够帮助你更好地理解和应用I2C通信。


全部评论: 0

    我有话说: