找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3785|回复: 3
打印 上一主题 下一主题
收起左侧

工业生产现场的光照强度控制系统设计 附单片机程序Proteus仿真

[复制链接]
跳转到指定楼层
楼主
用单片机控制总装车间中的LED照明系统,使其输出恒定照度的光,以满足总装生产工序中的照明需要。
要求:
1. 设计一个给LED供电的可控恒流源电路;
2. 要求恒流源输出电流大小可调,调节范围:下限为(学号末两位×100)mA ,上限为(学号末两位×10)mA;(310mA—3100mA)
3. 设计用户输入环节(硬件线路和程序),实现人工设定给LED供电的恒流源的电流大小;
4. 设计恒流源输出电流检测电路和显示电路,编程实现输出电流大小的检测和显示;
5. 构建闭环系统,并运用 数字控制算法(如PID)使输出电流相对稳定在用户设定的数值,利用Matlab作为辅助工具整定算法参数、仿真验证算法性能,并通过编程用单片机实现;
6. 设计、绘制系统电路 PCB,设计包含手写签名的 Logo,并放置在Top Layer的正中位置。

2. 硬件总体设计

2.1 总体设计方案

由设计要求可知,需使用MCS-51系列单片机,构建控制系统,实现LED灯亮度的控制。所以采用AT89C52 单片机为核心,以3*3按键键盘作为输入端,以达到控制所需输出电流的功能,并且由LCD1602显示模块可以显示输入电流的大小和电流源输出的电流大小。在设计中,采用PCF8591芯片进行AD/DA转换,单片机通过I2C通信协议控制PCF8591 AD转换输出的电压所需电压,输入压控电压源,通过采样电阻的电压DA转换获得电流源输出的电流值,经过单片机计算最后显示实际输出电流。
该直流电机控制系统的设计,在总体上大致可分为以下6个部分组成:AT89C52单片机最小系统,3*3按键键盘,直流稳压源,1602显示模块,AD/DA转换模块,可控电流源模块。系统总体方案图如图 1 所示。
图 1  系统总体方案图

2.2 工作原理

2.2.2 直流稳压电源原理

本设计共用到电源有四种:即± 12V、+5V、负载电源。可选用的有开关电源和稳压电源两种,由于开关电源的纹波系数比较大。因此采用常用的稳压电源来作为整个系统的电源。稳压电源由电源变压器、整流电路、滤波电路和稳压电路组成,如图 2 所示:
图2 直流稳压电源原理图
整流和滤波电路:整流作用是将交流电压 变换成脉动电压。滤波电路一般由电容组成, 其作用是脉动电压中的大部分纹波加以滤除,以得到较平滑的直流电压。再通过稳压电路得到平直的直流电压。
图2 直流稳压电源仿真图

2.2.2 电流源原理

首先,在数控方面采用单片机比 CPLD 和 FPGA 等可编程逻辑器件好,因为此处只是一般用途的控制,没有必要选用价格昂贵的 CPLD 和 FPGA,而且他们用在此处并不合适,控制起来显得很麻烦。而单片机则不同,他有着非常成熟的技术,这方面的参考文献也很多,而且他从来就是用于控制方面的,在这方面有着天生的优势。还有他价格也不贵,仅几元人民币。对于这样的应用系统比较划得来。其次在恒流源方面,我们方案也很好。从理论上看,运放是接成比较器的,作为模拟反馈的,这样在只要运放的输入不变,那么三极管的Vbe是不变的,根据三极管的共射极输入特性可知,Vbe不变时,Ie和Ic也保持不变,而且Ic=βIb, Ie=(1+β)Ib 。当β比较大时Ic≈Ie 。当运放的输入改变时,也改变了Vbe值,这样也就改变了Ic和Ie的值,而且这个变化基本也是呈线性的。这也就是本系统的恒流原理。由于器件受温度的影响以及局部非线性的存在,这样的恒流源不能做到真正的恒流,因此,当外界条件发生变化时,我们要及时给予补偿,只有这样才能做到真正的恒流。这也就是为什么要加入模数转换器的真正原因,他能实时测量电流的变化并按照一定的算法及时给予补偿,采用数字补偿逐次逼近的方式作为反馈调整环节,由程序控制调节功率管的输出。当改变负载大小时,基本上不影响电流的输出。模数转换器还起到测量的作用,同时送显示让我们知道实际的电流输出值。

