Kilka osób zadawało mi pytania związane z BASCOMem, tak więc postanowiłem coś napisać dla ogółu, może się komuś przyda.
Opis ograniczę do podstawowych komend przydatnych w latarkowym świecie i ATtiny13...
Na razie w procesorze nic nie musimy zmieniać, ustawienia fabryczne są wystarczające. Fusebity itp, zostawmy sobie na później.
Zaczynając pracę z Bascomem, musimy mu podać z jakim procesorem będziemy pracować. Możemy tego dokonać z menu głównego, "Options", "Compiler", "Chip" i tu z opcji wybieramy attint13. Można zaczynać...
Deklaracja zmiennych.
Dim L As Byte
Dim T As Eram Byte At &62
Dim U1 As Word
Dim - jest komendą odpowiedzialną za zarezerwowanie przestrzeni w pamięci, dla zmiennej, której będziemy używać
As Byte - określa typ zmiennej czyli ile miejsca rezerwujemy. Możliwe są określenia:
Bit - pojedyncza informacja "0" lub "1"
Byte - to jeden bajt (8 bitów, 0 - 255)
Word - 2 bajty (16 bitów czyli zakres 0 - 65535), np. odczyt ADC (10 bitów)
As Eram - określa, że zmienna będzie zapisana w nieulotnej pamięci, jej wartość będzie więc pamiętana pomimo wyłączenia procesora (np. pamięć trybu)
At - określa konkretną lokalizację zmiennej, przydatne w połączeniu z Eram, choć w przypadku jednej zmiennej niekonieczne, gdyż przydzielanie pamięci idzie od najniższego adresu, więc procesor za każdym razem odwoła się do tego samego miejsca.
Etykiety, to bardzo pomocne narzędzie, określają one miejsca, do których można skierować program instrukcjami Goto, Gosub...
Etykieta wygląda tak:
Wlacz/color]
Nie można tu stosować polskich znaków oraz słów zastrzeżonych przez kompilator, np. Start, Config, Loop itp.
Przykłady:
If Pinb.4 = 1 Then Goto Pomiar
........
Pomiar/color]
W podanym przykładzie program po natrafieniu na rozkaz skoku, przeniesie realizację komend do linii następnej po etykiecie "Pomiar:"
Aby procesor mógł się komunikować ze światem zewnętrznym musimy też określić funkcję wszystkich jego portów. Co ważne, możemy określić funkcję każdego pinu osobno. Służy do tego polecenie "Config"
Config PINB.1 = Output
Config PINB.3 = Input
Config PORTB.4 = Input
Polecenia Pin i PORT możemy stosować zamiennie, jednak czasem Pin nie chce działać poprawnie i wtedy PORT działa OK. Aktualnie mamy ustawione piny nr 4 i 3 portu B jako wejście a pin 1 jako wyjście.
Piny 3 lub 4 możemy wykorzystać jako wejście sygnału od przycisku (klika) lub pomiaru napięcia (ADC), natomiast pin 1 może sterować LEDem, przetwornicą czy AMCkami.
Jeśli chcemy pod któryś pin podłączyć np. przycisk to warto wykonać instrukcję:
Set PORTB.4
Co spowoduje wystawienie na tym pinie sygnału "1" czyli napięcia zasilania poprzez tzw rezystor podciągający, czyli normalnie procesor odczyta stan tego pinu jako "1" po zwarciu do masy, otrzymamy informację "0". Jest to jedyny wypadek, kiedy możemy bezkarnie zwierać pin do masy. Ma to tą zaletę, że nie musimy montować dodatkowego rezystora.
W przypadku gdy pin mamy ustawiony jako wyjście..
Set PORTB.1
spowoduje ustawienie logicznej "1" na pinie, a
Reset PORTB.1
spowoduje wystawienie "0" na danym pinie
Aby użyć przetwornika analogowo-cyfrowego, trzeba też go skonfigurować.
Config ADC = Single , Prescaler = 8 , Reference = Internal
Ustawiamy więc tryb pracy (Single - pojedyncze wyzwalanie) podział zegara systemowego (prescale) oraz, co bardzo ważne, ustawiamy wewnętrzne źródło napięcia odniesienia 1,1V (Internal)
Poleceniem związanym z powyższym jest:
U1 = Getadc(3)
Spowoduje to odczytanie z wejścia ADC3 napięcia i zapisanie jego wartości w zmiennej U1, przy czym npięcie 1,1V to wartość 1023, tak więc dla napięć wyższych trzeba stosować odpowiednie dzielniki.
Możemy więc w przybliżeniu określić, że wartość 1 ADC odpowiada 0,001075V. Biorąc pod uwagę, że największą dokładność uzyskujemy pod koniec zakresu pomiarowego, najczęściej stosowanym dzielnikiem jest 1:4 czyli zestaw rezystorów 1k/3k lub 10k/30k. Taki dzielnik daje nam możliwość pomiaru napięcia max na poziomie 1,1Vx4=4,4V. Dostajemy więc możliwość poprawnego pomiaru nawet ogniw naładowanych do 4,35V
Przykłady:
ADC = U / 0,001075 / 4 (ADC = napięcie pomiarowe / współczynnik pomiarowy / współczynnik podziału dzielnika wejściowego)
3,00V - ADC = 697
2,85V - ADC = 662
Ważną rzeczą jest, że jako określenie numeru wejścia ADC, możemy stosować zmienną numeryczną np:
U1 = Getadc(A)
gdzie zmienna A może przyjmować wartości od 0 do 3
Pozostaje konfiguracja PWM:
Config Timer0 = Pwm , Compare B Pwm = Clear Down , Prescale = 1
Za generowanie sygnału PWM odpowiada Timer0, posiada on dwa rejestry i przypisane do nich dwa wyjścia PWMa i PWMb, możemy je skonfigurować osobno lub razem. Clear Down oznacza, że timer będzie odliczał do zera od zadanej wartości, możemy odwrócić proporcje sygnału PWM stosując parametr Clear Up
Wartość PWM wpisujemy bezpośrednio do odpowiednich rejestrów, które można też traktować jako zmienne i używać do obliczeń, lub same mogą być wynikiem obliczeń, np.:
Pwm0b = 80
lub
Pwm0b = A
lub
A = Pwm0b
lub
Pwm0b = Pwm0b + 2
Drugim rejestrem jest:
Pwm0a
Rejestrowi można przypisać wartości od 0 do 255, przy czym 0 powoduje pojawienie się na wyjściu stałego sygnału logicznego 0 (wyłączenie PWM), a 255 pojawienie się stałej wartości 1, czyli max.
Ciekawostką jest system pracy PWM w normalnym trybie, de facto PWM jest 16 itowy, ale z 2 bitową rozdzielczością. Ma to związek z pracą timera, otóż praca jego polega na zliczaniu w te i z powrotem a każde przejście przez wartość zapisaną w rejestrze, powoduje zmianę stanu wyjścia PWM.
Przyjmijmy, że zapisujemy Timer0a = 50, wartość timera zmienia się następująco
0 - 50 tu następuje zmian stanu wyjścia PWMa
51 - 255 - przechodzimy do liczenia w dół
255 - 50 - następuje zmiana stanu wyjścia PWMa
50 - 0 i znów w górę
0 - 50 - 255 itd.
Aby obliczyć częstotliwość PWM, częstotliwość zegara dzielimy przez preskaler a następnie przez 512.
Aby podnieść częstotliwość PWM można ustawić tryb fastPWM, który powoduje zliczanie timera tylko w jedną stronę i wtedy mamy fck / prescaler / 256. Niestety ten tryb możemy ustawić tylko zapisując bezpośrednio rejestry konfiguracyjne.
Kwestia ustawiania poziomów jasności jest w tym przypadku względna, gdyż finalna wartość określana jest wydajnością samego sterownika (przetwornica, AMC), a my możemy ją określić w zakresie procentowym.
W związku z tym, że Timer0 jest 8 bitowy, więc mamy do dyspozycji 256 stanów, odrzucamy zero i zostaje 255 poziomów jasności, przy czym 255 oznacza 100%. Prosta matematyka 100/255=0,392. Mamy więc gotowy współczynnik %, czyli każde zwiększenie PWM o 1 powoduje wzrost jasności o 0,392%. Biorąc powyższe pod uwagę mamy możliwość uzyskać, w zaokrągleniu:
0,4% - PWM=1 veeery moon
5% - PWM=13
10% - PWM=26
30% - PWM=77
66% - PWM=169 itd.
Teraz reszta:
Goto Wlacz - Skok bezwzględny, program zostaje przekierowany do miejsca oznaczonego flagą Wlacz:
Gosub Wlacz - Skok bezwzględny do podprogramu Wlacz:
Wlacz/color]
........
Return Tu następuje powrót z podprogramu do instreukcji następnej po Gosub, która go wywołała
If warunek then polecenie
Warunek to może być:
A=0, L>10, B<>2.....
Może też to być sprawdzenie stanu pinu procesora
PinB.1 = 0
Polecenie, może być równaniem np. A=2 lub A=B czy A=A-1, może też być poleceniem skoku: Goto Wlacz, czy Gosub wlacz, np.:
If A = 56 then Goto Wlacz
Kolejną przydatną rzeczą są pętle warunkowe
For A = 4 to 32 step 4
......
Next
Pętla wykonuje wszystkie polecenia zawarte pomiędzy For a Next dopuki nie zostanie spełniony warunek A=32, przy czym zmienna w tym wypadku będzie w każdym kroku zwiększana o 4. Jeśli nie umieścimy "Step" to zmienna będzie standardowo zwiększana o 1
Alternatywnie możemy wykorzystać pętlę:
A=1
Do
........
Incr A
Loop Until A = 30
W tym wypadku będą wykonywane wszystkie instrukcje zawarte pomiędzy Do a Loop Until, aż A osiągnie wartość 30.
Incr A znaczy tyle samo co A=A+1, ale jest szybsze i zajmuje mniej pamięci. Analogicznie Decr A, będzie zmniejszać wartość zmiennej A.
Często przydaje się...
Waitms 2
Co spowoduje wprowadzenia opóźnienia do programu, w tym wypadku 2ms. Jako parametr możemy też użyć zmiennej
Waitms A
Shift U1, Right, 3
To polecenie spowoduje podzielenie zmiennej U1 przez 8, gdyż przesunięcie liczby o określoną ilość bitów w prawo jest jednoznaczne z dzieleniem (bez reszty) przez:
1 - 2
2 - 4
3 - 8
4 - 16 itd.
Analogicznie jeśli podamy Left 2, wykonamy mnożenie przez 4, szybki i zajmujący mało miejsca w pamięci sposób
On L Goto pocz , Tryb1, tryb2, Tryb3
To polecenie przydaje się gdy mamy wykonać skoki w różne miejsca programu, zależnie od wartości zmiennej (licznik klików), przy czym pierwszy parametr określa miejsce skoku dla L=0
Obliczanie średniej np. napięcia
Kod: Zaznacz cały
Do
Gosub Nap
Incr C
Loop Until C = 7
...
...
...
Nap:
U1 = Getadc(3)
U = U + U1
U1 = U
Shift U1 , Right , 3
Return
Kiedy następnie w głównej części programu natrafimy na:
Kod: Zaznacz cały
Gosub Nap
U = U - U1
If U1 < 670 Then Goto Dol
Procedura sprawdzania klika z mikroswitcha:
Kod: Zaznacz cały
Pwm:
Do
If Pinb.4 = 0 Then Goto Zmiana
Waitms 4
Gosub Nap
U = U - U1
If U1 < 670 Then Goto Dol
Loop
............
Zmiana:
B = 0
Zegar:
Gosub Zero
Do
Waitms 2
If Pinb.4 = 1 Then Goto Pomiar
Incr C
Loop Until C = 200
Kierunek:
On B Goto Pwm , Plus , Minus , Bat
Goto Pwm
...........
Pomiar:
If C < 4 Then Goto Pwm
B = B + 1
Waitms 4
C=0
Do
If Pinb.4 = 0 Then Goto Zegar
Waitms 2
Incr C
Loop Until C = 50
Goto Kierunek
Podprogram sprawdza czy minimalna długość przerwy jest większa od 4, znów prosta eliminacja drgań styków, jeśli była krótsza, wracamy na początek programu, jeśli była dłuższa, licznik klików zostaje zwiększony o 1. Teraz jeśli przerwa jest wystarczająco długa, skaczemy do interpretacji ilości klików, jeśli zmieściła się w zadanej długości to wracamy do pomiaru kolejnego naciśnięcia przycisku. proces ten jest powtarzany tak długo, aż przerwa w naciskaniu przycisku jest dłuższa od umownej wartości 50, co oznacza koniec "klikania" i przejście do Etykiety Kierunek: gdzie zależnie od ilości klików program zostaje skierowany do odpowiedniej procedury.
W głównej pętli znajduje się też, znany już fragment, odpowiedzialny z obniżenie trybu przy nadmiernym rozładowaniu ogniwa.
Na dziś tyle.
Pozdrawiam