IIC主从机通信问题

2019-07-20 12:08发布

目前手里有个项目,需要用到IIC通信;
主机用STM32模拟iic,从机用STM8硬件IIC。
现在的问题是主机可以与从机通信,也能讲数据读回来,但是有一点:
收到的第一个字节总是0XFF,然后才是我需要的数据;
但是收到的数据顺序总是不断变化;偶尔数据中还会出现一个字节是0xff。

希望有做过IIC主从机通信的朋友,给予帮助,感激不尽!!!

下面贴上代码:
主机的读数据函数

[mw_shl_code=c,true]
uint32_t read_one_byte(uint8_t s8_address)
{
        uint8_t i;
        uint32_t rec_32_buff;
        bsp_SimuI2C_start(&TouchI2cPort);
        bsp_SimuI2C_write_byte(&TouchI2cPort,s8_address);
        bsp_SimuI2C_SandAck(&TouchI2cPort);
        for(i=0;i<4;i++)
        {
                rec_32_buff<<=8;
          rec_32_buff+=bsp_SimuI2C_read_byte(&TouchI2cPort);
                bsp_SimuI2C_SandAck(&TouchI2cPort);
        }
        bsp_SimuI2C_stop(&TouchI2cPort);
        return rec_32_buff;
}
[/mw_shl_code]

接下来是STM8从机程序:
这是IIC中断函数
[mw_shl_code=c,true]
INTERRUPT_HANDLER(I2C_IRQHandler, 19)
{
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
   //接收发送
    u8 temp = 0;
    if (I2C->SR1&0x02)//地址已经匹配(读SR1,SR3清除该位)
    {
        temp = I2C->SR3&0x07;
    }
    else if ((I2C->SR1&0x84)&&(I2C->SR3&0x04))//数据字节传送完
    {
       if(data_len>=4)data_len=0;
       I2C->DR = My_Buffer[data_len];
       data_len++;
    }
    else if ((I2C->SR1&0x40)&&(0 == (I2C->SR3&0x04)))//接收时数据寄存器
    {
        temp = I2C->DR;    //读取数据寄存器
    }
    else if (I2C->SR1&0x10)//检测到停止位
    {
        I2C->CR2 = I2C->CR2;//清除停止位
    }
    //错误处理
    if (I2C->SR2&0x01)//总线错误
    {
        I2C->SR2 &= ~0x01;//清零
    }
    else if(I2C->SR2&0x02)//仲裁失败
    {
        I2C->SR2 &= ~0x02;//清零
    }
    else if(I2C->SR2&0x04)//应答失败
    {
        I2C->SR2 &= ~0x04;//清零
    }
    else if(I2C->SR2&0x08)//上溢、下溢
    {
        I2C->SR2 &= ~0x08;//清零
    }
    return;
}
[/mw_shl_code]

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
16条回答
fire_Man
1楼-- · 2019-07-21 16:17
 精彩回答 2  元偷偷看……
huanghan
2楼-- · 2019-07-21 19:04
 精彩回答 2  元偷偷看……
biglu
3楼-- · 2019-07-21 19:50
本帖最后由 biglu 于 2017-9-6 23:23 编辑