2.3 AT89C52最小系统

2.3.1 AT89C52芯片简介

              采用AT89C52是MSC-51系列单片机的升级版,由世界著名半导体公司 ATMEL在购买MSC-51设计结构后,利用自身优势技术——闪存生产技术对旧技术进行改进和扩展,同时使用新的半导体生产工艺,最终得到成型产品。与此同时,世界上其他的著名公司也通过基本的51内核,结合公司自身技术进行改进生产,推广了一批如51F020等高性能单片机。AT89C52片内集成256字节程序运行空间, 8K字节Flash存储空间,支持最大64k外部存储扩展。根据不同的运行速度和功耗的要求,时钟频率可以设置在0-33M之间。片内资源有4组I/O控制端口、3个定时器、8个中断、软件设置低耗能模式、看门狗和断电保护。可以在4V到5.5V宽电压范围内正常工作。不断发展的半导体工艺也让该单片机的功耗不断降低。同时,该单片机支持计算机并口下载,简单的数字芯片就可以制成下载线,仅仅几块钱的价格让该型号单片机畅销 10 年不衰。根据不同场合的要求,这款单片机提供了多种封装,本次设计根据最小系统有时需要更换单片机的具体情况,使用双列直插PID-40 的封装。

2.3.2 AT89C52最小系统组成

AT89C52最小系统由AT89C52芯片、复位电路和时钟电路组成。复位电路和时钟电路是维持单片机最小系统运行的基本模块。时钟电路采用12M晶振组成。复位电路通常分为两种:上电复位和手动复位。有时系统在运行过程中出现程序跑飞的情况,在程序开发过程中,经常需要手动复位,所以本次设计选用手动复位。
图3 AT89C52最小系统图

2.4 3*4按键键盘

键盘使用12个弹跳按钮形成3*4输入键盘,按钮键值为“0-9”、“确定”和“设置”。“0-9”一共10个按钮实现所需输出电流值的输入控制,控制范围为310mA-3100mA; “确定”键实现数据计算并输出所需电压,以控制电流源的输出电流;“设置”键实现二次数据输入,按下时会使数值返回默认值,以达到电流值的重新输入。
图4 3*4按键输入模块

2.5 LCD1602显示模块

2.5.1 LCD1602简介

点阵图形式液晶由M×N个显示单元组成,假设LCD显示屏有64行,每行有128列,每8列对应1字节的8位,即每行由16字节,共16×8=128个点组成。显示屏上64×16个显示单元与显示RAM区的1024字节相对应,每一字节的内容与显示屏上相应位置的亮暗对应。例如显示屏第一行的亮暗由RAM区的000H~00FH的16字节的内容决定,当(000H)=FFH时,屏幕左上角显示一条短亮线,长度为8个点;当(3FFH)=FFH时,屏幕右下角显示一条短亮线;当(000H)=FFH,(001H)=00H,(002H)=00H…,(00EH)=00H,(00FH)=00H时,在屏幕的顶部显示一条由8条亮线和8条暗线组成的虚线。这就是LCD显示的基本原理。
字符型液晶显示模块是一种专门用于显示字母、数字和符号等的点阵式LCD,目前常用16×1,16×2,20×2和40×2等的模块。一般的LCD1602字符型液晶显示器的内部控制器大部分为HD44780,能够显示英文字母、阿拉伯数字、日文片假名和一般性符号。

2.5.2 LCD1602连接与控制

