Elektroda.pl
Elektroda.pl
X

Search our partners

Find the latest content on electronic components. Datasheets.com
Elektroda.pl
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 3985 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:

    Code:

    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:

    Code:

    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
    Code:

    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:


    Code:


    Plik = "temDD_MM" + ".txt"

    Mid(plik , 4 , 5 ) = Data_plik

    Code:

    oraz w odczycie czasu

     Data_plik = Bcd(dday) + "_" + Bcd(mmonth)

    oraz zmieniłem wpis zapisu
    [/code]
    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

    Code:

    $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

    Code:

    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:
    Code:


    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ą.

    Code:

    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".

    Code:

    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

    Code:


    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 ):

    Code:

    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

    Code:

    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 )

    Code:

    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 )

    Code:

    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 9  
    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ń :)