打印

求助:单片机控制I2C总线

[复制链接]
1624|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lampardter|  楼主 | 2007-5-9 22:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我的毕业设计要用到单片机控制数字电位器(I2C接口的那种),现在调试程序时遇到了一些问题,我想可能是I2C时序的问题.

哪位大哥编过单片机控制I2C的程序,帮帮小弟.
下面是程序,帮小弟看看哪有问题?谢谢了!
 /*****************************************/
 /*单片机控制数字电位器程序*/
 /*****************************************/

#include <AT89X52.h>           // 引用标准库的头文件

#define uchar unsigned char 
#define uint unsigned int 

sbit SCL=0x90;                 //定义数字电位器的三个控制引脚
sbit SDA=0x91;
uchar idata Add;               //从器件地址
bit bdata NACK;                //器件坏或错误标志位
bit bdata nackFlag;            //非应答标志位

#define Add 0x50               //器件地址   0 1 0 1 0 0 0 0
#define RWCR 0x90             //读WCR指令  1 0 0 1 1/0 1/0 X X
#define WWCR 0xa0             //写WCR指令  1 0 1 0 1/0 1/0 X X
#define I_DWCR 0x20            //增加/减小WCR指令  0 0 1 0 1/0 1/0 X X                
#define WReg 0xc0              //写数据寄存器指令  1 1 0 0 1/0 1/0 1/0 1/0
#define Reg_WCR 0xd0           //指定数据寄存器到WCR  1 1 0 1 1/0 1/0 1/0 1/0

uchar value1;

uchar value2;

void delay(void)
{}


/*延时t毫秒*/
void delayms(uint t)
{
    uchar i;
    while(t--)
    {     /*对于12MHz时钟,延时约1ms*/ 
      for(i=0;i<125;i++)
         { }
      }
}

/*根据共阳极字形编码表获取0~9,A~F字型代码*/
uchar getcode(uchar i)
{
  uchar p;
  switch(i)
  {
      case 0:  p=0xc0; break;     /*0*/
    case 1:  p=0xf9; break;     /*1*/
    case 2:  p=0xa4; break;     /*2*/
    case 3:  p=0xb0; break;     /*3*/
    case 4:  p=0x99; break;     /*4*/
    case 5:  p=0x92; break;     /*5*/
    case 6:  p=0x82; break;     /*6*/
    case 7:  p=0xf8; break;     /*7*/
    case 8:  p=0x80; break;     /*8*/
    case 9:  p=0x98; break;     /*9*/
    case 10: p=0x77; break;     /*A*/
    case 11: p=0x7c; break;     /*B*/
    case 12: p=0x39; break;     /*C*/
    case 13: p=0x5e; break;     /*D*/
    case 14: p=0x79; break;     /*E*/
    case 15: p=0x71; break;     /*F*/
    default:         break;
  }
   return(p);
}

/*显示子程序*/
void display(uchar ch)
{
  uchar j,tmp,data1=0,data2=0,num_shi,num_ge,num;
  uint i;
  for(i=0;i<=3;i++)                //显示高四位
  {
   if((ch&0x80)==0x80)
    {
     tmp=1;
     for(j=0;j<3-i;j++)            //二进制转十六进制
         tmp=tmp*2;
    }
   else tmp=0;
   ch=ch<<1;
   data1=data1+tmp;
  }
  for(i=0;i<=3;i++)                //显示低四位
   {
    if((ch&0x80)==0x80)
     {
       tmp=1;
       for(j=0;j<3-i;j++)         //二进制转十六进制
       tmp=tmp*2;
     }
   else tmp=0;
   ch=ch<<1;
   data2=tmp+data2;
  }
  num=data1*16+data2;
  data1=num/10;                  //十六进制转十进制
  data2=num%10;
  num_shi=getcode(data1);        //按共阳极编码获取显示数字
  num_ge=getcode(data2);
  for(i=0;i<50;i++)
    {
      P2_2=0;                    //两个数码管都不亮
      P2_1=1;
      P0=num_shi;                //显示十位数字
      P2_2=1;
      delayms(10);
      P2_2=0;
        P2_1=0;  
      P0=num_ge; 
      P2_1=0;                    //显示个位数字
      delayms(10);
      P2_1=1;
    }
}


/*I2C总线初始化*/
void I2C_Init()
{
  SCL = 1;
  delay();
  SDA = 1;
  delay();
}


/*起始条件子函数*/
void start(void)
{
  SDA=1; 
  delay();                        //启动I2C总线
  SCL=1;
  delay();
  SDA=0;
  delay();
  SCL=0;
  delay();
 }

 /*停止条件子函数*/
 void stop(void)
 {
      SDA=0;
    SCL=1;
    delay();
    SDA=1;
    delay();
    SCL=0;
 }


 /*发送应答子函数*/
void ack(void)
 {
   SDA=0;
   delay();                       //发送应答位                
   SCL=1;
   delay();
   SCL=0;
   delay(); 
   SDA=1;                      
 }


/*发送非应答子函数*/
void n_ack(void)
{
   SDA=1;
   delay();                        //发送非应答位                     SCL=1;
   delay();
   SCL=0;
   delay();
}


/*应答位检查子函数*/
void checkack(void)
{
   SCL=0;
   delay();
   SDA=1; 
   delay();                      //应答检查位(将P1.0设置成输入,必须先向端口写1)           
   SCL=1;
   nackFlag=0;
   if(SDA==1)
       nackFlag=1;               //若SDA=1表明非应答,置位非应答标志F0
   SCL=0;
}

