近段時間我制造了一個集電流源、電壓源、充電和烙鐵于一身的“四用”電源,同時還有個顯示屏顯示。在設計過程中,我用到兩個單片機,一個負責變量采集,一個主負責顯示。于是我的同事就把這個“怪獸”叫做“雙核獨顯”電源。
核心是控制一個由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;
}
}
一個按鍵,既可響應長按,也可響應短按 。
?
?
評論
查看更多