我的毕业设计要用到单片机控制数字电位器(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); //无限循环,等待外部中断 }
|