近段时间我制造了一个集电流源、电压源、充电和烙铁于一身的“四用”电源,同时还有个显示屏显示。在设计过程中,我用到两个单片机,一个负责变量采集,一个主负责显示。于是我的同事就把这个“怪兽”叫做“双核独显”电源。
核心是控制一个由MOS管搭建的一个电压调节板,可以数控电压,因此得到一个电压源;通过电流反馈,调节电压,又得到一个电流源;通过电流电压反馈,得到一个锂电池充电器;通过烙铁温度反馈,得到一个恒温烙铁控制器,思路就是这么来的。单片机是飞思卡尔QD4,两个16bit定时器/PWM ,四通道10bitAD。它的主要功能有:1、电压源;2、电流源;3、充电器;4、恒温烙铁控制器。
下面是电路图:
主控电路
调压电路
调压电路中NMOS借鉴白光烙铁的电路,不过要做快速开关,图中的R9不能太大,我用500欧的,PWM 2KHZ可以。上拉电阻R13也很重要,在单片机异常是,保证关断输出。MOS后端的电路,可以参考DC芯片资料。
其中具体的焊接过程我就忽略不写了,相信大家根据我给的电路图就可以做出相对应的产品。
以下是一些总体图和测试图:
总体的样子
电源输入是用笔记本电源。输出是一个USB口,我平时用不到大电流,3A足够了,步进10ma。最大输出电压接近输入电压,步进0.01V。显示用的是nokia5110显示屏(上图是用5V供电,屏幕有杂点,下面改为3.7V,完美屏)。
输入由一个电位器,一个按键构成。电位器仿照示波器的用法,可以上下选择,也可以输入设定值。按键短按用来“确定”,长按“返回”这些信息由单片机1采集,单线发送给单片机2,显示。单线通信花了不少精力。采样电阻50m欧,用358放大。电流采集后要校正,消除偏差。
做好了这一大堆东西后,我们要对其进行基本的功能测试。
一、电压源
下图中:9.22V是实时采集的真实电压,S:设定值,I:电流
电压输出相应很快,示波器截图
快速扭动电位器,都可以用示波器作画了
二、电流源
下图中:0.44A是实时采集的真实电流,S:设定值,V:电压
三、充电模式
为了测试,把我移动电源的电池芯拆出来了。当时舍得的横流充阶段电流为300ma,这叫一个等啊
不过能看到这么多输出信息,挺爽的
0264mA是累计充电电量,I:当前充电电流,V:电池电压
四、烙铁模式
炊烟袅袅啊……公司的热成像仪送检了,无法校准温度。我是用公式直接算的,感觉偏低了。不过笔记本电源供电,刚刚的。爱死这个烙铁了
介绍一下这个USB烙铁
烙铁是用白光936烙铁柄改的,接了个USB头,外侧做电源线,usb的数据线接反馈电阻。经过测试,3A电流,usb口毫无问题,而且升温也不错,所以程序了限定3A。太大电流,笔记本电源会保护。
以下是我将产品组装进盒子里面的图示:
壳子是拆了一个12V/2A的电源的塑料壳,把这么大一坨东西,塞进去,可是费了功夫。
终于塞的差不多
进去了!!左面一张
右面一张
上面的是开机图片(怎么跟大哥大似的)……
到此为止所有的制作就已经完成了。
在制作过程中,我想给大家说一下我的一些编程方面的经验。
一、时基函数
我现在觉得这个函数应该是每个工程必须的,但回想我看过的单片机书,好像没有讲到这一点的,相见恨晚。
void TimePro()
{
if(!b_8msFG)
return;
b_8msFG = 0;
Tim8ms++;
PIHtim++;
if(KeyTim 《 255)
KeyTim++;
if(PIHtim 》 4)
{
TPM2C0SC = 0x48; //开外部中断
}
LCDTim++;
LCDFlashTim++;
if(Tim1ms 》 124)
{
Tim1ms = 0;
Tim1S++;
……
……
……
}
}
上面就是一个“时基函数”,当你的程序有几个外围需要同时控制时,再用NOP延时,直线执行已经忙不过来了,需要用上面的函数。
b_8msFG在8ms定时中断中置为1。TimePro()在主函数中调用。这样KeyTim、LCDTim这些计时变量就在一直计时。例如调用键盘程序,判断一下KeyTim是否到时间,到了执行,KeyTim清零,不到返回,再去调用别的函数体。这样分时复用CPU,避免了NOP来浪费系统资源,当几个外围执行周期不同时,更是这样 。
二、AD采样(数字滤波)
这个程序是公司的标准模块。大学时,AD采出来,我就直接用了。工作了才发现这样不好,采完后还要做一下数字滤波。数字滤波,不知谁起的这么好听的名字,唬住不少人。其实很简单,但很实用。在这里,实际操作就是:采六次,去掉最大最小值,剩四个求平均。以前对它的作用体会不深,当有一个单片机直接测交流真有效值的项目,一个不堪入目的波形进入单片机,数字滤波后,一下数值稳定不乱跳了,顿生感慨。
下面是程序:
void ADPro()
{
uchar n,i;
if(ADTim 《10) return;
ADTim = 0;
for(n=0;n《6;n++)
{
ADChannel = Channelin; //通道选择;
while(!ADC1SC1_COCO) NOP();//等待转换完成
ADC1SC1_COCO = 0;
ADNum = ADC1R; //取得AD值
// ADNum = 298;
if(0==n)
{
m_ADCSum = 0;
m_ADCMax = ADNum;
m_ADCMin = ADNum;
}
if(ADNum《m_ADCMin)
{
m_ADCMin = ADNum;
}
else if(ADNum》m_ADCMax)
{
m_ADCMax = ADNum;
}
m_ADCSum += ADNum;
ADNum = 0;
}
m_ADCSum=m_ADCSum-m_ADCMax;
m_ADCSum=m_ADCSum-m_ADCMin; //减去最大最小值
m_ADCSum = m_ADCSum》》2; //取均值
switch (Channelin)
{
case 0 :
ADSet = m_ADCSum;
break;
case 1 :
ADI = m_ADCSum;
break;
case 2 :
ADTemp = m_ADCSum;
break;
case 3 :
ADV = m_ADCSum;
break;
default:
break;
}
Channelin ++; //切换通道
if(Channelin 》 3)
Channelin = 0;
}
若是用AD来控制输出,更需要这样做。避免临界值时的误动作 。
三、键盘程序
//---------------------------------
//按键程序
//---------------------------------
void KeyPro()
{
if(KeyScanTim 《200) //20ms scan时基函数中计时
return;
KeyScanTim =0 ;
//KeySet
if(!PI_KeySet)
{
if(b_KeySetBac)
{
if(KeySetCount《255)
KeySetCount ++;
}
else
b_KeySetBac =1;
if(KeySetCount 》6)
{
b_KeySetLong = 1; //长按键,不需放手既可产生
KeyNum = 0;
KeySetCount =0;
b_KeySetBac =0;
LongKeyExitTim = 0;
}
}
else
{
if(b_KeySetBac && LongKeyExitTim 》 2)//防止长按后,产生一个多余的短按键
{
b_KeySet = 1; //短按键,放手后产生
KeyNum = 0;
}
b_KeySetBac =0;
KeySetCount = 0;
}
}
一个按键,既可响应长按,也可响应短按 。
评论
查看更多