logo elektroda
logo elektroda
X
logo elektroda
REKLAMA
REKLAMA
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

Atm16,Bascom. Jak zrealizować kilkakrotną zmianę stanu portu

karolczyzycki 28 Wrz 2009 23:07 6504 76
Najlepsze odpowiedzi LABEL_AI_GENERATED

Jak w BASCOM na ATmega16 poprawnie realizować wielokrotną zmianę stanu portu z użyciem timera, bez wchodzenia w błąd z wychodzeniem z przerwania przez GOTO?

Nie wychodź z przerwania przez GOTO — procedura ISR powinna być krótka, najlepiej tylko ustawiać flagę albo przełączać stan, a właściwą sekwencję czasów realizuj w pętli głównej lub drugim timerem [#7069212][#7285180] Jeśli program ma tylko generować impulsy, można użyć Waitms, ale trzeba pamiętać, że WAIT/WAITMS/WAITUS są tylko przybliżone i ich czas wydłużają przerwania [#7100605] Do sygnału NEC lepiej generować nośną sprzętowo na wyjściu OCxx timera w trybie CTC, a osobnym timerem albo logiką programu włączać i wyłączać tę nośną na czas ramki [#7075704][#7096031] Dla 8 MHz i preskalera 8 jeden tik to 1 µs, więc łatwiej liczyć opóźnienia, ale nadal nie należy robić ciężkiej logiki w ISR [#7096031] Jeśli chcesz skrócić kod, trzymaj czasy i stany w zmiennej/flagach, a nie skacz z przerwania do etykiet GOTO [#7069212][#7285180]
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA
  • #1 7069111
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Witam,
    Napisałem kawałek programu który ma generować przebieg na porcie b.0
    około 9ms - stan wysoki
    około 4,5ms - stan niski
    Użyłem do tego licznika, żeby odmierzał czas, dokładność tutaj akurat nie ma znaczenia.
    Problem w tym że nie działa to jak należy, tzn wykonuje się tylko jeden podprogram.
    Wiem że jest coś nie tak, bo po przepełnieniu licznika, wykonuje się znów ten sam podprogram.
    Jak zrobić żeby ustawić port jako "1" na jakiś czas, później zmienić na "0" na jakiś czas itd itd...

    Nie mam pomysłu na ten program...
    Jak można zrealizować, kilkakrotną zmiane stanu portu?
    Może być na podprogramach?


    $regfile = "m16def.dat"
    $crystal = 16000000                                         
    
    dim a as single
    Config Timer1 = Timer , Prescale = 1
    enable interrupts
    enable timer1
    on timer1 sygnal1
    cls
    
    Do
    loop                                                                                                    
    End
    
    
    sygnal1:
    
    timer1 = 65535
    incr a
    portb.0 = 1
    
     IF a = 308 then
       stop timer1
       a = 0
       goto sygnal2
     end if
    
    return
    
    
    sygnal2:
    
    start timer1
    timer1 = 65535
    incr a
    portb.0 = 0
     IF a = 150 then
       stop timer1
       a = 0
       goto koniec
    end if
    
    return
    
    
    koniec:
    portb.0 = 1
    end
  • REKLAMA
  • Pomocny post
    #2 7069212
    Konto nie istnieje
    Poziom 1  
  • #3 7071457
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    A jakąś podpowiedz? Czy może to być na podprogramach?
  • Pomocny post
    #4 7071864
    Konto nie istnieje
    Poziom 1  
  • #5 7073499
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    To jest program który powinien wygenerowac na portb.0 "1" na czas 9ms.
    $regfile = "m16def.dat"
    $crystal = 16000000                                      
    
    Dim A As Word    'Zmienna zwie;kszana i porównywana.
    Dim B As Byte     'Zmienna decyduja;ca z jaka; wartos'cia; be;dzie porównywana zmienna A.
    Config Timer1 = Timer , Prescale = 1 : Enable Interrupts : Enable Timer1 : On Timer1 Sygnal1
    
    b = 0
    a = 0
    PortB.0 = 0
    
    Do
    Loop
    End
    
    Sygnal1:
    Timer1 = 65376   'laduje do timera 65376 dla jednostki 10us (160 cylki x 0,0625us)
    Incr A
    
         If B = 0 Then
                  PortB.0 = 1                         ' na porcie pb.0 pojawi sie 1 na 9ms
                  If A >= 900 Then                 ' 10us * 900 = 9ms
                      A = 0                           
                      B = 1
                      goto koniec
                  end if
         End If
    
    Return
    
    koniec:
    portb.0 = 0
    end


    Jest to tylko teoria, bo rzeczywiście czas mierzony na oscyloskopie różni się i to sporo...
    W związku z tym nasuwa mi się kilka pytań:
    Nie wiem czy to słaba dokładność kwarca, czy ja coś robię źle...

    1. Czy dobrze obliczam czas?
    Dla:
    Częstotliwość: 16 MHz
    Prescale: 1
    Ilość cykli: 65536 (timer1)
    Czas taktu: 0,06250 us

    - jeśli 1 takt, to 0,0625us, więc 10us wynosi 160 taktów
    żeby procesor wykował 160 taktów muszę załadować 65376

    2. Czy za każdym razem jeśli w kodzie zmieniam wartość zegara, to w opcjach BASCOM też muszę zmienić?

    3. Czy z rezonatora 16MHz (zewn.) mogę taktować 1MHz'em? to się ustawia tylko fusebitami?

    4. Muszę uzyskać dokłądny czas 10us (który będę sobie później mnożył np razy 56, dla uzyskania 560us)
    Czy jest jakaś różnica w dokładności jeśli użyję oscylatora 1Mhz a 16MHz? (oczywiście resztę parametrów dobiorę do czasu 10us)
  • Pomocny post
    #6 7073547
    Konto nie istnieje
    Poziom 1  
  • #7 7073967
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Co do pytania 3, to chodzi mi o to że w procesorze mogę ustawić zegar, albo 1 labo 4 albo 8.
    A jeśli mam zewnętrzny kwarc 16, to można procesor taktować mniejszym zegarem np. 8 MHz'ami czy tylko taką prędkością jaki mam kwarc?

    Ja muszę mieć najmniejszą jednostkę 10us, bo potrzebny mi to jest do generowania kodu NEC.
    A np. logiczne zero w NECu to 560us wysoki i 560us niski.
    Żeby mieć liczbę całkowitą, to muszę użyć 10us.
  • REKLAMA
  • Pomocny post
    #8 7074458
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #9 7074553
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Ale mogę pisać to w bascomie a zrobić gdzie trzeba wstawki z asm?
    Czy cały progrma w asm?
  • Pomocny post
    #10 7074578
    Konto nie istnieje
    Poziom 1  
  • #11 7074713
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Przerwanie czyli to co procesor ma wykonać w czasie jednego cyklu?
    Tzn to wszystko: inf, then, tą pętlę zamienic na kod asm?
    Bo rozumiem że to są komendy które zajmują kilka cykli?
  • Pomocny post
    #12 7075204
    Konto nie istnieje
    Poziom 1  
  • Pomocny post
    #13 7075330
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    karolczyzycki napisał:

    A np. logiczne zero w NECu to 560us wysoki i 560us niski.
    Żeby mieć liczbę całkowitą, to muszę użyć 10us.

    Czemu nie można ustawić przerwania od razu co 560µs?
  • #14 7075356
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    ale u mnie jest problem w tym że przesunięcie występuje jeszcze przed etykietą signal.
    Tzn. jak laduje do licznika liczbę 65376 (zeby procesor wykonal 160 cykli, dla 10us) to nawet bez IF, już na oscyloskopie widać że to nie jest dokładnie 10us.


    Skoro wg Ciebie przesunięcie powodują komendy po signal, to taki kod powinien wygenereować "1" na 10us.
    Dobrze?

    $regfile = "m16def.dat" 
    $crystal = 16000000                                      
    
    Config Timer1 = Timer , Prescale = 1 : Enable Interrupts : Enable Timer1 : On Timer1 Sygnal1 
    
    PortB.0 = 0 
    
    Do 
    Loop 
    End 
    
    Sygnal1: 
    Timer1 = 65376   'laduje do timera 65376 dla jednostki 10us (160 cylki x 0,0625us)  
     PortB.0 = 1 
    goto koniec                            
    Return 
    
    koniec: 
    portb.0 = 0 
    end


    landy13 -> 560us to tylko przy "0"
    np. logiczna jedynka to 560us wysoki i 1690us niski

    A to juz jest problem bo nie da się podzielić 1690 przez 560 bez reszty...
    Dlatego jedyna największa jednostką jaką mogę używac to 10us.
    Mnożąc 10us razy 56 mam 560, razy 169, mam 1690 itd
  • Pomocny post
    #15 7075441
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    karolczyzycki napisał:

    A to juz jest problem bo nie da się podzielić 1690 przez 560 bez reszty...
    Dlatego jedyna największa jednostką jaką mogę używac to 10us.
    Mnożąc 10us razy 56 mam 560, razy 169, mam 1690 itd


    3*560=1680 To tylko 0,5% mniej od 1690. Każdy odbiornik to łyknie.
  • #16 7075461
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Ale mam tam napisane że to ma być częstotliwość 36kHz.
    Nie bardzo to rozumiem, czyli mam nadawać stan wysoki z częstotliwością 36kHz przez 560us?
  • Pomocny post
    #17 7075481
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    karolczyzycki napisał:
    czyli mam nadawać stan wysoki z częstotliwością 36kHz przez 560us?

    Otóż to. Tylko nie stan wysoki a nośną 36 kHz.
  • REKLAMA
  • Pomocny post
    #18 7075704
    Konto nie istnieje
    Poziom 1  
  • Pomocny post
    #19 7075828
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    I jeszcze jedno. Napisał Ci atom1477:
    Cytat:
    Wychodzisz z przerwania za pomocą GoTo. To jest problem.

    to go słuchaj, bo to mądry człowiek jest. Powtórzyłeś ten błąd we wszystkich programach w tym temacie.
  • Pomocny post
    #20 7075968
    epoxer
    Poziom 14  
    Posty: 95
    Pomógł: 1
    Ocena: 23
    Karol, miałem Ci napisać :P przez komunikator.. :D ale pisze tu.. może się przydać komuś :) pierwsze co to podam Ci pętle na 1us :) przy 16MHz w kodzie ASM

    
    $asm
      ldi R21, 0
      delay_1us:
        inc R21             
        cpi R21, 4        
      brlo delay_1us
    $end asm
    


    lub pisany kod z głowy :P ale jeszcze do udoskonalenia... :P całego przerwania na podstawie ostatniego Twojego skrawka kodu... :P

    na Pinie 0 w porcie B pojawi się stan wysoki na dokładnie 9us :)

    UWAGA! to kod dostosowany do 16MHz :P
    
    $asm
    ;gdzies po za przerwaniem
    ; Rejestr r22 ma wartosć 0
    clr R22
    ldi R20, 0xff
    out DDRB, R20 ; ustawienie Portu B jako wyjscia
    
    ;nastepnie wstawka w przerwaniu... :) 
    cpi R22, 0          ; sprawdzam czy r22 = 255 (1 cykl)
    brlo zero	          ;jezeli mniejsze to skocz do zero (2 cykle)
    			  ;w przeciwnym razie pomin skok i jedziemy dalej... ;P (1 cykl)
    ldi R20, (1<<PINB0) ;podnosimy stan pinu 0 na wysoki (1 cykl)
    out PORTB, R20	   ; przesyłamy na port B (1 cykl)
    ser R22               ;ustawienie 255 w r22, na to co u Ciebie w Bascomie oznaczone jako B :P 
    clr R21               ;zerowanie rejestru R21 (1 cykl)
    delay_us:
      inc R21                 ;zwiększenie R21 o jeden  (1 cykl)
      cpi R21, 35            ;porównanie bajta w R21 z liczbą 35 (1 cykl) 
    brlo delay_us         ; jezeli mniejsze od 35 to inkrementujemy (2 cykle)
    
    nop                     ;pusta instrukcja (1 cykl = 0,06us)
    nop                     ; dopelnienie do 9us petli bo będzie brakować :P :) 
    
    zero:
      ldi R20, (0<<PINB0) ; stan pinu 0 opuszczamy do zera :P (1 cykl)
      out PORTB, R20      ; przesyłamy na port B (1 cykl)
    
    endtim:
     reti ;wyjscie z przerwania
    $end asm
    

    Zapewne ktoś dopatrzy się błędów :D
    Jednak z mojej strony powiem, że Atom1477 dobrze kombinuje i warto sprawdzić jego przemyślenia... ;)
    Pozdrawiam
    :)
  • #21 7078343
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Na forum znalasłem program do odczytu kodów klawiszy do pilota NEC.
    Z tego co widzę to autor nie przejmował się zbyt dokłądnością.
    Nie wszystko tutaj rozumiem, mógłby ktoś w kilku słowach opisać jak to działa?

    Przepełnienie występuje co 96us
    co 96us wykonuje się etykieta tikers (nie wiem po co ta pętla 1200), to jest czas w którym powinien zostać odebrany cały sygnał? i jeśli ten czas minie, zmienne są zerowane i wraca do stanu początkowego?
    w momencie przerwania, (stan 0 na nóżce int0) program skacze do irfared
    I teraz:
    startuje licznik
    Nie wiem po co jest to:
    If Tik >= 139 And Tik < 150 Then  

    to jest przedział czasu w jaki procesor ma czekać na nagłówek?
    I dalej w jaki sposób jest odczytywana jedynka?

    '*******************************************************************************
    '* Filename    : IR NEC by http://www.sbprojects.com/knowledge/ir/ir.htm
    '* Revision    : 1.0
    '* Controller  : ATMEGA8
    '* Compiler    : BASCOM-AVR 1.11.8.3 DEMO
    '* Author      : Rubashka Vasiliy , Ukraine , 2007
    '* WWW         : http://ledeffects.net
    '* Mail        : info@ledeffects.net
    '* Thank you   : Aheir, aheir@radiokot.ru
    '*******************************************************************************
    $regfile = "m16def.dat"
    $crystal = 800000                                           'âíóo?aííeé aaía?aoî?
    '$lib "lcd4.lbx"
    Config Lcdpin = Pin , Rs = Portb.2 , E = Portb.3 , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7       'standard
    Config Lcd = 16 * 2
    Portb .1 = 1
    Config Pind.2 = Input
    Config Portc.2 = Output
    Config Timer0 = Timer , Prescale = 256                      '8000000/256=31250 Hz
    Config Int0 = Falling                                       'I?a?uâaíea iî niaäó
    Stop Timer0                                                 'înoaíaâëeâaai oaéia?
    Enable Timer0                                               '?aç?aoaai ?aáîoó oaéia?a0
    Enable Int0                                                 '?aç?aoaai ?aáîoó i?a?uâaíey0
    Enable Interrupts                                           '?aç?aoaai i?a?uâaíey
    
    On Timer0 Tikers                                            '?aáîoa iî oaéia?ó
    On Int0 Infrared                                            '?aáîoa iî i?a?uâaíe?
    
    Dim Tik As Word                                             'n÷¸o÷ee oeeîâ oaéia?a
    Dim Byt As Byte                                             'n÷¸o÷ee i?eíyouo áeo
    Dim Repeat_flag As Bit                                      'ôëaa iîâoî?a
    Dim Start_flag As Bit                                       'ôëaa noa?oîâîaî ónëîâey
    Dim Address As Byte                                         'áaéo aä?ana
    Dim Command As Byte                                         'áaéo eîiaíäu
    Dim Address_1 As Byte                                       'i?yiîé áaéo aä?ana
    Dim Command_1 As Byte                                       'i?yiîé áaéo eîiaíäu
    Dim Address_0 As Byte                                       'eíâa?níué áaéo aä?ana
    Dim Command_0 As Byte                                       'eíâa?níué áaéo eîiaíäu
    Dim Summa As Word
    
    
    Cls                                                         '*******************************************************************************
    
    Do                                                          'Îníîâíîé öeeë
    
                                                           'Î÷enoeoü AEE
    Cursor Off
    Locate 2 , 1                                                'Âueë?÷eoü eó?nî?
    Lcd Address ; " " ; Command                                 'Âuâanoe ía AEE AÄ?AN e EÎIIAÍÄÓ
    If Command = 8 Then Portc.2 = 1                             'Anëe íaaaoa eëaâeoa "P+" - âeë?÷eoü nâaoîäeîä
    If Command = 240 Then Portc.2 = 0                           'Anëe íaaaoa eëaâeoa "P-" - âueë?÷eoü nâaoîäeîä                                                 'Çaäa?aea 10 in
    Loop
    End                                                         'Eîíaö îníîâíîaî öeeëa
    
    '*******************************************************************************
    
     Tikers:                                                    '?aáîoa iî oaéia?ó
    
     Timer0 = 253                                               '31250/(256-253)=10416,66 Hz (96 ien)
                                                                 '254 - TV SAMSUNG, 253 - DVD SAMSUNG e ä?óaea NEC
     Incr Tik
     If Tik >= 1200 Then                                        'anëe ían÷eoaëe 1200 oeeîâ, ná?îneëe ân¸ â enoîäíîa nînoîyíea
     Tik = 0
     Repeat_flag = 0
     Start_flag = 0
     Address_1 = 0
     Command_1 = 0
     Address_0 = 0
     Command_0 = 0
     Command = 0
     Address = 0
     Stop Timer0                                                'înoaíaâëeâaai oaéia?
     End If
    
      Return
    '*******************************************************************************
    
     Infrared:                                                  '?aáîoa iî i?a?uâaíe?
    
      Start Timer0                                              'çaióneaai oaéia?
    
      If Tik >= 139 And Tik < 150 Then                          'anëe nëó÷eëînü îo 139 äî 150 oeeîâ - "NOA?O"
      Address = 1
      Repeat_flag = 0
      Start_flag = 1
      Address_1 = 0
      Command_1 = 0
      Address_0 = 0
      Command_0 = 0
      End If
    
      If Tik >= 116 And Tik < 139 Then                          'anëe nëó÷eëînü îo 116 äî 138 oeeîâ - "IÎÂOÎ?"
      Address = 2
      Repeat_flag = 1
      Start_flag = 0
      End If
    
      If Tik >= 22 And Tik < 116 And Start_flag = 1 Then        'anëe nëó÷eëînü îo 22 äî 115 oeeîâ - i?eíyëe "1"
       Incr Byt
    
        If Byt < 9 Then
         Shift Address_1 , Left
         Address_1 = Address_1 + 1
        End If
    
        If Byt >= 9 And Byt < 17 Then
         Shift Address_0 , Left
         Address_0 = Address_0 + 1
        End If
    
        If Byt >= 17 And Byt < 25 Then
         Shift Command_1 , Left
         Command_1 = Command_1 + 1
        End If
    
        If Byt >= 25 Then
         Shift Command_0 , Left
         Command_0 = Command_0 + 1
        End If
      End If
    
      If Tik >= 10 And Tik < 22 And Start_flag = 1 Then         'anëe nëó÷eëînü îo 10 äî 21 oeea - i?eíyëe "0"
       Incr Byt
    
        If Byt < 9 Then
         Shift Address_1 , Left
        End If
    
        If Byt >= 9 And Byt < 17 Then
         Shift Address_0 , Left
        End If
    
        If Byt >= 17 And Byt < 25 Then
         Shift Command_1 , Left
        End If
    
        If Byt >= 25 Then
         Shift Command_0 , Left
        End If
      End If
    
     Tik = 0
    
      If Byt = 32 Then                                          'anëe i?eíyëe 4 áaéoa, i?îâa?yai i?aâeëüíînoü i?e¸ia eîiaíäu
                                                                 'anëe aä?an eëe eîiaíäa 16-?e÷íua, i?îâa?ea ía i?îoîäeo, iîýoîió çaeîiiaíoe?îâaíî
        'Summa = Address_0 + Address_1
        'If Summa = 255 Then
        Address = Address_1
        'Else
        'Address = 0
        'End If
    
        'Summa = Command_0 + Command_1
        'If Summa = 255 Then
        Command = Command_1
        'Else
        'Command = 0
        'End If
      Byt = 0
      Repeat_flag = 0
      Start_flag = 0
      Stop Timer0                                               'înoaíaâëeâaai oaéia?
      End If
    
     Return
  • #22 7092390
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Witam.

    Napisałem taki najprostszy program bez żadnych pętli tylko kolejny stany.
    Na oscyloskopie czasy mniej więcej są dokładne (wiadomo że waitms nie jest takie precyzyjne) ale i tak coś nie działa.
    Mierząc oscyloskopem na diodzie nadawczej, przebieg jest OK.
    Ale na odbiorniku już sygnał jest zniekształcony, czasy przesynięte.


    Odbiornik NEC powinien pokazać 20DF 10EF, a pokazuje jakieś inne komendy dopiero, jak diodę przyłoże do odbiornika na 1mm.
    Czego brakuje w tym programie?

    $regfile = "m16def.dat"
    $crystal = 8000000
    
    config portc.7 = output
    portc.7 = 0
    
    start2:
    Do
    Waitms 100
    goto Send_Transmit
    Loop
    End
    
    
    
    Send_Transmit:
    
    '*****************HEADER*****************************
         Portc.7 = 1
         waitms 9
    
         Portc.7 = 0
         waitus 4500
    
    '*****************ADDRESS*****************************
    
    '20
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
    
    
    'DF
    
    
         Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
         Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
         Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                           ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                           ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                           ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
    
    '*****************COMMAND***********************************
    
    '10
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
         Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
          Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
          Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
    
    
    
         'EF
    
          Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                            ' 0
         waitus 600
         Portc.7 = 0
         waitus 600
          Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
          Portc.7 = 1                                            ' 1
         waitus 600
         Portc.7 = 0
         waitus 1730
    
    
    
    
    
    
    
    
    
      '***********************************************************
    
    
         Portc.7 = 1                                            ' koniec
         waitus 600
         Portc.7 = 0
         waitms 3100
    
      GOTO START2
    
    
  • Pomocny post
    #23 7092486
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    Cytat:
    Czego brakuje w tym programie?

    Nośnej. Dla NECa 38kHz.
  • #24 7095637
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Napisałem kod generowania nośnej, na oscyloskopie okres to 37us więc częstotliwość to 26kHz: (próbowałem już na różne sposoby ale nie dało się zwiększyć)

    $regfile = "attiny2313.dat"
    $crystal = 8000000
    Config Pinb.3 = Output
    Config Timer0 = Timer , Prescale = 1
    dim takt as integer
    Enable Interrupts : Enable Timer0 : On Timer0 przerwanie : Timer0 = 255
    takt = 0
    
    Do
      if takt = 300 then
      takt = 0
      portb.3 = 0
      waitms 200
      goto ir
    Loop
    End
    
    przerwanie:
    Timer0 = 255
    Toggle Portb.3
    incr takt
    Return


    Nie wiem teraz gdzie wstawić to włączanie i wyłączanie portu B.3.
    Zrobić to na IF, THEN?
    Próbowałem wstawić przykładową przerwę 200ms w pętlę DO, LOOP,(jak wyżej), ale nie działa.
    Jeśli zacznę wstawiać za dużo komend w etykietę "przerwanie" to znów czas się rozjedzie.
  • Pomocny post
    #25 7096031
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    Proponuję następujące zmiany:
    Dla zegara 8MHz
    Config Timer0 = Timer , Prescale = 8 

    wtedy jeden cykl = 1us - łatwo się liczy.
    Następnie w przerwaniu:


    Przerwanie:
          Timer0 = Timer0 + 213
          If Flaga = 1 Then
              Toggle Portc.7
            Else
              Portc.7 = 0
          End If
      Return

    Dalej w podprogramie "Send_transmit" zamiast: napisz: a zamiast:
    Portc.7 = 0   
    napisz: Powinno działać.

    Jeśli chodzi o ostatni program, to:
    Cytat:
    Próbowałem wstawić przykładową przerwę 200ms w pętlę DO, LOOP,(jak wyżej), ale nie działa.
    Jak sprawdzasz czy działa? Przecież to się nawet nie skompiluje.
  • #26 7098149
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    landy13 -> Poprzedni kod źle wkleiłem na forum, sprawdzam kompilując i programując.

    Przerobiłem kod, wysyła,ale jest problem z czasem...
    Atm16,Bascom. Jak zrealizować kilkakrotną zmianę stanu portu

    1. Fusebity są OK (załączam dla pewności)
    Atm16,Bascom. Jak zrealizować kilkakrotną zmianę stanu portu

    2. W kodzie zmieniłem na 8MHz (kod)

    $regfile = "attiny2313.dat"
    $crystal = 8000000
    Config Pinb.3 = Output
    Config Timer0 = Timer , Prescale = 8
    dim flaga as byte
    Enable Interrupts : Enable Timer0 : On Timer0 przerwanie : Timer0 = Timer0 + 213
    Do
    '*****************HEADER*****************************
         flaga = 1
         waitms 9
     Flaga = 0
         waitus 4500
    '*****************ADDRESS*****************************
    ...
    ...
    ...
    Loop
    End
    
    Przerwanie:
      Timer0 = Timer0 + 213
          If Flaga = 1 Then
              Toggle Portb.3
            Else
              Portb.3 = 0
          End If
    Return
    
  • Pomocny post
    #27 7098339
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    Cytat:
    To powinno mieć 9ms
    A ile ma? (nie znam się na takich oscyloskopach)
  • #28 7098433
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Jak dla mnie to 15ms
    Atm16,Bascom. Jak zrealizować kilkakrotną zmianę stanu portu
  • Pomocny post
    #29 7098541
    landy13
    Poziom 31  
    Posty: 1418
    Pomógł: 195
    Ocena: 260
    15ms do niczego nie pasuje. Wklej kod bezpośrednio z Bascoma, przepisywany może zawierać błędy.
  • #30 7098634
    karolczyzycki
    Poziom 20  
    Posty: 581
    Ocena: 43
    Ja już siedze nad tym kolejny dzień i ciągle mam problem z tymi czasami.
    Próbowałem przejść na ATMEGę 32 ale to samo.
    Nigdy nie ma 9ms, wiem że jakaś mała różnica może być, bo to wewn. zegar.
    Ale chyba nie aż taka (4ms)

    To jest kod który wgrywam.

    
    $regfile = "attiny2313.dat"
    $crystal = 8000000
    Config Pinb.3 = Output
    Config Timer0 = Timer , Prescale = 8
    
    dim flaga as byte
    Enable Interrupts : Enable Timer0 : On Timer0 przerwanie : Timer0 = Timer0 + 213
    
    
    Do
    
    
     '*****************HEADER*****************************
         flaga = 1
         waitms 9
     Flaga = 0
         waitus 4500
    '*****************ADDRESS*****************************
    '20
     Flaga = 1
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 1
         waitus 600
     Flaga = 0
         waitus 1730
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
    'DF
     Flaga = 1                                                  ' 1
         waitus 600
     Flaga = 0
         waitus 1730
     Flaga = 1                                                  ' 1
         waitus 600
     Flaga = 0
         waitus 1730
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 1
         waitus 600
     Flaga = 0
         waitus 1730
     Flaga = 1                                                  ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
    '*****************COMMAND***********************************
    '10
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 0
         waitus 600
     Flaga = 0
         waitus 600
     Flaga = 1                                                  ' 0
         waitus 600
     Flaga = 0
         waitus 600
      Flaga = 1                                                 ' 0
         waitus 600
     Flaga = 0
         waitus 600
      Flaga = 1                                                 ' 0
         waitus 600
     Flaga = 0
         waitus 600
    
         'EF
    
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 0
         waitus 600
     Flaga = 0
         waitus 600
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
      Flaga = 1                                                 ' 1
         waitus 600
     Flaga = 0
         waitus 1730
    
      '***********************************************************
     Flaga = 1                                                  ' koniec
         waitus 600
     Flaga = 0
         waitms 3100
    
    Loop
    End
    
    
    
    Przerwanie:
      Timer0 = Timer0 + 213
          If Flaga = 1 Then
              Toggle Portb.3
            Else
              Portb.3 = 0
          End If
    Return

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy realizacji wielokrotnej zmiany stanu portu mikrokontrolera Atmel AVR (głównie ATMega16, ATTiny2313) w języku BASCOM, z wykorzystaniem timerów i przerwań. Problemem było prawidłowe generowanie sygnału o określonych czasach trwania stanów wysokiego i niskiego (np. 9 ms i 4,5 ms) na porcie B.0, gdzie pierwotne podejście z użyciem GoTo w procedurze przerwania powodowało błędy i nieprawidłowe działanie. Zalecano zmianę koncepcji na użycie zmiennej flagowej sterującej stanem portu oraz modyfikację wartości porównania licznika w zależności od stanu flagi, co pozwala na przełączanie stanów w przerwaniu bez konieczności stosowania skoków GoTo.

