stm32模拟iic的主从机通信

两块stm32f407开发板进行模拟iic通信,想实现主机接收从机的数据,但现在主机可以发地址,但从机无法正常发送数据,目前已经成功了的是主机发送iic报文,从机可以正常进入中断实现判定,找不到从机无法发送数据的原因
主机配置代码

#include "myiic.h"
#include "delay.h"
#include "stm32f4xx_i2c.h"
#include "bsp_led.h"
#include "bsp_relay.h"


//初始化IIC
void IIC_Init(void)
{            
  GPIO_InitTypeDef  GPIO_InitStructure;
  I2C_InitTypeDef     I2C_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
    
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    

  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    IIC_SCL=1;
    IIC_SDA=1;
    
   GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1); 
   GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);

    
    I2C_DeInit(I2C1);
    I2C_InitStructure.I2C_Mode             = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle     = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1     = 0x03;     //从机地址,一定要设置正确
    I2C_InitStructure.I2C_Ack             = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed     = 100000;
    I2C_Init(I2C1, &I2C_InitStructure);
    
    NVIC_InitStructure.NVIC_IRQChannel                   = I2C1_EV_IRQn;//事件中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;//错误中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                 
  NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
    
  I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);   
  I2C_Cmd(I2C1, ENABLE);     
 
}


//产生IIC起始信号
void IIC_Start(void)
{
    SDA_OUT();     //sda线输出
    IIC_SDA=1;            
    IIC_SCL=1;
    delay_us(4);
     IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
    delay_us(4);
    IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}      
//产生IIC停止信号
void IIC_Stop(void)
{
    SDA_OUT();//sda线输出
    IIC_SCL=0;
    IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
     delay_us(4);
    IIC_SCL=1; 
    IIC_SDA=1;//发送I2C总线结束信号
    delay_us(4);                                   
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    SDA_IN();      //SDA设置为输入  
    IIC_SDA=1;delay_us(1);       
    IIC_SCL=1;delay_us(1);     
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL=0;//时钟输出0        
    return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=0;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}
//不产生ACK应答            
void IIC_NAck(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=1;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}                                          
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答              
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
      SDA_OUT();         
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;       
        delay_us(2);   //对TEA5767这三个延时都是必须的
        IIC_SCL=1;
        delay_us(2); 
        IIC_SCL=0;    
        delay_us(2);
    }     
}         
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL=0; 
        delay_us(2);
        IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
        delay_us(1); 
    }                     
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}

发送主函数

while(1){

            IIC_Start();//IIC开始信号
            IIC_Send_Byte(0x10);//发送从机地址,假设从机地址为0
            IIC_Wait_Ack();//等待应答
            IIC_Read_Byte(0);//给从机发送数据,从机收到数据后打开继电器和指示灯
            IIC_Stop();//IIC停止发送
                   delay_ms(1);

}


从机接收配置

#include "myiic.h"
#include "delay.h"
#include "stm32f4xx_i2c.h"
#include "led.h"
#include "bsp_relay.h"


/*---------IIC1---------------*/
uint8_t  Buffer_Rx_IIC1[40];//接收缓存
uint8_t  Rx_Idx_IIC1=0;//接收计数
uint8_t  Flag_RcvOK_IIC1 = 0;// 接收完成标志 
uint8_t  Tx_Idx_IIC1=0;//发送计数
u8 Response_Message[40];//发送缓存

u8 I2C1_ADDRESS;//7 位 I2C 地址
 


//初始化IIC
void IIC_Init(void)
{            
  GPIO_InitTypeDef  GPIO_InitStructure;
  I2C_InitTypeDef     I2C_InitStructure;
  NVIC_InitTypeDef NVIC_InitStructure;
    
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

    
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    

  GPIO_InitStructure.GPIO_Pin =GPIO_Pin_7 ;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//普通输出模式
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//上拉
  GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
    IIC_SCL=1;
    IIC_SDA=1;
    
   GPIO_PinAFConfig(GPIOB,GPIO_PinSource6,GPIO_AF_I2C1); 
   GPIO_PinAFConfig(GPIOB,GPIO_PinSource7,GPIO_AF_I2C1);

    
    I2C_DeInit(I2C1);
    I2C_InitStructure.I2C_Mode             = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle     = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1     = 0x10;     //从机地址,一定要设置正确
    I2C_InitStructure.I2C_Ack             = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed     = 100000;
    I2C_Init(I2C1, &I2C_InitStructure);
    
    NVIC_InitStructure.NVIC_IRQChannel                   = I2C1_EV_IRQn;//事件中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;//错误中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                 
  NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
    
  I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);   
  I2C_Cmd(I2C1, ENABLE);     
 
}


//产生IIC起始信号
void IIC_Start(void)
{
    SDA_OUT();     //sda线输出
    IIC_SDA=1;            
    IIC_SCL=1;
    delay_us(4);
     IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
    delay_us(4);
    IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}      
//产生IIC停止信号
void IIC_Stop(void)
{
    SDA_OUT();//sda线输出
    IIC_SCL=0;
    IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
     delay_us(4);
    IIC_SCL=1; 
    IIC_SDA=1;//发送I2C总线结束信号
    delay_us(4);                                   
}
//等待应答信号到来
//返回值:1,接收应答失败
//        0,接收应答成功
u8 IIC_Wait_Ack(void)
{
    u8 ucErrTime=0;
    SDA_IN();      //SDA设置为输入  
    IIC_SDA=1;delay_us(1);       
    IIC_SCL=1;delay_us(1);     
    while(READ_SDA)
    {
        ucErrTime++;
        if(ucErrTime>250)
        {
            IIC_Stop();
            return 1;
        }
    }
    IIC_SCL=0;//时钟输出0        
    return 0;  
} 
//产生ACK应答
void IIC_Ack(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=0;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}
//不产生ACK应答            
void IIC_NAck(void)
{
    IIC_SCL=0;
    SDA_OUT();
    IIC_SDA=1;
    delay_us(2);
    IIC_SCL=1;
    delay_us(2);
    IIC_SCL=0;
}                                          
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答              
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
      SDA_OUT();         
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;       
        delay_us(2);   //对TEA5767这三个延时都是必须的
        IIC_SCL=1;
        delay_us(2); 
        IIC_SCL=0;    
        delay_us(2);
    }     
}         
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK   
u8 IIC_Read_Byte(unsigned char ack)
{
    unsigned char i,receive=0;
    SDA_IN();//SDA设置为输入
    for(i=0;i<8;i++ )
    {
        IIC_SCL=0; 
        delay_us(2);
        IIC_SCL=1;
        receive<<=1;
        if(READ_SDA)receive++;   
        delay_us(1); 
    }                     
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack(); //发送ACK   
    return receive;
}



void I2C1_EV_IRQHandler(void)
{

  __IO uint32_t SR1Register =0;
  __IO uint32_t SR2Register =0;

  SR1Register = I2C1->SR1;
  SR2Register = I2C1->SR2;

    /* I2C1是从机(MSL = 0) */
  if((SR2Register &0x0001) != 0x0001)
  {
    /* 主机已发送地址,地址为被置位·(ADDR = 1: EV1(包括发送和接收)) */
    if((SR1Register & 0x0002) == 0x0002)
    {
        /* 清除标志位 */
        SR1Register = 0;
        SR2Register = 0;

        Rx_Idx_IIC1=0;
        Tx_Idx_IIC1=0;

        
    }



    /* 接收数据(RXNE = 1: EV2) */
    if((SR1Register & 0x0040) == 0x0040)
    {
            
        Buffer_Rx_IIC1[Rx_Idx_IIC1++] = I2C1->DR;
        SR1Register = 0;
        SR2Register = 0;
//      if(Buffer_Rx_IIC1[0] == 0x10)
//            {
//                GPIO_ResetBits(C1_PORT, C1_PIN);
//                GPIO_SetBits(L1_PORT, L1_PIN);
//            }


            

    }
    /* 检测到停止条件(STOPF =1: EV4) */
    if(( SR1Register & 0x0010) == 0x0010)
    {
        I2C1->CR1 |= 0x0001;
        SR1Register = 0;
        SR2Register = 0;
        Flag_RcvOK_IIC1 = 1;  
            


    }



    /* 发送数据(TxE = 1: EV3、EV3-1) */
    if((SR1Register & 0x0080) == 0x0080)
    {
        I2C1->DR = Buffer_Rx_IIC1[0]; 
        SR1Register = 0;
        SR2Register = 0;
   I2C_SendData(I2C1,0x10);
            
            
    }
    /* 检测到非应答(AF =1: EV3-2) */
    if(( SR1Register & 0x0400) == 0x0400)
    {
        I2C1->SR1 &= 0xFDFF;
        SR1Register = 0;
        SR2Register = 0;        
    }       
  }
}    


    void I2C1_ER_IRQHandler(void)
{

  __IO uint32_t SR1Register =0;
  __IO uint32_t SR2Register =0;
  SR1Register = I2C1->SR1;
  SR2Register = I2C1->SR2;

    if(I2C_GetITStatus(I2C1,I2C_IT_SMBALERT)) {
    }
    else if(I2C_GetITStatus(I2C1, I2C_IT_TIMEOUT)) {
    } 
    else if(I2C_GetITStatus(I2C1, I2C_IT_PECERR)) {
    } 
    else if(I2C_GetITStatus(I2C1, I2C_IT_OVR)) {

    }
    else if(I2C_GetITStatus(I2C1, I2C_IT_AF)) {

        I2C_ClearITPendingBit(I2C1, I2C_IT_AF);
    }
    else if(I2C_GetITStatus(I2C1, I2C_IT_ARLO)) {

    }
    else if(I2C_GetITStatus(I2C1, I2C_IT_BERR)) {

    }
        I2C1->CR1 |= 0x0001;
        SR1Register = 0;
        SR2Register = 0;    
}

