Всем привет. Имею скетч (не мой). Есть часть кода, которая измеряет напряжение на ардуинке. Код (C++): // return current VCC voltage in mV unsigned long readVCC() { unsigned long result; // Read 1.1V reference against AVcc ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA, ADSC)); result = ADCL; result |= ADCH << 8; result = 1126400L / result; // Back-calculate AVcc in mV return result; } Хочу сделать так, что-бы напряжение замерялось на аналоговом пине A4. На данный момент сделал так: Использовал опорное 1.1в. Код (C++): // return current VCC voltage in mV unsigned long readVCC() { unsigned long result; int val = analogRead(A4); result = (val / 1023 ) * 1100; return result; При подключении li-ion акб показало 1.1 вольт. Понял, что максимальное измеряемое напряжение будет 1.1в, что меня не устроило и решил сделать опорное 5 вольт. Делитель городить не захотел ибо он внесет свои погрешности. А вот 5 вольт у меня стабилизированы хорошо ( до сотых ) и измерять можно будет до 5 вольт. Код изменил, поменял множитель, прописал вместо Код (C++): analogReference(INTERNAL); Код (C++): analogReference(DEFAULT); Теперь напряжение не замеряет и показывает 0 вольт. На всякий случай прикладываю полный код.
Спасибо большое, все заработало, даже не знал о существовании данной функции. Код (C++): // return current VCC voltage in mV unsigned long readVCC() { unsigned long result; int val = analogRead(A4); result = map(val, 0, 1023, 0, 5000); return result; Serial.print(result); Теперь буду её использовать. А почему тогда (val / 1023 ) * 1100 не работало должным образом? Очень интересно. На другом проекте все отлично работало.
Целочисленное деление val / 1023 округляется до целого отбросом дробной части. В "другом проекте" может быть тип val был не целым или порядок операторов был другой.
Функция map() тоже целочисленная, точность не особо хорошая. Лучше так: Код (C++): long fmap(long x, long in_min, long in_max, long out_min, long out_max) { return floor(0.5 + (float)((x - in_min) * (out_max - out_min)) / (float)(in_max - in_min) + out_min); }
Хм... зачем так сложно-то? в итоге в скобках перемудрили, у вас "+ out_min" попал в знаменатель дроби, а ему там не место. Кроме того, действительные числа нам нужны только в операции деления, целочисленные сложение и умножение ошибок не дают, поэтому достаточно привести к действительному типу один из перандов - либо числитель, либо знаменатель. Код (C++): long fmap(long x, long in_min, long in_max, long out_min, long out_max) { return floor(0.5 + out_min + (float)((x - in_min) * (out_max - out_min)) / (in_max - in_min) ); } а вообще, в изначальном коде достаточно было добавить два символа, чтобы все заработало: (val / 1023.0 ) * 1100
Это не я перемудрил, вот оригинальная функция map из IDE 1.6.5 : Код (C++): long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
И это будет лучше, чем целочисленный map(). Только памяти съест много и скорости под плавающую точку.