打印

关于PIC16F887的I2C通信

[复制链接]
6478|13
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhuguangpeng|  楼主 | 2012-10-23 13:34 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我参照  877的例程 拷到 887里面结果仿真的时候出现问题,但现在问题不知道出现在什么地方? 我看了数据手册 感觉没有什么变化啊。  主机的程序

#include <pic.h>       
  
  //__CONFIG (HS & LVPDIS & WDTDIS);
  
#define  B1 RC0   // 按键B1状态由RC0端口输入
#define        XTAL_FREQ        4        // 外接晶振主频,单位为MHz

void DelayMS(unsigned int ms) //定义延时函数
{
  unsigned int j=0;
  for(ms;ms>0;ms--)
   for(j=27*XTAL_FREQ;j>0;j--) // 1MHz时约是27,其它主频请酌情修改
   {
   }
}  
void main( void )
{
  unsigned char i=1;
      //        TRISC0=1;    // RC0用于读取按钮B1的状态
       
        SSPEN=0;    // 关闭MSSP模块,初始化完毕后再打开
       
  TRISC3=1;   // 把SCL设为输入引脚
  TRISC4=1;   // 把SDA设为输入引脚
  SSPCON2=0;
   WCOL=0;     // 写冲突检测位清零,若发送数据不正确请检查此位   
  SSPM3=1;    //SSPM=1000,I2C主模式
  SSPM2=0;
  SSPM1=0;
  SSPM0=0;
   SMP=1;
  // I2C波特率=Fosc/(4*(SSPADD+1))
  // SSPADD=[(Fosc/(BandRate*4)]-1
  SSPADD = 0x9;            // 当主频为4Mhz时波特率为100kbps
  CKP=1;
  CKE=0;     // 使用I2C协议规范电平
       // 关闭斜率控制

  SSPIF=0;      //若使用SSPIF作为信号发送状态位则需要清空此位
  
  SSPEN=1;    // 使能MSSP模块
   
        while (1)
        {
   // if(B1==0)  // 若按键B1有变化
  //  {
      //DelayMS(100); // 消除机械按键前沿抖动
     // if(B1==0)  // 再判断为0说明是一次正常按键
     // {
        SEN=1;  // 发送起始位
        while(SEN); // SEN=1说明未发送完毕
        // 循环退出说明SEN=0,即发送完毕

   
        SSPBUF = 0b10010000; // 从机地址为0b1001000,写操作
        while(R_nW);  //RW=1说明数据发送进行中
        // 循环退出说明RW=0,即发送完毕
        if(ACKSTAT) // ACKSTAT为1说明未收到从机应答
          while(1); // 死循环,便于调试,实际项目中应做错误处理
         
        SSPBUF = i; //向从机写入数据i,即发送数据i
        while(R_nW);  //RW=1说明数据发送进行中
        // 循环退出说明RW=0,即发送完毕
        if(ACKSTAT) // ACKSTAT为1说明未收到从机应答
          while(1); // 死循环,便于调试,实际项目中应做错误处理
        
        PEN=1;  // 发送停止位
        while(PEN); // PEN=1说明未发送完毕
        // 循环退出说明PEN=0,即发送完毕

               i++;  // 为了能看到效果,发生数据自加一
        DelayMS(100); // 过滤机械按键的后沿抖动
      //}
   // }
         
        }
       
}
  从机的程序

/*  PIC16F877 I2C从机模式接收数据例程
*  把收到的数据显示在数码管上
*
*/

#include <pic.h>        // 改用PIC16F877控制

//  __CONFIG (HS & LVPDIS & WDTDIS);
  const char NumFont[10]={0x3F,0x06,0x5B,0x4F,0x66,
           0x6D,0x7D,0X07,0x7F,0x6F}; // 共阴极数码管字形码

interrupt ISR(void)
{
        char tmp;
        if(SSPIF==1)
        {
                SSPIF=0;
                if(D_nA==1)  // 1 是数据
                {
                        if(BF==1)  // 缓冲区满,说明从主机收到一个字节
                        {
                                tmp=SSPBUF;  // 保存收到的普通数据
                                PORTD=NumFont[tmp];  // 显示收到的数据
                        }
                        else  // BF=0,主机读取结束
                        {
                                if(R_nW==1) // 读标志位有效,说明主机还在继续读数据
                                {
          SSPBUF=0x06; // 把主机要的数据保存在SSPBUF中等待主机读取                                         
                                }
                                else
                                {  // 读标志位无效,说明主机已经读取完最后一个字节了
                                }
                        }
                }
                else  //0 是地址
                {
                        tmp=SSPBUF;
                        if( (tmp & 0b00000001)!=0) // R/W =1,read
                        {
                                SSPBUF=0x06;  // 准备好数据等待下一次主机读取
                        }
                        else  //R/W=0, write
                        {
                                // 等待下一次主机来数据放到SSPBUF中
                        }
                }
        }
CKP=1;
SSPOV=0; //  从机释放SCL

}
           
I2C_Init()
{
        SSPSTAT=0;
        TRISC3=1;
        TRISC4=1;
        SSPCON2=0B10000000;
        SSPADD=0B10010000; // 从机地址码范围:1001000x
        SSPCON=0B00110110;  
        SSPIE=1; // 允许SSPIF产生中断
        GIE=1;
        PEIE=1;
}

