logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[ATMEGA8][C/AvrStudio] Pomiar temperatury zaburza multipl.

overheat 21 Sie 2010 15:45 2309 20
REKLAMA
  • #1 8422511
    overheat
    Poziom 9  
    Witam! //pierwszy post na forum, pierwsze poważne starcie z AVR

    Skonstruowałem następujący układ do pomiaru temperatury z dokładnością do jedności (st. Celsiusza):
    - ATMEGA8
    - Sensor DS18B20
    - Podwójny wyświetlacz siedmiosegmentowy; ot z rodziny takich: http://www.goldmine-elec-products.com/images/G17024B.jpg

    Wszystko działa dobrze (o tym za moment). Wyświetlacz jest poprawnie multipleksowany (obie cyfry wyświetlają się dobrze), sensor pobiera poprawną temperaturę.

    Wyświetlacz LED jest multipleksowany timerem o częstych przerwaniach (kilkadziesiąt Hz). Temperatura jest aktualizowana z sensora w timerze o długim czasie trwania (przerwanie co kilka sekund).

    Problem:

    W momencie, gdy uC wpada w przerwanie, które aktualizuje temperaturę, wyświetlacz przestaje się multipleksować (wyświetla jedną cyfrę). Trwa to ~0.5s. I wygląda brzydko (!), a potem wraca do normy na kolejny cykl. Jeśli jednak tylko rzucić okiem np. na YouTube, wiele filmów przedstawia taki sam układ, który działa "płynnie" (aktualizacja temperatury nie niszczy multipleksacji).

    Gdzie tkwi mój błąd (leży pewnie w założeniach timerów wyświetlacza oraz sensora, lecz nie mogę go odnaleźć)?

    Kod głównego pliku programu (jak już wspomniałem - wyświetlacz oraz sensor działają poprawnie - problem tkwi w synchronizacji obydwu procesów):

    #include <stdlib.h>
    #include <avr/io.h>          
    #include <stdio.h>        
    #include <avr/interrupt.h> 
    #include <compat/ina90.h>    
      
    #include "dualDisplay.h"
    #include "ds18b20.h"
    
    char temp[20] = "00";
    
    // SENSOR TIMER EVENT
    ISR(TIMER1_COMPA_vect) 
    {
    	therm_read_temperature(temp);
    }
    
    // LED MULTIPLEX TIMER EVENT
    ISR(TIMER0_OVF_vect)
    {
    	showDigit(-1);
    	if(PORTB == _BV(0)) {		
    		showDigit((int)(atoi(temp)/10));
    		PORTB |= _BV(1);
        	PORTB &= ~_BV(0);
    	}
    	else {
    		showDigit((int)(atoi(temp)%10));
    		PORTB |= _BV(0);
    		PORTB &= ~_BV(1);	
    	}
    }
    
    void sensorTimerOn() 
    {
    	TCCR1B |= (1 << CS12) | (1 << CS10);
    }
    
    void ledMultiplexTimerOn()
    {
    	TCCR0 |= (1 << CS01);
      	TCNT0 = 0x00; 
    }
    
    
    int main()
    {
    	DDRD |= 0xff; //LCD
    	DDRB |= (_BV(0) | _BV(1)); // LED DISPLAY
    
    	therm_read_temperature(temp); // FIRST READING
    
    	sensorTimerOn();
    	ledMultiplexTimerOn();
    	TIMSK = (1 << TOIE0) | (1 << OCIE1A); // ENABLE TIMERS
    	
    	sei(); 
    	
    	for(;;) {}
    
    	return 0;
    }


    Dziękuję za pomoc!
    Pozdrawiam!
  • REKLAMA
  • Pomocny post
    #2 8422595
    enemyhilator
    Poziom 16  
    Problem pewnie leży w procedurze.
    therm_read_temperature(temp);
    Tam zapewne masz jakiegoś delay-a ustawionego (na czas potrzebny na konwersje temperatury przez DS-a). Musiał byś pokombinować, żeby przebudować tą funkcję a delay-a wbudować najlepiej w obsługę przerwań z timera z którego korzystasz.
    Np. Timer przerywa częściej, za każdym razem zwiększasz pewien licznik. Np. jedno przerwanie to 10 ms. Wysyłasz komendę konwersji do DS-a i czekasz 750 ms/10ms jakieś 75 przerwań z timera i odczytujesz zawartość ds-a. Nie korzystając z delay_ms.
  • REKLAMA
  • #3 8422620
    janbernat
    Poziom 38  
    Sprawdź czy w #include "ds18b20.h" nie ma przypadkiem _delay ms(750);
    Albo w którymś pliku .c.
  • #4 8423323
    overheat
    Poziom 9  
    enemyhilator napisał:
    Problem pewnie leży w procedurze.
    therm_read_temperature(temp);
    Tam zapewne masz jakiegoś delay-a ustawionego (na czas potrzebny na konwersje temperatury przez DS-a). Musiał byś pokombinować, żeby przebudować tą funkcję a delay-a wbudować najlepiej w obsługę przerwań z timera z którego korzystasz.
    Np. Timer przerywa częściej, za każdym razem zwiększasz pewien licznik. Np. jedno przerwanie to 10 ms. Wysyłasz komendę konwersji do DS-a i czekasz 750 ms/10ms jakieś 75 przerwań z timera i odczytujesz zawartość ds-a. Nie korzystając z delay_ms.


    Faktycznie - to brzmi logicznie. Ale przepisanie poniższego kodu w taki sposób będzie bardzo trudne. Zastanawiam się więc nad równie prostym wyświetlaczem, który nie będzie wymagał multipleksacji (jakieś pomysły?)

    #include <stdlib.h>
    #include <avr/io.h>          
    #include <stdio.h>
    #include <util/delay.h>
    #include "ds18b20.h"
    #include "dualDisplay.h"
    
    inline __attribute__((gnu_inline)) void therm_delay(uint16_t delay){
    	while(delay--) 
    		asm volatile("nop");
    }
    
    uint8_t therm_reset(){
    	uint8_t i;
    	//Pull line low and wait for 480uS
    	THERM_LOW();
    	THERM_OUTPUT_MODE();
    	therm_delay(us(240));
    	//Release line and wait for 60uS
    	THERM_INPUT_MODE();
    	therm_delay(us(60));
    	//Store line value and wait until the completion of 480uS period
    	i=(THERM_PIN & (1<<THERM_DQ));
    	therm_delay(us(240));
    	//Return the value read from the presence pulse (0=OK, 1=WRONG)
    	return i;
    }
    
    void therm_write_bit(uint8_t bit){
    	//Pull line low for 1uS
    	THERM_LOW();
    	THERM_OUTPUT_MODE();
    	therm_delay(us(1));
    	//If we want to write 1, release the line (if not will keep low)
    	if(bit) THERM_INPUT_MODE();
    	//Wait for 60uS and release the line
    	therm_delay(us(60));
    	THERM_INPUT_MODE();
    }
    
    uint8_t therm_read_bit(void){
    	uint8_t bit=0;
    	//Pull line low for 1uS
    	THERM_LOW();
    	THERM_OUTPUT_MODE();
    	therm_delay(us(1));
    	//Release line and wait for 14uS
    	THERM_INPUT_MODE();
    	therm_delay(us(14));
    	//Read line value
    	if(THERM_PIN&(1<<THERM_DQ)) bit=1;
    	//Wait for 45uS to end and return read value
    	therm_delay(us(15));
    	return bit;
    }
    
    uint8_t therm_read_byte(void){
    	uint8_t i=8, n=0;
    	while(i--){//Shift one position right and store read value
    		n>>=1;
    		n|=(therm_read_bit()<<7);
    	}
    	return n;
    }
    
    void therm_write_byte(uint8_t byte){
    	uint8_t i=8;
    	while(i--){
    		//Write actual bit and shift one position right to make
    		//the next bit ready
    		therm_write_bit(byte&1);
    		byte>>=1;
    	}
    }
    
    void therm_read_temperature(char *buffer){
    	// Buffer length must be at least 12bytes long! ["+XXX.XXXX C"]
    	uint8_t temperature[2];
    	int8_t digit;
    	uint16_t decimal;
    	//Reset, skip ROM and start temperature conversion
    	therm_reset();
    	therm_write_byte(THERM_CMD_SKIPROM);
    	therm_write_byte(THERM_CMD_CONVERTTEMP);
    	//Wait until conversion is complete
    	while(!therm_read_bit());
    	//Reset, skip ROM and send command to read Scratchpad
    	therm_reset();
    	therm_write_byte(THERM_CMD_SKIPROM);
    	therm_write_byte(THERM_CMD_RSCRATCHPAD);
    	//Read Scratchpad (only 2 first bytes)
    	temperature[0]=therm_read_byte();
    	temperature[1]=therm_read_byte();
    		//therm_reset();
    	//Store temperature integer digits and decimal digits
    	digit=temperature[0]>>4;
    	digit|=(temperature[1]&0x7)<<4;
    	//Store decimal digits
    		//decimal=temperature[0]&0xf;
    		//decimal*=THERM_DECIMAL_STEPS_12BIT;
    	//Format temperature into a string [+XXX.XXXX C]
    	//sprintf(buffer, "%+d.%04u C", digit, decimal);
    	sprintf(buffer, "%d", digit);
    }
  • REKLAMA
  • Pomocny post
    #5 8423616
    kondziom
    Poziom 13  
    Pomyśl nad zastosowaniem rejestru przesuwnego. Np 74HC595. Można te układy łączyć. Potrzebne będą trzy linie procesora. Jedna do ustawienia wprowadzanego bitu druga to zegar rejestru przesuwnego a trzecia służy do przeniesienia danych z rejestru na wyjścia. Układ ma 8-io bitowe wyjście czyli do podwójnego wyświetlacza będą potrzebne dwie takie kostki. Jeśli chcesz to jutro jak znajdę chwilę czasu to Ci to rozrysuję jak podłączyć.
  • REKLAMA
  • #7 8423764
    overheat
    Poziom 9  
    kondziom napisał:
    Pomyśl nad zastosowaniem rejestru przesuwnego. Np 74HC595. Można te układy łączyć. Potrzebne będą trzy linie procesora. Jedna do ustawienia wprowadzanego bitu druga to zegar rejestru przesuwnego a trzecia służy do przeniesienia danych z rejestru na wyjścia. Układ ma 8-io bitowe wyjście czyli do podwójnego wyświetlacza będą potrzebne dwie takie kostki. Jeśli chcesz to jutro jak znajdę chwilę czasu to Ci to rozrysuję jak podłączyć.

    McMonster napisał:
    http://www.protostack.com/forum/blog.php?u=2&b=35

    Już ktoś to kiedyś rozrysował, nie trzeba się powtarzać.

    Wygląda doskonale! (a przynajmniej na pierwszy rzut oka) Z początkiem tygodnia zakupie te układy i dam znać, jak poszło ;-)
  • #8 8423782
    McMonster
    Poziom 32  
    Kup od razu kilka, rejestry przesuwające, a szczególnie 74595, to strasznie przydatna rzecz. Na pewnym znanym serwisie aukcyjnym u jednego użytkownika za niecałe 3 zł można kupić 5 sztuk w DIP lub SMD i trochę innych części elektronicznych w niskiej cenie.
  • #9 8438220
    overheat
    Poziom 9  
    Sprawa rozwiązana - 2x 74HC595 załatwiło problem. Faktycznie - przydatne i proste zarazem układy. Teraz pozostał tylko stabilizator 7805 z 9v na 5v i można trawić płytkę.

    Pozdrawiam!
  • #10 8438881
    tmf
    VIP Zasłużony dla elektroda
    A nie prościej było zamiast pakować dodatkowe scalaki, napisać porządnie obsługę 1-wire? Przecież za pomocą UARTa można to zrobić prawie całkowicie sprzętowo bez zaangażowania procesora. Tak naprawdę to poprawiając nieco twoje procedury do 1-wire można z łatwością zlikwidować ich wpływ na multipleksowanie.
  • #11 8439140
    kondziom
    Poziom 13  
    Ale do sterowania tymi układami wystarczy 3 linie a nie 10 i nie są one drogie. To zależy wszystko od tego co dla kogo jest prostszym rozwiązaniem i każdy ma swoje racje.
  • #12 8439550
    tmf
    VIP Zasłużony dla elektroda
    Skoro pierwotnie starczało mu IO na multipleksowanie to przecież nagle mu ich nie ubyło, prawda? A zawsze układ bez 3 dodatkowych scalaków jest prostszy niż z nimi. Ale już pomijając nawet ten fakt, to sprawne procedury obsługi 1-wire i tak kiedys mu się przydadzą, więc poprawa tego co ma nie będzie czasem straconym.
  • #13 8440386
    overheat
    Poziom 9  
    tmf napisał:
    Skoro pierwotnie starczało mu IO na multipleksowanie to przecież nagle mu ich nie ubyło, prawda? A zawsze układ bez 3 dodatkowych scalaków jest prostszy niż z nimi. Ale już pomijając nawet ten fakt, to sprawne procedury obsługi 1-wire i tak kiedys mu się przydadzą, więc poprawa tego co ma nie będzie czasem straconym.
    Starczało. Lecz podejście do sprawy mam czysto hobbystyczne, toteż chciałbym, aby było jak najprościej. A z tymi scalakami jest. Druga sprawa to to, iż układ będzie fancy-termometrem pokojowym zasilanym baterią 9v. Dzięki temu, że rejestry "trzymają wyświetlacz", mogę tylko co 20s wybudzać uC i aktualizować temperaturę, aby następnie ponownie go uśpić. Zawsze trochę mA "do przodu" (choć ogólnie nie jestem do końca przekonany, czy te rejestry same więcej nie pożerają ;P).

    Anyway - dzięki za podsunięte pomysły!
  • #14 8440424
    djmdp
    Poziom 16  
    Eee tam, panowie wszystko jest do zrobienia, ja tak przebudowałem funkcję DS,a że nie dość, że nie blokuje przerwań, to jeszcze mierzy i kontroluje 4 jego błędy, więc odrobinę chęci, pomyślunku i wszystko da się zrobić zamiast angażować kolejne niepotrzebne elementy do projektu. W skrócie, delaye zamienić na instrukcje odpowiednio napisane if, oraz odmierzanie czasu podpiąć pod odpowiednio spreparowany timer, co do błędów to wykorzystać timeouty, oraz kontrolę CRC. Pozdrawiam.
  • #15 8440468
    tmf
    VIP Zasłużony dla elektroda
    overheat napisał:
    tmf napisał:
    Skoro pierwotnie starczało mu IO na multipleksowanie to przecież nagle mu ich nie ubyło, prawda? A zawsze układ bez 3 dodatkowych scalaków jest prostszy niż z nimi. Ale już pomijając nawet ten fakt, to sprawne procedury obsługi 1-wire i tak kiedys mu się przydadzą, więc poprawa tego co ma nie będzie czasem straconym.
    Starczało. Lecz podejście do sprawy mam czysto hobbystyczne, toteż chciałbym, aby było jak najprościej. A z tymi scalakami jest. Druga sprawa to to, iż układ będzie fancy-termometrem pokojowym zasilanym baterią 9v. Dzięki temu, że rejestry "trzymają wyświetlacz", mogę tylko co 20s wybudzać uC i aktualizować temperaturę, aby następnie ponownie go uśpić. Zawsze trochę mA "do przodu" (choć ogólnie nie jestem do końca przekonany, czy te rejestry same więcej nie pożerają ;P).

    Anyway - dzięki za podsunięte pomysły!


    No to żeś pojechał. Myślisz, że te rejestry prądu nie biorą? Zapewniam cię, że 3 rejestry biorą go więcej niż nieuśpiony procesor.
  • #16 8440588
    kondziom
    Poziom 13  
    W dokumentacji piszą że pobiera 80uA przy zasilaniu 6V i 25st Celsiusza. Ja bardziej martwiłbym się samym wyświetlaczem. Przecież on zje taką baterię w tydzień. Jakby bardzo ograniczyć jego prąd to dłużej ale wtedy w dzień nic nie będzie widać.
  • #17 8441790
    marek_Łódź
    Poziom 36  
    McMonster napisał:
    http://www.protostack.com/forum/blog.php?u=2&b=35
    Już ktoś to kiedyś rozrysował, nie trzeba się powtarzać.


    Swego czasu robiłem podobny układ na rejestrach 74164, rezygnując z rezystorów (wykorzystując wewnętrzne rezystory scalaka). Układ się grzał porządnie, ale pracował kilka lat i się nie spalił. Do tego cały wyświetlacz wisiał na kilkunastometrowym kablu (był sterowany z procesora 8751).

    Jeszcze prościej można załatwić temat scalonym sterownikiem wyświetlacza na I2C - SAA1064.

    Zalety
    - dwie linie sterujące, zamiast trzech (standardowe I2C, które mogą sterować również inne układy)
    - brak oporników na segmentach
    - programowa regulacja jasności

    Wady - nieco wyższa cena

    http://www.datasheetcatalog.com/datasheets_pdf/S/A/A/1/SAA1064.shtml

    Układ może sterować bezpośrednio dwie cyfry lub w trybie multipleksowanym cztery (potrzebne dwa dodatkowe tranzystory przełączające pary cyfr).
  • #18 8441822
    gaskoin
    Poziom 38  
    skąd bierzecie informacje o scalakach różnego typu? Zaraz ktoś wyjedzie ze sterownikiem pralki na SPI
  • #19 8441860
    marek_Łódź
    Poziom 36  
    gaskoin napisał:
    skąd bierzecie informacje o scalakach różnego typu
    Elementarna umiejętność operowania wyszukiwarkami. Umiejętne operowanie przyciskiem "szukaj" jest cenniejsze od umiejętności pisania, czytania i liczenia ;) .
  • #20 8441948
    overheat
    Poziom 9  
    marek_Łódź napisał:
    McMonster napisał:
    http://www.protostack.com/forum/blog.php?u=2&b=35
    Już ktoś to kiedyś rozrysował, nie trzeba się powtarzać.


    Swego czasu robiłem podobny układ na rejestrach 74164, rezygnując z rezystorów (wykorzystując wewnętrzne rezystory scalaka). Układ się grzał porządnie, ale pracował kilka lat i się nie spalił. Do tego cały wyświetlacz wisiał na kilkunastometrowym kablu (był sterowany z procesora 8751).

    Jeszcze prościej można załatwić temat scalonym sterownikiem wyświetlacza na I2C - SAA1064.

    Zalety
    - dwie linie sterujące, zamiast trzech (standardowe I2C, które mogą sterować również inne układy)
    - brak oporników na segmentach
    - programowa regulacja jasności

    Wady - nieco wyższa cena

    http://www.datasheetcatalog.com/datasheets_pdf/S/A/A/1/SAA1064.shtml

    Układ może sterować bezpośrednio dwie cyfry lub w trybie multipleksowanym cztery (potrzebne dwa dodatkowe tranzystory przełączające pary cyfr).
    Czym go zasilałeś/na ile starczało ogniwo (jeśli ogniwo)?
  • #21 8442044
    marek_Łódź
    Poziom 36  
    overheat napisał:
    Czym go zasilałeś/na ile starczało ogniwo (jeśli ogniwo)?
    Który? Układ na 74164 nie bardzo się nadaje do zasilania bateryjnego. W przypadku SAA1064 pobór energii jest zależny bezpośrednio od jasnosci świecenia wyświetlacza, a dane można znaleźć w datasheet (link powyżej).
    kondziom napisał:
    Ja bardziej martwiłbym się samym wyświetlaczem. Przecież on zje taką baterię w tydzień. Jakby bardzo ograniczyć jego prąd to dłużej ale wtedy w dzień nic nie będzie widać.
    Nic dodać, nic ująć. Licząc delikatnie średni prąd 20mA (trochę przymało na dwie cyfry, chyba, że akurat będzie -1 stopień Celsjusza), bateria 2000mAh starczy na 4 doby, chyba że temperatura wyswietlana będzie na żądanie.
REKLAMA