Elektroda.pl
Elektroda.pl
X
Please add exception to AdBlock for elektroda.pl.
If you watch the ads, you support portal and users.

Atmega32 Bascom Zapis na SD i komunikacja UART pytania

maximus22_kr 16 Feb 2011 19:52 4021 14
  • #1
    maximus22_kr
    Level 18  
    Witam
    Chciałem zapytać, czy możliwa jest zmiana nazwy pliku w którym zapisują się wyniki - np co dziennie inna nazwa pliku ( np. powiązana z datą ) ? Używam PCF8583 i w sumie mógłbym brać informacje z zmiennych dnia i miesiąca lub dokonywać zmiany o 23:59:59.
    Używam standardowego kodu do zapisu:

    
    Sub Write_to_sd()
    Local Errorcode As Byte                                     ''()
         Gbdriveerror = Driveinit()
        If Gbdriveerror = 0 Then
          Errorcode = Initfilesystem(1)
          If Errorcode <> 0 Then
             Blad_sd = 1
          Else
             Reset Sd_dioda                                     'Zapala diodę LED
             Open "pomiar.txt" For Append As #2                 'otwórz plik pomiar.txt aby dopisać dane
             Write #2 , Data_pcf , "," , Czas_pcf , "," , "Pokoj" , Ss1 , "," , "Kaloryfer" , Ss2 , "," , "Zewnatrz" , Ss3       'zapisz dane: data, czas , odczyt temperatury
             Flush #2                                           'zapisz bufor pliku na karcie SD
             Close #2                                           'zamknij kanał transmisji sprzętowego urządzenia
             Blad_sd = 0                                        'ustaw zmienna na 0
             Set Sd_dioda                                       'zgaś diodę LED
          End If
        Else
          Reset Sd_dioda                                        'zapala diodę LED
          Blad_sd = 1
       End If
    
    End Sub
                          


    I drugie pytanie, tym razem o komunikacje UART. W ramach ćwiczeń połączyłem ATmega z komputerem i generalnie jest OK, tzn odbieram dane z uC i mogę sterować wyświetlaniem z PC. Ale posługuję się wyłącznie liczbami.
    Czy można wykorzystać litery lub litery + cyfry ?
    Jakiego polecenia użyć, czy trzeba zbierać wszystkie znaki do bufora ?

    W tej chwili robię to tak:

    
    Dim B As Byte
    
    B = Inkey()
    
    If B = 1 Then
    
         Gosub Temp1
    
    End If
    
    If B = 2 Then
    
         Gosub Temp2
    
     End If
    
    If B = 3 Then
    
         Gosub Temp3
    
    End If
                         
  • #2
    Fredy
    Level 27  
    zamiast :
    dim b as byte zrób
    dim b as string*1

    a następnie :

    if b="1"

    if b="a"

    if b=":"

    itd
  • #3
    maximus22_kr
    Level 18  
    Kierunek dobry, ale to pozwala na użycie tylko jednego znaku, który od razu jest przesyłany i następuje wykonanie instrukcji.
    Chciałbym aby instrukcja była wykonana po wpisaniu np. tekst1

    Chyba trzeba zastosować bufor, który będzie dopisywał do stringu kolejne znaki i dopiero po pojawieniu się znaku CR ( czyli kod ASCI 13 ) sprawdzał, czy jest to właściwy string.

    znalazłem coś takiego
    
    Do                            'Odbierz znak po znaku
      Kod = Inkey()
      Uart_txt = Uart_txt + Chr(kod)       'Zapisz w Uart_txt
      Bufor = Ischarwaiting()     
    Loop Until Bufor = 0 Or Kod = 13 'Zakoncz jeśli CR(Kod=13) lub brak znaku Bufor=0. 
    
    
  • #4
    maximus22_kr
    Level 18  
    Problem ze zmianą nazwy pliku rozwiązałem - oczywiście należy pamiętać, że nazwa pliku może być ośmio znakowa.

    W kodzie dodałem:


    
    
    Plik = "temDD_MM" + ".txt"
    
    Mid(plik , 4 , 5 ) = Data_plik
    

    
    oraz w odczycie czasu
    
     Data_plik = Bcd(dday) + "_" + Bcd(mmonth)
    

    oraz zmieniłem wpis zapisu
    [/code]
    
    Open Plik For Append As #2
    
    
    



    Problem z tekstem wysyłanym po UART częściowo też.

    Powstał nowy gdy dołożyłem UART do sterowania PWM

    
    $regfile = "m32def.dat"
    $crystal = 8000000
    $baud = 9600                                                ' predkość transmisji
    $hwstack = 32                                               ' rozmiar stosu sprzętowego
    $swstack = 10                                               ' rozmiar stosu
    $framesize = 40                                             ' rozmiar ramki
    
    'Config Serialin = Buffered , Size = 4
    'On Urxc Odczyt_rs
    'Enable Urxc
    
    '********************* Konfiguracja wejść i wyjść
    Config Porta.5 = Input                                      'Pc.0, Pc1 jako wejścia
    Set Porta.5
    Config Porta.6 = Input                                      'wszystkie jako wyjścia
    Set Porta.6
    
    
    '********************* Konfiguracja wyświetlacza
    Config Lcdbus = 4
    Config Lcdpin = Pin , Db4 = Portc.4 , Db5 = Portc.5 , Db6 = Portc.6 , Db7 = Portc.7 , E = Portc.2 , Rs = Portc.3
    Config Lcd = 16 * 2
    
    '********************* Deklaracje znaków specjalnych LCD
    
    Deflcdchar Print 0 , 32 , 4 , 4 , 4 , 31 , 14 , 4 , 32
    Deflcdchar 1 , 32 , 4 , 14 , 31 , 4 , 4 , 4 , 32
    Cls
    
    
    '********************* Konfiguracja Timer0
    
    Config Timer1 = Pwm , Prescale = 64 , Compare A Pwm = Clear Up , Compare B Pwm = Clear Up
    
    Enable Interrupts
    Enable Timer1
    
    
    '********************* Deklaracje podprogramów
    Declare Sub Up1
    Declare Sub Dn1
    Declare Sub Up2
    Declare Sub Dn2
    Declare Sub On1
    Declare Sub Off1
    Declare Sub Odczyt_rs
    
    
    '********************* Deklaracje wejść i wyjść
    W1 Alias Pina.5
    W2 Alias Pina.6
    St1 Alias Portd.5
    St2 Alias Portd.4
    
    '********************* Deklaracje zmiennych
    Dim A As Byte                                               ' zmienna określająca kierunek PWM
    Dim B As Byte                                               ' zmienna określająca kierunek PWM
    Dim C As Byte                                               ' zmienna określająca współczynnik szybkości zmian
    Dim E As String * 4
    Dim F As String * 4
    Dim Bufor As Byte
    
    
    '********************* Deklaracje wartości zmiennych
    A = 3
    B = 3
    C = 5
    
    
    '********************* Ustawienie wartości wyświetlanych przed uruchomieniem programu głównego
    
    Cls
    Locate 1 , 1                                                'ustawiamy pozycje kursora
    Lcd "St1="                                                  'wyświetl tekst
    Cursor Off Noblink                                          'wyłącz miganie kursora
    
    Locate 2 , 1                                                'ustawiamy pozycje kursora
    Lcd "St2="                                                  'wyświetl tekst
    Cursor Off Noblink                                          'wyłącz miganie kursora
    
    
    '********************* Program główny
    Do
    'F = Inkey()
    Call Odczyt_rs
    
    
     If W1 = 0 Then                                             ' jesli przycisk W1 wciśnięty
    
     If A = 3 Then                                              ' jeśli zmienna A = 3
     Gosub Up1
       Waitms 3                                                 ' idź do podprogramu Up1
     If W1 = 1 Then
     Locate 1 , 5
        Lcd " "                                                 'jesli przycisk W1 rozłączony
     Decr A                                                     ' zmniejsz wartość zmiennej A o 1
    
    End If
    End If
    End If
    
    If W1 = 0 Then                                              ' jesli przycisk W1 wciśnięty
    If A = 2 Then                                               ' jeśli zmienna A = 2
    Gosub Dn1
       Waitms 3                                                 ' idź do podprogramu Dn1
    If W1 = 1 Then
     Locate 1 , 5
        Lcd " "                                                 'jesli przycisk W1 rozłączony
    Incr A                                                      ' zwiększ wartość zmiennej A o 1
    
    End If
    End If
    End If
    
    
     If W2 = 0 Then
     If B = 3 Then
    Gosub Up2
     If W2 = 1 Then
     Locate 2 , 5
        Lcd " "
     Decr B
    
    End If
    End If
    End If
    
    If W2 = 0 Then
    If B = 2 Then
    Gosub Dn2
    If W2 = 1 Then
     Locate 2 , 5
        Lcd " "
     Incr B
    
    End If
    End If
    End If
    
    
    If E = "q" Or E = "onn1" Then
    Pwm1a = 255
    
    End If
    
    If E = "w" Or E = "off1" Then
    Pwm1a = 0
    
    End If
    
    
    
    
    Loop
    End
    
    '********************* Podprogramy
    
    Up1:
        If Pwm1a < 255 Then                                     ' rozjaśnianie LED na wyjściu 1 - Portd.5
        Pwm1a = Pwm1a + C
        Waitms 5
      Locate 1 , 5
        Lcd Chr(1)
        End If
        If Pwm1a = 255 Then
        Locate 1 , 7
        Lcd "100%"
       If W1 = 1 Then
        Waitms 700
        Locate 1 , 7
        Lcd "    "
        End If
        End If
       Return
    
    
    Dn1:
    
    If Pwm1a > 0 Then                                           ' ściemianie LED na wyjściu 1 - Portd.5
        Pwm1a = Pwm1a - C
        Waitms 5
        Locate 1 , 5
        Lcd Chr(0)
        End If
        If Pwm1a = 0 Then
        Locate 1 , 7
        Lcd "  0%"
       If W1 = 1 Then
        Waitms 700
        Locate 1 , 7
        Lcd "    "
        End If
        End If
        Return
    
    Up2:
      If Pwm1b < 255 Then
        Pwm1b = Pwm1b + C
        Waitms 10
        Locate 2 , 5
        Lcd Chr(1)
        End If
        If Pwm1b = 255 Then
        Locate 2 , 7
        Lcd "100%"
       If W2 = 1 Then
        Waitms 700
        Locate 2 , 7
        Lcd "    "
        End If
        End If
    
        Return
    
    Dn2:
    If Pwm1b > 0 Then
        Pwm1b = Pwm1b - C
        Waitms 10
        Locate 2 , 5
        Lcd Chr(0)
        End If
        If Pwm1b = 0 Then
        Locate 2 , 7
        Lcd "  0%"
       If W2 = 1 Then
        Waitms 700
        Locate 2 , 7
        Lcd "    "
        End If
        End If
        Return
    
    On1:
    Pwm1a = 255
    
    Return
    
    Off1:
    Pwm1a = 0
    
    Return
    
    
    Odczyt_rs:
    
    E = ""
    
    Do
                                                              'Odbierz znak po znaku
      F = Inkey()
      E = E + Chr(f)                                            'Zapisz w Uart
      Bufor = Ischarwaiting()
    Loop Until Bufor = 0 Or F = "13"
    
    Return
    
    


    Działa tylko opcja sterowania przez pojedyncze znaki - trochę za mało
    Czytając posty na forum wydaje mi się, że to przerwanie robi trochę problemów
  • #7
    maximus22_kr
    Level 18  
    Dziękuje koledze Xury, ten przykład z sms.bas był jak najbardziej trafny, oczywiście po drobnej modyfikacji

    
    Config Serialin = Buffered , Size = 4
    Enable Interrupts
    
    Dim E As String * 4
    Dim F As Byte
    F = 0 
    Declare Sub Odczyt_rs 
    Do 
    
    Call Odczyt_rs 
    
    End
    
    Odczyt_rs:
      E = ""
    
      Do
        F = Inkey()
        Select Case F
           Case 0                                               'nic
           Case 13 : If E <> "" Then Exit Do                    ' jeśli coś odebrane
           Case Else
            E = E + Chr(f)                                      ' utwórz ciąg
        End Select
    
      Loop
    
    Return
    
    


    U mnie działa to tak, że wpisanie ciągu który pasuje do jednego z warunków i naciśnięcie Enter powoduje sterowanie daną końcówką uC. U mnie string jest 4 znakowy. W moim przykładzie steruję dwoma wyjściami PWM ( czyli z timer0 ) oraz steruję procedurami ściemniania/rozjaśniania obydwu wyjść.

    Dodano po 1 [godziny] 1 [minuty]:

    Teraz zastanawiam się jak zrobić, aby była możliwość wpisania wartości PWM

    czyli coś takiego - oczywiście kod abstrakcyjny, tylko chodzi o idee:
    
    
    Dim D As Byte 
    Dim E As String * 4
    
    If E = "pow1:" + "ddd" Then
    D = "ddd"
    Pwm1a = D
    
    End If
    
    


    czyli do UART wysyłam
    pwm1:125 , gdzie 125 to wartość PWM
  • #9
    maximus22_kr
    Level 18  
    Dziękuję, mam tylko drobny kłopot
    Nie wiem jak ustawić warunek do badania
    Czy samo pojawienie się "pwm1:" powinno uruchomić wyciąganie znaków i konwersje, czy "pwm1: "

    wydaje mi się, że powinienem użyć najpierw MID a później VAL
    Zamienia tekstową reprezentację liczby na jej postać dziesiętną.
    Czyli z całego stringa zmiennej E najpierw wyciągnąć trzy znaki z ciągu licząc od szóstej pozycji, a następnie przez VAL zamienić na postać dziesiętną.

    
    If E = "pwm1:   " Then
    Gosub Konw_pwm1
    
    End If
    
    Konw_pwm1:
    
    D = Mid(e , 6 , 3)
    G = Val(d)
    
    Return
    
    
  • #10
    maximus22_kr
    Level 18  
    Witam
    Jak użyję kodu, czyli podam "na sztywno".

    
    Dim D1 As String * 8
    Dim D2 As String * 8
    Dim G as Byte
    
    D1 = "pwm1:050"
    D2 = Mid(d1 , 6 , 3)       ' wyciągnięcie liczby 050
    
    G = Val(d2)                  ' usunięcie 0
    


    otrzymuję wynik G = 50, czyli wszystko OK, natomiast nie udaje mi się zmusić programu do współpracy z stringiem E
  • #11
    maximus22_kr
    Level 18  
    Można prosić o dodatkowe wskazówki ? Może Kolega Xury coś pomoże ?

    dodałem w głównym programie

    
    
    Call Konw_pwm1 
    
    Konw_pwm1:
    
    
    D2 = Mid(e , 6 , 3)
    
    G = Val(d2)
    
    Pwm1a = G
    
    Return
    


    Efekt jest taki, że wpisanie np. "pwm1:120" ustawia Pwm1a na 120 i podając liczbową wartość Pwm działa jak trzeba, można poleceniem Off1 wyłączyć ( pwm1a = 0 ), nie działa włączanie ( pwm1a = 255 ) oraz rozjaśnianie ( pwm1a + C, C=5 ) oraz ściemnianie ( pwm1a -C, C = 5 )

    Zastanawiam się, czy nie można w podprogramie do odczytu dodać "case" sprawdzający wprowadzone znaki, czyli coś takiego ( oczywiście kod zapewne nieco abstrakcyjny ):

    
    Odczyt_rs:
      E = ""
    
      Do
    
        F = Inkey()
        Select Case F
           Case 0 to 4      'sprawdzenie pierwszych znaków
           E1 = Lookup(0, pwm)
           Case 13 : If E <> "" Then Exit Do                    ' jeśli coś odebrane
           Case Else
            E = E + Chr(f)                                      ' utwórz ciąg
        End Select
    
      Loop
    
    Return
    
    Pwm:
    Data 112 , 119 , 109 , 49 , 58                              ' pwm1: w  ASCII
    Data 112 , 119 , 109 , 50 , 58                              ' pwm2: w  ASCII
    
    


    Może trzeba ustalić jakiś "standard" komunikacji i np. przyjąć dwa warunki badania czyli
    ABCDE to będzie polecenie/funkcja
    123 to będzie wartość
  • #12
    xury
    Automation specialist
    Coś namieszałeś w tym podprogramie odbioru z UART.
    Najpierw czytasz do zmiennej F, potem to Case 0 to 4 (?). Jeśli używasz ASCII to skąd niby mogły by się odebrać takie wartości ? Potem nagle ni z tego i owego pojawia się zmienna E bez związku z odczytem.
    Myślę, że ciągle mylisz kod ASCII z liczbami i przez to masz problemy.
    Możesz też przed parsowaniem tekstu sprawdzić jego długość (Len)
    I w zależności od długości "wycinać" odpowiednią ilość znaków przeznaczonych do konwersji na liczbę. Np. jeśli wysyłasz "pwm1:120" to długość będzie 8 i możesz ciąć trzy ostatnie od tyłu. Jeżeli 7 (pwm1:55) to wycinasz dwa od tylu itd.

    Każde parsowanie wymaga jakiegoś standardu. Inaczej musisz przewidywać wszystkie anomalie w programie co jest trochę trudne.
    Jeżeli to co parsujesz jest liczbą to musi działać prawidłowo rozjaśnianie i ściemnianie. Podstawą jest prawidłowe parsowanie i to sobie sprawdzaj na symulatorze i wnoś poprawki.
  • #13
    maximus22_kr
    Level 18  
    Z pewnością masz rację z tym zamieszaniem ASCII, zwłaszcza, że ludzie raczej potocznie tego nie stosują.

    Chyba brakuje też trochę wyobraźni, mimo, że na kartce papieru całkiem mi to nieźle wychodzi - czasami :D

    Tak łatwo się nie poddam i jeszcze trochę to po wałkuję - założenie zrobiłem takie, cztery litery + trzy cyfry

    
    Odczyt_rs:
      E = ""
      Do
        F = Inkey()
        Select Case F
           Case 0                                                      ' jeśli 0 to nic nie ma
           Case 10                                                    ' ignoruj znak nowej linii
           Case 13 : If E <> "" Then Exit Do                    ' jeśli coś odebrane
           Case Else
            E = E + Chr(f)                                             ' utwórz ciąg E
        End Select
      Loop
    


    Do tej pory było prosto - ciąg znaków po wciśnięciu ENTER był porównywany z warunkami i jeśli któryś pasował, to była wykonywana instrukcja.

    Parsowanie z jednej strony wymaga sporo pogłówkowania, ale daje więcej możliwości.

    założenie cztery litery ( zawsze ) + trzy cyfry ( max )
    Przychodzi z terminala:
    onnn1 ( 1 oznacza wyjście Pwm1a, czyli włącz Pwm1a na maxa )

    
    Dim E As String*7
    Dim H As String*7
    Dim H1 As String*3
    Dim H2 As String*4
    Dim H3 As Byte
    Dim K As Byte
    Dim K1 As Byte
    Dim K2 As Byte
    
    E = H                     ' trzeba by ją zapisać do pomocniczej zmiennej H
    
    polecenie [b]LEN()[/b] faktycznie by się tutaj przydało, bo bez tego nie wiadomo ile wyciąć MID, czyli potrzebny warunek(i) wraz zmienna [b]K[/b] typu byte.
    
    K = LEN(H)
    Warunek
    If K = 5 Then
     If   K1 = 5 Then
        K2 = 1
     End If
    End If
    
    Następnie MID wyciągnąć z stringu cyfry, czyli
    H1 = MID(H , 5 , 1 )
    H3 = VAL(H1)
    czy nie powinno się wyciągnąć ze stringu również pierwszej jego części ?
    H2 =MID(H , 1 , 4 )
    
    i wtedy badanie warunku powinno wyglądać tak
    If H2 = "onnn" Then
     If H3 = "1" Then
      Pwm1a = 255
     End If
    End If
    


    Tylko jak to będzie w przypadku
    Z terminala przychodzi
    pwma150 ( czyli ustaw wartość 150 dla Pwm1a )

    
    K = LEN(H)
    Warunek
    If K = 7 Then
     If   K1 = 5 Then
        K2 = 3
     End If
    End If
    
    Następnie MID wyciągnąć z stringu cyfry, czyli
    H1 = MID(H , 5 , 3 )
    H3 = VAL(H1)
    czy nie powinno się wyciągnąć ze stringu również pierwszej jego części ?
    H2 =MID(H , 1 , 4 )
    
    i wtedy badanie warunku powinno wyglądać tak
    If H2 = "pwma" Then
    Pwm1a = H3
    End If
    


    Pewnie mój tok myślenia jest do niczego, ale spróbować nie zaszkodzi
  • #14
    xury
    Automation specialist
    No sposób parsowania danych i porównywania zależy wyłącznie od ciebie. Nie ma znaczenia jak to zrealizujesz jeżeli cel będzie ten sam, a mianowicie prawidłowe działanie. Można też parsowanie realizować np. za pomocą rozdzielania danych w stringu np. przecinkami jak to ma się np. w plikach csv. Wtedy dane mogą mieć różną długość byle by tylko kolejność była zawsze zgodna. Parsując dane po prostu znajdujemy przecinki i obrabiamy dane pomiędzy nimi.
  • #15
    uczesietak
    Level 10  
    Witam serdecznie :)
    Panowie, można i w ten sposób rozwiązać wyciąganie liczby z ciągu tekstowego .

    Code: basic4gl
    Log in, to see the code


    Mniej obciąża procesor.

    Pozdrawiam Pilny uczeń :)