使用proteus,8051单片机,与pcf8591进行ad转换
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include
- #define uint unsigned int
- #define uchar unsigned char
- sbit sda=P2^0; //自定义由普通IO口模拟I2C
- sbit scl=P2^1;
- sbit dm=P2^6; //段锁存
- sbit wm=P2^7;
- uchar code table[]={0x3f,0x06,0x5b,0x4f,
- 0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
- void Delay(uint n)
- {
- uint i,j;
- for(i=n;i>0;i--)
- for(j=110;j>0;j--);
- }
- void delay() //延时几微秒。延时函数在很多函数里都要用它。至少要大于4.7us
- {;;} //当你把这个函数写在用它这个函数的前面就不用声明了
- void init() //初始化总线。将总线都拉高以释放
- {
- scl=1;
- delay(); //I2C总线使用时一般都要延时5us左右
- sda=1;
- delay();
- }
- void start() //启始信号。 时钟信号为高电平期间,数据总线产生下降沿。
- { //为什么要下降沿,且sda先要为1。因为先要保证数据线为空才能工作
- sda=1; //先释放数据总线。高电平释放
- delay();
- scl=1;
- delay();
- sda=0;
- delay();
- }
- void stop()
- {
- sda=0; //先要有工作状态才能释放,sda=0时在工作状态
- delay();
- scl=1;
- delay();
- sda=1; //释放数据总线
- delay();
- }
- void respons() //应答函数
- {
- uchar i=0;
- scl=1; //每个字节发送完后的第九个时钟信号的开始
- delay();
- while((sda==1)&&(i<255)) //此处i的定义使用了uchar.只要填一个小于255的就行
- i++; //此处的sda是从机的
- scl=0; //表示主器件默认从器件已经收到而不再等待。不再等待之后,时钟的高电平过了就是低电平,所以scl=0
- //此时第酒个时钟信号结束
- }
- void writebyte(uchar d) //写一字节,每次左移一位
- {
- uchar i,temp;
- temp=d;
- for(i=0;i<8;i++)
- {
- temp=temp<<1;
- scl=0; //数据传输期间要想sda可变,先把时钟拉低。此处要给sda赋值
- delay();
- sda=CY; //CY为左移移入PSW寄存器中的的CY位。
- delay();
- scl=1; //sda有数据了。保持数据稳定
- delay();
- }
- scl=0; //此处是写数据,是属于数据传输过程中。只有在时钟信号为低电平期间
- delay(); //数据总线才可以变化。
- sda=1; //所以要想释放数据总线,就必须先把时钟拉低
- delay();
- /*此处释放总线写在末尾是因为调用它时,前面有起始函数释放了总线*/
- }
- uchar readbyte()
- {
- uchar i,k;
- scl=0;
- delay();
- sda=1;
- delay();
- /*此处释放总线放在前面是因为一般都是先写后读,保险起见,释放一下总线*/
- for(i=0;i<8;i++)
- {
- scl=1; //一个时钟信号的开始
- delay();
- k=(k<<1)|sda; //实质是把sda的数据,最先传来的放在最高位,依次往下排
- scl=0; //一个时钟信号结束
- delay();
- }
- return k;
- }
- void display(uchar bai,uchar shi,uchar ge)
- {
- dm=1;
- P0=table[bai]; //显示第一位
- dm=0;
- P0=0xff; //消隐
- wm=1;
- P0=0xfe;
- wm=0;
- P0=0x00; //消除仿真乱码
- Delay(5);
-
- dm=1;
- P0=table[shi]; //显示第二位
- dm=0;
- P0=0xff; //消隐
- wm=1;
- P0=0xfd;
- wm=0;
- P0=0x00; //消除仿真乱码
- Delay(5);
-
- dm=1;
- P0=table[ge]; //显示第三位
- dm=0;
- P0=0xff; //消隐
- wm=1;
- P0=0xfb;
- wm=0;
- P0=0x00; //消除仿真乱码
- Delay(5);
- }
- /*void write(uchar addr,uchar dat)
- {
- start(); //初始化
- writebyte(0x90); //调用写一字节函数.PCF8591为1001。此处是给从机发送写信号(最低位是0)
- respons(); //调用应答函数让从机应答
- writebyte(addr); //写入地址
- respons(); //每写一字节都要应答
- writebyte(dat);
- respons();
- stop();
- }*/
- uchar read(uchar addr)
- {
- uchar dat;
- start();
- writebyte(0x90); //从此处的发送地址和方向位0到从机
- respons(); //此处的从机产生应答。属于“伪写”。用于确定和哪台机子通信
- writebyte(addr);
- respons();
- start();
- writebyte(0x91); //从此处开始,从机向主机写数据。读的方向位为1
- respons();
- dat=readbyte();
- stop();
- return dat; //读得的数据要返回
- }
- void main()
- {
- uchar ge,shi,bai,n;
- init();
- while(1)
- {
- n=read(0x00); //此处是读取内存的不同位置。至于从哪儿开始应该没要求
- ge=n%10;
- shi=n%100/10;
- bai=n/100;
- display(bai,shi,ge);
- }
- }