简易数控直流电源设计 1 设计任务设计出有一定输出电压范围和功能的数控电源。 2 设计要求 (1)输出电压:范围0~+9.9V,步进0.1V,纹波不大于10mV; (2)输出电压值由LCD显示; (3)由“+”、“-”两键分别控制输出电压步进增减; (4)输出电压可预置在0~9.9V之间的任意一个值; (5)自制键盘设置电压值。 3 设计原理与总体方案 3.1 总体设计方案 鉴于目前数控直流源一般采取运放构成的电流-电压转换电路与单片机结合,设计方案大多为开环系统,主控制器仅用于数字给定及显示,没有对输出电流进行检测和控制。本文在传统电路设计的基础上,利用控制系统中反馈与控制原理,引入电流负反馈,在采样电阻上获取和电流成正比的采样电压,并接人运算放大器的反向输入端,实现负反馈,形成恒流输出的闭环控制系统; 软件方面,将具有全局寻优能力但收敛速度慢的遗传算法和具有收敛速度快且局部寻优能力强的直接搜索法结合在一起,设计基于遗传算法和直接搜索策略的混合优化算法,充分利用了遗传算法的全局搜索能力并以此作为优化过程的“粗调”,同时利用直接搜索法良好的局部搜索能力作为优化过程的“微调”,集中了两者的优点,而克服了两者的弱点,得到的目标函数值较遗传退火策略更优,而且一致性更好,用于PID参数整定是具有整定速度快,调节时间短,稳态误差小等优点。同时结合PID算法,形成软件闭环,实现对输出电流的精确控制。 系统工作原理如下:由键盘预置电压值,输入到单片机;采样电阻采集的电压信号经D/A转换器送入单片机,当两值之差绝对值为零或不大于设定值时,不作任何调整;当两值之差大于设定值时,运用PID算法进行调整,送人D/A转换,调整输出电压,直到差值在允许的范围内。单片机控制液晶显示电流的设定值、实际输出值和电压步进值。 3.2 显示模块选择 LCD(Liquid Crystal Display)显示器是利用液晶显示技术来进行图像表现的显示装置,从液晶显示器的结构来看,无论是笔记本电脑还是桌面系统,采用的LCD显示屏都是由不同部分组成的分层结构。LCD显示器按照控制方式不同可分为被动矩阵式LCD及主动矩阵式LCD两种。 LCD由两块玻璃板构成,厚约1mm,其间由包含有液晶材料的5μm均匀间隔隔开。因为液晶材料本身并不发光,所以在显示屏两边都设有作为光源的灯管,而在液晶显示屏背面有一块背光板(或称匀光板)和反光膜,背光板是由荧光物质组成的可以发射光线,其作用主要是提供均匀的背景光源。 背光板发出的光线在穿过第一层偏振过滤层之后进入包含成千上万液晶液滴的液晶层。液晶层中的液滴都被包含在细小的单元格结构中,一个或多个单元格构成屏幕上的一个像素。在玻璃板与液晶材料之间是透明的电极,电极分为行和列,在行与列的交叉点上,通过改变电压而改变液晶的旋光状态,液晶材料的作用类似于一个个小的光阀。在液晶材料周边是控制电路部分和驱动电路部分。当LCD中的电极产生电场时,液晶分子就会产生扭曲,从而将穿越其中的光线进行有规则的折射,然后经过第二层过滤层的过滤在屏幕上显示出来。 3.3键盘选择 键盘实际上是一组开关的集合:当开关按下时,两根导线接通;当开关释放时,两根导线断开。我们通过键盘的输入设置预置值。 3.3.1高低电平翻转矩阵键盘 矩阵键盘又称行列键盘,它是用四条I/O线作为行线,四条I/O线作为列线组成的键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4*4个。这种行列式键盘结构能有效地提高单片机系统中I/O口 最常见的键盘一般由16个按键组成,在单片机中正好可以用一个P口实现16个按键功能。当无按键闭合时,P3.0~P3.3与P3.4~P3.7之间开路。当有键闭合时,与闭合键相连的两条I/O口线之间短路。判断有无按键按下的方法是:第一步,置列线P3.4~P3.7为输入状态,从行线P3.0~P3.3输出低电平,读入列线数据,若某一列线为低电平,则该列线上有键闭合。第二步,行线轮流输出低电平,从列线P3.4~P3.7读入数据,若有某一列为低电平,则对应行线上有键按下。综合一二两步的结果,可确定按键编号。但是键闭合一次只能进行一次键功能操作,因此须等到按键释放后,再进行键功能操作,否则按一次键,有可能会连续多次进行同样的键操作。 识别按键的方法很多其中,最常见的方法是扫描法 按键按下时,与此键相连的行线与列线导通,行线在无按键按下时处在高电平。如果所有的列线都处在高电平,则按键按下与否不会引起行线电平的变化,因此必须使所有列线处在电平。这样,当有按键按下时,改键所在的行电平才回由高变低。才能判断相应的行有键按下。 3.3.2独立按键式键盘 独立按键式直接用I/O口线构成的单个按键电路,其特点式每个按键单独占用一根I/O口线,每个按键的工作不会影响其他I/O口线的状态。独立按键的典型应用如图所示。独立式按键电路配置灵活,软件结构简单,但每个按键必须占用一个I/O口线,因此,在按键较多时,I/O口线浪费较大,不宜采用。 独立按键的软件常采用查询式结构。先逐位查询没跟I/O口线的输入状态,如某一根I/O口线输入为低电平,则可确认该I/O口线所对应的按键已按下,然后,再转向该键的功能处理程序。 独立按键数量少,可根据实际需要灵活编码。矩阵键盘,按键的位置由行号和列号唯一确定,因此可以分别对行号和列号进行二进制编码,然后两值合成一个字节,高4位是行号,低4位是列号。相比较而言高低电平反转矩阵键盘占用的I/O接口少,实现的键数较多,比较符合我们的设计需求。 3.4主控芯片选择 51系列是基本型,包括8051、8751、8031、8951.这四个机种区别,仅在于片内程序储存器。8051为4KBROM,8751为4KBEPROM,8031片内无程序储存器,8951为4KBEEPROM。其他性能结构一样,有片内128B RAM,2个16位定时器/计数器,5个中断源。其中,8031性价比较高,又易于开发,目前应用面广泛。 51系列单片机的特点:8位cpu;片内带振荡器,频率范围为1.2MHz~12MHz;片内带128B的数据存储器;片内带4KB的程序存储器;程序存储器的寻址空间为64KB;片外数据存储器的寻址空间为64KB;128个用户位寻址空间;21个字节特殊功能寄存器;4个8位的I/O并行接口:P0、P1、P2、P3;两个16位定时、计数器;两个优先级别的五个中断源;一个全双工的串行I/O接口,可多机通信;111条指令,包含乘法指令和除法指令;片内采用单总线结构;有较强的位处理能力;采用单一+5V电源。
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3001.tmp.png 图1 MCS-51基本结构图 4 硬件电路设计 总体设计图:
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3002.tmp.jpg 图2 电路设计图 4.1 DAC电路 一个8位D/A转换器有8个输入端(其中每个输入端是8位二进制数的一位),有一个模拟输出端。输入可有2^8=256个不同的二进制组态,输出为256个电压之一,即输出电压不是整个电压范围内任意值,而只能是256个可能值。下图是DAC0832的逻辑框图和引脚排列。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3012.tmp.jpg 图3 DAC0832的逻辑框图和引脚排列 D0~D7:数字信号输入端。 ILE:输入寄存器允许,高电平有效。 CS:片选信号,低电平有效。 XFER:传送控制信号,低电平有效。 WR1:写信号1,低电平有效。 WR2:写信号2,低电平有效。 IOUT1、IOUT2:DAC电流输出端。 Rfb:是集成在片内的外接运放的反馈电阻。 Vref:基准电压(-10~10V)。 Vcc:是源电压(+5~+15V)。 DAC0832输出的是电流,所以须经过一个外接的运算放大器转换成电压。 AGND:模拟地 NGND:数字地,可与AGND接在一起使用。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3013.tmp.jpg 图4 DAC电路 4.2矩阵键盘模块 在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图4所示。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3024.tmp.jpg 图5 矩阵式键盘
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3035.tmp.jpg 图6 键盘电路设计 4.3 显示部分 1602液晶也叫1602字符型液晶,它由若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符,每位之间有一个点距的间隔,每行之间也有间隔,起到了字符间距和行间距的作用。1602LCD是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。 1602采用标准的16脚接口,其中:第1引脚:GND为电源地;第2引脚:VCC接5V电源正极;第3引脚:V0为液晶显示器对比度调整端;第4引脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器;第5引脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作;第6引脚:E(或EN)端为使能端,高电平(1)时读取信息,负跳变时执行指令;第7~14引脚:D0~D7为8位双向数据端。第15~16脚:空脚或背灯电源。第15引脚背光正极,第16引脚背光负极。 表1 液晶1602A各个管脚的介绍 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3045.tmp.jpg 图7 LCD电路设计 4.4 自制电源模块 自制电源输出+12V、-12V及+5V的电压 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3046.tmp.jpg 图8 自制电源 4.5 主控芯片 AT89C51 提供以下标准功能:4k 字节Flash 闪速存储器,128字节内部RAM,32 个I/O 口线,两个16位定时/计数器,一个5向量两级中断结构,一个全双工串行通信口,片内振荡器及时钟电路。同时,AT89C51可降至0Hz的静态逻辑操作,并支持两种软件可选的节电工作模式。空闲方式停止CPU的工作,但允许RAM,定时/计数器,串行通信口及中断系统继续工作。掉电方式保存RAM中的内容,但振荡器停止工作并禁止其它所有部件工作直到下一个硬件复位。 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3057.tmp.jpg 图9 主控芯片电路 4.6 放大电路 放大电路是增加电信号幅度或功率的电子电路。应用放大电路实现放大的装置称为放大器。它的核心是电子有源器件,如电子管、晶体管等。为了实现放大,必须给放大器提供能量。常用的能源是直流电源,但有的放大器也利用高频电源作为泵浦源。放大作用的实质是把电源的能量转移给输出信号。 放大电路本身的特点: 一、有静态和动态两种工作状态,所以有时往往要画出它的直流通路和交流通路才能进行分析; 二、电路往往加有负反馈,这种反馈有时在本级内,有时是从后级反馈到前级,所以在分析这一级时还要能"瞻前顾后"。在弄通每一级的原理之后就可以把整个电路串通起来进行全面综合。
file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3058.tmp.jpg 图10 放大电路
5 软件设计流程 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3068.tmp.jpg 图11 软件设计流程图 注:在稳压输出端用万用表的电压档测输出电压,将会基本等于从键盘的输入电压。
6 仿真 6.1 仿真问题及解决 (1)D/A转换电路没有正常工作; 问题原因:D0-D7接口出现错误。 (2)步进0.1的程序出现问题; 问题原因:没有写入浮点型函数。
6.2 仿真结果及分析 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps3069.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps307A.tmp.jpg 图12 输入3.2V电压时的仿真输出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps307B.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps308C.tmp.jpg 图13 输入5.9V电压时的仿真输出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps308D.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps309D.tmp.jpg 图14 输入6.3V电压时的仿真输出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps309E.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps309F.tmp.jpg 图15 输入8.3V电压时的仿真输出值 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps30B0.tmp.jpgfile:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps30B1.tmp.jpg 图16 输入9.1V电压时的仿真输出值
表2 测得的数据和从键盘输入的数据 数据分析: 误差不超过0.03 误差分析: (1)电路中元器件的影响 (2)外界对输出电压的干扰,导致输出有误差
参考文献 [1]唐俊瞿,许雷,张群瞻.单片机原理与应用[M].北京:冶金工业出版社,2003 [2]李广弟,朱月秀,冷祖祁.单片机基础[M].北京:北京航空航天大学出版社,2007 [3]李光飞.单片机课程设计实例指导[M].北京:北京航空航天大学出版社,2004.9 [4]张洪润,兰清华.单片机应用技术教程[M].北京:清华大学出版社,1997.11 [5]李华.MCS—51系列单片机实用接口技术[M]..北京:北京航空航天大学出版社,1993 [6]李朝青.单片机原理及接口技术[M]..北京:北京航空航天大学出版社,1998
附录 仿真图 file:///C:\Users\ADMINI~1\AppData\Local\Temp\ksohtml\wps30C2.tmp.jpg
源程序 #include<reg51.h> /*头文件以及变量定义*/ #include<math.h> #define uchar unsigned char #define uint unsigned int sbit rs=P2^4; sbit rw=P2^5; sbit ea=P2^6; uchar num,i,key,j=0; float a2; uchar keyscan(void); uchar code table[6]="Please"; uchar code table1[16]=" enter letter..."; uchar code table2[16]="0123456789abcde."; float table3[6]; uchar code table4[8]="volt(v):"; uchar code table5[6]="error!"; uchar table6[6]; void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); }
void write_com(uchar com) { rs=0; rw=0; P0=com; delay(5); ea=1; delay(5); ea=0; } void write_date(uchar date) { rs=1; rw=0; P0=date; delay(5); ea=1; delay(5); ea=0; } void disvol() { write_com(0x80+0x40); //写电压 for(num=0;num<8;num++) { write_date(table4[num]); delay(10); } }
void init() { delay(5); write_com(0x38); write_com(0x0c); write_com(0x06); write_com(0x01); write_com(0x80); for(num=0;num<6;num++) { write_date(table[num]); delay(20); } write_com(0x80+0x40); for(num=0;num<0x10;num++) { write_date(table1[num]); delay(20); } } void diserr() { write_com(0x80+0x40); for(num=0;num<6;num++) { write_date(table5[num]); delay(20); } delay(2000); }
void he_zhi() { uint a1,a3,c11,c12; float b1,b2,b3,b4,c1,c2,h; if(table3[0]!='.') //整数加点 { if(!table3[1]) { if(j==1) { table3[1]='.'; } }
if(!table3[2]) { if(j==2) { table3[2]='.'; } }
if(table3[1]=='.') { b1=table3[0]; b2=table3[2]/10; b3=table3[3]/100; h=b1+b2+b3; a2=h*256/10; a3=a2; a1=a3+1; c1=a2-a3; c2=a1-a2; c11=1000*c1; c12=1000*c2; if(c11>c12) { P1=a1; } else { P1=a3; } //光标显示位 if(j==1) { write_com(0x80+0x49); } if(j==3) { write_com(0x80+0x4b); } if(j==4) { write_com(0x80+0x4c); }
}
else if(table3[2]=='.') { b1=table3[0]*10; b2=table3[1]; b3=table3[3]/10; b4=table3[4]/100; h=b1+b2+b3+b4; if(h<=10) { a2=h*256/10; a3=a2; a1=a3+1; c1=a2-a3; c2=a1-a2; c11=1000*c1; c12=1000*c2; if(c11>c12) { P1=a1; } else { if(a3==256) { P1=255; } else { P1=a3; } } if(j==2) { write_com(0x80+0x4a); }
}
else { write_com(0x01); diserr(); } } else { write_com(0x01); diserr(); } }
if(table3[0]=='.') { write_com(0x01); diserr(); }
}
void qingchu(uchar p) { uchar z; for(z=0;z<=5;z++) { table3[z]=p; } } void jia(uchar dat) //步进函数 { switch(dat) { case 0: write_date(table2[1]); break; case 1: write_date(table2[2]); break; case 2: write_date(table2[3]); break; case 3: write_date(table2[4]); break; case 4: write_date(table2[5]); break; case 5: write_date(table2[6]); break; case 6: write_date(table2[7]); break; case 7: write_date(table2[8]); break; case 8: write_date(table2[9]); break; case 9: write_date(table2[0]); break; } table3[2]++; if(table3[2]==10) table3[2]=0; } void jian(uchar dat) { switch(dat) { case 0: write_date(table2[9]); break; case 1: write_date(table2[0]); break; case 2: write_date(table2[1]); break; case 3: write_date(table2[2]); break; case 4: write_date(table2[3]); break; case 5: write_date(table2[4]); break; case 6: write_date(table2[5]); break; case 7: write_date(table2[6]); break; case 8: write_date(table2[7]); break; case 9: write_date(table2[8]); break; } table3[2]--; if(table3[2]==-1) table3[2]=9; }
void main() { init();
delay(4500); write_com(0x01); write_com(0x80+0x40); write_com(0x0f); disvol(); i=0x80+0x48;
while(1) { key=keyscan(); delay(100); switch(key) { case 0xee:write_com(i); write_date(table2[0]);table3[j]=0;j++; // table2[16]="0123456789abcde." i++; break;//0 case 0xde:write_com(i); write_date(table2[1]);table3[j]=1;j++; i++; break;//1 case 0xbe:write_com(i); write_date(table2[2]);table3[j]=2;j++; i++;break;//2 case 0x7e:write_com(i); write_date(table2[3]);table3[j]=3;j++; i++;break;//3 case 0xed:write_com(i); write_date(table2[4]);table3[j]=4;j++; i++;break;//4 case 0xdd:write_com(i); write_date(table2[5]);table3[j]=5;j++; i++;break;//5 case 0xbd:write_com(i); write_date(table2[6]);table3[j]=6;j++; i++;break;//6 case 0x7d:write_com(i); write_date(table2[7]);table3[j]=7;j++; i++;break;//7 case 0xeb:write_com(i); write_date(table2[8]);table3[j]=8;j++; i++;break;//8 case 0xdb:write_com(i); write_date(table2[9]);table3[j]=9;j++; i++;break;//9 case 0xe7:write_com(i); write_date(table2[15]);table3[j]='.';j++; i++;break; case 0xbb:write_com(0x80+0x48+2); jia(table3[2]); break;//加 case 0x7b:write_com(0x80+0x48+2); jian(table3[2]); break;//减 case 0xd7:he_zhi(); i=0x80+0x48; j=0; break; case 0xb7:write_com(0x01); qingchu(0); j=0; disvol(); write_com(0x80+0x48); i=0x80+0x48; break;
} } } uchar keyscan(void) { uchar cord_h,cord_l; P3=0x0f; cord_h=P3&0x0f; if(cord_h!=0x0f) { delay(100); if(cord_h!=0x0f) { cord_h=P3&0x0f; P3=cord_h|0xf0; cord_l=P3&0xf0; return(cord_h+cord_l); } }return(0xff); }
|