Omówiono także ograniczenia dokładności czasowej wynikające z obsługi przerwań w BASCOM, gdzie czas obsługi przerwania i instrukcje języka wysokiego poziomu wydłużają rzeczywiste czasy, co utrudnia precyzyjne odmierzanie krótkich impulsów (np. 10 µs). Wskazano, że dla precyzyjnego generowania sygnałów o czasie rzędu mikrosekund konieczne jest stosowanie asemblerowych wstawek w procedurach przerwań lub wykorzystanie trybu CTC timerów do generowania nośnej (np. 36-38 kHz) sprzętowo na pinach OCxx.

Poruszono temat generowania sygnałów zgodnych z protokołem NEC (np. impulsy 560 µs i 1690 µs), gdzie nośna 36-38 kHz powinna być generowana sprzętowo, a włączanie i wyłączanie nośnej sterowane timerem lub flagą w programie głównym. Dyskutowano także o problemach z dokładnością funkcji waitms i waitus w BASCOM, które są zakłócane przez przerwania i działanie timerów, co powoduje wydłużenie rzeczywistych czasów oczekiwania.

W zakresie przechowywania i wysyłania kodów pilotów IR rozważano różne metody: przechowywanie kodów w zmiennych typu String lub w EEPROM, z zaleceniem stosowania zmiennych typu Byte do efektywnego zarządzania bitami i unikania nadmiernego zużycia pamięci. Podkreślono, że EEPROM adresuje bajty, a nie pojedyncze bity, więc manipulacja bitami odbywa się w RAM po odczycie.

Wskazano, że w procedurach przerwań należy minimalizować kod, najlepiej ustawiać flagi, które są obsługiwane w pętli głównej, co zmniejsza opóźnienia i ryzyko zakłóceń działania programu. Dyskutowano także o taktowaniu procesora, gdzie przy kwarcu 16 MHz można uzyskać jednostkę 10 µs, ale przy niższych częstotliwościach (np. 1 MHz) precyzja jest niewystarczająca.

Podsumowując, efektywne generowanie sygnałów czasowych w BASCOM wymaga stosowania flag sterujących w przerwaniach, minimalizacji kodu w procedurach przerwań, ewentualnych wstawek asemblerowych dla precyzji, oraz wykorzystania sprzętowych timerów w trybie CTC do generowania nośnej sygnału IR zgodnego z protokołem NEC. Przechowywanie kodów pilotów najlepiej realizować w EEPROM w postaci bajtów, a nie bitów czy stringów, dla optymalizacji pamięci i łatwości obsługi.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA