ADC de bir lineerlik hatası var. Bu tip basit ADC lerde olur zaten.
Öncelikle R1 ve R2 gerilim bölücü dirençleri sök, soğumasını bekle. Sonra da tam olarak direnç değerlerini ölç ve bir kenara yaz. Cihaz 1 saat çalışsın, sonra da AREF i ölç ve bir kenara yaz.
Bir de şu anda kullandığın formülü de yaz. Daha önceki mesajlarda belki vardır bu bilgiler ama şu an için bir özet olması bakımından yeniden yazmakta fayda var. Formül ile olabilecek en yakın sonucu elde edelim.
Bunu elde edince, geri kalan hatayı da interpolasyon ile çözmen gerekecek. Mesela 10 farklı voltaj ölçümünü yapıp gerçek voltaj, hesaplanan voltaj tablosu yapacaksın. Sonra bu tabloya göre ölçülen değeri düzelteceksin. Ama önce yukarıdakileri halledelim. interpolasyonu sonra yaparız.
MULTİMETRE | EKRAN |
5.04V | 4.99V |
7.546V | 7.51V |
10V | 9.98V |
12.437V | 12.39V |
15.14V | 15.08V |
17.5V | 17.43V |
20.05V | 19.83V |
22.5V | 21.99V |
25.16V | 24.01 |
//Voltaj Değişkenleri ///////////////
const int voltajRead = A6;
int voltajDeger = 0;
const float R1 = 17996.0;
const float R2 = 3229.0;
float voltaj = 0.0;
float girisVoltaji = 0.0;
//////////////////////////////////////
// Voltaj Okuma Kodları /////////////////////////////////////////
voltajDeger = analogRead(voltajRead);
voltaj = (voltajDeger * 4.995) / 1023;
girisVoltaji = voltaj * (R1 + R2) / R2;
///////////////////////////////////////////////////////////////
float gercek_deger[] =
{
5.04,
7.546,
*
*
*
};
float olculen_deger[] =
{
4.99,
7.51,
*
*
*
};
#include <stdio.h>
// Function to perform interpolation
float interpolate(float adc_table[], float real_table[], int size, float adc_value) {
// Clamp adc_value to the bounds of adc_table
if (adc_value <= adc_table[0]) {
return real_table[0];
} else if (adc_value >= adc_table[size - 1]) {
return real_table[size - 1];
}
// Find the segment [i, i+1] containing adc_value
int i;
for (i = 0; i < size - 1; i++) {
if (adc_table[i] <= adc_value && adc_value < adc_table[i + 1]) {
break;
}
}
// Perform linear interpolation
float adc_low = adc_table[i];
float adc_high = adc_table[i + 1];
float real_low = real_table[i];
float real_high = real_table[i + 1];
float real_value = real_low + ((adc_value - adc_low) / (adc_high - adc_low)) * (real_high - real_low);
return real_value;
}
int main() {
// Example tables
float adc_table[10] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0};
float real_table[10] = {0.0, 0.95, 1.8, 2.7, 3.55, 4.4, 5.2, 6.1, 7.0, 7.9};
// Test with a sample adc_value
float adc_value = 3.25;
float real_value = interpolate(adc_table, real_table, 10, adc_value);
printf("ADC Value: %.2f, Real Value: %.2f\n", adc_value, real_value);
return 0;
}
Eve geçeyim bakacağım abi. Biraz dışarı çıkmam gerekti. Ben çıkmayalı çok şey değişmiş dışarıda.Böyle bir algoritmayı hemen chatgpt ye yazdırabilirsin, ama doğru çalışmazsa sarfedeceğin zaman, yeni yazmaktan daha uzun olabilir Ama mantığını anlaman için bana verdiği cevabı ekleyeyim buraya
38526 eklentisine bak
Şu da ürettiği kod. Bana çok kalabalık geldi, ama dediğim gibi, olayın mantığını anlamak için kullan, aynen kopyama
C:#include <stdio.h> // Function to perform interpolation float interpolate(float adc_table[], float real_table[], int size, float adc_value) { // Clamp adc_value to the bounds of adc_table if (adc_value <= adc_table[0]) { return real_table[0]; } else if (adc_value >= adc_table[size - 1]) { return real_table[size - 1]; } // Find the segment [i, i+1] containing adc_value int i; for (i = 0; i < size - 1; i++) { if (adc_table[i] <= adc_value && adc_value < adc_table[i + 1]) { break; } } // Perform linear interpolation float adc_low = adc_table[i]; float adc_high = adc_table[i + 1]; float real_low = real_table[i]; float real_high = real_table[i + 1]; float real_value = real_low + ((adc_value - adc_low) / (adc_high - adc_low)) * (real_high - real_low); return real_value; } int main() { // Example tables float adc_table[10] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; float real_table[10] = {0.0, 0.95, 1.8, 2.7, 3.55, 4.4, 5.2, 6.1, 7.0, 7.9}; // Test with a sample adc_value float adc_value = 3.25; float real_value = interpolate(adc_table, real_table, 10, adc_value); printf("ADC Value: %.2f, Real Value: %.2f\n", adc_value, real_value); return 0; }
Abi Elektronik yükle zaten bir işimiz kalmadı. Multimetre bağladığımız sürece istediğimiz gibi çalışıyor. Tek yapmamız gereken voltaj ve akımı doğru ölçüp ekrana yansıtmak. Bitirelim aradan çıksın istiyorum. Bu interpolasyon işini ha burada öğrenmişim ha güç kaynağında. Eninde sonunda lazım olacak. Yani bunu bırakıp güç kaynağına da geçsem, orada da bilmiyorum.Orada yapılan iş aslında üçgen benzerliğinden bir oran buluyorsun. O bulunan oranı da düzeltme faktörü olarak kullanıyorsun.
İstersen bu voltaj ölçüm işi üzerinde çalışırken Demonte güç kaynağı V3 üzerinde çalış, böylece ben de burada paralel test ederim. Veya elektronik yük için şimdilik bu voltaj akım ölçüm işini bir kenara bırak ve elektronik yükün kendisini sağlam ve çalışır hale getirelim.
Daha elektronik yükte yapılması gereken bir sürü test var. Sana bir test ve iş planı vereyim
1) Stabil olarak çekilebilecek minimum akım nedir? Yani sürekli olarak değişmeyen, az çok sabit kalan minimum akım nedir?
2) Maksimum voltajı 30V olarak belirledik. Voltaj 30V u geçerse MCU nun çıkışı kesmesi lazım.
3) Maksimum voltajda çekilebilecek maksimum akım nedir? Yani MOSFET lerin sıcaklığının güvenli bir limitte sabit kaldığı maksimum akım nedir?
4) Bu güç limiti belirlendikten sonra, MCU'nun bu güç limitinin belli bir marjını geçtiği anda çıkışı kesmesi lazım.
5) MOSFET sıcaklık limiti aşılırsa çıkışın kesilmesi lazım.
6) Belli bir akım ayarlandığında, voltaj değişirse akım sabit kalıyor mu?
7) Voltajı potansiyometre ile sürekli değiştirirken akım sabit kalıyor mu?
8) Elektronik yükü 1A ayarlayıp akımı 3A yaparsan akım ayarlanan değere düzgün bir şekilde çıkıyor mu? Yoksa overshoot var mı? Varsa ne kadar?
9) Elektronik yükü 3A ayarlayıp akımı 1A yaparsan akım ayarlanan değere düzgün bir şekilde iniyor mu? Yoksa undershoot var mı? Varsa ne kadar?
Bu testlerin yapılıp yükün davranışının net olarak anlaşılması lazım. Ondan sonra artık buna güvenip her yerde rahatlıkla kullanırsın.
Testlerin yapılması kolay yav. Gören de phase margin, loop stability testi yapacağını sanar
// Referans ve ADC ölçümleri ///////////////////////////////////////
float adc_values[] = {5.01, 7.51, 9.98, 12.39, 15.08, 17.43, 19.83, 21.99, 24.01}; // ADC değerleri
float ref_values[] = {5.04, 7.546, 10, 12.437, 15.14, 17.5, 20.05, 22.50, 25.16}; // Multimetre ölçümleri
int num_points = 9; // Veri noktalarının sayısı
////////////////////////////////////////////////////////////////////
// Interpolasyon fonksiyonu ////////////////////////////////////////////////////////////////////
float interpolate(float adc_value) {
for (int i = 0; i < num_points - 1; i++) {
// Eğer adc_value iki nokta arasındaysa
if (adc_value >= adc_values[i] && adc_value <= adc_values[i + 1]) {
// Doğrusal interpolasyon
float slope = (ref_values[i + 1] - ref_values[i]) / (adc_values[i + 1] - adc_values[i]);
return ref_values[i] + slope * (adc_value - adc_values[i]);
}
}
// Eğer aralık dışında bir değer alınırsa, sınır değerleri döndür
if (adc_value < adc_values[0]) return ref_values[0];
if (adc_value > adc_values[num_points - 1]) return ref_values[num_points - 1];
return 0; // Hata durumu
}
/////////////////////////////////////////////////////////////////////////////////////////////////
// Voltaj Okuma Kodları /////////////////////////////////////////
voltajDeger = analogRead(voltajRead);
voltaj = (voltajDeger * 4.995) / 1023;
girisVoltaji = voltaj * (R1 + R2) / R2;
float corrected_voltaj = interpolate(girisVoltaji);
///////////////////////////////////////////////////////////////
display.print("Volt:");
display.println(corrected_voltaj);
Olayı yazılımsal olarak anladım. Bundan sonrası kolay. ver örneği al reel değeri.Özellikle düşük voltaj tarafına fazla örnek vermek lazım. 0.5 1.0 2.0 3.0 gibi. Aynı şekilde üst voltaj sınırına da. Lineerlik buralarda daha kötü oluyor.
Yok ben almıyım o zaman.Kablolarda voltaj düşüyor ondan daha az ölçüyorsun. Eğer güç kaynağının regülasyonu doğru çalışıyormu diye test etmek istiyorsan, ölçümü DOĞRUDAN pass transistörlerin emitter'inden yapman lazım.
// Akım Okuma Kodları ////////////////////////////////////////
akimDeger = analogRead(akimRead);
voltajDususu = (akimDeger * 4.994) / 1023;
akim = voltajDususu / 0.256;
//////////////////////////////////////////////////////////////
Multimetreyi en düşük kademe V moduna alıp kablonun başı ile sonu arasındaki (aynı kablo üzerindeki (-) yada (+)) gerilim düşümünü ölçerseniz sebebini anlayacaksınız.Olayı yazılımsal olarak anladım. Bundan sonrası kolay. ver örneği al reel değeri.
Şimdi bir şey dikkatimi çekti. 14.1V 1A akım çekmeye başladım güç kaynağından. Voltaj 13.47V'a düştü. Bu değer multimetrede de aynı, yük ekranında da aynı. O zaman sorun güç kaynağında oluyor değil mi?