Projekt początkującego na Attiny2313


Jestem początkujący z dziedzinie elektroniki i mikrokontrolerów i jako początkowy projekt potrzebuję wykonać otwieranie 3 zamków.

Opis zastosowania:

Są 3 zamki elektromagnetyczne, przy których zamontowano po jednym przycisku żądania otwarcia. Po przyciśnięciu sygnał trafia do uC, co powoduje zapalenie się danej diody LED oraz uruchomienie buczka na 2 sekundy.
Aby otworzyć dany zamek, operator używa przycisku, co skutkuje zgaszeniem diody oraz wysterowaniem cewki przekaźnika obsługującego dany zamek.
Przysick reset wyłącza wszystkie diody led.

Zasilanie 12V podane na stabilizator oparty o układ LM7805:

S1, S2, S3 - przyciski służące do zgłoszenia żądania otwarcia danego zamka (zapalenie diody, buczek)
S4, S5, S6 - przyciski służące do otworzenia danego zamka (wysterowanie przekaźnika)
S7 - przycisk resetujący (zgaszenie diod)
LED1, LED2, LED3 - lampa sygnalizująca zgłoszenie
BUZZER - powiadomienie przez 2 sekundy dźwiękiem o zgłoszeniu
K1, K2, K3 - przekaźniki z cewką 5V, które sterują zamkiem

Obecny kod w Bascomie

'************* Konfiguracja uC *****************
'***********************************************
$regfile = "attiny2313.dat"
$crystal = 8000000                                          'wewnetrzny oscylator 8MHz
 
Config Portb=output                          'cały port b  jako wyjścia
       Portb=&B00000000                     'wszędzie stan spoczynkowy-0
Config Portd=input                         'cały port d jako wejścia
       Portd=&B1111111                      'wszędzie stan spoczynkowy-1
 
'Config Timer0 = Timer , Prescale = 8
'Enable Timer0 : On Timer0 Prztimer0
'Enable Interrupts
'********** Konfiguracja uC Koniec  ************
 
SW1 Alias Pind.0
SW2 Alias Pind.1
SW3 Alias Pind.2
SW4 Alias Pind.3
SW5 Alias Pind.4
SW6 Alias Pind.5
SW7 Alias Pind.6
LED1 Alias Portb.0
LED2 Alias Portb.1
LED3 Alias Portb.2
BUZZ Alias Portb.4
REL1 Alias Portb.5
REL2 Alias Portb.6
REL3 Alias Portb.7
 
'**************** Program *******************
Do
    Waitms 200
    if SW1=0 then Gosub Zapal1             'jeżeli przycisk 1 wciśnięty
    if SW2=0 then Gosub Zapal2             'jeżeli przycisk 2 wciśnięty
    if SW3=0 then Gosub Zapal3             'jeżeli przycisk 3 wciśnięty
    if SW4=0 then Gosub Otworz1            'jeżeli przycisk 4 wciśnięty
    if SW5=0 then Gosub Otworz2            'jeżeli przycisk 5 wciśnięty
    if SW6=0 then Gosub Otworz3            'jeżeli przycisk 6 wciśnięty
    if SW7=0 then Gosub Zeruj              'jeżeli przycisk 7 wciśnięty
 
  Loop                                     'koniec petli
End                                        'koniec programu
 
Zeruj:
  Reset BUZZ
  Reset LED1
  Reset LED2
  Reset LED3
  Reset REL1
  Reset REL1
  Reset REL1
Return
 
Buzzer:
  Set BUZZ
  Waitms 1000
  Reset BUZZ
Return
 
Zapal1:
  Set LED1
  Gosub Buzzer
Return
 
Zapal2:
  Set LED2
  Gosub Buzzer
Return
 
Zapal3:
  Set LED3
  Gosub Buzzer
Return
 
Otworz1:
  Set REL1
  Waitms 1000
  Reset REL1
Return
 
Otworz2:
  Set REL2
  Waitms 1000
  Reset REL2
Return
 
Otworz3:
  Set REL3
  Waitms 1000
  Reset REL3
Return

Z przeczytanych tekstów dotyczących mikrokontrolerów wydaje mi się, że powyższy kod powinien funkcjonować.
Zdaję sobie sprawę, że jeszcze niedociągnięcia dotyczące poleceń waitms - lepiej je zrobić na timerach... narazie chcę uruchomić projekt, aby zobaczyć jak działa, a potem będę mógł dopracować kod.




Portret użytkownika gosc

jak na pierwszy raz nieźle

