Kondensator jako pamięć
: piątek 07 lut 2014, 17:27
Witam
Jak wiadomo, podstawowym problemem przy rozpoznawaniu klików, jest trwałość pamięci eeprom. Analizując swoje doświadczenia z użytkowania latarek jak i użytkowników ,mniej zaawansowanych "światełkowo" zauważyłem, że zmiana trybów, nie jest wcale tak chętnie używana, a najczęściej, ustawiony jest jeden uniwersalny tryb wykonujący czarną robotę.
Większość procedur rozpoznawania klików, wykorzystuje zapis do eeprom po włączeniu latarki, następnie po jakimś czasie zapis jest zmieniany. Jeśli program przy starcie trafi na zapisaną komórkę eepromu, traktuje to jako sygnał do zmian. Problem polega na tym, że w czasie normalnej eksploatacji, mamy dwa zapisy do eepromu. Oczywiście można stosować sposoby na rozłożenie zapisu na wiele komórek itp. W zasadzie to zapis do komórki nie jest szkodliwy, a tylko jej skasowanie.
Ja postanowiłem pójść inną drogą i stworzyć pojedynczą komórkę RAM . Co daje takie rozwiązanie, otóż zapisy do eepromu, dokonywane są tylko w przypadku wykrycia kliku. Zwyczajne włączenie latarki nie wprowadza żadnych zmian do pamięci, tak więc mamy małą oszczędność pamięci.
Zasada pracy mojego rozwiązania jest bardzo prosta. Po starcie procesora, program sprawdza, czy na kondensatorze, występuje określone napięcie. Jeśli napięcie na kondensatorze jest, oznacza to, że przerwa w zasilaniu była bardzo krótka, czyli wystąpił klik, co jest sygnałem do wprowadzenia zmian... Co nam to daje, a no możemy teraz zmieniać tryby pojedynczym klikiem.
Jeśli program podczas startu nie stwierdzi obecności napięcia na kondensatorze, przechodzi dalej bez ingerencji w parametry. Skąd jednak napięcie na kondensatorze? Otóż zaraz po sprawdzeniu, obecności napięcia na pinie, jest on podciągany do plusa. Przy stosowanej pojemności około 1µF i rezystancji podciągającej procesora w okolicach kilkudziesięciu kiloomów (około 60k) bardzo szybko mamy napięcie zasilania na kondensatorze.
Problemem jednak okazało się wykrycie napięcia, mimo iż rezystancja wejściowa pinów to przedział megaomów, to zwykłe wykrycie stanu okazało się niewystarczające. Zmiana kondensatora na większy, była by bezcelowa, w związku rezystancją podciągającą. Nie chciałem do ładowania używać ustawiania stanu wysokiego po zmianie portu na wyjście, gdyż mogło by to przeciążyć port. Dodanie dodatkowego rezystora, też odrzuciłem jako mało praktyczne w realizacji.
Aby uprościć realizację przeróbki, postanowiłem wykorzystać jako pady lutownicze "gwiazdki" służące pierwotnie do zmiany grupy trybów. Czasem zdarzają się driverki, mające przygotowane pady do lutowania zworek, tu będzie jeszcze łatwiej.
Tak to wygląda w implementacji, jak widać kondensator w rozmiarze 805 jest wlutowany pomiędzy gwiazdką a minusem - masą.
Teraz przyszedł czas na rozwiązania programowe. Skoro zwykłe sprawdzenie pinu jest niewystarczające, to przecież mamy do dyspozycji przetwornik ADC, którym możemy wykryć naprawdę niskie napięcia.
Napisałem bardzo prosty program, który jest działający, jednak za względu na pewne uproszczenia, bardziej przyda się do nauki programowania początkującym, niż bezmyślnego wgrywania do procesorów.
Oto listing:
//sterownik ATtiny 13A 4 tryby stałe
//Fck = 9,6MHz
//Divide by 8 ON
#define F_CPU 1200000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
unsigned int short Ntryb=0; //numer trybu w pamięci ram
unsigned int short Lklik=0; //licznik klików w pamięci ram
unsigned int short A=1;
unsigned int short B=0;
unsigned int short EEMEM Numertrybu; //numer trybu w pamięci eeprom
unsigned int short EEMEM Licznikklikow; //licznik klików w pamięci eeprom
void przerwa(unsigned int czas) //przerwa 5ms x czas
{
while (czas > 1) //wykonuj dopóki czas >1
{
czas--; //zmniejsz czas o 1
_delay_ms(5); //czekaj 5ms
}
}
void Mryg() //mrugnięcie
{
B = OCR0B; //zapamiętaj jasność
OCR0B = 0; //zgaś LEDa
przerwa(25); //odczekaj 125ms, przekaż funkci liczbę 25
OCR0B = B; //przywróć jasność
przerwa(25); //funkcja opóźnienia 5ms, wykona się 25x
}
void Zakrestrybow() //sprawdzanie dopuszczalnego zakresu numeru trybu
{
if (Ntryb > 4) Ntryb = 1;
if (Ntryb < 1) Ntryb = 4;
eeprom_update_byte(&Numertrybu,Ntryb); //zapisz numer trybu jeśli się zmienił
}
void Jasnosci() //ustalanie poziomu jasności według trybu
{
switch(Ntryb)
{
case 1: OCR0B = 2; break; //0,8%
case 2: OCR0B = 64; break; //25%
case 3: OCR0B = 127; break; //50%
case 4: OCR0B = 255; break; //100%
}
}
void Zaswiec() //ustalenie trybu
{
Zakrestrybow(); //sprawdź zakres trybów
Jasnosci(); //ustal jasność
}
unsigned int pomiarnapiecia() //funkcja pomiaru napięcia
{
ADCSRA|= (1<<ADSC); //start konwersji
while (ADCSRA &(1<<ADSC)); //czekaj na koniec konwersji
return ADC; //zwróć wynik pomiaru
}
void Napiecie() //zabezpieczenie podnapięciowe
{
unsigned int T1=0;
ADMUX&= ~(1<<MUX1); //pomiar napięcia na dzielniku ADC 1 - skasuj MUX1, MUX0 = 1
ADMUX|= (1<<REFS0); //Vref = 1,1V - REFS0 = 1
T1 = pomiarnapiecia(); //wykonaj pomiar napięcia aku, wynik zapisz jako T1
if (T1<515) //jeśli napięcie niższe niż 3,0V - to:
{
if (OCR0B > 1) OCR0B>>=1; //jeśli PWM większy niż 1 to zmniejsz jasność o połowę
Mryg(); //mrugnij
}
}
void Strobo() //stroboskop o jasności 30%
{
eeprom_write_byte(&Licznikklikow, 255); //wykasowanie licznika klików, aby po wyjściu nie zmienić trybu
while(1)
{
OCR0B = 0; //zgaś LEDa
przerwa(25); //odczekaj 125ms
OCR0B = 85; //jasność 30%
przerwa(25); //odczekaj 125ms
Napiecie(); //sprawdź napięcie baterii
}
}
int main()
{
unsigned int T1=0; //zmienna 2 bajty, do zapisu wartości pomiaru ADC
Lklik = eeprom_read_byte(&Licznikklikow); //odczyt licznika klików
ADCSRA|= (1<<ADEN); //załączenie ADC
ADCSRA|= (1<<ADPS1) | (1<<ADPS0); //prescaler = 8
ADMUX=3; //ustaw pomiar napięcia na kondensatorze ADC3 PB3
//Vref = Vcc bo REFS0 =0 w ADMUX
T1 = pomiarnapiecia();
if (T1 > 50) Lklik++; //jeśli było napięcie, zwiększ licznik klików
if (Lklik > 5) Lklik = 0; //wyzeruj licznik klików jeśli większy od 5
eeprom_update_byte(&Licznikklikow, Lklik); //aktualizacja licznika klików jeśli się zmienił
PORTB|= (1<<PB3); //naładuj kondensator, podciągnij PB3 do VCC
TCCR0B|=(1<<CS00); //ustaw Timer0 prescaler = 1
TCCR0A|=(1<<WGM00)|(1<<COM0B1); //phase correct PWM - normalny PWM
DDRB|= (1<<PB1); //ustaw PB1 jako wyjście
Ntryb = eeprom_read_byte(&Numertrybu);
Zaswiec(); //ustaw jasność odczytanego trybu
przerwa(50); //odczekaj 250ms, czy będzie następny klik
eeprom_update_byte(&Licznikklikow, 0); //jeśli nie było klika, wyzeruj licznik klików w eprom
switch(Lklik) //wykonaj polecenie, zależnie od ilości klików
{
case 1:Ntryb++;break; //1 klik - tryb w górę
case 2:Ntryb--;break; //2 kliki - tryb w dół
case 3:Strobo();break; //3 kliki - stroboskop
}
Zaswiec(); //ustaw jasność po zmianach
while(1) //Pętla pomiarowa zabezpieczeń baterii, latarka swieci
{
Napiecie();
przerwa(1000); //odczekaj 5s
}
}
Jak widać program jest przeznaczony dla ludzi, którzy zaczynają przygodę z programowaniem, w związku z tym umieściłem sporo komentarzy przy liniach. Po kompilacji otrzymamy kod, który będzie chodził na driverkach 3 - 4 AMC, przy 8 już są problemy, ale też nie jest to "full wypas" więc trzeba się pogodzić z pewnymi ograniczeniami.
oprogramowanie ma 4 tryby zmieniane w pętlach, w górę i w dół. Dodatkowo jest strobo o jasności 30% wywoływane 3 - klikiem, oraz najprostsza ochrona ogniwa.
Życzę owocnych prób, zaczynającym przygodę z "C".
Pozdrawiam
Jak wiadomo, podstawowym problemem przy rozpoznawaniu klików, jest trwałość pamięci eeprom. Analizując swoje doświadczenia z użytkowania latarek jak i użytkowników ,mniej zaawansowanych "światełkowo" zauważyłem, że zmiana trybów, nie jest wcale tak chętnie używana, a najczęściej, ustawiony jest jeden uniwersalny tryb wykonujący czarną robotę.
Większość procedur rozpoznawania klików, wykorzystuje zapis do eeprom po włączeniu latarki, następnie po jakimś czasie zapis jest zmieniany. Jeśli program przy starcie trafi na zapisaną komórkę eepromu, traktuje to jako sygnał do zmian. Problem polega na tym, że w czasie normalnej eksploatacji, mamy dwa zapisy do eepromu. Oczywiście można stosować sposoby na rozłożenie zapisu na wiele komórek itp. W zasadzie to zapis do komórki nie jest szkodliwy, a tylko jej skasowanie.
Ja postanowiłem pójść inną drogą i stworzyć pojedynczą komórkę RAM . Co daje takie rozwiązanie, otóż zapisy do eepromu, dokonywane są tylko w przypadku wykrycia kliku. Zwyczajne włączenie latarki nie wprowadza żadnych zmian do pamięci, tak więc mamy małą oszczędność pamięci.
Zasada pracy mojego rozwiązania jest bardzo prosta. Po starcie procesora, program sprawdza, czy na kondensatorze, występuje określone napięcie. Jeśli napięcie na kondensatorze jest, oznacza to, że przerwa w zasilaniu była bardzo krótka, czyli wystąpił klik, co jest sygnałem do wprowadzenia zmian... Co nam to daje, a no możemy teraz zmieniać tryby pojedynczym klikiem.
Jeśli program podczas startu nie stwierdzi obecności napięcia na kondensatorze, przechodzi dalej bez ingerencji w parametry. Skąd jednak napięcie na kondensatorze? Otóż zaraz po sprawdzeniu, obecności napięcia na pinie, jest on podciągany do plusa. Przy stosowanej pojemności około 1µF i rezystancji podciągającej procesora w okolicach kilkudziesięciu kiloomów (około 60k) bardzo szybko mamy napięcie zasilania na kondensatorze.
Problemem jednak okazało się wykrycie napięcia, mimo iż rezystancja wejściowa pinów to przedział megaomów, to zwykłe wykrycie stanu okazało się niewystarczające. Zmiana kondensatora na większy, była by bezcelowa, w związku rezystancją podciągającą. Nie chciałem do ładowania używać ustawiania stanu wysokiego po zmianie portu na wyjście, gdyż mogło by to przeciążyć port. Dodanie dodatkowego rezystora, też odrzuciłem jako mało praktyczne w realizacji.
Aby uprościć realizację przeróbki, postanowiłem wykorzystać jako pady lutownicze "gwiazdki" służące pierwotnie do zmiany grupy trybów. Czasem zdarzają się driverki, mające przygotowane pady do lutowania zworek, tu będzie jeszcze łatwiej.
Tak to wygląda w implementacji, jak widać kondensator w rozmiarze 805 jest wlutowany pomiędzy gwiazdką a minusem - masą.
Teraz przyszedł czas na rozwiązania programowe. Skoro zwykłe sprawdzenie pinu jest niewystarczające, to przecież mamy do dyspozycji przetwornik ADC, którym możemy wykryć naprawdę niskie napięcia.
Napisałem bardzo prosty program, który jest działający, jednak za względu na pewne uproszczenia, bardziej przyda się do nauki programowania początkującym, niż bezmyślnego wgrywania do procesorów.
Oto listing:
//sterownik ATtiny 13A 4 tryby stałe
//Fck = 9,6MHz
//Divide by 8 ON
#define F_CPU 1200000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
unsigned int short Ntryb=0; //numer trybu w pamięci ram
unsigned int short Lklik=0; //licznik klików w pamięci ram
unsigned int short A=1;
unsigned int short B=0;
unsigned int short EEMEM Numertrybu; //numer trybu w pamięci eeprom
unsigned int short EEMEM Licznikklikow; //licznik klików w pamięci eeprom
void przerwa(unsigned int czas) //przerwa 5ms x czas
{
while (czas > 1) //wykonuj dopóki czas >1
{
czas--; //zmniejsz czas o 1
_delay_ms(5); //czekaj 5ms
}
}
void Mryg() //mrugnięcie
{
B = OCR0B; //zapamiętaj jasność
OCR0B = 0; //zgaś LEDa
przerwa(25); //odczekaj 125ms, przekaż funkci liczbę 25
OCR0B = B; //przywróć jasność
przerwa(25); //funkcja opóźnienia 5ms, wykona się 25x
}
void Zakrestrybow() //sprawdzanie dopuszczalnego zakresu numeru trybu
{
if (Ntryb > 4) Ntryb = 1;
if (Ntryb < 1) Ntryb = 4;
eeprom_update_byte(&Numertrybu,Ntryb); //zapisz numer trybu jeśli się zmienił
}
void Jasnosci() //ustalanie poziomu jasności według trybu
{
switch(Ntryb)
{
case 1: OCR0B = 2; break; //0,8%
case 2: OCR0B = 64; break; //25%
case 3: OCR0B = 127; break; //50%
case 4: OCR0B = 255; break; //100%
}
}
void Zaswiec() //ustalenie trybu
{
Zakrestrybow(); //sprawdź zakres trybów
Jasnosci(); //ustal jasność
}
unsigned int pomiarnapiecia() //funkcja pomiaru napięcia
{
ADCSRA|= (1<<ADSC); //start konwersji
while (ADCSRA &(1<<ADSC)); //czekaj na koniec konwersji
return ADC; //zwróć wynik pomiaru
}
void Napiecie() //zabezpieczenie podnapięciowe
{
unsigned int T1=0;
ADMUX&= ~(1<<MUX1); //pomiar napięcia na dzielniku ADC 1 - skasuj MUX1, MUX0 = 1
ADMUX|= (1<<REFS0); //Vref = 1,1V - REFS0 = 1
T1 = pomiarnapiecia(); //wykonaj pomiar napięcia aku, wynik zapisz jako T1
if (T1<515) //jeśli napięcie niższe niż 3,0V - to:
{
if (OCR0B > 1) OCR0B>>=1; //jeśli PWM większy niż 1 to zmniejsz jasność o połowę
Mryg(); //mrugnij
}
}
void Strobo() //stroboskop o jasności 30%
{
eeprom_write_byte(&Licznikklikow, 255); //wykasowanie licznika klików, aby po wyjściu nie zmienić trybu
while(1)
{
OCR0B = 0; //zgaś LEDa
przerwa(25); //odczekaj 125ms
OCR0B = 85; //jasność 30%
przerwa(25); //odczekaj 125ms
Napiecie(); //sprawdź napięcie baterii
}
}
int main()
{
unsigned int T1=0; //zmienna 2 bajty, do zapisu wartości pomiaru ADC
Lklik = eeprom_read_byte(&Licznikklikow); //odczyt licznika klików
ADCSRA|= (1<<ADEN); //załączenie ADC
ADCSRA|= (1<<ADPS1) | (1<<ADPS0); //prescaler = 8
ADMUX=3; //ustaw pomiar napięcia na kondensatorze ADC3 PB3
//Vref = Vcc bo REFS0 =0 w ADMUX
T1 = pomiarnapiecia();
if (T1 > 50) Lklik++; //jeśli było napięcie, zwiększ licznik klików
if (Lklik > 5) Lklik = 0; //wyzeruj licznik klików jeśli większy od 5
eeprom_update_byte(&Licznikklikow, Lklik); //aktualizacja licznika klików jeśli się zmienił
PORTB|= (1<<PB3); //naładuj kondensator, podciągnij PB3 do VCC
TCCR0B|=(1<<CS00); //ustaw Timer0 prescaler = 1
TCCR0A|=(1<<WGM00)|(1<<COM0B1); //phase correct PWM - normalny PWM
DDRB|= (1<<PB1); //ustaw PB1 jako wyjście
Ntryb = eeprom_read_byte(&Numertrybu);
Zaswiec(); //ustaw jasność odczytanego trybu
przerwa(50); //odczekaj 250ms, czy będzie następny klik
eeprom_update_byte(&Licznikklikow, 0); //jeśli nie było klika, wyzeruj licznik klików w eprom
switch(Lklik) //wykonaj polecenie, zależnie od ilości klików
{
case 1:Ntryb++;break; //1 klik - tryb w górę
case 2:Ntryb--;break; //2 kliki - tryb w dół
case 3:Strobo();break; //3 kliki - stroboskop
}
Zaswiec(); //ustaw jasność po zmianach
while(1) //Pętla pomiarowa zabezpieczeń baterii, latarka swieci
{
Napiecie();
przerwa(1000); //odczekaj 5s
}
}
Jak widać program jest przeznaczony dla ludzi, którzy zaczynają przygodę z programowaniem, w związku z tym umieściłem sporo komentarzy przy liniach. Po kompilacji otrzymamy kod, który będzie chodził na driverkach 3 - 4 AMC, przy 8 już są problemy, ale też nie jest to "full wypas" więc trzeba się pogodzić z pewnymi ograniczeniami.
oprogramowanie ma 4 tryby zmieniane w pętlach, w górę i w dół. Dodatkowo jest strobo o jasności 30% wywoływane 3 - klikiem, oraz najprostsza ochrona ogniwa.
Życzę owocnych prób, zaczynającym przygodę z "C".
Pozdrawiam