Strona 1 z 3

Kondensator jako pamięć

: piątek 07 lut 2014, 17:27
autor: Pyra
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. :idea:
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.
Obrazek
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

: piątek 07 lut 2014, 18:12
autor: Mieciu
Pyra
bardzo dobry temat :-)
Powoli przymierzam się do budowy swojego sterownika 30-50W na arduino pro mini, mosfetach , czujniku prądu INA139 i czujniku temp LM35. Wczoraj zastanawialem się właśnie nad obsługą drugiego trybu.

Czy dobrze zrozumiałem że w części init dokonuję odczytu ADC z pinu podpiętego do kondensatora i jeżeli nic nie wykryję to dopiero ustawiam pin na high i lecę w pierwszym trybie?
Jeżeli natomiast coś wykryję przy starcie to lecę z drugim trybem i rowniez ustawiam pin na high?

Na jak długo starcza taka kombinacja RC 60k&#937; 1&#181;F żeby się rozładowało do 0?
Boję się że z ADC będę miał bardzo długo niezerowy odczyt, przecież jednostka to 5V/1024 czyli teoretycznie 0,00488V.

Fajnie jakbyś rozwinął temat... jakiś schemacik i fragment kodu może?

: piątek 07 lut 2014, 18:28
autor: Pyra
Witam
Schemat jest standardowy:
Obrazek
Oczywiście zamiast ATtiny13V musi być ATtiny13a. Nie wiem dlaczego, ale z wersją V, wykrywanie klika nie działa prawidłowo :-|
Kod jak widzisz umieściłem cały, nie stanowi on żadnej konkurencji dla Bociana i grega, ale ma służyć do przedstawienia idei.

Pozdrawiam
PS: jak słusznie zauważył alienth dzielnik w 105C wygląda inaczej, są to rezystory 19k1 i 4k7.

: piątek 07 lut 2014, 18:49
autor: ElSor
Widzę Sławku, że podałeś ładną bazę do dalszych modyfikacji.
Tylko czy aby na pewno podany kod realizuje "void Strobo() //stroboskop o jasności wybranego trybu", bo ja widzę, że mrugać ma z mocą 30% (skonfigurowaną w programie).

PS muszę się dowartościować szukając potknięć mistrza :razz:

: piątek 07 lut 2014, 18:55
autor: Pyra
Witam
ElSor pisze:PS muszę się dowartościować szukając potknięć mistrza :razz:
Raczej "miszcza" ;) W "C" dopiero raczkuję...
Masz rację, jakoś mi to umknęło, fragment przekopiowałem z innego programu i zmieniłem funkcję, a zapomniałem o komentarzu :-|
Pozdrawiam

: piątek 07 lut 2014, 18:58
autor: Mieciu
Dzieki za wskazówki
Ja będę swój kod w arduino pisał, w czystym C jeszcze się nie bawiłem.

: sobota 08 lut 2014, 19:40
autor: ElSor
Właśnie robię próby driverka. Kondensator z odzysku o pojemności 3,3uF (porównuję napięcie po starcie z wartością 200 zamiast 50). Dodany beacon pod 4-klikiem, strobo ustawione, by migało z mocą trybu, z którego zostało wywołane i nieco szybsze niż fabrycznie. Cóż mogę napisać - to chyba pierwszy "gotowiec" który działa bez problemu zaraz po zaprogramowaniu i który zostanie w którejś z moich latarek na stałe, oczywiście po drobnych poprawkach pod mój gust.
Sławku, ponownie zainspirowałeś mnie do zrobienia czegoś fajnego i pokazałeś drogę, więc za to chwała i dzięki Ci :!:

: sobota 08 lut 2014, 21:52
autor: Pyra
Witam
ElSor pisze:... Cóż mogę napisać - to chyba pierwszy "gotowiec" który działa bez problemu zaraz po zaprogramowaniu ...
He he, podam małą ciekawostkę, otóż są osoby, które autorytatywnie wypowiadały się, że to nie ma prawa działać (całe szczęście nie z naszego forum).
Jak uczy historia, wszyscy wiedzą, że coś jest niemożliwe, potem znajdzie się ktoś kto tego nie wie, i to zrobi ;)
Pozdrawiam