void control(void)
    {
            if(Buffer_Rx_IIC1[0] == 0x01)
                {
                    ch1_ON;
                  GPIO_ResetBits(C1_PORT, C1_PIN);
                    GPIO_SetBits(L1_PORT, L1_PIN);
              IIC_Send_Byte(0x10);
                    
                }            
    }
    
void check_address(void)
    {
        delay_ms(300);
    if(relay_A0_READ == 1 || relay_A1_READ == 0) // " 0 1 "
            {
                if(relay_A2_READ == 0 || relay_A3_READ == 0)
                {
                        I2C1_ADDRESS = 0X01;
                }
                else if(relay_A2_READ == 1 || relay_A3_READ == 0)
                {
                        I2C1_ADDRESS = 0X05;
                }
                else if(relay_A2_READ == 0 || relay_A3_READ == 1)
                {
                        I2C1_ADDRESS = 0X09;
                }
            }
               if(relay_A0_READ == 0 || relay_A1_READ == 1) // " 1 0 "
            {
                if(relay_A2_READ == 0 || relay_A3_READ == 0)
                {
                        I2C1_ADDRESS = 0X02;
                }
                else if(relay_A2_READ == 1 || relay_A3_READ == 0)
                {
                        I2C1_ADDRESS = 0X06;
                }
                else if(relay_A2_READ == 0 || relay_A3_READ == 1)
                {
                        I2C1_ADDRESS = 0X0A;
                }
            }
               if(relay_A0_READ == 1 || relay_A1_READ == 1) // " 0 0 "
            {
                if(relay_A2_READ == 0 || relay_A3_READ == 0)
                {
                        I2C1_ADDRESS = 0X03;
                }
                else if(relay_A2_READ == 1 || relay_A3_READ == 0)
                {
                        I2C1_ADDRESS = 0X07;
                }
                else if(relay_A2_READ == 0 || relay_A3_READ == 1)
                {
                        I2C1_ADDRESS = 0X0B;
                }
            }
            
               if(relay_A0_READ == 0 || relay_A1_READ == 0) // " 1 1 "
            {
                if(relay_A2_READ == 1 || relay_A3_READ == 0)
                {
                        I2C1_ADDRESS = 0X04;
                }
                else if(relay_A2_READ == 0 || relay_A3_READ == 1)
                {
                        I2C1_ADDRESS = 0X08;
                }
                else if(relay_A2_READ == 1 || relay_A3_READ == 1)
                {
                        I2C1_ADDRESS = 0X0C;
                }
            }
        
                
    }
    
    

这是目前在示波器上显示的主机接收从机数据的时序图

img


这里我发现主机正常发地址,从机也能正常进中断,但之后的一字节数据iic的SDA就锁死高电平,怎么都调不了

程序很奇怪呢,既然是IO模拟,为什么又启用了硬件I2C?是不是模拟的时序和硬件的时序产生了冲突

搞个逻辑分析仪来进行调试吧,示波器深度不够,不太好调,从机IIC确实得使用中断,会使用HAL库么,这里有篇博客写得还不错,你可以按照这个方式先跑一跑,看一下波形正不正常。若是跑得通,回头一步步调试自己的工程,可能是你主机模拟的时序不是很好,具体你要结合你的通信波形进行分析。
https://blog.csdn.net/qq_36561846/article/details/117474070

接收

/*接收应答信号,若接收到非应答信号,则发送停止信号(SDA低电平表示应答,高电平表示非应答)*/
unsigned char IIC_Soft::IIC_ReceiveACK()
{
    unsigned char state;
    IIC_DataDir(DIRECTION_IN);    //SDA为输入模式
    
    SET_SDA;                                        //释放SDA
    SET_SCL;
    state = READ_SDA;
    RESET_SCL;
    if(state)                                        //若接收到非应答信号,发送停止信号
    {
        IIC_Stop();
    }
    return state;
}