Добрый день.
Делаю вольтметр на ATtiny85 и TM1637. За основу взят скетч Самодельный вольтметр для батареек от Sega-san. Алгоритм измерения протестировал контролем по serial. Точность понравилась, практически одна сотая вольта. У автора применен OLED дисплей. Мне надо выводить на TM1637.
Проблема в том, что при использовании этого индикатора, начинает сбиваться процесс измерения. Если без вывода на индикатор, точность измерения одна сотая. При включении функции вывода точность падает до 3 десятых и показания прыгают в этих пределах, что не устраивает. Вот код:
[code]
/* ATtiny85 Battary_tester TM1637 & Serial
*********************************************
* ATtiny85 @ 8 MHz (internal); BOD(2,7V); Optiboot
********************************************
* TM1637 ATtiny85
* <<------>>
* PB5-| |-VCC
* CLK--PB3-| |-PB2--DIO
* AIN--PB4-| |-PB1--Serial Rx
* GND-| |-PB0--Serial Tx
*
********************************************
* V2 - библиотекa TM1637Display https://github.com/jasonacox/TM1637TinyDisplay
*/
// НАСТРОЙКА
/*
* Ставим #define NASTROYKA 1
* Заливаем код, запускаем, запоминаем значение на дисплее, например 5291
* Измеряем мультиметром реальное напряжение на выходе преобразователя, например 4999 (это в мВ)
* Считаем (4999/5291)*1.1=1.0392931
* Считаем 1.0392931*1023*1000 = 1063196
* Записываем результат в строку 100 в виде result = 1063196L
* Ставим #define NASTROYKA 0
* Заливаем код, запускаем, готово.
*/
#include <TM1637TinyDisplay.h>
#define NASTROYKA 0
long Vcc;
float Vbat;
#define CLK PB3
#define DIO PB2
#define t1_Interval 1000 // время (1000) милисекунд
// тонкая настройка алгоритма сглаживания shumodav()
#define ts 5 // *table size* количество строк массива для хранения данных, для девиации +/- 2 отсчёта оптимально 4 строки и одна в запас.
#define ns 25 // *number samples*, от 10..до 50 максимальное количество выборок для анализа 1й части алгоритма
#define ain A2 // какой аналоговый вход читать (А2 это PB4)
#define mw 50 // *max wait* от 15..до 200 ms ожидать повтора отсчёта для 2 части алгоритма
unsigned int myArray[ts][2], aread, firstsample, oldfirstsample, numbersamples, rezult;
unsigned long prevmillis = 0;
boolean waitbegin = false; //флаг включённого счётчика ожидания повтора отсчёта
unsigned long timer1;
TM1637TinyDisplay display(CLK, DIO);
//---------------------------------------------
void setup(){
// инициируем Serial
Serial.begin(9600);
// инициируем дисплей
display.begin();
display.setBrightness(BRIGHT_7);
}
//---------------------------------------------
void loop(){
if(millis() - timer1 >= t1_Interval){ // ищем разницу
timer1 = millis();
for(byte i = 0; i < 5; i++){Vcc += readVcc();}
Vcc /= 5;
shumodav();
Vbat = ((rezult / 1023.0) * Vcc) / 1000;
if(Vbat >= 0.95){
#if NASTROYKA
Serial.println(rezult);
#else
Serial.println(Vbat, 2);
// выводим на индикатор
// display.showNumber(Vbat, 2);
#endif
}
Vcc = 0;
}
}
//---------------------------------------------
long readVcc(){ // чтение реального напряжения питания
// Read 1.1V reference against AVcc
// set the reference to Vcc and the measurement to the internal 1.1V reference
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
ADMUX = _BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
ADMUX = _BV(MUX5) | _BV(MUX0);
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
ADMUX = _BV(MUX3) | _BV(MUX2);
#else
ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
#endif
delay(75); // Wait for Vref to settle
ADCSRA |= _BV(ADSC); // Start conversion
while (bit_is_set(ADCSRA, ADSC)); // measuring
uint8_t low = ADCL; // must read ADCL first - it then locks ADCH
uint8_t high = ADCH; // unlocks both
long result = (high << 8) | low;
// индикатор показывал 4990, вольтметр 4576мВ (4576/4990)*1.1=1.008737
result = 1063196L / result; // Calculate Vcc (in mV); 1031938 = 1.008737*1023*1000
return result; // Vcc in millivolts
}
//---------------------------------------------
void shumodav(){ // главная функция
// заполнить таблицу нолями в начале цикла
for(int s=0; s<ts; s++){
for(int e=0; e<2; e++){myArray[s][e] = 0;}
}
// основной цикл накопления данных
for(numbersamples=0; numbersamples<ns; numbersamples++){
#if NASTROYKA
aread = readVcc();
#else
aread = analogRead(ain);
#endif
// уходим работать с таблицей
tablework();
}
// заполнен массив, вычисляем максимально повторяющееся значение
int max1 = 0; // временная переменная для хранения максимумов
for(byte n=0; n<ts ; n++){
if(myArray[n][1] > max1){ // перебор 2-х элементов строк
max1 = myArray[n][1]; // запомним куда больше всего попало
firstsample = myArray[n][0]; // его 1 элемент = промежуточный результат.
}
}
//*****вторая фаза алгоритма *********//
// если старый отсчёт не равен новому,
//и флага включения счёта времени небыло, то
if(oldfirstsample != firstsample && waitbegin == false){
prevmillis = millis(); // скидываем счётчик времени на начало
waitbegin = true; // активируем флаг ожидания
}
// если до истечения лимита времени отсчёт сравнялся
// со старым, то снимаем флаг
if(waitbegin == true && oldfirstsample == firstsample){
waitbegin = false;
rezult = firstsample;
}
// если всё таки отсчёт не сравнялся, а время ожидания вышло
if(waitbegin == true && millis() - prevmillis >= mw){
oldfirstsample = firstsample;
waitbegin = false;
rezult = firstsample; // то признаём новый отсчёт конечным результатом функции
}
}
//---------------------------------------------
void tablework() { // функция внесения данных в таблицу
// если в таблице совпадает отсчёт, то инкрименировать
// его счётчик во втором элементе
for(byte n=0; n<ts; n++){
if(myArray[n][0] == aread){
myArray[n][1] ++;
return;
}
}
// перебираем ячейки что б записать значение aread в таблицу
for(byte n=0; n<ts; n++){
if(myArray[n][0] == 0){ // если есть пустая строка
myArray[n][0] = aread;
return;
}
}
// если вдруг вся таблица заполнена раньше чем кончился цикл,
// то счётчик циклов на максимум
numbersamples = ns;
}
//END------------------------------------------
[/code]
Если 79 строку закомментировать результат измерения будет выводится только в serial, и точность составит одну сотую вольта. Если её раскомментировать и выводить на TM1637, то результат измерения будет прыгать в диапазоне 3 десятых вольта.
Автор, к сожалению помочь не смог, сказал, что алгоритм брал здесь на форуме у товарища dimax. Поэтому и обращаюсь к форуму и уважаемому dimax, как сделать, что бы при выводе на TM1637 процесс измерения не сбивался и точность осталась прежней. Пробовал с тремя разными библиотеками TM1637, на всех сбивается.