Jak oprogramowałeś to samodzielnie to nawet nieźle wyszło. ((-;

Gdy nie jesteś pewien funkcjonowania odpal symulator, spróbuj popróbować z debounce.

Portret użytkownika meciarz

dzisiaj zmontowałem układ na

dzisiaj zmontowałem układ na płytce, załadowałem program i na razie jest dobrze, tzn. działa zgodnie z założeniem.
Fusebitów nie zmieniałem.
Jeśli chodzi o debounce, to jak zrozumiałem jest to programowe wykluczenie drgań styków (sprawdza czy przycisk jest faktycznie wciśnięty), czyli mogę użyć:

Config debounce = 25
 
Debounce SW1,0 , Zapal1         'zamiast  if SW1=0 then Gosub Zapal1

Nie ogarniam jeszcze o co chodzi konkretnie z Timer, jak odpowiednio wyliczyć, aby 1sek to była rzeczywiście 1sek

Z innej beczki:
Domyślnie jest włączony dzielnik częstotliwości ale on tyczy się oscylatora, tak?? czyli wewn. ustawiony na 8MHz /8 pracuje jako 1MHz, a sam procesor z 20MHz?

Portret użytkownika Grzeniu 73

Timer w zasadzie jak sie go

Timer w zasadzie jak sie go zrozumie to jest dosyć prosty.Proponuje Ci sciagnac sobie programik z Tej strony.Nazywa sie kalkulator avr. Dzieki niemu łatwo sprawdzić co ile jest przerwanie.
Timer po skonfigurowaniu przechodzi do przerwania co określony czas.Np:kwarc 16mhz Timer0 preskaler 256 przerwanie będzie co mniej więcej 4 ms. Teraz w przerwaniu zwiększasz sobie jakaś zmienna az osiągnie np:100ms
czyli 25 przerwan i masz 100ms.Nie bede podawał przykładów bo jak zerkniesz w programy Mirelya to praktycznie w każdym ma skonfigurowany Timer.Patrz na Przytimer: .Sterowanie przyciskami tez zrob tak jak to robi Mirley .Debounce to to samo Waitms.Jak będzie program rozbudowany to kiepsko to działa. Dzielnik dzieli tylko Timer. Procesor dalej jest taktowany 20mhz. Przez używanie Wait praktycznie nic więcej nie zrobisz w tym programie ,bo on większa cześć czasu czeka. Niestety tego programu nie dopracujesz zeby działał na Timerze,praktycznie całość musisz napisać od nowa.Na pocieszenie praktycznie wszystko co Ci potrzebne znajdziesz tu na stronce.Wystarczy ,ze poczytasz sobie projekty wraz z opisami. Co do urządzenia to chyba kiepsko to będzie działać.Przyciskiem załączasz zamek i dopóki nie wciśniesz reset będzie cały czas trzymał.Jeżeli to do drzwi to kiepskie rozwiązanie.Przycisk powinien załączyć zamek i powiedzmy po 5 sekundach go wyłączyć automatycznie.

Portret użytkownika meciarz

Dziękuję wszystkim

Dziękuję wszystkim zaangażowanym za pomoc.
Poprawiłem dzisiaj kod, korzystając z timera i teraz działa jak zakładałem, bez zwłok podczas wykonywania wait
Poniżej użyty kod

$regfile = "attiny2313.dat"
$crystal = 8000000
 
Config Portb = Output
       Portb = &B00000000
Config Portd = Input
       Portd = &B1111111
 
 
Config Timer0 = Timer , Prescale = 256
Enable Timer0 : On Timer0 Przerwanie0
Enable Interrupts
 
Dim Buzz_2s As Byte , Rel1_2s As Byte , Rel2_2s As Byte , Rel3_2s As Byte
 
SW1 Alias Pind.0
SW2 Alias Pind.1
SW3 Alias Pind.2
SW4 Alias Pind.3
SW5 Alias Pind.4
SW6 Alias Pind.5
SW7 Alias Pind.6
LED1 Alias Portb.0
LED2 Alias Portb.1
LED3 Alias Portb.2
BUZZ Alias Portb.4
REL1 Alias Portb.5
REL2 Alias Portb.6
REL3 Alias Portb.7
 
Do
    If Sw1 = 0 Then Gosub Zapal1
    If Sw2 = 0 Then Gosub Zapal2
    If Sw3 = 0 Then Gosub Zapal3
    If Sw4 = 0 Then Gosub Otworz1
    If Sw5 = 0 Then Gosub Otworz2
    If Sw6 = 0 Then Gosub Otworz3
    If Sw7 = 0 Then Gosub Zeruj
 
  Loop
End
 
Przerwanie0:
  If Buzz = 1 Then
    Incr Buzz_2s
        If Buzz_2s = 30 then
          Buzz_2s = 0
          Reset Buzz
        end if
  end if
 
  If Rel1 = 1 Then
    Incr Rel1_2s
        If Rel1_2s = 30 then
          Rel1_2s = 0
          Reset Rel1
        end if
  end if
 
  If Rel2 = 1 Then
    Incr Rel2_2s
        If Rel2_2s = 30 then
          Rel2_2s = 0
          Reset Rel2
        end if
  end if
 
  If Rel3 = 1 Then
    Incr Rel3_2s
        If Rel3_2s = 30 then
          Rel3_2s = 0
          Reset Rel3
        end if
  end if
 
Return
 
Zeruj:
  Reset Buzz
  Reset Led1
  Reset Led2
  Reset Led3
  Reset Rel1
  Reset Rel2
  Reset Rel3
Return
 
Buzzer:
  Set Buzz
Return
 
Zapal1:
  Set Led1
  Gosub Buzzer
Return
 
Zapal2:
  Set Led2
  Gosub Buzzer
Return
 
Zapal3:
  Set Led3
  Gosub Buzzer
Return
 
Otworz1:
  Reset Led1
  Set Rel1
Return
 
Otworz2:
  Reset Led2
  Set Rel2
Return
 
Otworz3:
  Reset Led3
  Set Rel3
Return

A jeszcze się tylko dopytam dla upewnienia: czy mogę wyłączyć dzielnik /8 jeśli korzystam z wew oscylatora?

Portret użytkownika Grzeniu 73

Kwarc nie ma znaczenia wew,

Kwarc nie ma znaczenia wew, czy zew.Program masz lepszy:) Jednak obsługa przycisków jest nie poprawna,tutaj akurat wciśniecie powoduje ,tylko wyłączenie to dlatego działa,gdybyś miał toggle lub incr/decr nie działałoby to poprawnie.Nie masz żadnego opóźnienia w pętli głównej.W zasadzie gosub jest tu nie potrzebne możesz to od razu napisać przy obsłudze przycisku.W przerwaniu masz flage_2s w rzeczywistości tam będzie około 250ms.Przerwanie jest wywoływane co 8,19 ms.Idziesz w dobra stronę jeszcze jedna poprawka i będzie już ok.Zobacz jak stosuje Mirley obsługę przycisków.Jak ja zrozumiesz to będziesz stosował w każdym projekcie,bo lepszego sposobu nie widziałem.

Portret użytkownika gosc

witam, no tak dla 8MHz by

witam,
no tak dla 8MHz by wyszło że 8,19 ms, ale jeśli mam (domyślnie) włączony dzielnik przez 8, to chyba przerwanie wychodzi co 65,536 ms i wydaje mi się że rzeczywiście były to 2 s (choć ze stoperem nie sprawdzałem) ;)
Co do obsługi przycisków, to przejrzę projekty Mirleya, aby to poprawić.

