OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7206|回复: 16

iic误码率问题

[复制链接]

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
发表于 2013-11-12 11:39:45 | 显示全部楼层 |阅读模式
 我用的mcu模拟iic从机(速度100k左右),主机(模拟ic)接收从机数据,差不多每隔5s,主机接收的数据就会出错,蛋疼的那些错误数据都是一样的,有啥解决方法啊。
速度100k是不是太大了?
只为摆正你的倒影,我倾倒了整个世界。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-11-12 12:06:19 | 显示全部楼层
回复【楼主位】菜鸟鸡哥:
---------------------------------
IIC接收数据时你是不是移多了一位,我刚开始就是这样,后来修正了
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 12:26:57 | 显示全部楼层
回复【2楼】Badu_Space:
---------------------------------
我用一个大数组测试的,从机发送数组中的数据,主机大部分接收的这个数组是ok的,只有几次接收数据NG,代码应该没问题的
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-11-12 12:29:19 | 显示全部楼层
回复【3楼】菜鸟鸡哥:
---------------------------------
我试过最大传输了160bit,没出现问题,贴代码出来看看
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 12:37:07 | 显示全部楼层
void IIC_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);      
  //配置PB6 B7 为开漏输出  刷新频率为10Mhz
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   //应用配置到GPIOB 
   GPIO_Init(GPIOA, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;       
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   //应用配置到GPIOB 
   GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/**************************实现函数********************************************
*函数原型: void IIC_Start(void)
*功  能: 产生IIC起始信号
*******************************************************************************/
void IIC_Start(void)
{
SDA_OUT();     //sda线输出
IIC_SDA=1;      
IIC_SCL=1;
delay_us(7);
  IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
delay_us(1);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
// delay_us(5);
}

/**************************实现函数********************************************
*函数原型: void IIC_Stop(void)
*功  能:     //产生IIC停止信号
*******************************************************************************/   
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
delay_us(1);
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
  delay_us(7);
IIC_SCL=1; 
delay_us(7);
IIC_SDA=1;//发送I2C总线结束信号
delay_us(1);
IIC_SCL=0;    
}

/**************************实现函数********************************************
*函数原型: u8 IIC_Wait_Ack(void)
*功  能:     等待应答信号到来 
//返回值:1,接收应答失败
//        0,接收应答成功
*******************************************************************************/
u8 IIC_Wait_Ack(void)
{
u16 ucErrTime=0;
IIC_SCL=0;
SDA_IN();      //SDA设置为输入  
IIC_SDA=1;
// delay_us(5); //这里加了就出错,原因不明(产生了一个SCL高电平貌似,导致从机触发中断,误操作)   
IIC_SCL=1;delay_us(8);  
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime>1500)
{
IIC_Stop();
return 1;
}
//  delay_us(1);
}
IIC_SCL=0;//时钟输出0     
return 0;  
/* IIC_SCL = 0;  

        IIC_SDA = 1;   
        SDA_IN();      //SDA设置为输入  
        IIC_SCL = 1;   
        delay_us(20);      //15us??,????  
          
        if(1 == IIC_SDA)    // ?SDA=1?????,???????ACK_Flag  
                return 1;  
        SDA_OUT();  
        IIC_SCL = 0;  
return 0;*/

}

/**************************实现函数********************************************
*函数原型: void IIC_Ack(void)
*功  能:     产生ACK应答
*******************************************************************************/
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0;
// delay_us(2);  // (加了出错)
IIC_SCL=1;
delay_us(8);
IIC_SCL=0;
}

/**************************实现函数********************************************
*函数原型: void IIC_NAck(void)
*功  能:     产生NACK应答
*******************************************************************************/     
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;
// delay_us(2);   // (加了出错)
IIC_SCL=1;
delay_us(8);
IIC_SCL=0;
}

/*****************I2C读正常**************************/  
#if 1  
    IIC_Start();  
    IIC_Send_Byte(0xa5);  
