STM32F103CB I2C硬件从机(多主模式下先收后发)
多主模式下作为从机中断先接收数据,然后作为主机再发送数据,代码配置如下:
1.硬件I2C及中断配置
void I2C1_Slave_Init(void)
{
sysBoardIdRead(&sysSalve.boardAddress);
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
NVIC_InitTypeDef NVIC_InitStructure; // NVIC初始化结构体
I2C_InitTypeDef I2C_InitStructure; // I2C初始化结构体
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 使能I2C1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // 使能GPIOB时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 使能AFIO时钟
/* I2C配置: SCL and SDA */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // 配置GPIOB的6和7引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置GPIO速度为50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 设置GPIO模式为复用开漏输出
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化GPIOB
/* 配置I2C事件中断 */
NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn; // 配置I2C1事件中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 设置抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 设置子优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化NVIC
/* 配置I2C错误中断以具有更高的优先级 */
NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn; // 配置I2C1错误中断通道
NVIC_Init(&NVIC_InitStructure); // 初始化NVIC
/* I2C配置 */
I2C_InitStructure.I2C_Mode = I2C_Mode_SMBusHost; // 设置I2C模式为I2C I2C_Mode_I2C
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; // 设置I2C占空比为2
I2C_InitStructure.I2C_OwnAddress1 = sysSalve.boardAddress; // 设置I2C从机地址
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; // 使能I2C应答
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; // 设置I2C应答地址为7位
I2C_InitStructure.I2C_ClockSpeed = I2C1_CLOCK_FRQ; // 设置I2C时钟速度
/* 使能I2C外围设备 */
I2C_Cmd(I2C1, ENABLE); // 使能I2C1外设
I2C_Init(I2C1, &I2C_InitStructure); // 应用I2C配置
I2C_ITConfig(I2C1, I2C_IT_EVT, ENABLE); // 使能I2C1事件中断
I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE); // 使能I2C1缓冲中断
I2C_ITConfig(I2C1, I2C_IT_ERR, ENABLE); // 使能I2C1错误中断
I2C1_Ram_Init(); // 初始化I2C1 RAM
}
2.中断接收数据配置
/*******************************************************************************
* 函数名 : I2C1_ClearFlag
* 描述 : 清除地址标志和停止标志
* 输入 : 无
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void I2C1_ClearFlag(void)
{
/* 清除地址标志 */
while((I2C1->SR1 & I2C_SR1_ADDR) == I2C_SR1_ADDR)
{
I2C1->SR1; // 读取SR1寄存器
I2C1->SR2; // 读取SR2寄存器
}
/* 清除停止标志 */
while((I2C1->SR1&I2C_SR1_STOPF) == I2C_SR1_STOPF)
{
I2C1->SR1; // 读取SR1寄存器
I2C1->CR1 |= 0x1; // 清除STOPF标志
}
}
/*******************************************************************************
* 函数名 : I2C1_EV_IRQHandler
* 描述 : I2C1 事件中断触发请求.中断接收数据
* 输入 : 无
* 输出 : 无
* 返回 : 无
*******************************************************************************/
void I2C1_EV_IRQHandler(void)
{
uint32_t event;
event = I2C_GetLastEvent(I2C1); // 读取I2C1的最后事件
if(event == I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED)
{
i2c1_mode = I2C1_MODE_SLAVE_ADR_WR;// 主机已发送从机地址以向从机发送数据
}
if(event == I2C_EVENT_SLAVE_BYTE_RECEIVED)
{
i2c_buffer_data[frameLength++] = I2C_ReceiveData(I2C1);//存储数据
}
if(event == I2C_EVENT_SLAVE_STOP_DETECTED)
{
// 主机已发送STOP
I2C1_ClearFlag();
i2c1_mode = I2C1_MODE_WAITING;
memcpy(rx_i2c_buffer_data,i2c_buffer_data,frameLength);
rxCompleteFlag = 1;
rx_i2c_data_test();
frameLength = 0;//重置索引
}
// 清除所有相关的中断标志
I2C_ClearITPendingBit(I2C1, I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR);
}
void I2C1_ER_IRQHandler(void)
{
if (I2C_GetITStatus(I2C1, I2C_IT_AF))
{
I2C_ClearITPendingBit(I2C1, I2C_IT_AF); // 清除应答失败中断标志
}
}
3.发送数据配置
uint32_t i2c_master_send_buffer_data(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite)
{
I2CTimeout = I2CT_LONG_TIMEOUT;
//判断IIC总线是否忙碌
while(I2C_GetFlagStatus(I2C_PORT, I2C_FLAG_BUSY))
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
}
//重新赋值
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送起始信号
I2C_GenerateSTART(I2C_PORT,ENABLE);
while( I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_MODE_SELECT)==ERROR)//检测EV5
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(2);
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
//发送设备写地址
I2C_Send7bitAddress(I2C_PORT,addr,I2C_Direction_Transmitter);
//检测EV6事件
while( I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(3);
}
while(Num_ByteToWrite)
{
I2C_SendData(I2C_PORT,*data);
I2CTimeout = I2CT_FLAG_TIMEOUT;
while( I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTING)==ERROR)
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(5);
}
Num_ByteToWrite--;
data++;
}
I2CTimeout = I2CT_FLAG_TIMEOUT;
while( I2C_CheckEvent(I2C_PORT,I2C_EVENT_MASTER_BYTE_TRANSMITTED )==ERROR)//检测EV8_2
{
if((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(6);
}
//发送停止信号
I2C_GenerateSTOP(I2C_PORT,ENABLE);
return 1;
}
static uint32_t I2C_TIMEOUT_UserCallback(uint8_t errorCode)
{
/* 阻止通信和所有进程 */
EEPROM_ERROR("I2C waitOutTime!errorCode = %d",errorCode);
I2C1_Slave_Init();
return 0;
}
4…h文件配置如下:
/* 定义防止递归包含 ----------------------------------------------------------*/
#ifndef _I2C_H
#define _I2C_H
/* 包含的头文件 --------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_i2c.h"
#include "misc.h"
/* 宏定义 --------------------------------------------------------------------*/
#define OWN_ADDRESS 0x20 //设备自身地址,主机地址
#define I2C_RETRY_COUNT 10 // 定义重试次数
#define I2C_TX_TIMEOUT 1000 // 发送超时时间,单位毫秒
#define I2C_PORT I2C1 // IIC端口
#define I2CSLAVE_ADDR 0x86 // 从机地址
#define I2C1_CLOCK_FRQ 400000 // I2C传输速率(400 kHz)
#define I2C1_RAM_SIZE 256 // RAM大小
#define I2C1_MODE_WAITING 0 // 等待命令
#define I2C1_MODE_SLAVE_ADR_WR 1 // 收到从机地址(写入)
#define I2C1_MODE_ADR_BYTE 2 // 接收到ADR字节
#define I2C1_MODE_DATA_BYTE_WR 3 // 数据字节(写入)
#define I2C1_MODE_SLAVE_ADR_RD 4 // 已接收从机地址(待读取)
#define I2C1_MODE_DATA_BYTE_RD 5 // 数据字节(待读取)
//等待次数20240820
#define I2CT_FLAG_TIMEOUT ((uint32_t)0x1000)
#define I2CT_LONG_TIMEOUT ((uint32_t)(10 * I2CT_FLAG_TIMEOUT))
void I2C1_Slave_Init(void);
/* 函数申明 ------------------------------------------------------------------*/
void I2C1_Init_Config(void);
uint32_t i2c_master_send_buffer_data(uint8_t addr,uint8_t *data,uint16_t Num_ByteToWrite);
void I2C1_ClearFlag(void);
void Set_I2C1_Ram(uint8_t adr, uint8_t val);
uint8_t Get_I2C1_Ram(uint8_t adr);
void I2C1_Ram_Init(void);
void I2C1_ClearFlag(void);
void slave_rx_data(void);
#endif /* _I2C_H */
5.源码链接:STM32F103CB I2C通信源码