用单片机控制总装车间中的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主程序:
- ///*************************************************************************
- ///工业生产中的产品数量自动计量系统创新设计
- ///功能:通过MUC-51芯片控制电流源输出电流,实现LED灯亮度控制
- ///*************************************************************************
- #include<reg52.h>
- #include<iic.h>
- #include<lcd1602.h>
-
- #define KEY_PRESET(code) { P1=code; temp=P1; temp=temp&code; delay(10);}
-
- uchar str1[16]="310mA<=I<=3100mA";
- uchar str2[16]="set: out: ";
- uchar str3[16]=" Error occurred ";
- uchar dianliu[4]={0,0,0,0};
-
- uchar key_num,key_flag,key_count=0,OK_flag;
- ulong pian,bai,shi,ge,set_value;
- float key_value;
- uchar h,l,temp;
- ulong back_voltage1,back_current;
-
- void get_Data();
- void set_Data();
- uchar keyscan();
- bit DACconversion(uchar sla,uchar c,uchar Val);
- bit ISendByte(uchar sla,uchar c);
- uchar IRcvByte(uchar sla);
- void delay1(uint j);
- ///*************************************************************************
- ///主函数
- ///*************************************************************************
- void main()
- {
- INIT_I2c();//iic总线初始化
- LCD_Init();//LCD1602初始化
- while(1)
- {
- get_Data();
- set_Data();
- }
-
- }
-
- //*******************************************************************
- //DAC 变换, 转化函数
- //*******************************************************************
- bit DACconversion(uchar sla,uchar c, uchar Val)
- {
- Start_I2c(); //启动总线
- SendByte(sla); //发送器件地址
- if(ack==0)return(0);
- SendByte(c); //发送控制字节
- if(ack==0)return(0);
- SendByte(Val); //发送DAC的数值
- if(ack==0)return(0);
- Stop_I2c(); //结束总线
- return(1);
- }
- //*******************************************************************
- //ADC发送字节[命令]数据函数
- //*******************************************************************
- bit ISendByte(uchar sla,uchar c)
- {
- Start_I2c(); //启动总线
- SendByte(sla); //发送器件地址
- if(ack==0)return(0);
- SendByte(c); //发送数据
- if(ack==0)return(0);
- Stop_I2c(); //结束总线
- return(1);
- }
- //*******************************************************************
- //ADC读字节数据函数
- //*******************************************************************
- uchar IRcvByte(uchar sla)
- {
- uchar c;
- Start_I2c(); //启动总线
- SendByte(sla+1); //发送器件地址
- if(ack==0)return(0);
- c=RcvByte(); //读取数据0
- Ack_I2c(1); //发送非就答位
- Stop_I2c(); //结束总线
- return(c);
- }
- ///*************************************************************************
- ///按键扫描函数
- ///*************************************************************************
- uchar keyscan()
- {
- KEY_PRESET(0X0F);
- if(temp!=0X0F)//是否有键按下
- {
- delay(10);
- temp=P1;
- temp=temp&0X0F;
- if(temp!=0X0F) //确实有键按下
- {
- key_flag=1;//按下键标志位
- switch(temp)
- {
- case 0X0E:h=0;break; //行
- case 0X0D:h=1;break;
- case 0X0B:h=2;break;
- case 0X07:h=3;break;
- default:break;
- }
- KEY_PRESET(0XF0);
- switch(temp)
- {
- case 0XE0:l=0;break; //列
- case 0XD0:l=1;break;
- case 0XB0:l=2;break;
- case 0X70:l=3;break;
- default:break;
- }
- key_num=3*h+l;//按下键的键值
- if(key_num<=9) key_count++;
- while(temp!=0XF0)//等待释放
- {
- temp=P1;
- temp=temp&0XF0;
- }
- }
- }
- return key_num;//返回键值
- }
- void get_Data()
- {
- uchar i;
- keyscan(); //键盘扫描
- if(key_flag==1)//有键按下
- {
- if(key_num<=9&&key_count<5) //只允许输入一个四位的数值
- {
- if(key_count==1)//输入电流值第一位
- {
- LCD_Manifest(2,4,keyscan());
- pian=keyscan();
- }
- if(key_count==2)//输入电流值第二位
- {
- LCD_Manifest(2,5,keyscan());
- bai=keyscan();
- }
- if(key_count==3)//输入电流值第三位
- {
- LCD_Manifest(2,6,keyscan());
- shi=keyscan();
- }
- if(key_count==4)//输入电流值第四位
- {
- LCD_Manifest(2,7,keyscan());
- ge=keyscan();
- }
- key_flag=0; //按下键标志位清零
- }
- if(key_num==10&&key_count>=4)//确认键按下
- OK_flag=1;//确认键按下标志位
- if(key_num==11)//设置键按下
- {
- OK_flag=0;//确认键按下标志位清零
- key_count=0; //按下数字计数清零
- LCD_Write_Cmd(0x80);//数据指针定位到第一行第一个字处
- for(i=0;i<16;i++)
- LCD_Write_Data(str1[i]);//液晶显示第一行待?
-
- LCD_Write_Cmd(0x80+0x40);//将数据指针定位到第二行第一个
- for(i=0;i<16;i++)
- LCD_Write_Data(str2[i]);//液晶显示第二行写
-
- }
- }
-
- }
- void set_Data()
- {
- if(OK_flag==1) //按下确定键,将数值送给DA
- {
- uchar i;
- key_value=pian*1000+bai*100+shi*10+ge;
- if(key_value>=310&&key_value<=3100)
- {
- key_value=key_value/5000*255;
- set_value=(uchar)key_value;//将按键输入值变成整形赋给变量
-
- DACconversion(0x90,0x40,set_value) ; //DAC转换
- delay(100);
-
- ISendByte(0x90,0x40);//通道一ADC转换
- delay(100);
- back_voltage1=IRcvByte(0x90);
-
- back_current=back_voltage1*5000/255;
- dianliu[0]=back_current/1000;
- dianliu[1]=back_current%1000/100;
- dianliu[2]=back_current%1000%100/10;
- dianliu[3]=back_current%1000%100%10;
-
-
- LCD_Manifest(2,12,dianliu[0]);//输出电流值千位
- LCD_Manifest(2,13,dianliu[1]);//输出电流值百位
- LCD_Manifest(2,14,dianliu[2]);//输出电流值十位
- LCD_Manifest(2,15,dianliu[3]);////输出电流值个位
- }
- else
- {
-
- LCD_Write_Cmd(0x80+0x40);//将数据指针定位到第二行第一个
- for(i=0;i<16;i++)
- LCD_Write_Data(str3[i]);//液晶显示第二行写
- }
- }
- }
复制代码
4. 系统仿真 4.1系统仿真图: 图8 系统仿真图 4.2 PCB图 图9 PCB图 4.3 3D视图 图10 3D视图 5. 元器件清单列表 6. 设计总结
在查找资料的过程中,由于参数比较苛刻,所以很少有例子进行参考,只得尽可能完成自己的设计,在数模和模数转换的芯片中,由于ADC0809和DAC0832两个芯片所需引脚比较多,所以选择比较简单的PCF8591芯片,进行设计,但是同时也是导致电流难以达到设计要求,只能加大负载电压,在电流源的设计中,由于做简单模型,实际应用仍需加许多的支路已达到供电电压的滤波作用,本设计还有许多不能不完善的地方。在这次设计中,我发现一个完整的方案仍然会有很多不足之处,在实际的使用可能还有不稳定的情况,所以,还需要努力学习。
全部资料51hei下载地址:
工业控制系统综合设计.zip
(695.03 KB, 下载次数: 65)
|