0
收藏
微博
微信
复制链接

51单片机AD转换pcf8591源程序+Proteus仿真

提问于
2024-12-05 20:46

使用proteus,8051单片机,与pcf8591进行ad转换
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
cd865afc9ae39b65b43606619ebb3f.jpg

单片机源程序如下:

  1. #include
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. sbit sda=P2^0; //自定义由普通IO口模拟I2C
  5. sbit scl=P2^1;
  6. sbit dm=P2^6;  //段锁存
  7. sbit wm=P2^7;
  8. uchar code table[]={0x3f,0x06,0x5b,0x4f,
  9. 0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

  10. void Delay(uint n)
  11. {
  12.         uint i,j;
  13.         for(i=n;i>0;i--)
  14.                 for(j=110;j>0;j--);
  15. }

  16. void delay()  //延时几微秒。延时函数在很多函数里都要用它。至少要大于4.7us
  17. {;;}          //当你把这个函数写在用它这个函数的前面就不用声明了

  18. void init()  //初始化总线。将总线都拉高以释放
  19. {
  20.         scl=1;
  21.         delay();  //I2C总线使用时一般都要延时5us左右
  22.         sda=1;
  23.         delay();
  24. }

  25. void start() //启始信号。 时钟信号为高电平期间,数据总线产生下降沿。
  26. {            //为什么要下降沿,且sda先要为1。因为先要保证数据线为空才能工作
  27.         sda=1;   //先释放数据总线。高电平释放
  28.         delay();
  29.         scl=1;
  30.         delay();
  31.         sda=0;
  32.         delay();
  33. }

  34. void stop()
  35. {
  36.         sda=0;  //先要有工作状态才能释放,sda=0时在工作状态
  37.         delay();
  38.         scl=1;
  39.         delay();
  40.         sda=1;  //释放数据总线
  41.         delay();
  42. }

  43. void respons()  //应答函数
  44. {
  45.         uchar i=0;
  46.         scl=1;  //每个字节发送完后的第九个时钟信号的开始
  47.         delay();
  48.         while((sda==1)&&(i<255))   //此处i的定义使用了uchar.只要填一个小于255的就行
  49.         i++;                       //此处的sda是从机的
  50.         scl=0; //表示主器件默认从器件已经收到而不再等待。不再等待之后,时钟的高电平过了就是低电平,所以scl=0
  51.                //此时第酒个时钟信号结束
  52. }

  53. void writebyte(uchar d)  //写一字节,每次左移一位
  54. {
  55.         uchar i,temp;
  56.         temp=d;
  57.         for(i=0;i<8;i++)
  58.         {
  59.                 temp=temp<<1;
  60.                 scl=0;        //数据传输期间要想sda可变,先把时钟拉低。此处要给sda赋值
  61.                 delay();
  62.                 sda=CY;       //CY为左移移入PSW寄存器中的的CY位。
  63.                 delay();
  64.                 scl=1;        //sda有数据了。保持数据稳定
  65.                 delay();
  66.         }
  67.         scl=0;            //此处是写数据,是属于数据传输过程中。只有在时钟信号为低电平期间
  68.         delay();          //数据总线才可以变化。
  69.         sda=1;            //所以要想释放数据总线,就必须先把时钟拉低
  70.         delay();         
  71.         /*此处释放总线写在末尾是因为调用它时,前面有起始函数释放了总线*/
  72. }

  73. uchar readbyte()
  74. {
  75.         uchar i,k;
  76.         scl=0;
  77.         delay();
  78.         sda=1;
  79.         delay();
  80.         /*此处释放总线放在前面是因为一般都是先写后读,保险起见,释放一下总线*/
  81.         for(i=0;i<8;i++)
  82.         {
  83.                 scl=1;     //一个时钟信号的开始
  84.                 delay();
  85.                 k=(k<<1)|sda;    //实质是把sda的数据,最先传来的放在最高位,依次往下排
  86.                 scl=0;    //一个时钟信号结束
  87.                 delay();
  88.         }
  89.         return k;
  90. }

  91. void display(uchar bai,uchar shi,uchar ge)
  92. {
  93.         dm=1;
  94.         P0=table[bai]; //显示第一位
  95.         dm=0;
  96.         P0=0xff;       //消隐
  97.         wm=1;
  98.         P0=0xfe;
  99.         wm=0;
  100.         P0=0x00;        //消除仿真乱码
  101.         Delay(5);
  102.        
  103.         dm=1;
  104.         P0=table[shi]; //显示第二位
  105.         dm=0;
  106.         P0=0xff;       //消隐
  107.         wm=1;
  108.         P0=0xfd;
  109.         wm=0;
  110.         P0=0x00;        //消除仿真乱码
  111.         Delay(5);
  112.        
  113.         dm=1;
  114.         P0=table[ge]; //显示第三位
  115.         dm=0;
  116.         P0=0xff;       //消隐
  117.         wm=1;
  118.         P0=0xfb;
  119.         wm=0;
  120.         P0=0x00;        //消除仿真乱码
  121.         Delay(5);
  122. }

  123. /*void write(uchar addr,uchar dat)
  124. {
  125.         start();          //初始化
  126.         writebyte(0x90);      //调用写一字节函数.PCF8591为1001。此处是给从机发送写信号(最低位是0)
  127.         respons();            //调用应答函数让从机应答
  128.         writebyte(addr);      //写入地址
  129.         respons();            //每写一字节都要应答
  130.         writebyte(dat);
  131.         respons();
  132.         stop();
  133. }*/

  134. uchar read(uchar addr)
  135. {
  136.         uchar dat;
  137.         start();
  138.         writebyte(0x90);      //从此处的发送地址和方向位0到从机
  139.         respons();            //此处的从机产生应答。属于“伪写”。用于确定和哪台机子通信
  140.         writebyte(addr);
  141.         respons();
  142.         start();
  143.         writebyte(0x91);      //从此处开始,从机向主机写数据。读的方向位为1
  144.         respons();
  145.         dat=readbyte();
  146.         stop();
  147.         return dat;           //读得的数据要返回
  148. }

  149. void main()
  150. {
  151.         uchar ge,shi,bai,n;
  152.         init();
  153.         while(1)
  154.         {
  155.                 n=read(0x00);      //此处是读取内存的不同位置。至于从哪儿开始应该没要求
  156.                 ge=n%10;
  157.                 shi=n%100/10;
  158.                 bai=n/100;
  159.                 display(bai,shi,ge);
  160.         }
  161. }

收藏 42 0 0