LCD1602显示模块与单片机P2.5、P2.6、P2.7以及P0口连接,通过单片机编写LCD控制子程序,实现LCD1602的数据传输和显示控制。以显示用户输入电流的值以及电流源最后输出的值。通过LCD1602实现人机交互的功能,以达到实时显示输出电流大小的显示。
图5 LCD1602显示模块

2.6 AD/DA转换模块

2.6.1 PCF8591简介

PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。PCF8591具有4个模拟输入、1个模拟输出和1个串行I2C总线接口。PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。

2.6.2 PCF8591转换模块

由于系统要求同时要求AD/DA转换,而如果采用单独的AD/DA芯片,需要的控制引脚比较多,而PCF8591芯片集成了4个AD转换引脚和一个DA转换引脚,适合系统的所需的要求,同时使用I2C通信协议,只需要连接单片机两个引脚,节约了单片机的引脚,并且使用简单,控制方便。
图6 AD/DA转换模块

2.7 可控电流源模块

用“运放 +大功率三极管”的结构构成恒流源。大功率三极管选用 TIP122 型号,它是应用范围广、功率小、频率低的达林顿,NPN 极性型,特征频率 :1000(MHz),集电极允许电流:8(A),集电极最大允许耗散功率:48(W)。其性能满足本设计要求,同时可以通过功率管的不同容量来满足不同的应用要求。采用常用的大功率电阻作为采样电阻,输出电流波动比较大,而康锰铜丝是一种温度特性佳的阻性元件,选其作为取样电阻,其两端电压正比于流过的电流,因此该电压的反馈就是负载电流的反馈。
图7可控电流源模块

3. 程序设计

3.1主程序:


  1. ///*************************************************************************
  2. ///工业生产中的产品数量自动计量系统创新设计
  3. ///功能:通过MUC-51芯片控制电流源输出电流,实现LED灯亮度控制
  4. ///*************************************************************************
  5. #include<reg52.h>
  6. #include<iic.h>
  7. #include<lcd1602.h>

  8. #define KEY_PRESET(code) { P1=code; temp=P1; temp=temp&code; delay(10);}

  9. uchar str1[16]="310mA<=I<=3100mA";
  10. uchar str2[16]="set:    out:    ";
  11. uchar str3[16]=" Error occurred ";
  12. uchar dianliu[4]={0,0,0,0};

  13. uchar key_num,key_flag,key_count=0,OK_flag;
  14. ulong pian,bai,shi,ge,set_value;
  15. float key_value;
  16. uchar h,l,temp;
  17. ulong back_voltage1,back_current;

  18. void get_Data();
  19. void set_Data();
  20. uchar keyscan();
  21. bit DACconversion(uchar sla,uchar c,uchar Val);
  22. bit ISendByte(uchar sla,uchar c);
  23. uchar IRcvByte(uchar sla);
  24. void delay1(uint j);
  25. ///*************************************************************************
  26. ///主函数
  27. ///*************************************************************************
  28. void main()
  29. {
  30.               INIT_I2c();//iic总线初始化
  31.               LCD_Init();//LCD1602初始化
  32.               while(1)
  33.               {            
  34.                             get_Data();
  35.                             set_Data();            
  36.               }                                         
  37.             
  38. }

  39. //*******************************************************************
  40. //DAC 变换, 转化函数              
  41. //*******************************************************************
  42. bit DACconversion(uchar sla,uchar c,  uchar Val)
  43. {
  44.    Start_I2c();              //启动总线
  45.    SendByte(sla);            //发送器件地址
  46.    if(ack==0)return(0);
  47.    SendByte(c);              //发送控制字节
  48.    if(ack==0)return(0);
  49.    SendByte(Val);            //发送DAC的数值
  50.    if(ack==0)return(0);
  51.    Stop_I2c();               //结束总线
  52.    return(1);
  53. }
  54. //*******************************************************************
  55. //ADC发送字节[命令]数据函数              
  56. //*******************************************************************
  57. bit ISendByte(uchar sla,uchar c)
  58. {
  59.    Start_I2c();              //启动总线
  60.    SendByte(sla);            //发送器件地址
  61.    if(ack==0)return(0);
  62.    SendByte(c);              //发送数据
  63.    if(ack==0)return(0);
  64.    Stop_I2c();               //结束总线
  65.    return(1);
  66. }
  67. //*******************************************************************
  68. //ADC读字节数据函数              
  69. //*******************************************************************
  70. uchar IRcvByte(uchar sla)
  71. {
  72.               uchar c;
  73.    Start_I2c();          //启动总线
  74.    SendByte(sla+1);      //发送器件地址
  75.    if(ack==0)return(0);
  76.    c=RcvByte();          //读取数据0
  77.    Ack_I2c(1);           //发送非就答位
  78.    Stop_I2c();           //结束总线
  79.    return(c);
  80. }
  81. ///*************************************************************************
  82. ///按键扫描函数
  83. ///*************************************************************************
  84. uchar keyscan()
  85. {
  86.      KEY_PRESET(0X0F);
  87.               if(temp!=0X0F)//是否有键按下
  88.               {
  89.                             delay(10);
  90.                             temp=P1;
  91.                             temp=temp&0X0F;
  92.                             if(temp!=0X0F) //确实有键按下
  93.                             {
  94.                                key_flag=1;//按下键标志位
  95.                                switch(temp)
  96.                                {
  97.                                              case 0X0E:h=0;break; //行
  98.                                           case 0X0D:h=1;break;
  99.                                              case 0X0B:h=2;break;
  100.                                              case 0X07:h=3;break;
  101.                                           default:break;
  102.                                }
  103.                                KEY_PRESET(0XF0);
  104.                                switch(temp)
  105.                                {
  106.                                              case 0XE0:l=0;break; //列
  107.                                           case 0XD0:l=1;break;
  108.                                              case 0XB0:l=2;break;
  109.                                           case 0X70:l=3;break;
  110.                                           default:break;
  111.                                }
  112.                                key_num=3*h+l;//按下键的键值
  113.                      if(key_num<=9) key_count++;
  114.                                while(temp!=0XF0)//等待释放
  115.                                {
  116.                                                temp=P1;
  117.                                             temp=temp&0XF0;
  118.                                }
  119.                             }
  120.               }            
  121.               return key_num;//返回键值
  122. }
  123. void get_Data()
  124. {
  125.                                uchar i;
  126.                                keyscan(); //键盘扫描
  127.                             if(key_flag==1)//有键按下
  128.                               {
  129.                                           if(key_num<=9&&key_count<5) //只允许输入一个四位的数值
  130.                                              {
  131.                                                              if(key_count==1)//输入电流值第一位
  132.                                                                       {
  133.                                                                                        LCD_Manifest(2,4,keyscan());
  134.                                                                                        pian=keyscan();
  135.                                                                       }
  136.                                                                       if(key_count==2)//输入电流值第二位
  137.                                                                       {
  138.                                                                                        LCD_Manifest(2,5,keyscan());
  139.                                                                                        bai=keyscan();
  140.                                                                       }
  141.                                                                       if(key_count==3)//输入电流值第三位
  142.                                                                       {
  143.                                                                                       LCD_Manifest(2,6,keyscan());
  144.                                                                                        shi=keyscan();
  145.                                                                       }
  146.                                                                       if(key_count==4)//输入电流值第四位
  147.                                                                       {
  148.                                                                                       LCD_Manifest(2,7,keyscan());
  149.                                                                                        ge=keyscan();
  150.                                                                       }
  151.                                                                       key_flag=0;  //按下键标志位清零
  152.                                              }
  153.                                              if(key_num==10&&key_count>=4)//确认键按下
  154.                                                                OK_flag=1;//确认键按下标志位            
  155.                                              if(key_num==11)//设置键按下
  156.                                              {
  157.                                                               OK_flag=0;//确认键按下标志位清零
  158.                                                                         key_count=0; //按下数字计数清零
  159.                                                                         LCD_Write_Cmd(0x80);//数据指针定位到第一行第一个字处
  160.                                                                                     for(i=0;i<16;i++)
  161.                                                                                                   LCD_Write_Data(str1[i]);//液晶显示第一行待?

  162.                                                                         LCD_Write_Cmd(0x80+0x40);//将数据指针定位到第二行第一个
  163.                                                                         for(i=0;i<16;i++)
  164.                                                                                     LCD_Write_Data(str2[i]);//液晶显示第二行写
  165.                                                                         
  166.                                              }
  167.                               }
  168.                              
  169. }
  170. void  set_Data()
  171. {
  172.               if(OK_flag==1) //按下确定键,将数值送给DA
  173.                     {               
  174.                                   uchar i;
  175.                                               key_value=pian*1000+bai*100+shi*10+ge;
  176.                                             if(key_value>=310&&key_value<=3100)
  177.                                             {
  178.                                                           key_value=key_value/5000*255;              
  179.                                                 set_value=(uchar)key_value;//将按键输入值变成整形赋给变量
  180.                                                          
  181.                                                           DACconversion(0x90,0x40,set_value) ; //DAC转换
  182.                                                 delay(100);   
  183.                                                          
  184.                                                           ISendByte(0x90,0x40);//通道一ADC转换
  185.                                                           delay(100);
  186.                                       back_voltage1=IRcvByte(0x90);
  187.                                                                                        
  188.                                                           back_current=back_voltage1*5000/255;
  189.                                                           dianliu[0]=back_current/1000;
  190.                                                           dianliu[1]=back_current%1000/100;
  191.                                                           dianliu[2]=back_current%1000%100/10;
  192.                                                           dianliu[3]=back_current%1000%100%10;


  193.                                                           LCD_Manifest(2,12,dianliu[0]);//输出电流值千位
  194.                                                           LCD_Manifest(2,13,dianliu[1]);//输出电流值百位
  195.                                                 LCD_Manifest(2,14,dianliu[2]);//输出电流值十位
  196.                                                 LCD_Manifest(2,15,dianliu[3]);////输出电流值个位
  197.                                           }
  198.                                           else
  199.                                           {
  200.                                                          
  201.                                              LCD_Write_Cmd(0x80+0x40);//将数据指针定位到第二行第一个
  202.                                                                         for(i=0;i<16;i++)
  203.                                                                                     LCD_Write_Data(str3[i]);//液晶显示第二行写
  204.                                           }
  205.                               }            
  206. }