Portret użytkownika Grzeniu 73

Trochę ja nie rozumie albo

Trochę ja nie rozumie albo Ty.Jeżeli masz w fuse bitach 1mhz to w programie tez tak powinieneś mieć.I wtedy masz tak jak mówisz przerwanie co 65536 ms .Jeżeli jednak masz 8mhz tak jak to jest to w programie to masz przerwanie co 8,19

Portret użytkownika kaktus

obsługa przerwań

Postaw duży nacisk na to aby w "obsłudze" przerwania było jak najmniej kodu. Jego wykonywanie nie może "trwać długo" bo zaburza to ideologię i hierarchię takiego programowania. Ustawiaj tam np znacznik/flagę, a w pętli głównej wykonuj "całą robotę". ;-)

-

"Cierpliwym być musisz, by wiedzę zgłębiać tajemną, gdyż ciemna strona mocy niszczącą i silną jest.".

Portret użytkownika meciarz

Podsumowując, tak wygląda

Podsumowując, tak wygląda ostateczny schemat:

przekaźniki zostały podłączone przez tranzystor, gdyż prąd z attiny był zbyt mały, aby ruszyć cewkę.
Kod programu:

$regfile = "attiny2313.dat"
$crystal = 1000000
 
'końcówki PB2 do PB4 jako wyjścia, a reszta (PB0, PB1, PB5 do PB7) jako wejścia
Config Portb = &B00011100
       Portb = &B11100011
'końcówki PD0 do PD4 jako wyjścia, a od PD5 do PD6 końcówki jako wejścia
Config Portd = &B0011111
       Portd = &B1100000
 
 
Config Timer0 = Timer , Prescale = 256
Enable Timer0 : On Timer0 Przerwanie0
Enable Interrupts
 
