STM32是一款广泛应用于嵌入式系统的微控制器。I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,用于连接微控制器和外设。在本文中,我将为您提供一个详细的代码案例,帮助您学习STM32的I2C总线通信。
首先,我们需要准备的材料和环境:
- STM32开发板(例如STM32F4 Discovery)
- I2C外设(例如一个I2C温度传感器)
- Keil MDK开发工具
接下来,我们将按照以下步骤进行开发:
第一步:创建新的工程
- 打开Keil MDK,选择“Project” -> “New Project”。
- 在弹出的对话框中,选择您的STM32型号(例如 STM32F407VG)。
- 输入项目名称和保存路径,点击“Save”按钮。
- 在“Manage Project Items”对话框中,选择“Device”选项卡,然后双击“Startup”文件夹下的“STM32F4xx_StdPeriph_Startup.s”文件。
第二步:配置I2C外设
- 打开“stm32f4xx_conf.h”文件,在包含的库文件部分添加下面这行代码:
#include "stm32f4xx_i2c.h"
- 在“stm32f4xx_conf.h”文件中,找到以下定义,并取消注释:
#define USE_I2C2
- 打开“main.c”文件。
- 在“main.c”文件的开头添加以下代码:
#include "stm32f4xx.h"
#include "stm32f4xx_i2c.h"
- 在“main.c”文件中的“main()”函数中,添加以下代码:
// 初始化I2C外设
I2C_InitTypeDef I2C_InitStruct;
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE); // 使能I2C2总线时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // 使能GPIOB时钟
// 配置SCL和SDA引脚
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
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);
// 将引脚设置为I2C功能
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_I2C2);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_I2C2);
// 配置I2C外设
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 = 0x00; // 设置主机地址
I2C_InitStruct.I2C_Ack = I2C_Ack_Disable;
I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C2, &I2C_InitStruct);
// 使能I2C外设
I2C_Cmd(I2C2, ENABLE);
第三步:编写I2C读写函数
- 在“main.c”文件的开头添加以下代码:
#include <stdio.h>
- 在“main.c”文件中的“main()”函数之前,添加以下函数定义:
// I2C写函数
void I2C_Write(uint8_t deviceAddr, uint8_t regAddr, uint8_t data) {
// 等待I2C空闲
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
// 生成起始信号
I2C_GenerateSTART(I2C2, ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
// 发送设备地址和写模式
I2C_Send7bitAddress(I2C2, deviceAddr, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// 发送寄存器地址
I2C_SendData(I2C2, regAddr);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 发送数据
I2C_SendData(I2C2, data);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 发送停止信号
I2C_GenerateSTOP(I2C2, ENABLE);
}
// I2C读函数
uint8_t I2C_Read(uint8_t deviceAddr, uint8_t regAddr) {
uint8_t data;
// 等待I2C空闲
while(I2C_GetFlagStatus(I2C2, I2C_FLAG_BUSY));
// 生成起始信号
I2C_GenerateSTART(I2C2, ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
// 发送设备地址和写模式
I2C_Send7bitAddress(I2C2, deviceAddr, I2C_Direction_Transmitter);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
// 发送寄存器地址
I2C_SendData(I2C2, regAddr);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_TRANSMITTED));
// 重新生成起始信号
I2C_GenerateSTART(I2C2, ENABLE);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_MODE_SELECT));
// 发送设备地址和读模式
I2C_Send7bitAddress(I2C2, deviceAddr, I2C_Direction_Receiver);
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED));
// 禁用ACK
I2C_AcknowledgeConfig(I2C2, DISABLE);
// 读取数据
while(!I2C_CheckEvent(I2C2, I2C_EVENT_MASTER_BYTE_RECEIVED));
data = I2C_ReceiveData(I2C2);
// 发送停止信号
I2C_GenerateSTOP(I2C2, ENABLE);
return data;
}
第四步:测试I2C通信
- 在“main.c”文件的“main()”函数中,添加以下代码:
// 向I2C设备写入一个字节的数据
I2C_Write(0xA0, 0x00, 0x01);
// 从I2C设备读取一个字节的数据
uint8_t data = I2C_Read(0xA0, 0x00);
// 打印读取到的数据
printf("Read data: %d\n", data);
第五步:编译和下载
- 点击Keil MDK的“Project” -> “Rebuild all”。编译完成后,会生成一个名为“project_name.hex”的可执行文件。
- 将STM32开发板连接到计算机上,并使用ST-Link或类似的工具将可执行文件下载到开发板中。
至此,我们已经完成了一个简单的STM32的I2C总线通信的代码案例。您可以根据您的需求和硬件外设做相应的修改和扩展。希望这个案例能够帮助您更好地理解STM32的I2C总线通信。