在單片機系統里對模擬量的處理要比數字量稍顯復雜,但是只要掌握了使用技巧,使用起來也很簡單,很多朋友一開始比較糾結于單片機的底層語言,非要先弄個明白才罷休,其實大可不必,重要的是我們要先學會怎么應用。
現以鉛酸電池電壓檢測及充電電流檢測為例講解模擬量的硬件和程序的設計。
如圖1為28節鉛酸電池的電壓檢測電路,1--14節組成電池組1,15--28節組成電池組2;第1節正極為BAT+,14與15節之間為BATM,第28節負極為BAT-。輸入端的8個二極管的作用是鉗位作用;電路計算如圖所示。
圖1:電池組電壓檢測電路
如圖2為鉛酸電池的充電電流檢測電路,TA1為工頻電流互感器,輸入的4個二極管為整流二極管,電流流過R37(510Ω)形成壓差△V。電路計算如圖所示。
圖2:電池組充電電流檢測電路
如圖3為單片機STM32F103CBT6,圖1和圖2的模擬信號輸入至單片機的PA5、PA6、PA7。
圖3:STM32F103CBT6單片機
由于代碼較多,為便于瀏覽,我就把其中一部分以截圖的形式展示
如圖4為單片機adc.c文件的底層配置,把PA5、PA6、PA7端口配置成模擬輸入模式。
圖4:配置端口模式
如圖5對以上三個模擬量進行模數轉換并緩存入數組ADC_ConvertedValue[3],得到的AD值的范圍是0~4096。
圖5:模數轉換并緩存
如圖6把以上兩個配置函數整合在一起,定義成模擬量的初始化函數void ADC1_Init(void)。
圖6:初始化
如圖7在adc.h文件里聲明函數void ADC1_Init(void),另外幾個函數也在adc的c文件里定義的,后面附上源程序(非截圖)。
圖7:聲明函數
如圖8在main()主函數里調用ADC1_Init()初始化函數(要去掉void),初始化函數一定要放在while(1)的前面,表示在進入while(1)無限循環前只執行一次。Analog_Processing()為模擬量處理函數,要放在while(1)無限循環里面(該函數在下面講)。
圖8,函數調用
以下為模擬量在main.c文件里的定義。
s16 Charging_Current; //充電電流實際值
s16 Battery1_Voltage; //電池組1電壓實際值
s16 Battery2_Voltage; //電池組2電壓實際值
s16 Battery_Voltage; //電池組總電壓值
下面三個函數的定義都在adc.c文件里面定義的。
以下代碼為模擬量處理函數:①對數組ADC_ConvertedValue[3]緩存值進行濾波處理;②對濾波后的AD值轉換為實際值。
/******************************
模擬量處理函數
******************************/
void Analog_Processing(void)
{
//對AD值進行濾波
ADC_Charging_Current=Filter(ADC_ConvertedValue[0],ADC_Charging_Current,1,10);
ADC_Battery1_Voltage=Filter(ADC_ConvertedValue[1],ADC_Battery1_Voltage,1,10);
ADC_Battery2_Voltage=Filter(ADC_ConvertedValue[2],ADC_Battery2_Voltage,1,10);
//AD值轉換為實際值
Charging_Current = Adc_To_Act(ADC_Charging_Current, 10, 4096, 0, 220);//22.0A
Battery1_Voltage = Adc_To_Act(ADC_Battery1_Voltage, 10, 4096, 0, 267);//267V
Battery2_Voltage = Adc_To_Act(ADC_Battery2_Voltage, 10, 4096, 0, 267);//267V
//兩組電壓相加得到總電壓
Battery_Voltage = Battery1_Voltage + Battery2_Voltage;
}
以下代碼為濾波函數,濾波函數有很多,采用合適的才是最實用的(該函數濾波后的值是連續變化的,有些濾波函數濾波后的值是跳變的)。
/******************************
濾波函數(base/k越大,容性越大)
該函數相當于是一個電容,通常取值k=1,base=10
******************************/
u16 Filter(u16 NewData, u16 OldData, u8 k, u8 base)
{
u16 uiResult;
if (NewData 》 OldData)
{
uiResult = NewData - OldData;
uiResult *= k;
uiResult += base 》》 2;
uiResult /= base;
uiResult = OldData + uiResult;
}
else if (OldData 》 NewData)
{
uiResult = OldData - NewData;
uiResult *= k;
uiResult += base 》》 2;
uiResult /= base;
uiResult = OldData - uiResult;
}
else
{
uiResult = NewData;
}
return(uiResult);
}
使用方法如下:NewData表示最新采用的模擬量;OldData表示濾波后的模擬量。
ADC_Battery1_Voltage=Filter(ADC_ConvertedValue[1],ADC_Battery1_Voltage,1,10);
為便于邏輯計算、控制及顯示,以下代碼是把AD值轉換為實際值,
/******************************
AD值轉換實際值函數
******************************/
s16 Adc_To_Act(s16 Adc_Value, s16 Pre_Adc_Min, s16 Pre_Adc_Max, s16 Pre_Act_Min, s16 Pre_Act_Max)
{
s32 _temp;
s32 _range;
_temp = (s32)((Adc_Value - Pre_Adc_Min) * (Pre_Act_Max - Pre_Act_Min) / (Pre_Adc_Max-Pre_Adc_Min)) + Pre_Act_Min;
_temp = Adc_Value - Pre_Adc_Min;
_range = Pre_Act_Max - Pre_Act_Min;
_temp = _temp * _range;
_range = Pre_Adc_Max - Pre_Adc_Min;
_temp = _temp + _range / 2;
_temp = _temp / _range;
_temp = _temp + Pre_Act_Min;
return(_temp);
}
使用方法如下:Adc_Value表示要轉換的模擬量;Pre_Adc_Min表示模擬量AD值的最小值;Pre_Adc_Max表示模擬量AD值的最大值;Pre_Act_Min表示轉換后實際值的最小值;Pre_Act_Max表示轉換后實際值的最大值;(以下最大實際值220表示22.0A,是因為數碼管顯示需要小數表示)。
Charging_Current = Adc_To_Act(ADC_Charging_Current, 10, 4096, 0, 220);//22.0A
要點:
①模擬量的采樣電路,我多采用運放的差分放大電路,原因是被測電壓可以和運放不用共地,且可有效抑制共模噪聲,可達到較高的精確線性測量,比如以上電池組的被測電壓的誤差與實際相差在0.3V左右;
②電池組輸入至運放的8個1M的電阻是兩個為一組的,且功率至少1/4W以上,因為在高壓下的電阻容易老化,為保險起見,通常一個電阻的最大壓差在100V以下為宜;
③電池組分為兩組檢測,一是為了降低元件所承受的電壓,二是為了監視兩組電池電壓之間是否平衡,達到保護電池目的。
③函數應功能模塊化,且具備通用性質,便于移植和調用,對于很多朋友應先學會如何使用,底層代碼只要會配置就完全足夠了。
當然,以上提供的設計是我通常的做法,能滿足大多數的常規應用。
編輯:lyn
-
鉛酸電池
+關注
關注
8文章
264瀏覽量
25582 -
模擬量
+關注
關注
5文章
491瀏覽量
25505 -
硬件
+關注
關注
11文章
3252瀏覽量
66113
原文標題:模擬量采集從硬件到程序,從濾波到實際值轉換,多少人懂了
文章出處:【微信號:mcu168,微信公眾號:硬件攻城獅】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論