Witam,
W chwili obecnej pracuje nad termometrem, sterowanym na pilota. Pilot wysyła dane w kodzie RC5. Wysłane dane trafiają na odbiornik podczerwieni TSOP31236 (36kHz). W momencie gdy dane nie docierają na wyjściu odbiornika jest stan wysoki, gdy odbierze jakiś sygnał na wyjściu jest poziom niski. Wyjście odbiornika podczerwieni jest podpięte do wyjścia INT0. A więc, w momencie gdy poziom przejdzie z 1 na 0 powinno zostać wywołane przerwanie (niezależnie od kodu RC5, ma tylko zapalić diodę).
Obsługa przerwania jest prosta
Oczywiście, wcześniej musiałem odblokować przerwania czyniąc to w następujący sposób
Teraz trochę o samym programie i układzie. Program w pętli pobiera temperaturę otoczenia po czym ją konwertuje (trwa to 750ms, a w międzyczasie multipleksuje wyświetlanie temperatury na wyświetlaczu). Następnie skonwertowana temperatura jest poddawana obróbce, aby przerobić ją na taką, którą mogę wyświetlić na wyświetlaczu po czym znów następuje multipleksowanie. Wszystko działa ok, pod warunkiem, że w kodzie nie ma linijki sei(); (ale wtedy nie działa odbieranie danych z pilota). Gdy włączenie globalnego przerwania występuje w kodzie cale działanie układu ulega zmianie. Tzn układ pobiera temperaturę, jednak wyświetla tylko jedną cyfrę temperatury i to jedynie na krótką chwile. Potem znika na blisko sekundę i pojawia się na nowo.
Ponadto, obsługa przerwania powinna spowodować zapalenie się diody. Jednakże, gdy dane z pilota zostają odebrane dioda się zapala, a następnie gaśnie (gdy odbiornik przestaje odbierać podczerwień). W programie jednak nigdzie nie wygaszam diody.
Poniżej przedstawiam kod programu, postarałem się go skomentować w miarę jasno. Nie należy zawracać sobie głowy przy definicjach i funkcjach obsługi 1-wire. One działają poprawnie bo temperatura była już pobierana wielokrotnie dobrze wyświetlana na wyświetlaczu.
Zdaje sobie sprawę, że kod jest dość długi do sprawdzenia. Ale najprawdopodobniej błąd jest w funkcji main (), a większość kodu to obsługa 1wire.
Streszczając to co napisałem wyżej:
1. Dlaczego dioda gaśnie mimo, że przerwanie ją tylko zapala. (podpięta jest do portu D, pinu 5)
2. Dlaczego błędnie wyświetlana jest temperatura tj. widać jedną migotającą cyfrę.
Będę wdzięczny, za wszelką pomoc
W chwili obecnej pracuje nad termometrem, sterowanym na pilota. Pilot wysyła dane w kodzie RC5. Wysłane dane trafiają na odbiornik podczerwieni TSOP31236 (36kHz). W momencie gdy dane nie docierają na wyjściu odbiornika jest stan wysoki, gdy odbierze jakiś sygnał na wyjściu jest poziom niski. Wyjście odbiornika podczerwieni jest podpięte do wyjścia INT0. A więc, w momencie gdy poziom przejdzie z 1 na 0 powinno zostać wywołane przerwanie (niezależnie od kodu RC5, ma tylko zapalić diodę).
Obsługa przerwania jest prosta
ISR(INT0_vect)
{
_delay_ms(50);
PORTD |= _BV(5); // Zapal diodę
}
Oczywiście, wcześniej musiałem odblokować przerwania czyniąc to w następujący sposób
MCUCR |= 0x02; // przerwanie aktywne opadającym zboczem
GIMSK |= 0b01000000; // zezwol na INT0;
...
sei(); // globalne przerwanie odblokowane
Teraz trochę o samym programie i układzie. Program w pętli pobiera temperaturę otoczenia po czym ją konwertuje (trwa to 750ms, a w międzyczasie multipleksuje wyświetlanie temperatury na wyświetlaczu). Następnie skonwertowana temperatura jest poddawana obróbce, aby przerobić ją na taką, którą mogę wyświetlić na wyświetlaczu po czym znów następuje multipleksowanie. Wszystko działa ok, pod warunkiem, że w kodzie nie ma linijki sei(); (ale wtedy nie działa odbieranie danych z pilota). Gdy włączenie globalnego przerwania występuje w kodzie cale działanie układu ulega zmianie. Tzn układ pobiera temperaturę, jednak wyświetla tylko jedną cyfrę temperatury i to jedynie na krótką chwile. Potem znika na blisko sekundę i pojawia się na nowo.
Ponadto, obsługa przerwania powinna spowodować zapalenie się diody. Jednakże, gdy dane z pilota zostają odebrane dioda się zapala, a następnie gaśnie (gdy odbiornik przestaje odbierać podczerwień). W programie jednak nigdzie nie wygaszam diody.
Poniżej przedstawiam kod programu, postarałem się go skomentować w miarę jasno. Nie należy zawracać sobie głowy przy definicjach i funkcjach obsługi 1-wire. One działają poprawnie bo temperatura była już pobierana wielokrotnie dobrze wyświetlana na wyświetlaczu.
///////////////////////////////////////////////////////////////////////////////
// MAKRODEFINICJE
///////////////////////////////////////////////////////////////////////////////
#define OW_PIN 6 // numer pinu magistrali 1wire
#define OW_WY DDRD |= _BV(OW_PIN) // ustawienie magistrali jako wyjscie
#define OW_WE DDRD &= ~_BV(OW_PIN) // ustawienie magistrali jako wejscie
#define WE_1 (PIND >> OW_PIN) & 0x01 // bit na wejsciu ustawiony
#define WE_0 !WE_1 // bit na wejsciu wyzerowany
#define UST255 PORTB = 0xFF // gasi wszystkie segmenty wyswietlacza
#define SEGA ~_BV(5) // zapala segment A itd
#define SEGB ~_BV(4)
#define SEGC ~_BV(0)
#define SEGD ~_BV(2)
#define SEGE ~_BV(3)
#define SEGF ~_BV(7)
#define SEGG ~_BV(6)
#define SEGADP ~_BV(1)
#define ZERO UST255; PORTB &= SEGA; PORTB &= SEGB; PORTB &= SEGC; PORTB &= SEGD; PORTB &= SEGE; PORTB &= SEGF // zapala konkretne cyfry
#define JEDEN UST255; PORTB &= SEGB; PORTB &= SEGC
#define DWA UST255; PORTB &= SEGA; PORTB &= SEGB; PORTB &= SEGG; PORTB &= SEGE; PORTB &= SEGD
#define TRZY UST255; PORTB &= SEGA; PORTB &= SEGG; PORTB &= SEGD; PORTB &= SEGC; PORTB &= SEGB
#define CZTERY UST255; PORTB &= SEGF; PORTB &= SEGG; PORTB &= SEGB; PORTB &= SEGC
#define PIEC UST255; PORTB &= SEGA; PORTB &= SEGF; PORTB &= SEGG; PORTB &= SEGC; PORTB &= SEGD
#define SZESC PIEC; PORTB &= SEGE
#define SIEDEM JEDEN; PORTB &= SEGA;
#define OSIEM ZERO; PORTB &= SEGG;
#define DZIEWIEC UST255; PORTB &= SEGA; PORTB &= SEGB; PORTB &= SEGC; PORTB &= SEGD; PORTB &= SEGF; PORTB &= SEGG
#define DZIESIATKI PORTA = 0b10 // wybiera do wyswietlenia cyfrę dziesiatek
#define JEDNOSCI PORTA = 0b01 // wybiera do wyswietlenia cyfrę jednosci
///////////////////////////////////////////////////////////////////////////////
// PLIKI NAGŁOWKOWE
///////////////////////////////////////////////////////////////////////////////
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h>
///////////////////////////////////////////////////////////////////////////////
// ZMIENNE GLOBALNE
///////////////////////////////////////////////////////////////////////////////
char bufor[2]; // przechowuje cyfrę jednosci i dziesiatek
///////////////////////////////////////////////////////////////////////////////
// WYSYŁANIE
///////////////////////////////////////////////////////////////////////////////
void WyslijBit(char bit) // WYSŁANIE BITU (1-wire)
{
_delay_us(3);
OW_WY;
_delay_us(5);
if (bit == 1)
{
OW_WE;
_delay_us(90);
}
else
{
_delay_us(90);
OW_WE;
}
}
void WyslijBajt(char znak) // WYSŁANIE BAJTU (1-wire)
{
unsigned char i, pom;
for (i=0; i<8; i++)
{
pom = znak>>i;
pom &= 0x01;
WyslijBit(pom);
}
_delay_us(100);
}
///////////////////////////////////////////////////////////////////////////////
// INICJALIZACJA
///////////////////////////////////////////////////////////////////////////////
int Reset(void) // RESET (1-wire)
{
int podlaczony = 0;
OW_WY;
_delay_us(500);
OW_WE;
_delay_us(45);
if (WE_0)
podlaczony = 1;
_delay_us(350);
if (WE_1)
podlaczony = 1;
else
podlaczony = 0;
return podlaczony;
}
///////////////////////////////////////////////////////////////////////////////
// ODBIERANIE
///////////////////////////////////////////////////////////////////////////////
unsigned char OdbierzBit(void) // ODEBRANIE BITU (1-wire)
{
char bit = 0;
_delay_us(5);
OW_WY;
_delay_us(5);
OW_WE;
_delay_us(15);
if (WE_1)
bit = 0x01;
_delay_us(50);
return bit;
}
unsigned char OdbierzBajt(void) // ODEBRANIE BAJTU (1-wire)
{
unsigned char i, wartosc = 0;
for (i=0; i<8; i++)
{
if (OdbierzBit())
wartosc |= 0x01<<i;
_delay_us(15);
}
return wartosc;
}
///////////////////////////////////////////////////////////////////////////////
// MULTIPLEKSOWANIE
///////////////////////////////////////////////////////////////////////////////
void Multipleksuj(int x)
{
int i;
for (i=0; i<x; i++)
{
JEDNOSCI; // wyswietl cyfrę jako cyfrę jednosci
switch (bufor[1]) // w zaleznosci jaka cyfra byla w buforze rob switch
{
case '0':
ZERO; // wyswietl 0 itd
break;
case '1':
JEDEN;
break;
case '2':
DWA;
break;
case '3':
TRZY;
break;
case '4':
CZTERY;
break;
case '5':
PIEC;
break;
case '6':
SZESC;
break;
case '7':
SIEDEM;
break;
case '8':
OSIEM;
break;
case '9':
DZIEWIEC;
break;
}
_delay_ms(10);
DZIESIATKI; // zapal cyfrę dziesiatek i wyswietl zawartosc bufora
switch (bufor[0])
{
case '0':
ZERO;
break;
case '1':
JEDEN;
break;
case '2':
DWA;
break;
case '3':
TRZY;
break;
case '4':
CZTERY;
break;
case '5':
PIEC;
break;
case '6':
SZESC;
break;
case '7':
SIEDEM;
break;
case '8':
OSIEM;
break;
case '9':
DZIEWIEC;
break;
}
_delay_ms(10);
}
}
///////////////////////////////////////////////////////////////////////////////
// PRZERWANIA
///////////////////////////////////////////////////////////////////////////////
ISR(INT0_vect)
{
_delay_ms(50);
PORTD |= _BV(5); // zapal diode (reakacja na dane wyslane z pilota)
}
///////////////////////////////////////////////////////////////////////////////
// PROGRAM GŁÓWNY
///////////////////////////////////////////////////////////////////////////////
int main(void) // MAIN
{
char temperatura[2];
int temp;
char temporary;
div_t wynik;
MCUCR |= 0x02; // zbocze opadajace
GIMSK |= 0b01000000; // zezwol na INT0;
DDRD = 0b1111010;
PORTD = 0x00;
DDRA = 0xFF;
PORTA = 0b00;
DDRB = 0xFF;
PORTB = 0xFF;
UCSRB = 1 << TXCIE | 1 << TXEN; // przygoruj USART do nadawania
UBRRL = 25;
_delay_ms(100);
sei(); // wlacz globalne przerwania
while (1) // nieskonczona petla
{
if(Reset()) jesli znaleziono urzadzenie podpiete do 1 wire wykonaj kod
{
WyslijBajt(0xCC); // skip rom
WyslijBajt(0x44); // konwersja temperatury
Multipleksuj(38); // multipleksowanie w czasie trwania konwersji (zeby nie bylo przerwy w wyswietlaniu na czas konwersji)
Reset();
WyslijBajt(0xCC); // skip rom
WyslijBajt(0xBE); // odczytaj temperaturę
temporary = OdbierzBajt(); // przerabianie temperatury na znaki (tylko cyfra dziesiatek i jednosci)
temperatura[0] = (temporary >> 4);
temperatura[1] = (OdbierzBajt() << 4);
temp = temperatura[0];
temp |= temperatura[1];
Reset();
WyslijBajt(0xCC);
WyslijBajt(0xBE);
UDR = OdbierzBajt();
UDR = OdbierzBajt(); // wysyla temperaturę USART -> RS232
wynik = div(temp, 10);
bufor[0] = wynik.quot + 48;
bufor[1] = wynik.rem + 48;
Multipleksuj(100); // ponownie multipleksowane (ok 2sek)
Reset();
}
}
}
Zdaje sobie sprawę, że kod jest dość długi do sprawdzenia. Ale najprawdopodobniej błąd jest w funkcji main (), a większość kodu to obsługa 1wire.
Streszczając to co napisałem wyżej:
1. Dlaczego dioda gaśnie mimo, że przerwanie ją tylko zapala. (podpięta jest do portu D, pinu 5)
2. Dlaczego błędnie wyświetlana jest temperatura tj. widać jedną migotającą cyfrę.
Będę wdzięczny, za wszelką pomoc