bit getack(void)
{
  bit ack;
  SCL=0;
  delay();
  SDA=1;
  delay();
  SCL=1;
  delay();
  ack=SDA;
  SCL=0;
  delay();
  return ack;
}

/*发送数据子程序*/
void send(uchar ch)

  uchar BitCounter=8;          //位数控制
  uchar tmp;
  tmp=ch;
  while(BitCounter--)  
   {
    if((tmp&0x80)==0x80)        //如果最高位是1 
      {
        SDA=1;                  //发送1
        SCL=1;
        delay();
        SDA=0;
        SCL=0;
      }
    else
      {
        SDA=0;                  //发送0
        SCL=1;
        delay();
        SCL=0;
      }
    tmp=tmp<<1;                 //左移
  }  
}

/*接收数据子程序*/
uchar receive(void)
{
  uchar BitCounter=8;
  uchar tmp=0;
  uchar ch;
  while(BitCounter--)
  {
    SDA=1;
    SCL=1;
    tmp=tmp<<1;                //左移1位
    if(SDA==1)
       tmp=tmp|0x01;           //若接收到的位为1 ,则数据最后一位置1
    else
       tmp=tmp&0xfe;           //否则数据最后一位置0
    SCL=0;
  }
  ch=tmp;
  return(ch);
}

/*写WCR子程序*/
void WR_WCR(uchar ch)
{
   start();                   //发送启动信号
   send(Add);                 //发送地址字节
   //checkack();                //检查应答位          
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
   send(WWCR);                //写WCR指令
   //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
   send(ch);                  //向WCR中写入0x22
  // checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
   stop();                    //结束信号
}

/*写数据寄存器子程序*/
void WR_Reg(uchar ch)
{
  start();                   //发送启动信号
  send(Add);                 //发送地址字节
  //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
  send(WReg);                //写数据寄存器指令
  delayms(10);
 // while(SDA==1);             //                    
  //checkack();                //检查应答位
  if(getack())
    {
      NACK=1;
      stop();
      return;
    }
   send(ch);                  //向数据寄存器中写入0x22
   //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
   stop();                    //结束信号
}


/*指定数据寄存器到WCR子程序*/
void Reg_to_WCR(void)
{
  start();                   //发送启动信号
  send(Add);                 //发送地址字节
  //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
  send(Reg_WCR);             //数据寄存器到WCR指令
  delayms(5);
  //checkack();                //检查应答位                
  if(getack())
    {
      NACK=1;
      stop();
      return;
    } 
  stop();                    //结束信号
}
  

/*读WCR子程序*/
uchar RD_WCR(void)
{
  uchar ch_read;
  start();
  send(Add);
  //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return 0x10;
    }
  send(RWCR);                 //读WCR指令
  ack();
  ch_read=receive();
  n_ack();
  stop();
  return(ch_read);
}

/*增加WCR子函数*/
void INC_WCR(void)
{
  uchar i;
  start();
  send(Add);
  //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
  send(I_DWCR);
  //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      stop();
      return;
    }
  for(i=0;i<3;i++)            //WCR增加3
     {
       SCL=0;
       delay();
       SDA=1;
       delay();
       SCL=1;
       delayms(5);
     }
  SCL=0;
}
 
/*减小WCR子函数*/
void DEC_WCR(void)
{
  uchar i;
  start();
  send(Add);
  //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      return;
    }
  send(I_DWCR);
  //checkack();                //检查应答位
   if(getack())
    {
      NACK=1;
      return;
    }
  for(i=0;i<3;i++)           //WCR减少3
    {
      SCL=0;
      delay();
      SDA=0;
      delay();
      SCL=1;
      delayms(5);
    }
  SCL=0;
}


/*外部中断0服务子程序,增加WCR值*/
void int0svr(void)  interrupt 0 
{
  EA=0;
  INC_WCR();
  delayms(100);
  value1=RD_WCR();
  delayms(100);
  display(value2);
  EA=1;
}

/*外部中断1服务子程序,减小WCR值*/
void int1svr(void)  interrupt 2 
{
 
  EA=0;
  DEC_WCR();
  delayms(100);
  value2=RD_WCR();
  delayms(100);
  display(value2);
  EA=1;
}




/*主函数*/
void main(void)
{
   uchar value;
   EA=1;
   EX0=1;                     //打开外部中断0
   EX1=1;                     //打开外部中断1
   TCON=0x05;                 //设定外部中断INT0,INT1为负边沿触发
   
   I2C_Init();
   WR_WCR(0x11);              //向WCR中写入初值
  // WR_Reg(0x20);
  //delayms(100);
  // Reg_to_WCR();
   delayms(10);             
   value=RD_WCR();            //读出WCR值
   delayms(100);
   display(value);            //显示WCR值 +value+
   delayms(100);
   while(1);                  //无限循环,等待外部中断
}



  
   

  
   
  

相关帖子

沙发
computer00| | 2007-5-9 23:50 | 只看该作者

自己去网上搜索吧,程序模拟I2C的程序很多的

使用特权

评论回复
板凳
ayb_ice| | 2007-5-10 07:32 | 只看该作者

现在的毕业设计很流行这样...

使用特权

评论回复
地板
9398711029| | 2007-5-10 08:14 | 只看该作者

毕业设计不是有指导老师吗?不能浪费了学校的资源啊

使用特权

评论回复
5
nust1996| | 2007-5-10 10:01 | 只看该作者

现在的毕业设计变的这么简单了吗

有问题要学会自己研究,用示波器抓时序看看,现在太多的人不太会利用手头上的工具,有了网络,忘了思考

使用特权

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

本版积分规则

4

主题

5

帖子

0

粉丝