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

Rejestrator temperatury [ATtiny2313][C]

pibza 29 Gru 2010 23:59 3856 15
  • #1 8932575
    pibza
    Poziom 10  
    Witam wszystkich Forumowiczów!
    Jestem uczniem 3 klasy technikum i już od pół roku zacząłem interesować się programowaniem uK. Pisałem w C bo to dla mnie prosty język. Ostatnio zadałem sobie problem (no dobra chcę zaszpanować przed kumplami :P). Chcę zrobić dobory rejestrator temperatury w pokoju. Wybrałem sobie uK ATtiny 2313, układ DS1820 (czujka temperatury) i pamięć eeprom 24c04 do przechowywania wyników. Zakres temperatury miał być od 15 do 50C z krokiem 0,1C. I gdy zabrałem się za pisanie programu natrafiłem na kilka problemów  Linia 1-wire jest chyba dobrze napisana, tylko wydaje mi się że coś nie hula zapis do pamięci. I kompletnie nie umiem poradzić sobie z przesłaniem tych danych do kompa.. Opis układu: Po wciśnięciu przycisku S1 rejestrator ma zacząć działać. Przerwanie (zbocze z układu NE555) budzi go z trybu idle (obniżony pobór mocy) i następuje obsługa linii 1-wire. Nie wiem czy dobrze zrealizowałem warunek końca (czyli ma zliczyć do 1440 (tyle pomiarów) i potem się wyłączy.. Po włączeniu przycisku S2 ma się dokonać przesłanie danych do komputera i tu już kompletnie nie wiem jak to zrobić… Może inny algorytm? Bardzo proszę o pomoc i wszelką poradę!!


    Oto mój listning programu:


    
    
    #include <avr\io.h>
    #include <stdio.h>
    #include <inttypes.h>
    #include <avr\delay.h>
    #include <avr\interrupt.h>
    #include <avr\sleep.h>
    #include <avr/eeprom.h> 
    
    
    #define DQ 9
    
    #define SET_DQ DDRD &= ~_BV(DQ)
    #define CLR_DQ DDRD |= _BV(DQ)
    #define IN_DQ PIND & _BV(DQ)
    
    int i = 1; // zmienna sterujaca zapisaem do pamięci
    
    char msb, lsb, temp;
    
    float d1, d2;
    
    // procedura opóźniająca o (5+5*t)* 0,25 us dla 4MHz kwarcu
    void delay(unsigned char t)
    {
    	do
    	{
    		asm("nop");
    		
    	}while(--t);
    }
    
    // procedura reset
    void ow_reset(void)
    {
    	CLR_DQ; // stan niski na linii 1wire
    	delay(255); //
    	delay(119); // opóźnienie ok 480us
    	//delay(1);
    	SET_DQ;// stan wysoki na linii 1wire
    	delay(255); //
    	delay(119); // opóźnienie ok 480 us
    }
    // procedura zapisu bitu na linię 1wire
    void ow_write_bit(char b)
    {
    	cli(); // zablokowanie przerwań
    	CLR_DQ; // stan niski na linii 1wire
    	delay(7); // opóźnienie 10us
    	if(b)
    		SET_DQ; // jeśli parametr jest niezerowy to ustaw stan wysoki na linii
    	delay(80); // opóźnienie 100us
    	SET_DQ; // stan wysoki na linii 1wire
    	sei(); // odblokowanie pzrerwań
    }
    
    char ow_read_bit(void)
    {
    	cli();
    	CLR_DQ;
    	delay(1);
    	SET_DQ;
    	delay(11);
    	sei();
    	if(IN_DQ)
    		return 1;
    	else
    		return 0;
    }
    
    unsigned char ow_read_byte(void)
    {
    	unsigned char i;
    	unsigned char value = 0;
    	for (i=0;i<8;i++)
    	{
    		if(ow_read_bit()) value|=0x01<<i;
    		delay(6);
    	}
    	return(value);
    }
    
    void ow_write_byte(char val)
    {
    	unsigned char i;
    	unsigned char temp;
    	for (i=0; i<8; i++)
    	{
    		temp = val >> i;
    		temp &= 0x01;
    		ow_write_bit(temp);
    	}
    	delay(5);
    }
    
    
    
    
    
    
    int main ()
    {
    	//ustawienie wyjść portów
    	DDRD = 0x73;
    	PORTD = 0x77;
    	
    	DDRB = 0xff;
    	PORTB = 0xff;
    	
    	
    	
    	
    	sei();
    	
    	set_sleep_mode(SLEEP_MODE_IDLE); //tryb power-down gdyby tracił zawartość RAM czy można tryb Idle ( bity z 11 na 00)
    	
    	int zakoncz = 1440; // ilość ileracji programu
    	
    	//pobranie temperatur w doborym cyklu 
    	while(zakoncz)
    	{
    		
    		zakoncz--;
    		sleep_mode(); 
    	}
    	
    	
    	// wyłącznie całego układu
    	cli();
    	set_sleep_mode(SLEEP_MODE_PWR_DOWN); 
    	sleep_mode();
    	
    	return (0);
    }
    ISR(SIGN_INT1)
    {
    		
    		ow_reset();
    		ow_write_byte(0xCC);
    		ow_write_byte(0x44);
    		_delay_ms(250);
    		_delay_ms(250);
    		_delay_ms(250);
    		ow_reset();
    		ow_write_byte(0xCC);
    		ow_write_byte(0xBE);
    		lsb = ow_read_byte();
    		msb = ow_read_byte();
    
    		lsb = lsb >> 4;
    		msb &= 0x07;
    		msb = msb << 4;
    		temp = lsb | msb;
    		d2 = temp / 10;
    		d1 = temp % 10;
    		eeprom_write_block(&d2,(0x04+&i), sizeof(&d2)); 
    		eeprom_write_block(&d1,(0x08+&i), sizeof(&d1));  //argumentem jest adres, a drugim dana, powinno więc bć eeprom_write_byte(&liczba_LED,1);,  
    		i = i *4;
    }
    
    	
    
    


    Tutaj zamieszczam swój schemat ideowy.

    Rejestrator temperatury [ATtiny2313][C]
  • #2 8932709
    LordBlick
    VIP Zasłużony dla elektroda
    Następny... Procedura przerwania nie służy do obsługi Litanii do Św. Diody... Ustaw te wypociny w main tak, aby sprawdzały czy było przerwanie (np. jakąś zmienną globalną z atrybutem volatile) i coś z tym robiły gdy zaszło.
  • #3 8933940
    pibza
    Poziom 10  
    Wprowadziłem sugerowanie zmiany (dziękuję bardzo!). Ostatnio zapomniałem dodać, że komunikacja z komputerem miała by się odbywać poprzez port USB) ale mam nadzieję, że jest to czytelne z schematu. I co dalej miałbym zmienić/wprowadzić?
  • #5 8935749
    pibza
    Poziom 10  
    tak - pisałem o tym we wstępie. Ale wyjątkowo nie umię poradzić sobie z tym problemem. I dlatego proszę o pomoc..
  • #6 8937587
    LordBlick
    VIP Zasłużony dla elektroda
    Może wymuszę pewną logikę w dyskusji - skoro masz kod, to czy z nim coś zrobiłeś ? Czy kompilator sypie błędami i jakimi ? Jeśli nie to do jakiego momentu dochodzi (łatwe do stwierdzenia przy pomocy symulacji lub LED podpiętej pod wolny pin) ?
  • #7 8938134
    pibza
    Poziom 10  
    Heh… Ja widzę, że się nie rozumiemy. Kompilator nie informuje o żadnych błędach, program jest napisany dobrze, ale nie umiem sobie poradzić z przeniesieniem zapisanych danych w pamięci 24C08. Kompletnie nie wiem jak to rozwiązać. A skoro nie wiem jak to zrobić, nie jestem w 100% czy w pamięci jest zapisywana liczba o żądanej dokładności – DS18B20. Cały problem polega na przeniesieniu danych z pamięci do komputera, nawet tego nie zacząłem pisać w programie, bo kompletnie nie wiem jak. Domyślam się, że trzeba będzie skorzystać z rejestru USART – asynchroniczny lub synchroniczny nadajnik lub odbiornik – Attiny2313 posiada taki rejestr.
  • #8 8939320
    LordBlick
    VIP Zasłużony dla elektroda
    Po co przenosić cokolwiek do PC ? Wstawiasz w kodzie porównanie z jakąś wartością odczytaną, którą wcześniej zapisywałeś, i jeśli się zgadza to np. LED świeci... Nadmienię jeszcze że t2313 ma również USI mogące pracować w trybie TWi czyli I²C do obsługi EEPROM... A co do zabierania się do czegokolwiek to google odpowiadają najszybciej ;)
  • #9 8943336
    pibza
    Poziom 10  
    heh... Jak rejestrator dobowy zapisuje co minutę pomiar, bo jak to ma być na LED wyświetlane? :/ poza tym dane sobie na kompie w Excel'u obrobię i mam wykres. Poza tym wiem, że wujek Google wie niby wszystko ale gdy przychodzi co do czego to nie ma nic :/ Pomiarów jest 1440! i one muszą być zapisane do pamięci a z pamięci na PC!
  • #10 8944129
    LordBlick
    VIP Zasłużony dla elektroda
    Miałem na myśli etap sprawdzenia kodu zapisu do pamięci, a nie docelowy. Najczęściej projekt rozwija się etapami. Poprawność kodu na etapie odczyt/zapis eeprom można najprościej sprawdzić tak, jak proponowałem. Jeśli chodzi o przesyłanie danych, to jest na AVRFreaks tutorial obsługi transmisji na przerwaniach oraz bez przerwań(oczywiście jest to okazja do szlifowania angielskiego technicznego).
  • #11 8964331
    pibza
    Poziom 10  
    Zabrałem się ostro do pracy i już wiem, gdzie tkwi błąd! uC nie obsługuje przerwania. Pozmianiałem kilka razy kod ale to nadal nic nie dało
  • #12 8964457
    LordBlick
    VIP Zasłużony dla elektroda
    Pomieszałeś dwa sposoby obsługi transmisji - nie można stosować dwóch w tym samym czasie.
    Proponuję tu obsługę na przerwaniach i do niej się odniosę.
    1. Nie widzę wywołania inicjalizacji nadawania USART w main(). Powinno to polegać na włączeniu na stałe TXCIE. UDRIE natomiast włączasz na starcie transmisji i na jej końcu wyłączasz.
    2. W przerwaniu od TXC jest totalny chaos:
    - Nazwa wektora SING_USART0_TXC coś śpiewająca... ;)
    - Radośnie odkryłem tu ... inicjalizację USART, która nie będzie wywołana, bo USART nie został zainicjowany...
    - Co to za while ? Poczytaj jeszcze raz o obsłudze przerwań - mają być jak najkrótsze i żadnych dziwnych pętli.
    - To przerwanie służy do zakończenia transmisji, a nie kontynuacji, w przypadku, gdy nie musimy reagować po zakończeni transmisji (np. w RS485 przełączanie na odbiór), nie ma potrzeby w ogóle się nim przejmować - wystarczy zostawić je "na pusto".
    3. Brakuje obsługi UDRE w przerwaniu do obsługi właściwej transmisji.
    4. nadajznak() do kosza, w samym przerwaniu od UDRE (wywoływane, gdy wysłanie nastepnego znaku jest możliwe) wpisujesz UDR0=dana_z_np_bufora; i nic więcej nie kombinujesz z pętlami - na jedno przerwanie może być wysłany tylko jeden bajt.
    5. Dane z eeprom (odczyt z tej pamięci musi być niezależny od transmisji) najpierw przygotowujesz w pętli głównej (bufor ?) a w przerwaniu wysyłasz jeden bajt przygotowanych danych. Oczywiście musisz sobie sterowanie pomiędzy main i przerwaniem jakoś ułożyć (wskaźnik jakiegoś bufora typu voilatie), aby main nadążał z danymi z eeprom, którego odczyt jest wooolnyyy...
    W ATtiny2313 jest tylko jeden USART, więc nie występuje numeracja rejestrów i bitów tych rejestrów (nie UBRR0, tylko UBRR itd.)
    Ogólnie to proszę sobie poczytać Datasheet-a od układu w sekcji USART.
  • #13 8964884
    mirekk36
    Poziom 42  
    A ja proponuję poczytać jednak przynajmniej jakiś kurs C albo książkę bo na chwilę obecną poza setką błędów, które opisał m.in kolega wyżej to twój program (o ile można go nazwać programem) przede wszystkim wykona się tylko JEDEN RAZ i KONIEC. Zatrzyma się na amen, a ty czekasz czy coś się dzieje.
  • #14 8965034
    kaczart
    Poziom 14  
    Zacznij od "Kurs programowania mikrokontrolerów w C" przedstawiany kilka lat temu w elektronice dla wszystkich (znadziesz w necie). Już po pierwszej lekcji byś wiedział że w main, musisz dać pętle nieskończoną (a nie jakieś while(zakoncz)), a w obsługach przerwań wywoływać tylko krótkie czasowo procedury. Przerobisz 5-6 lekcji z tego kursu i bez problemu zrobisz, to co chcesz zrobić. Do DS18x20 znajdziesz również gotowe biblioteki w C - dobrze jest się uczyć na takich gotowcach i podglądać jak inni piszą kod.

    pozdrawiam
  • #15 8965862
    asembler
    Poziom 32  
    Ja bym się zastanowił na zasilaniu rejestratora z baterii. Pomijając większą ilośc zastosowań (mozemy zostawic w lodówce) to dodatkowo nie ma potrzeby dołączania zewnetrznej pamięci bo stosując np atmege 8 mamy do dyspozycji RAM 1024 pomiarów. W zalezności od gęstości pomiarów można pokryc pomiarami dość długi odcinek czasu (4 tyg.)Dodatkowo bardzo prosto zrealizowac nie tylko zapis temperatury ale też czas w którym te pomiary były dokonywane.
  • #16 13030795
    pibza
    Poziom 10  
    Dziękuję za pomoc

    Pozdrawiam :)
REKLAMA