From a968de353b007e247391470626d01152519de09c Mon Sep 17 00:00:00 2001 From: "Jan \"Yenya\" Kasprzak" Date: Sun, 13 Jul 2014 22:17:01 +0200 Subject: [PATCH] Rozepsan popis a dalsi moznosti v main.c --- POPIS | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- main.c | 80 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 128 insertions(+), 38 deletions(-) diff --git a/POPIS b/POPIS index 5dfeb58..682b104 100644 --- a/POPIS +++ b/POPIS @@ -29,18 +29,6 @@ PB2: termistor, zapojit mezi piny 1 a 2+3 konektoru PB2 PB3: termistor, zapojit mezi piny 1 a 2+3 konektoru PB3 PB4: ovládání motoru, zapojit mezi piny 2 a 3 konektoru PB4 -Motory lze řídit i přes PWM (viz dokumentace Timer/Counter 1, -pin PB1 je pak OC1A, pin PB4 je OC1B. Doporučuju T/C1 časovat z PLL clock -na 32 MHz, čímž se získá PWM o frekvenci 256 kHz, což by mělo na plynulé -řízení motoru stačit. - -Termistory jsou čitelné přes A/D převodník (PB2 je ADC1, PB3 je ADC2). -Podle typu termistoru použít vhodnou napěťovou referenci ADC (asi interní 1.1V). -Před vstupem PB0, PB2 a PB3 je low-pass filtr z 220nF kondenzátoru -a 15k odporu, což by mělo ořezávat frekvence vyšší než cca 50 Hz. -Tentýž kanál ADC tedy nemá smysl vyhodnocovat častěji. - -Možná půjde využít i vestavěný teploměr (viz dokumentace A/D převodníku). Programování: ============= @@ -55,3 +43,77 @@ Programová flash umožňuje 10_000 přepsání (OK), EEPROM umožňuje "jen" 100_000 přepsání (pozor na to při logování do EEPROM, ať se příliš často nepřepisuje ta stejná adresa, například při zacyklení programu). + +Řízení motorů čerpadel: +======================= +Motory lze řídit buďto posíláním logické 1 nebo 0 na výstupy PB1, PB4, +anebo by mělo být možné i plynulé řízení přes PWM (viz dokumentace +Timer/Counter 1, pin PB1 je pak OC1A, pin PB4 je OC1B. Doporučuju +T/C1 časovat z PLL clock na 32 MHz, čímž se získá PWM o frekvenci 256 kHz, +což by mělo na plynulé řízení motoru stačit. Je případně možné použít i +64 MHz, což má o něco větší odběr v klidu (asi o 2 mA). Nebo PLL clock +zapínat jen na dobu, kdy má jet čerpadlo. Pozor na dostatečně velkou +střídu PWM, aby se motor vůbec roztočil. + + +Analogové vstupy: +================= +Analogové vstupy PB2, PB3 (ADC1, ADC3) jsou vybaveny low-pass filtrem +z 220nF kondenzátoru a 15k odporu, což by mělo ořezávat frekvence vyšší +než cca 50 Hz. Tentýž kanál ADC tedy nemá smysl vyhodnocovat častěji. +Mezi +5V a horní pin analogového vstupu je umístěn 300K odpor, dolní pin +je zapojený na zem. Podle toho je třeba vybírat součástku, jejíž odpor +budeme měřit: + +Nejlépe je použít měření A/D převodníkem proti interní +1.1V napěťové referenci. ADC má rozlišení 10 bitů, takže chceme +na napěťové děličce dělící +5V pomocí 300K odporu a odporu čidla mít rozsah +napětí od 0.001 do 1.1 voltu, což dává rozsah odporů cca 60 Ohmů až 84 kOhmů. +Podle toho je potřeba volit druh čildla. + +U termistorů tomu odpovídají například tyto NTC termistory s odporem 10kOhm +při 25 stupních - tímto pokryjí teploty -15 až 150 stupňů: +http://www.gme.cz/ntc640-10k-p118-042 +http://www.ges.cz/cz/ntc-0-2-10k-GES05303342.html + +U fotoodporů pro detekci pouze denního světla je to víceméně jedno - i velké +odpory mají na denním světle pod 1 kOhm: +http://www.ges.cz/cz/ldr-05-75-GES05100338.html +http://www.gme.cz/vt83n2-p520-059 + + +Digitální vstup pro plovák: +=========================== +Vstup na pinu PB0 je také vybaven low-pass filtrem jako analogové vstupy, +mělo by sloužit k odfiltrování přechodových jevů při spínání a rozepínání +kontaktu. Možná ale bude i tak třeba udělat SW test na to, aby změněný stav +sepnutí vydržel aspoň nějakou dobu (50 ms). + +Pro vstup je třeba mít zapnutý interní pull-up rezistor (příslušný bit +v registru PORTB nastavit na jedničku). + + +Náměty: +======= +- Použít interní teploměr (ADC4) jako odhad teploty vzduchu + (podle toho, kde bude zařízení umístěno). +- Časování dělat přes watchdog, například s rozlišením 16 s: + watchdog probudí CPU (viz firmware "step-up" na stránce tinyboard), + je potřeba potvrdit. Druhý příchod watchdogu bez potvrzení může + resetovat CPU (pro případ zacyklení) +- Proudové nároky: běží-li čerpadlo, nemá cenu řešit. Jinak PLL clock + má asi 6mA v 64MHz režimu, 2mA v 32MHz režimu, ADC má asi 2mA, + CPU taky 2mA, nějaké mA sežerou napěťové děličky u analogových vstupů. +- Osadit LEDku pro signalizaci napájení? Cca 2-10 mA podle typu. +- Regulace termistor + fotoodpor: fotoodporem poznat den/noc, termistorem + na vstupu od kolektoru do nádrže řídit vypnutí (až začne příchozí + teplota klesat, vypnout čerpadlo). +- Regulace 2x termistor: zapnout čerpadlo, pokud za pár vteřin nezačne + růst teplota příchozí vody do nádrže nad teplotu odchozí vody, + vypnout čerpadlo a počkat hodinu, dvě. +- Dívat se na stav registru MCUSR (viz logging.c) a rozlišovat, jestli + jsme se probudili resetem, power-on, watchdog resetem, brown-outem,atd. +- Mít uložené regulační proměnné v eeprom a při ladění upravovat jen EEPROM, + ne program samotný. +- a už mě to nebaví, stejně to nikdo nebude číst :-) + diff --git a/main.c b/main.c index 0fbb919..07ef6cc 100644 --- a/main.c +++ b/main.c @@ -42,7 +42,10 @@ static void init_tc1() // OCR1B = 0; // stride } -// precte synchronne (busy-waitem) jednu hodnotu z A/D prevodniku +// Precte synchronne (busy-waitem) jednu hodnotu z A/D prevodniku. +// Alternativa je nastavit bit ADSC a ADIE, delat neco jineho, +// a pockat az prijde ADC interrupt (viz firmware "step-up" na strance +// tinyboard). static uint16_t read_adc_sync() { uint16_t rv; @@ -59,6 +62,25 @@ static uint16_t read_adc_sync() return rv; } +// vyber kanalu A/D prevodniku (datasheet tabulka 17-4 v sekci 17.13.1) +typedef enum { ADC1, ADC3, ADC4 } adc_channel; +static void select_adc_channel(adc_channel c) +{ + switch (c) { + case ADC1: + ADMUX = _BV(REFS1) | _BV(MUX0); // ADC1 (PB2), 1.1V ref + break; + case ADC3: + ADMUX = _BV(REFS1) | _BV(MUX1) | _BV(MUX0); // ADC3 (PB3), 1.1V ref + break; + case ADC4: + ADMUX = _BV(REFS1) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0) // ADC4 (temperature), 1.1V ref + break + ; + } +} + + // analog to digital converter // datasheet sekce 17 static void init_adc() @@ -71,26 +93,27 @@ static void init_adc() ; DIDR0 = _BV(ADC1D) | _BV(ADC3D); // disable dig. input on ADC1, ADC3 (PB2, PB3) - ADMUX = _BV(REFS1) // 1.1V internal reference - | _BV(MUX3) | _BV(MUX2) | _BV(MUX1) | _BV(MUX0) // ADC4 (temperature) - ; + select_adc_channel(ADC4); // do the first conversion, drop the result read_adc_sync(); } +// priklad vselijakych moznosti, co tenhle HW umi int main(void) { unsigned char i; - init_log(); + init_log(); // viz logging.c - detekce poctu resetu, atd. log_byte(0x42); // zkouska logovani log_flush(); // nezapomenout vylit buffer power_all_disable(); /* vypneme cele I/O, pak zapneme co bude potreba */ - DDRB |= _BV(DDB4); // PB4 as output + DDRB |= _BV(DDB4); // PB4 as output (lze misto tohoto pouzit jako PWM) + + PORTB |= _BV(PB0); // PB0 interni pull-up (aby tady byla 1, pokud je plovak rozepnuty) enable_pll_clock(); init_tc1(); @@ -101,30 +124,35 @@ int main(void) // cli(); // priklad prace s A/D prevodnikemo - // init_adc() necha ADMUX nastaveny na ADC4 (teplomer), jinak - // tady lze ADMUX prestavit na neco jineho (pozor na napetovou - // referenci REFS) - log_word(read_adc_sync()); // nacteme teplotu, zalogujeme + select_adc_channel(ADC4); // interni teplomer na cipu + log_word(read_adc_sync()); // nacteme teplotu cipu, zalogujeme // interpretace vysledku: datasheet sekce 17.12 log_flush(); + // ve smycce budeme merit jak se meni hodnota na ADC3 (PB3) + select_adc_channel(ADC3); + while(1) { - for (i = 0; i < 16; i++) { - // zapiname/vypiname portb4 v sudem/lichem kroku - if (i & 1) { - PORTB |= _BV(PORTB4); - } else { - PORTB &= ~_BV(PORTB4); - } - - // hodnopta PWM pro PB1 (OC1A) - // jdeme od 128 do 248, napriklad: - OCR1A = 0x80 + (i << 3); - - // busy-wait, nebo se muzeme nechat casovat - // pomoci watchdogu (WDT, datasheet sekce 7.4.5) - // nebo pomoci Timer/Counter 0 (datasheet sekce 11) - _delay_ms(1500); + // PB4 (motor 2) zapínáme podle sepnutí plováku PB0 + if (PINB & _BV(PINB0)) { // rozepnuto (1) + PORTB &= ~_BV(PORTB4); + } else { // sepnuto (0) + PORTB |= _BV(PORTB4); } + + // hodnota PWM pro PB1 (OC1A) + // jdeme od 128 do 248, napriklad: + OCR1A = 0x80 + (i << 3); + + // busy-wait, nebo se muzeme nechat casovat + // pomoci watchdogu (WDT, datasheet sekce 7.4.5) + // nebo pomoci Timer/Counter 0 (datasheet sekce 11) + _delay_ms(1500); + + i++; + i &= 0xF; + + log_word(read_adc_sync()); // nacteme hodnotu, zalogujeme + log_flush(); } } -- 2.43.5