复制代码

4. 系统仿真

4.1系统仿真图:

图8 系统仿真图

4.2 PCB图

图9 PCB图

4.3 3D视图

图10 3D视图

5. 元器件清单列表

6. 设计总结
  在查找资料的过程中,由于参数比较苛刻,所以很少有例子进行参考,只得尽可能完成自己的设计,在数模和模数转换的芯片中,由于ADC0809和DAC0832两个芯片所需引脚比较多,所以选择比较简单的PCF8591芯片,进行设计,但是同时也是导致电流难以达到设计要求,只能加大负载电压,在电流源的设计中,由于做简单模型,实际应用仍需加许多的支路已达到供电电压的滤波作用,本设计还有许多不能不完善的地方。在这次设计中,我发现一个完整的方案仍然会有很多不足之处,在实际的使用可能还有不稳定的情况,所以,还需要努力学习。




全部资料51hei下载地址:
工业控制系统综合设计.zip (695.03 KB, 下载次数: 62)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:328014 发表于 2020-1-6 02:11 | 只看该作者
好资料,51黑有你更精彩!!!
回复

使用道具 举报

板凳
ID:379452 发表于 2020-6-30 19:37 | 只看该作者
这个设计好的不得了
回复

使用道具 举报

地板
ID:966905 发表于 2021-9-18 10:01 | 只看该作者
真不错,很有用
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表