STM32F103CB I2C硬件从机(多主模式下先收后发,亲测可用)

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通信源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

九点两刻

你的支持是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值