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.

Wpis do Attiny 13 EEPROM danych z USART

koczis_ws 09 Jan 2022 19:38 1083 39
  • #1
    koczis_ws
    Level 27  
    Witam serdecznie,
    Mam pewien program sterujący wentylatorem w łazience, który już działa dobrze.
    Ten program ma pewne parametry, które nim sterują. Niby mogę te parametry wpisać jako stałe do programu i w wypadku ich zmiany zaprogramować mikrokontroler ponownie. Ale ja chciałbym je wpisać do EEPROM i korygować ich wartości przez USART bez konieczności ponownego programowania.
    Attiny 13 nie ma wbudowanego USART, więc zainstalowałem programowy.
    Code: c
    Log in, to see the code


    Przesyłanie danych działa dobrze, ale jest problem z tym, że procedura blokuje działanie głównej pętli programu. Nie pomogło dodanie warunku liczenia pętli (zmienna n).
    Testowy program wygląda tak:
    Code: c
    Log in, to see the code

    LED powinien migać, ale niestety zapala się na stałe a mignie tylko w trakcie przesyłania danych przez USART.
    Miganie pojawia się gdy odblokuję linię '//return -1;' w funkcji uart_rx ale wtedy nie ma transmisji.
  • #2
    GanzConrad
    Level 25  
    Nie pasuje mi to, że "Dana" to char, skoro przyjmuje wartości ujemne.
    Led powinien migać 10 razy na sekundę, może miga szybciej bo masz źle ustawioną stałą czasową dla _delay_ms ?
    Poza tym, miganie zrobiłbym w Timerze, który byłby wyłączany na czas działania Uart.
  • #3
    tmf
    Moderator of Microcontroller designs
    Przede wszystkim masz błędną koncepcję obsługi UART - przenieś to na przerwania. Tak jak masz to teraz, z delay w pętli głównej to będzie działać tylko przez przypadek i okresowo.
    Po drugie, jeśli w funkcji odbioru znaku czekasz w nieskończoność na jakiś stan to nic dziwnego, że ci to blokuje pętlę główną.
    Moja rada - podepnij rxd pod pin z przerwaniem, w ISR odbieraj znaki. Wtedy nawet od biedy z delay. Wersja optymalniejsza - użyj dodatkowo timera i jego przerwań.
    Zajrzyj też do noty Atmela na temat implementacji soft UART - masz tam gotowe kody.
  • #4
    koczis_ws
    Level 27  
    GanzConrad wrote:
    Nie pasuje mi to, że "Dana" to char, skoro przyjmuje wartości ujemne.

    Tak , ale tu tylko test a zmiana Dana na int nic nie zmieniła.
    GanzConrad wrote:
    Led powinien migać 10 razy na sekundę, może miga szybciej bo masz źle ustawioną stałą czasową dla _delay_ms ?

    Jak odremuję tą podaną linię to miga 10 razy na sek.
    tmf wrote:
    Tak jak masz to teraz, z delay w pętli głównej to będzie działać tylko przez przypadek i okresowo.

    Nie, działa perfekcyjnie.
    tmf wrote:
    Po drugie, jeśli w funkcji odbioru znaku czekasz w nieskończoność na jakiś stan to nic dziwnego, że ci to blokuje pętlę główną.

    Przecież dodałem inkrementację zmiennej n i po przepełnieniu powinno wyjść z pętli i funkcji (return -1; ).

    Może proponowane zmiany poprawiły by sytuację, ale narazie nie mam pewności czy wystarczy na to skąpej pamięci Tiny13.
    Ale w międzyczasie wymyśliłem inne podejście. Niech sobie funkcja blokuje, ale będzie ona wywołana po uruchomieniu guzikiem procedury ustawiania parametrów zamiast wymuszania jakimś kodem z USART. W końcu w 99.99999999% czasu pracy programu USART nie będzie potrzebny.
  • #5
    kamyczek
    Level 38  
    Tiny 13 nie ma sprzętowego uarta ,więc programowy uart zawsze będzie blokował wykonywanie pętli głównej programu . Jego obsługę musi wykonać mikrokontroler tak jak program. Żeby to mogło działać to trzeba użyć przerwań i timera do obsługi uarta programowego a w czasie gdy ten liczy opóźnienia obsługiwać resztę . Tyle że najlepiej to takie rzeczy pisze się w asemblerze , szczególnie jak mikrokontroler ma 1k pamięci i takie zasoby jak ten . Możesz za to użyć sobie attiny 25, 45 lub 85 tam masz w najlepszym układzie 8k ale to i tak nie zmieni faktu że obsługa uarta musi być napisana z pomocą timera i przerwań , bo o wielowątkowości .to przy 8 bitowcach możesz zapomnieć .
  • #6
    koczis_ws
    Level 27  
    Ja to rozumiem. Przesyłanie danych tym programowym UART działa b. dobrze. Zastanawiam się tylko czemu inkrementacja zmiennej n nie wyrywa z pętli.
    Code: c
    Log in, to see the code

    Układ mam już zrobiony łącznie z PCB pod Tinny13, więc pozostanę przy tym. Jak bym miał zmieniać mikrokontroler to na Atmegę 8, która ma wbudowany UART.
    Ale poddałem się i zrobiłem tak, że wejście do funkcji przesyłania parametrów jest wyzwalane przyciskiem, a kończy się po przesłaniu bajtu STOP ( u mnie to znak @).
    Wybrany parametr ustawia się przesyłając kolejno znak START ( u mnie # ), potem numer parametru a następnie wartość. Wartości są jednobajtowe co upraszcza sprawę.
    Bajty przesyłam terminalem Putty, ale mam własny i przerobię go tak żeby ułatwić sobie pracę.
    Code: c
    Log in, to see the code

    Jeśli ktoś ma lepszy spsób to chętnie zobaczę.
  • #7
    koczis_ws
    Level 27  
    No i wyszło szydło z wora :(
    Wziąłem inną Tiny i nie działa przesył przez UART. Podejrzewam różnice w taktowaniu zegara.
    Myślę, że można pożonglować stałą 'UART_BIT_LENGTH' tylko nie wiem jak to ugryźć.
    Próbowałem różnie, np. zapisywałem w EEPROM żeby nie przeprogramowywać co chwilę mikrokontrolera z różnymi wartościami stałej , ale głównym problemem jest to , że _delay_us(wartosc) przyjmuje tylko stałą. Czy jest jakaś możliwość definiowania stałej za pomocą zmiennej?
  • #8
    gps79
    Level 30  
    koczis_ws wrote:
    Podejrzewam różnice w taktowaniu zegara.
    Fusebity dobrze ustawiłeś?

    no i chyba lepiej będzie użyć F_CPU
    Code: c
    Log in, to see the code
  • #10
    kamyczek
    Level 38  
    No trzeba tam wpisać wartość kalibracji przy starcie i będzie ok. T13 sama automatycznie tego nie robi , ale jak ktoś potrafi się pobawić to da się to zrobić tak że sama sobie odczytuje i wpisuje gdzie trzeba i działa bo pisałem swego czasu urządzenie które działa na rc i używa wewnętrznego oscylatora RC .
  • #12
    gps79
    Level 30  
    Przy pierwszym odbieranym bicie zaczekałbym połowę czasu trwania bitu, aby zminimalizować desynchronizację która może nastąpić w trakcie odbierania bajtu:
    Code: c
    Log in, to see the code
  • #13
    kamyczek
    Level 38  
    Wartość kalibracji masz wpisaną fabrycznie w układ , więc czytasz i wpisujesz albo w program , albo jak potrafisz ją przeczytać bezpośrednio , bo tak też się da , to czytasz to co producent wpisał i wpisujesz do odpowiedniego rejestry i masz jak dobrze pamiętam 0,1% błąd więc uart programowy działa jak powinien , chyba że ustawisz jakąś kosmicznie dużą prędkość to się jakiś byk może zdarzyć ...
  • #14
    bart-projects
    Level 24  
    @kamyczek - słabo znasz sprawę

    Do @koczisws . Układ jest wstępnie skalibrowany. Bajt kalibracji znajduje się w rejonie sygnatury i jest automatycznie wpisywany do rejestru zarządzającego oscylatorem OSCCAL. Wiec teoretycznie nie musisz tego robić.

    Można o tym poczytać w minutę. Otwierasz PDF do Tiny13 i w wyszukiwarce wpisujesz OSCCAL - kieruje do Register summary gdzie sobie przy nim klikasz na stronę (u mnie 26) i gotowe.
    Potem szukasz "SIGNATURE" i znowu kilka zdań. Prosta sprawa.

    Niemniej można go skalibrować "ręcznie" dokładniej, ale przy pomocy na przykład AVR ISP MkII w Atmel Studio. On go tam jakoś programuje i każe mu machać pinem po czym mierzy częstotliwość. Na końcu może Tobie zapisać bajt kalibracji we flash albo eeprom. Taki bajt wtedy musisz sobie odczytać sam i po restarcie uC wpisać do OSCCAL.
    Możesz też "tuningować na piechotę sam pisząc jakiś programik do częstotliwości i przed uruchomieniem programu zmieniając wartość OSCCAL.
    Zapisaną wartość bajtu kalibracji odczytuje wiekszość programatorów więc wtedy najczęściej wartość zwiększasz sobie tylko lub zmniejszasz o jeden.
    Należy pamiętać, że tuning OSCCAL jest przewidziany dla prędkości 4.8MHz i 9.6MHz a nie dla 1.2MHz

    Wpis do Attiny 13 EEPROM danych z USART
  • #15
    koczis_ws
    Level 27  
    bart-projects wrote:
    Należy pamiętać, że tuning OSCCAL jest przewidziany dla prędkości 4.8MHz i 9.6MHz a nie dla 1.2MHz

    I tu jest pies itd. . . . .
    Ja mam prędkość 1MHz bo przy takiej są prawidłowe czasy dla _delay. Więc zabawa z kalibracją nie wchodzi w rachubę.
    W bibliotece do wysyłania danych jest możliwość korekcji czasu poprzez ustawienie OCR0A.
    Dla odbierania trzeba by wyliczyć stałą 'UART_BIT_LENGTH', ale jak to zrobić?
  • #16
    kamyczek
    Level 38  
    Tak z pewnością tak napisali , tylko czasem warto to sprawdzić , bo bywa z tym ci piszą różnie . Można sobie zwrócić przez uarta wartość rejestru , będzie widać czy na pewno tak jest jak napisali .
  • #17
    jvoytech
    Level 14  
    koczis_ws wrote:
    bart-projects wrote:
    Należy pamiętać, że tuning OSCCAL jest przewidziany dla prędkości 4.8MHz i 9.6MHz a nie dla 1.2MHz

    I tu jest pies itd. . . . .
    Ja mam prędkość 1MHz bo przy takiej są prawidłowe czasy dla _delay. ...

    _delay jest softwarowe i żeby czasy były prawidłowe musisz zadeklarować F_CPU (jako makro lub w ustawieniach preprocesora) tak aby był zgodny z częstotliwością rezonatora oraz ewentualnie dodatkowo uwzględnić podzielniki częstotliwości (fusebity).

    Code: c
    Log in, to see the code


    Quote:
    Dla odbierania trzeba by wyliczyć stałą 'UART_BIT_LENGTH', ale jak to zrobić?

    trzeba zamienić to 1e-6 na "1/F_CPU", żeby nie być zależny od tego 1MHz, na przykład tak:
    Code: objc
    Log in, to see the code
  • #18
    bart-projects
    Level 24  
    Przecież to na palcach albo w głowie można policzyć... :D
    Tiny13A jest specyficzne bo ma oscylator 9.6MHz a nie 8MHz jak reszta uC więc z podzielnikiem CKDIV8 kręci się na 1.2MHz.
    Teraz najprostsze... Baud 9600 tak? F_CPU 9600_000 tak? Ktoś nie widzi korelacji?
    Zostaje 1000 ... a przy podzielniku CKDIV8 125....

    Tylko o tej "specyficzności" Tiny13 trzeba pamiętać bo potem żadne "czasy" nie pasują.
  • #19
    koczis_ws
    Level 27  
    bart-projects wrote:
    Przecież to na palcach albo w głowie można policzyć...

    Można łatwo policzyć pod warunkiem, że oscylator daje dokładnie 9.6 MHz. Ale jak nie, to trzeba zmierzyć tą prawdziwą i dla niej wyliczyć prawidłowe UART_BIT_LENGTH.
  • #20
    kamyczek
    Level 38  
    Jeśli kalibracja wpisuje się automatycznie tak jak tam pisał bart to się kolego czepiasz nie tego co powinieneś . Masz błąd w programie i tylko tyle , wygeneruj sobie w prosty sposób sygnał prostokątny na wolnym pinie i zweryfikuj jaką ma częstotliwość . Uart powinien działać bez problemu przy błędzie prędkości rzędu 2% .
    I zacznij kolego od analizatora i wysłania 1 bajtu i sprawdzenia jaką ma rzeczywiście prędkość , i jak wygląda przebieg , czy przypadkiem nie jest zdeformowany przez inne operacje wykonywane losowo w czasie wysyłania przez uart .
  • #21
    koczis_ws
    Level 27  
    kamyczek wrote:
    Jeśli kalibracja wpisuje się automatycznie tak jak tam pisał bart to się kolego czepiasz nie tego co powinieneś . Masz błąd w programie i tylko tyle

    Zmierzyłem rzeczywiste czasy generowane przez _delay_ms dla dwóch egzemplaży Tiny, z których jeden pracował a drugi nie. Różnice czasów wynosiły 6.25%. Przeliczyłem i skorygowałem program dla tego niepracującego.

    Code: c
    Log in, to see the code


    We właściwościach projektu wpisałem F_CPU=1060000UL
    To zadziałało :) Teraz mogę ustawiać parametry przez UART.
  • #22
    koczis_ws
    Level 27  
    Opanowałem odbieranie danych z UART, ale pojawił sie nowy problem.
    Napisałem sobie własny terminal i przystosowałem go do przesyłania parametrów , które są zapisywane do EEPROM mikrokontrolera. Działa, ale problem jest z przesyłaniem bajtów większych niż 127. Problem jest raczej w programie w VisualBASIC a nie w AVR bo testowałem i AVR odbiera 8 bitów.
    Poniżej fragmet programu terminala odpowiedzialny za przesył danych w sekwencji: # , nr_danej , wartość_danej.
    Code: vbnet
    Log in, to see the code


    Dla danych większych niż 127 zawsze zapisuje się do EEPROM wartość '3F' niezależnie od przesyłanej danej.
  • #23
    bart-projects
    Level 24  
    Jak to przesyłasz? Hexstring czy Binary? Jak parsujesz?
    Podstawowy typ w VB to INT ale da się własnie zadeklarować coś jako Byte i potem parse...

    Po tym co przedstawiłeś nie da sie pomóc, a;le bez problemu można w VB działać na bajtach tyllko np. 0F dla PC to F kiedy ma to wysłać.
  • #24
    kamyczek
    Level 38  
    koczis_ws wrote:
    Zmierzyłem rzeczywiste czasy generowane przez _delay_ms dla dwóch egzemplarzy Tiny, z których jeden pracował a drugi nie. Różnice czasów wynosiły 6.25%. Przeliczyłem i skorygowałem program dla tego niepracującego.


    To teraz sobie odpowiedz sam jak Tiny sobie automatycznie wpisuje kalibrację , ale oczywiście są tacy co wierzą ślepo w to co napisali ... Jeśli będziesz cwany to sobie zrobisz taką procedurę ,która albo będzie czytała z eeproma , albo z flash , albo bezpośrednio z zapisanej w fabryce kalibracji i przy starcie wpisze ją w odpowiedni rejestr bo z tego co dobrze pamiętam że błąd po wpisaniu kalibracji jest albo 0,1 albo 0,5% co się z twoją wartością jakoś zupełnie nie pokrywa . Jak zrobisz wszystko jak należy to każdy działa bez liczenia i myślenia ...
  • #25
    koczis_ws
    Level 27  
    Typy zmiennych są w listingu. Tu przesyłam jako String, próbowałem jako Byte ale to nic nie dało. Poczytałem o kodach ASCII i znalazłem informację, że kody powyżej 127 mogą być przesyłane w 2 bajtach i może o to chodzi, że przesyłany jest tylko starszy bajt ? Ja tu wysyłam paczkę 3 bajtów po jednym bajcie co 0.4 sek.

    Dodano po 14 [minuty]:

    kamyczek wrote:
    Jeśli będziesz cwany to sobie zrobisz taką procedurę ,która albo będzie czytała z eeproma , albo z flash , albo bezpośrednio z zapisanej w fabryce kalibracji i przy starcie wpisze ją w odpowiedni rejestr


    Niestety nie jestem taki cwany i sobie nie poradzę. A za takie "pomoce" serdecznie dziękuję.
  • #26
    bart-projects
    Level 24  
    Napisz jakich danych sie spodziewasz w urządzeniu bo myslisz ze to mu wysyłasz :D
    Kody powyżej 127 nie muszą być wysyłane w dwóch bajtach. Do 127 to zwykłe ASCII potem są okrojone narodowe i tak mozna kupić wysiwietlacze z róznym kodowaniem, ale zawsze te pierwsze127 znaków jest wspólne.
    Co innego UTF8(dwa bajty) i tu na pewno nie ma znaczenia bo ASCII to najcząściej jeden bajt.
  • #27
    koczis_ws
    Level 27  
    Skoro przesyłanie bajtów mniejszych od 127 odbywa się bez problemu to wymyśliłem chytry sposób.
    W programie VB dzielę parametr przez 2 , a w programie AVR mnożę przez 2 przed wpisem do EEPROM. Oczywiście ma to pewne wady. Z liczbami parzystymi jest OK ale nieparzyste po takiej konwersji są mniejsze lub większe o 1. No i jest mniejsza rozdzielczość, ale tu nie ma to znaczenia. Narazie tak zostawię bo szkoda czasu, a może w przyszłości znajdę bardziej eleganckie rozwiązanie.
  • #28
    bart-projects
    Level 24  
    Tu nie chodzi o chytrość. 127 można zakodować na siedmiu bitach. Tak jak osiem na trzech bitach...
    Mozna mieć typ char albo właśnie taki który tylko pomiesci 12 ale też -128
    Wzsystko zależy od implementacji i tego co przetwarza urządzenie końcowe.

    Dodano po 7 [minuty]:

    może inaczej.. signed or unsigned char
    Ta jedynka binarnie z przodu robi róznicę
  • #30
    bart-projects
    Level 24  
    Deal with it :D
    A tak poważniej to żeby odzyskać BYTE to w VB trzeba troche sie nagimnastykować.
    Właśnie zależy czy przesłano binarnie czy HexString Ascii