//    Receive_SLAVE_ACK();  
    if(IIC_Wait_Ack()){  
       
      return;  
    } 
 // IIC_Wait_Ack(); 
    IIC_Send_Byte(0xB0);            //读的长度     20    0001 0100
 //   Receive_SLAVE_ACK();  
    if(IIC_Wait_Ack()){  
      return;  
    } 
// IIC_Wait_Ack(); 
    for(i=0;i<24;i++){ 
if(i!=23) {
        receive_slave = IIC_Read_Byte(1);
//      printf("%4x",receive_slave);
}
else   
{
receive_slave = IIC_Read_Byte(0);
// printf("%4x\r\n",receive_slave);
read_end=1;
}

    
    }  
    IIC_Stop();  

#endif
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 12:38:25 | 显示全部楼层
主机程序
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 12:41:31 | 显示全部楼层
void EXTI9_5_IRQHandler(void) 
{  
/*        if(P1IFG>0)         //按键中断  
        {  
          1IFG = 0;  
          LED1 = ~LED1;  
        }  
        1IF = 0;          //清中断标志  
 */  
   if(EXTI_GetITStatus(EXTI_Line8) != RESET)   
   {   
// EXTI_ClearITPendingBit(EXTI_Line2);  //清除LINE3上的中断标志位  
     switch(STATE){  
        case START_STATE:     //SCL高电平时候,SDA从高到低
              //SDA_(IN);
  MO_SDA_IN2();    //接收主机发来的数据
              if(MO_READ_SDA2){   //判断是否进入start
                while(MO_READ_SDA2);
  if(MO_IIC_SCL2>0)                
                  {
//    while(MO_IIC_SCL2);
STATE = CONTROL_STATE;
  }
//   else
//   {
//     STATE = START_STATE;
//    printf("state:%d\r\n",STATE);
//   }                                      
              }  
              break;  
        case CONTROL_STATE: 
 MO_SDA_IN2();    //接收主机发来的数据 
              address <<= 1;  
              if(1 == MO_READ_SDA2)  
                  {
   address |= 0x01;
// printf("1\r\n");
  }
    
              else  
                  {
   address |= 0x00;
  }
              ncount++;  
              if(8 == ncount){  
                  ncount = 0;   
                    
                  if((address & 0xfe) == 0xa4){      //fe=1111 1110 只有0xA4 0xA5  符合条件
                     STATE = ACK_STATE;
//  STATE = WRITE_STATE;                                         
                 }  
                  else  
                      {STATE = NOACK_STATE;
   }                                  
              }  
              break;  
        case ACK_STATE:                 
  MO_SDA_OUT2();  
  MO_IIC_SDA2=0;  
              if((write_end == 1) || (read_end == 1) ){  //已经读完或者写完 
   MO_SDA_OUT2();  
  MO_IIC_SDA2=0;  
                  STATE = STOP_STATE;
                  write_end = 0;  
                  read_end = 0;  
              }  
              else{  
                  if((address & 0x01) == 0x00)       //主机写SLAVE   0xA4
                      {
  STATE = WRITE_STATE;
   }
                  else{   //主机读SLAVE    0xA5
                      STATE = READ_STATE;
                  }  
              }  
              break;  
        case NOACK_STATE:  
  MO_SDA_OUT2();   
   MO_IIC_SDA2=1; 
              address = 0;  
                  STATE = START_STATE;
              break;  
 case READ_STATE:                            //主机读从机  
              if(!length_ACK){                      //主机发送过从机长度  
                    
                 // SDA_(IN);
  MO_SDA_IN2();    //接收主机发来的数据                            
                  add <<= 1;  
                //  if(1 == SDA)
if(MO_READ_SDA2==1)   
                      add |= 0x01;  
                  else  
                      add |= 0x00;  
                    
                  ncount++;  
                  if(8 == ncount){  
                      length_ACK = 1;           //主机发送长度给从机        
 //                     LED0 = 0;  
//                      UART1_Send_u8(send_len); 
     //                printf("%d\r\n",send_len); 
                 if(add==0xB0)
 {
  send_len=24;  //
//  send_len=60;  //
 }
 else  if(add==0xB1)
 {
  send_len=14;    //information  }
                      ncount = 0;  
                      STATE = ACK_STATE;
//   printf("state:%d\r\n",STATE);  
                  }  
              }  
              else{  
                //  SDA_(OUT);
 MO_SDA_OUT2();
 if(add==0xB0)   
//  Temp = write_buff[read_num];
 Temp =test_send[read_num];
  else if(add==0xB1)  Temp = write_buf[read_num]; 
                  Temp <<= ncount;          
                  if((Temp & 0x80) == 0x80)  
  MO_IIC_SDA2=1;  
                  else  
  MO_IIC_SDA2=0;  
                  ncount++;  
                  if(ncount == 8){    //移了7位,正好读一个字节  
                      ncount = 0;  
                      read_num++;  
                      if(read_num >= send_len){//读完了所有数据  
                          read_num = 0;  
                          read_end = 1;  
                          length_ACK = 0;    //将接收长度置0  
STATE = W_NOACK_STATE;
  //                      STATE = STOP_STATE;
                      }      
                     if(!read_end) 
  STATE = W_ACK_STATE;  //从机发送一个字节数据后,等待接收主机的ACK
//   STATE = READ_STATE;
//   printf("state:%d\r\n",STATE);  
                  }     
              }  
              break;
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 12:42:03 | 显示全部楼层
回复【4楼】Badu_Space:
---------------------------------
帮忙看下吧
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-11-12 12:58:29 | 显示全部楼层
回复【8楼】菜鸟鸡哥:
---------------------------------
你的GPIO设置成开漏的话外部要加上啦电阻的喔,如果设置成推挽输出、上啦输出,这样外部就不用上啦电阻

你的接收应答信号那里是不是很啰嗦啊,搞那么长干嘛,尤其是你还用到中断,这样你就要算好时间才行,不然这个数据还没发送或者接收完成,下个中断来了,把它给打断了,这样就容易出错
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 13:18:23 | 显示全部楼层
回复【9楼】Badu_Space:
---------------------------------
模拟iic从机代码,就是要这么长,的确是蛋疼的地方啊
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 13:22:13 | 显示全部楼层
回复【9楼】Badu_Space:
---------------------------------
还有一种是查询法来模拟iic的,无奈查询法的效率没有中断高
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-11-12 14:53:25 | 显示全部楼层
回复【11楼】菜鸟鸡哥:
---------------------------------
你可以看下STC官网有一个模拟IIC从机的Demo,你可以看下,简短
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 15:16:43 | 显示全部楼层
回复【12楼】Badu_Space:
---------------------------------
帅哥,能给个网址啊,刚刚搜了一下没搜到啊
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-11-12 15:21:37 | 显示全部楼层
回复【13楼】菜鸟鸡哥:
---------------------------------
http://www.mcu-memory.com/
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

42

主题

173

帖子

0

精华

高级会员

Rank: 4

积分
549
金钱
549
注册时间
2013-6-18
在线时间
59 小时
 楼主| 发表于 2013-11-12 16:40:43 | 显示全部楼层
回复【14楼】Badu_Space:
---------------------------------
网址打不开啊
只为摆正你的倒影,我倾倒了整个世界。
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-11-12 16:45:23 | 显示全部楼层
我发一个给你,汇编语言的

IO口模拟I2C(主+从).rar

16.36 KB, 下载次数: 748

现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-11-12 16:45:56 | 显示全部楼层
回复【15楼】菜鸟鸡哥:
---------------------------------
这个附件就是在它的网站上面下载的,你看看
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-9 05:41

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表