[mw_shl_code=c,true]u16 SendBuf[16]={0x00,0X01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f}; //IIC的发送测试数组
__IO uint8_t Slave_Buffer_Rx[255];  
uint16_t *p1;  //存放数据的指针(用于接收的数组,要定义为全局)
__IO uint8_t Slave_Buffer_Tx[3]={ 1, 3, 5 };
u8 SendIndex=0; //发送索引
u16 Event=0;    //I2C通讯事件号        
/****************************** I2C Interrupt routine ******************************/
INTERRUPT_HANDLER(I2C_IRQHandler, 19)
{
    u8 i;                                

    p1 = SendBuf;  //指针p1用来,向主机发送数据
    Event = I2C_GetLastEvent(); //先获取IIC通讯的Event

    /******************************  Receive *******************************/
        if(I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED==Event) //地址匹配+从机作为接收方
    {   
        for(i=0;i<5;i++)
        {
            while( !I2C_CheckEvent(I2C_EVENT_SLAVE_BYTE_RECEIVED )); //当收到一字节
            *(p1++) = I2C_ReceiveData(); //将接收到的iic data放入接收指针p1
            printf("%c",*(p1-1)); // (used for test)
        }
        //3 - stop communication
        while(!I2C_CheckEvent(I2C_EVENT_SLAVE_STOP_DETECTED )); //等待主机发来stop
        printf("%c",0xf3); //show communication endind (used for test)
    }

    /******************************  Transmit *******************************/
    if(I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED ==Event )
    {
        I2C_ClearFlag(I2C_FLAG_ADDRESSSENTMATCHED);
    }   
    if(I2C_EVENT_SLAVE_TRANSMITTER_ADDRESS_MATCHED==Event) //地址匹配+从机作为发送方
    {
        SendIndex=0;
    }
    if(I2C_EVENT_SLAVE_BYTE_TRANSMITTING==Event) //地址匹配+从机作为发送方
    {
        I2C->DR = Slave_Buffer_Tx[SendIndex];
        SendIndex++;
    }

    /****************************  Error & Stop *****************************/
    if(I2C_EVENT_SLAVE_ACK_FAILURE ==Event )
    {
        //当没收到ACK,暂时先初始化一下,避免错误
        I2C_Init(I2C_Speed, I2C1_SLAVE_ADDRESS7, I2C_DUTYCYCLE_2,
            I2C_ACK_CURR, I2C_ADDMODE_7BIT, 16);
    }
    if(I2C_EVENT_SLAVE_STOP_DETECTED==Event) //收到结束标志
    {
        I2C->CR2 |= I2C_CR2_ACK;
    }
}

[/mw_shl_code]
前段时间测试的时候弄的 stm8的硬件中断IIC从机 先看看吧 stm32的有空再发

[mw_shl_code=c,true]void IIC_Slave_Init(void)
{
  u8 Input_Clock = 0x0;

  Input_Clock = CLK_GetClockFreq()/1000000; //获取当前系统时钟频率
  IIC_GPIO_Init(); //IIC IO初始化
  I2C_DeInit(); //IIC寄存器复位

  I2C_Cmd(ENABLE); //IIC使能 (!!! 一定要在I2C_Init前面 !!!)  
  I2C_Init(I2C_Speed, I2C_SLAVE_ADDRESS7, I2C_DUTYCYCLE_2,
            I2C_ACK_CURR, I2C_ADDMODE_7BIT, Input_Clock); //IIC初始化
  I2C_ITConfig((I2C_IT_TypeDef)(I2C_IT_ERR | I2C_IT_EVT | I2C_IT_BUF),ENABLE); //IIC中断配置
}
void IIC_GPIO_Init(void)
{
//IIC_SDA设置为 高速开漏输出, 默认低电平
GPIO_Init(IIC_SDA_PORT, IIC_SDA_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
//IIC_SCL设置为 高速开漏输出, 默认低电平
GPIO_Init(IIC_SCL_PORT, IIC_SCL_PIN, GPIO_MODE_OUT_OD_LOW_FAST);
}[/mw_shl_code]

[mw_shl_code=c,true]/* IIC相关宏定义 */
#define I2C_Speed              100000   //IIC通讯速度(100kHz)
#define I2C_SLAVE_ADDRESS7     0x30     //从机I2C地址[/mw_shl_code]
荆白雪
4楼-- · 2019-07-21 23:33
 精彩回答 2  元偷偷看……
荆白雪
5楼-- · 2019-07-22 00:14
huanghan 发表于 2017-9-5 22:24
有的,上传你个给你们看看里面的说明文件,这个工程不全,要的话,明天整理你们

恩恩,好的,谢谢
xuande
6楼-- · 2019-07-22 00:26

如果没有接触过IIC,先用CPU操作一个硬件的从机吧,
等熟悉了时序再说。

不过,这个思路很奇葩,
用CPU做IIC的从机?
那我干脆用SPI总线,就多一根线。

一周热门 更多>