: sobota 08 lut 2014, 22:26
autor: ElSor
Pyra pisze:Jak uczy historia, wszyscy wiedzą, że coś jest niemożliwe, potem znajdzie się ktoś kto tego nie wie, i to zrobi ;)
Przypomniałeś mi tym właśnie sytuację z pracy z minionej środy. Poszedłem na sąsiedni dział pomóc chłopakom w montażu elektryki. Stali biedni i się głowili jak to zrobić, bo na rysunku jest to tak i tak. Ja nieświadom tego mówię, że tak i tak i nie trzeba nic przerabiać. Jeszcze chwilę postali i patrzyli na mnie jak na jakiegoś guru. Jeszcze jak im dodałem, że 7 lat robię w tej firmie to w ogóle słuchali mnie jak swojego przełożonego ;-)

Co do driverka to już siedzi w Convoyu S4 :mrgreen: :mrgreen: :mrgreen:
1 klik - przełącza tryby w górę w pętli od 2-5
2 klik - przełącza tryby w dól do 1
3 klik - włącza tryb 5 lub 1 w zależności od tego w którym trybie aktualnie jestem
4 klik włącza szybkie strobo z mocą z której został wywołany o wypełnieniu +/- 40% (4 jednostki czasu świeci a przez 6 jest ciemno)
5 klik włącza "police strobe" o mocy 100%
6 klik włącza beacon o mocy 100%
Latarki używam jako rowerowej a że prawie zawsze jest w kieszeni to także jako EDC.

: sobota 08 lut 2014, 22:42
autor: fotorondo
Z programowaniem zwykle jest tak ze zanim nie puścimy progsa po n poprawkach kodu to się nie dowiemy czy działa i czy zadziała.

po przejrzeniu kodu nie da się stwierdzić w 100% jego prawidłowości

Tak mi się wydaje.

pozdrawiam

: czwartek 27 lut 2014, 09:02
autor: pralat
Witam
Na wstępie dzięki za podzielenie się swoją wiedzą i kodem.
Chciałem uczynić kilka sugestii oszczędnościowych, jeżeli można. W ATTiny13A zawsze brakuje miejsca na dodatkowe bajery, więc może komuś przyda się parę dodatkowych bajtów.
Pyra pisze:void przerwa(unsigned int czas) //przerwa 5ms x czas
funkcja wywoływana jest z minimalnym parametrem 25, co daje sleep 125 ms. Można więc przerobić ją tak:
void przerwa(uint8_t czas)
...
_delay_ms(125); //czekaj 125ms
...

Dzięki temu ograniczy się argument funkcji z dwóch bajtów do jednego. To w praktyce da o kilka bajtów mniejszy kod.

Tak samo globalne zmienne, np. unsigned int short Ntryb=0 i pozostałe. Jeżeli można, warto zamienić je na 8-bitowe (uint8_t).

Dodatkowo funkcję Jasnosci() można zrobić bez pomocy switcha:

Kod: Zaznacz cały

void Jasnosci&#40;&#41; //ustalanie poziomu jasności według trybu
&#123;
	static const uint8_t jasnosc&#91;&#93; = &#123; 2, 64, 127, 255 &#125;;
	OCR0B = jasnosc&#91;Ntryb - 1&#93;;
&#125;
Oczywiście trzeba zadbać o odpowiednie wartości zmiennej Ntryb, ale widzę, że jest to robione

Po tych zmianach z początkowych 618 bajtów wynikowego kodu zrobiło się 484 (kompilowane gcc 4.5.3 z opcją -Os)

Pozdrawiam.

: czwartek 27 lut 2014, 16:04
autor: Pyra
Witam
Dzięki za sugestie. Widzę, że przeanalizowałeś kod, i o to chodziło, aby dać działającą bazę do rozwoju.
Zdaję sobie sprawę, że kod nie jest optymalny, gdyż z wrodzonego lenistwa, .... ;)
Pozdrawiam

: wtorek 11 mar 2014, 13:15
autor: alienth
Sławku mam pytanie,
czy w tej części kodu:

Kod: Zaznacz cały

if &#40;T1<515&#41;	 //jeśli napięcie niższe niż 3,0V
w nawiasie nie powinna być wartość 644 ?

Dla wartości 515 z wyliczeń wychodzi mi, że zmniejszasz PWM dopiero poniżej ~2,39V

Chyba, że ja coś źle liczę to proszę o poprawienie :)

: wtorek 11 mar 2014, 17:36
autor: Pyra
Witam
Masz rację, umieszczony schemat dotyczy driverka AK-47 i miał tylko przedstawić ogólną topologię układu. W 105C dzielnik składa się z rezystorów 1% 19k1 oraz 4k7.
Pozdrawiam

: środa 12 mar 2014, 03:11
autor: ElSor
Było kilka wersji 105C. U mnie wartość ADC=518 przełącza przy ok 2,9V.