void main( void )
{
  unsigned char i=0,EEP_Address=0,EEP_Data=0;
         TRISD=0; // 为了读取按钮B1的状态
         PORTD=0;
        I2C_Init();    // 初始化I2C
        while (1)
        {  // 等待中断产生
        }

在用887 仿真的时候会出现如图所示的错误 难道是不可以通用还是有什么其他的问题啊?
       
}

11.jpg (121.18 KB )

11.jpg
沙发
NE5532| | 2012-10-23 14:20 | 只看该作者
按功能模块逐个调试,不要想一抄了事。

使用特权

评论回复
板凳
airwill| | 2012-10-25 20:54 | 只看该作者
I2C 主从机联合调试, 的确是个蛮讨厌的事情, 出了问题两方面都要考虑, 建议用个好的工具, 比如逻辑分析仪来帮助你分析, 问题是出在了主机还是从机, 收发的数据是否合法等等.

使用特权

评论回复
地板
chengqing3968| | 2013-9-16 15:41 | 只看该作者
敢问楼主实现了嘛……求指导!

使用特权

评论回复
5
涵潇舒雅| | 2013-10-21 15:59 | 只看该作者
chengqing3968 发表于 2013-9-16 15:41
敢问楼主实现了嘛……求指导!

问一下 你有没有实现啊 我也想咨询一下

使用特权

评论回复
6
涵潇舒雅| | 2013-10-21 15:59 | 只看该作者
chengqing3968 发表于 2013-9-16 15:41
敢问楼主实现了嘛……求指导!

请问你的实现了吗???

使用特权

评论回复
7
涵潇舒雅| | 2013-10-21 16:01 | 只看该作者
airwill 发表于 2012-10-25 20:54
I2C 主从机联合调试, 的确是个蛮讨厌的事情, 出了问题两方面都要考虑, 建议用个好的工具, 比如逻辑分析仪来 ...

我用protues仿真能到成功,但是实际应用却出了问题,从机的SSPIF没有置位,进入不了中断,很是不理解、、

使用特权

评论回复
8
涵潇舒雅| | 2013-10-22 09:52 | 只看该作者
airwill 发表于 2012-10-25 20:54
I2C 主从机联合调试, 的确是个蛮讨厌的事情, 出了问题两方面都要考虑, 建议用个好的工具, 比如逻辑分析仪来 ...

版主我也有关于i2c的问题,能不能帮我分析一下啊,不胜感激

使用特权

评论回复
9
caoyonglu| | 2013-12-11 07:45 | 只看该作者
问题解决了没,如何解决的

使用特权

评论回复
10
949155525| | 2013-12-20 23:11 | 只看该作者
逻辑分析仪   妙解决

使用特权

评论回复
11
Anlen| | 2014-6-12 15:32 | 只看该作者
为什么SSPIF一直都不置位,?

使用特权

评论回复
12
小鱼儿1045| | 2014-6-19 14:41 | 只看该作者
IIC基本就是时序问题!还有数据格式。

使用特权

评论回复
13
perry_peng| | 2014-6-20 08:43 | 只看该作者
不用中断不可以吗

使用特权

评论回复
14
perry_peng| | 2014-6-20 09:10 | 只看该作者
本帖最后由 perry_peng 于 2014-6-20 09:15 编辑

中断麻烦,我以前用的与pcf8574通信。
非中断模式:

uint8 i2c_waitIdle()
{
  uint16 timeout = 0x3ff;
  /**<
   * RW or SEN or RSEN or PEN or RCEN or ACKEN will indicate if the MSSP
   * is in Idle mode.
   */
  while ((SSPSTAT & 0x04 /*RW*/) || (SSPCON2 & 0x1f))  
    if (!--timeout)                                        // Check timeout.
      return 1;
  return 0;
}

uint8 pcf8574_write_port(uint8 addr, uint8 val)
{
  uint8 ret = 1;
  
  if (i2c_waitIdle())
    goto __i2c_write_finish;
  delayUsx(5);
  /*SSPCON2bits.*/SEN = 1;          // Initiate Start condition on SDA and SCL pins.
  delayUsx(15);
  if (i2c_waitIdle())               // Wait for bus idle
    goto __i2c_write_finish;
  delayUsx(5);
  SSPBUF = 0x40 | (addr << 1);      // send address bits with R/W bit
  if (SSPCON2 & 0x40)               // ACKSTAT = 0; Acknowledge was received from slave.
    goto __i2c_write_finish;
  delayUsx(15);
  if (i2c_waitIdle())               // Wait for bus idle
    goto __i2c_write_finish;
  delayUsx(5);
  SSPBUF = val;                     // send data.
  if (SSPCON2 & 0x40)               // ACKSTAT = 0; Acknowledge was received from slave.
    goto __i2c_write_finish;
  delayUsx(15);
  ret = 0;
__i2c_write_finish:
  i2c_waitIdle();                   // Wait for bus idle.
  delayUsx(5);
  /*SSPCON2bits.*/PEN = 1;          // Initiate STOP condition.
  delayUsx(35);
  
  return ret;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

23

帖子

1

粉丝