Dim Buzz_2s As Byte , Rel1_2s As Byte , Rel2_3s As Byte , Rel3_3s As Byte
Buzz_2s = 0
Rel1_2s = 0
Rel2_3s = 0
Rel3_3s = 0
 
Dim Tmp_sw1 As Byte , Tmp_sw2 As Byte , Tmp_sw3 As Byte , Tmp_sw4 As Byte , Tmp_sw5 As Byte , Tmp_sw6 As Byte , Tmp_sw7 As Byte
Tmp_sw1 = 0
Tmp_sw2 = 0
Tmp_sw3 = 0
Tmp_sw4 = 0
Tmp_sw5 = 0
Tmp_sw6 = 0
Tmp_sw7 = 0
 
Sw1_P1 Alias Pind.6
Sw2_P2 Alias Pinb.0
Sw3_P3 Alias Pinb.1
Sw4_O1 Alias Pinb.5
Sw5_O2 Alias Pinb.6
Sw6_O3 Alias Pinb.7
Sw7_RST Alias Pind.5
 
Buzz Alias Portd.0
LedOtwarcie Alias Portd.1
Led1 Alias Portd.2
Led2 Alias Portd.3
Led3 Alias Portd.4
Rel1 Alias Portb.2
Rel2 Alias Portb.3
Rel3 Alias Portb.4
 
Do
    If Sw1_P1 = 0 And Tmp_sw1 = 1 Then
      Tmp_sw1 = 0
      Gosub Zapal1
    End If
    If Sw2_P2 = 0 And Tmp_sw2 = 1 Then
      Tmp_sw2 = 0
      Gosub Zapal2
    End If
    If Sw3_P3 = 0 And Tmp_sw3 = 1 Then
      Tmp_sw3 = 0
      Gosub Zapal3
    End If
    If Sw4_O1 = 0 And Tmp_sw4 = 1 Then
      Tmp_sw4 = 0
      Gosub Otworz1
    End If
    If Sw5_O2 = 0 And Tmp_sw5 = 1 Then
      Tmp_sw5 = 0
      Gosub Otworz2
    End If
    If Sw6_O3 = 0 And Tmp_sw6 = 1 Then
      Tmp_sw6 = 0
      Gosub Otworz3
    End If
    If Sw7_RST = 0 And Tmp_sw7 = 1 Then
      Tmp_sw7 = 0
      Gosub Zeruj
    End If
 
    If Buzz_2s = 31 then
      Buzz_2s = 0
      Reset Buzz
    End If
 
    If Rel1_2s = 30 then
      Rel1_2s = 0
      Reset Rel1
    End If
 
    If Rel2_3s = 45 then
      Rel2_3s = 0
      Reset Rel2
    End If
 
    If Rel3_3s = 45 then
      Rel3_3s = 0
      Reset Rel3
    End If
 
    If Rel1 = 0 AND Rel2 = 0 AND Rel3 = 0 then
      Reset LedOtwarcie
    End If
 
  Loop
End
 
Przerwanie0:
  If Sw1_P1 = 0 Then Tmp_sw1 = 1
  If Sw2_P2 = 0 Then Tmp_sw2 = 1
  If Sw3_P3 = 0 Then Tmp_sw3 = 1
  If Sw4_O1 = 0 Then Tmp_sw4 = 1
  If Sw5_O2 = 0 Then Tmp_sw5 = 1
  If Sw6_O3 = 0 Then Tmp_sw6 = 1
  If Sw7_RST = 0 Then Tmp_sw7 = 1
 
  If Buzz = 1 Then
    Incr Buzz_2s
  End If
 
  If Rel1 = 1 Then
    Incr Rel1_2s
  End If
 
  If Rel2 = 1 Then
    Incr Rel2_3s
  End If
 
  If Rel3 = 1 Then
    Incr Rel3_3s
  End If
 
Return
 
Zeruj:
  Reset Buzz
  Reset Led1
  Reset Led2
  Reset Led3
  Reset Rel1
  Reset Rel2
  Reset Rel3
Return
 
Buzzer:
  Set Buzz
Return
 
Zapal1:
  Set Led1
  Gosub Buzzer
Return
 
Zapal2:
  Set Led2
  Gosub Buzzer
Return
 
Zapal3:
  Set Led3
  Gosub Buzzer
Return
 
Otworz1:
  Reset Led1
  Set LedOtwarcie
  Set Rel1
Return
 
Otworz2:
  Reset Led2
  Set LedOtwarcie
  Set Rel2
Return
 
Otworz3:
  Reset Led3
  Set LedOtwarcie
  Set Rel3
Return