I2C (Inter-Integrated Circuit) 是一种串行通信协议,常用于连接微控制器和外部设备。在本教程中,我们将介绍如何在STM32微控制器上使用I2C协议进行通信。
在开始之前,我们需要确保我们的开发环境已经设置好了。我们需要安装STM32CubeMX和Keil MDK开发工具,并配置好STM32微控制器的项目。
在本教程中,我们将使用STM32F407微控制器作为示例来演示I2C通信。首先,让我们开始配置I2C控制器。
- 打开STM32CubeMX并创建一个新的项目。
- 选择我们的微控制器型号 "STM32F407VG"。
- 在 "Pinout & Configuration" 标签页中,选择合适的引脚来连接I2C总线上的SDA和SCL线。这些引脚的选择取决于你的硬件连接。在本教程中,我们将使用PB6引脚作为SDA线,PB7引脚作为SCL线。
- 在 "Configuration" 标签页中,找到 "I2C1" 配置项,并启用它。
- 在 "Mode" 选项中选择 "I2C"。
- 配置 "I2C Speed" 为适当的速度。常见的速度有100kHz、400kHz等。在本教程中,我们将选择100kHz。
- 配置合适的 "I2C Own Address",这是我们的微控制器的地址。
- 确认配置并生成代码。
一旦代码生成完毕,我们就可以开始编写我们的I2C通信代码。
在Keil MDK中打开生成的项目,我们将需要在主函数中添加以下代码来初始化和使用I2C控制器。
首先,我们需要包含相关的头文件。
#include "stm32f4xx.h"
接下来,我们将定义一些宏来配置I2C控制器。
#define I2C_SPEED 100000 // I2C通信速度为100kHz
#define I2C_OWN_ADDRESS 0x50 // I2C通信的从机地址
然后,我们将定义一个函数来初始化I2C控制器。
void I2C_Init(void)
{
// 使能I2C1时钟和复位I2C1控制器
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
RCC->APB1RSTR |= RCC_APB1RSTR_I2C1RST;
RCC->APB1RSTR &= ~RCC_APB1RSTR_I2C1RST;
// 配置GPIOB引脚用作I2C1总线
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER &= ~(GPIO_MODER_MODE6 | GPIO_MODER_MODE7);
GPIOB->MODER |= (GPIO_MODER_MODE6_1 | GPIO_MODER_MODE7_1);
GPIOB->OTYPER |= (GPIO_OTYPER_OT6 | GPIO_OTYPER_OT7);
GPIOB->OSPEEDR |= (GPIO_OSPEEDR_OSPEED6 | GPIO_OSPEEDR_OSPEED7);
GPIOB->PUPDR &= ~(GPIO_PUPDR_PUPD6 | GPIO_PUPDR_PUPD7);
GPIOB->PUPDR |= (GPIO_PUPDR_PUPD6_0 | GPIO_PUPDR_PUPD7_0);
GPIOB->AFR[0] |= (4 << GPIO_AFRL_AFRL6_Pos) | (4 << GPIO_AFRL_AFRL7_Pos);
// 配置I2C1控制器
I2C1->CR1 = 0;
I2C1->CR2 = (42 << I2C_CR2_FREQ_Pos);
I2C1->CCR = (I2C_SPEED <= 100000) ? 0x50 : (I2C_SPEED <= 400000) ? 0x14 : 0x0D;
I2C1->TRISE = (I2C_SPEED <= 100000) ? 0x13 : (I2C_SPEED <= 400000) ? 0x02 : 0x00;
I2C1->OAR1 = (I2C_OWN_ADDRESS << I2C_OAR1_ADD1_Pos) | I2C_OAR1_OA1EN;
I2C1->CR1 |= I2C_CR1_PE;
}
接下来,我们将定义一些函数来发送和接收I2C数据。
void I2C_WriteData(uint8_t address, uint8_t *data, uint8_t length)
{
// 等待I2C总线空闲
while ((I2C1->SR2 & I2C_SR2_BUSY) != 0);
// 发送START信号
I2C1->CR1 |= I2C_CR1_START;
while ((I2C1->SR1 & I2C_SR1_SB) == 0);
// 发送从机地址和写操作
I2C1->DR = (address << 1) & ~I2C_OAR1_ADD1;
while ((I2C1->SR1 & I2C_SR1_ADDR) == 0);
(void)I2C1->SR2;
// 发送数据
for (uint8_t i = 0; i < length; i++)
{
I2C1->DR = data[i];
while ((I2C1->SR1 & I2C_SR1_TXE) == 0);
}
// 发送STOP信号
I2C1->CR1 |= I2C_CR1_STOP;
}
void I2C_ReadData(uint8_t address, uint8_t *data, uint8_t length)
{
// 等待I2C总线空闲
while ((I2C1->SR2 & I2C_SR2_BUSY) != 0);
// 发送START信号
I2C1->CR1 |= I2C_CR1_START;
while ((I2C1->SR1 & I2C_SR1_SB) == 0);
// 发送从机地址和读操作
I2C1->DR = (address << 1) | I2C_OAR1_ADD1;
while ((I2C1->SR1 & I2C_SR1_ADDR) == 0);
(void)I2C1->SR2;
// 读取数据
for (uint8_t i = 0; i < length; i++)
{
while ((I2C1->SR1 & I2C_SR1_RXNE) == 0);
data[i] = I2C1->DR;
}
// 发送STOP信号
I2C1->CR1 |= I2C_CR1_STOP;
}
现在我们可以在主函数中使用上述的I2C函数来进行数据收发。
int main(void)
{
// 初始化I2C控制器
I2C_Init();
// 发送数据示例
uint8_t dataToSend[] = {0xA5, 0x5A, 0xAA};
I2C_WriteData(0x55, dataToSend, sizeof(dataToSend));
// 接收数据示例
uint8_t dataToReceive[3];
I2C_ReadData(0x55, dataToReceive, sizeof(dataToReceive));
while (1)
{
// 主循环
}
}
这样,我们就完成了STM32微控制器上使用I2C协议进行通信的入门教程。希望对你有所帮助!