Skocz do zawartości

Problem z dziwnym zachowaniem programu z timerami


Sheppard25

Pomocna odpowiedź

Czesc, mam wydawaloby sie prosty kod. Niestety zachowuje sie bardzo nieintuicyjnie, mam wrazenie ze to przez jakies opoznienia wewnatrz mikrokontrolera albo sam mikrokontroler nie zdazyl wszystkiego ustawic? Timer za czesto? (Co 1ms) Nie wiem. 

Zalozenie jest proste. Metoda send ma ustawic liczbe 16bitowa do wyslania, po czym wystawic jej pierwszy bit do wyslania. Timer odczytuje ten bit, wysyla zakodowany w Manchester i wywoluje ponownie funkcje, ktora tym razem ustawia nastepny bit i tak 16 razy az cala liczba zostanie wyslana. Tzn takie jest zalozenie. Niestety problem jest taki, ze po drodze gdzies gubione sa bity, ciezko mi zdebugowac co sie dzieje, poniewaz printy sie nie wyswietlaja (albo nie zawsze, moze to tez kwestia samej biblioteki uart, ktora ma delaye). Natomiast kod ktory wrzucam, bez printow, ktory powinien dzialac, nie wysyla niczego (sprawdzam analizatorem logicznym). Natomiast odokomentowujac delay'e w main.cpp juz wysyla.

Ciezko mi sprecyzowac problem poniewaz wlasciwie mozna by powiedziec - nie dziala, dzieja sie rzeczy niestworzone 🙂 . Jakby ktos biegly byl w stanie rzucic okiem na kod, moze wylapie juz czytajac go gdzie jest problem.

Dzieki

main.cpp

#include <avr/io.h>
#include <util/delay.h>
#include <MsUart.h>
#include "MsRf.h"
#include "MsHuminitySensor.h"

#define TX_PIN PB4
#define ADC_PIN PB4

MsRf rf;

ISR(TIM0_COMPA_vect)
{
    rf.onTimerInterrupt();
}

int main()
{
    rf.send(456);

    // _delay_ms(10); // z tym delayem wysyla dane
    while (1)
    {
    }

    return 0;
}

MsRf.cpp

#include "MsRf.h"

MsUart uart(&DDRB, &PORTB, 4);

MsRf::MsRf()
{
    bitToTransmit = BitState::NODATA;
    bitIndex = 0;
    data = 0;
    transmitting = false;

    init();
    MsTimer::init();
}

void MsRf::init()
{
    DATA_DDR |= (1 << DATA_PIN);
}

// Zmiana funkcji send, która teraz przyjmuje liczbę uint16_t zamiast stringa
void MsRf::send(uint16_t number)
{
    this->data = number;     // Przechowuj liczbę w polu `data`
    setNextManchesterBits(); // Zainicjuj pierwszy zestaw bitów do transmisji
}

void MsRf::setNextManchesterBits()
{
    // Sprawdzanie bitu na pozycji `bitIndex`
    uint8_t bit = ((data >> bitIndex) & 1);

    if (bit == 1)
    {
        bitToTransmit = BitState::HIGH;
    }
    else if (bit == 0)
    {
        bitToTransmit = BitState::LOW;
    }

    bitIndex++;

    // Jeżeli wszystkie 16 bitów zostały przesłane, resetujemy bitIndex
    if (bitIndex >= 16)
    {
        bitIndex = 0; // Resetujemy indeks bitów
        data = 0;     // Koniec danych do transmisji
        bitToTransmit = BitState::NODATA;
    }
}

void MsRf::transmitFirstBit()
{
    if (bitToTransmit == BitState::LOW)
    {
        // uart.print("1");

        DATA_PORT |= (1 << DATA_PIN); // Gdy bit jest 0 najpierw pierwszy bit do góry
    }
    else
    {
        // uart.print("0");

        DATA_PORT &= ~(1 << DATA_PIN); // Gdy bit jest 1 najpierw pierwszy bit do dołu
    }
}

void MsRf::transmitSecondBit()
{
    if (bitToTransmit == BitState::LOW)
    {
        // uart.print("0");

        DATA_PORT &= ~(1 << DATA_PIN); // Gdy bit jest 0 drugi bit na dół
    }
    else
    {
        // uart.print("1");

        DATA_PORT |= (1 << DATA_PIN); // Gdy bit jest 1 drugi bit do góry
    }
}

void MsRf::onTimerInterrupt()
{

    if (bitToTransmit != BitState::NODATA && !transmitting)
    {
        transmitFirstBit();
        transmitting = true;
        return;
    }

    if (bitToTransmit != BitState::NODATA && transmitting)
    {
        transmitSecondBit();
        setNextManchesterBits(); // Pobierz kolejne bity Manchester

        transmitting = false;
    }
}

 

Edytowano przez Sheppard25
Link do komentarza
Share on other sites

Wiem, to nie jest odpowiedź na pytanie, ale może wrzuć cały kompilowalny kod na githuba? Jeżeli nie znasz gita to zdecydowanie WARTO POZNAĆ. 

Często problem jest w zupełnie innym miejscu niż myślisz. Po takich wycinkach trudno zgadnąć.

Link do komentarza
Share on other sites

Nie widzę zdefiniowanego zegara F_CPU. Nie wiem, na której AVRce to robisz, ale mogą być rozbieżności z zegarem nadajnika i odbiornika przez to, że właśnie nie zdefiniowałeś symbolu F_CPU, szczególnie jeśli gdzieś wewnętrznie wykorzystywane są delaye - choć tych nie widzę. Wartość domyślnego taktowania, na pewno jest w dokumentacji, ale wiem że czasami trzeba się naszukać - sam spędziłem chyba z godzinę wertując dokumentację do ATmegi4809 😅.

Dodatkowo, tak jak pisał etet100, przydałby się szerszy pogląd na projekt - plik MsRf.h między innymi.

Link do komentarza
Share on other sites

(edytowany)

@etet100 Jasne, proszę bardzo: https://github.com/sheppard30/Czujnik-wilgotnosci---nadajnik . Githuba oczywiście znam, jestem programistą 10 lat ponad tylko inna technologia 😉 

@Tradiatore 

F_CPU chyba jest zdefiniowane gdzieś w bibliotekach ponieważ najeżdżając pokazuje poprawne taktowanie zgodne z fusbitami 

Kontroler: Attiny13a (ten malutki) 🙂 

Odbiornik wydaje mi sie ze dziala dobrze, bo jak uda sie przeslac jakies dane to czasy trwania bitow sa dosc zblizone do poprawnych. 

 

PS Czy 1ms to nie za czesto na przerwanie? Moze ten mikrokontroler sie po prostu dławi, nie daje rady wykonać w 1ms tych wszystkich operacji?

Edytowano przez Sheppard25
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Brakuje MsUart. On przypadkiem nie korzysta z timerów? Nie masz tu konfliktu?

Jeśli masz wątpliwości czy 1ms to nie za szybko to po prostu zacznij od dużo dłuższych czasów. Nawet takich które są obserwowalne gołym okiem.

 

Link do komentarza
Share on other sites

Nie sprawdzałem, czy się kompiluje, ale z tego co napisał OP wynikało, że tak. Jeśli jednak brakuje biblioteki no to problem jakby w połowie rozwiązany.

Link do komentarza
Share on other sites

@etet100 @Tradiatore Celowo Wam wrzucilem wersje z wykomentowanym/usunietym wywolaniem biblioteki UART zeby pokazac ze bez niej to tez nie dziala. Ona nie ma w sobie timera, ma jednego delay'a na dlugosc taka jaka oczekuje odbiornik z danym boudem czyli np 1sek/9600. Ale tak jak napisalem, w przykladzie na repo tej biblioteki nie uzywam. 

Z wiekszymi czasami pewnie bedzie lepiej ale zastanawiam sie czy przy tym ze ten mikrokontroler jest maly i zadan na nim nie bedzie duzo, nie lepiej bedzie ustawic po prostu timera np z przerwaniami co 1 sekunde a bity wiadomosci wysylac z delayami (poniewaz zadna inna operacja na tym kontrolerze i tak nie bedzie wywolywana, ktora te delaye by zablokowaly). 

//edit ok widze ze jest stworzony obiekt UART ale ja nie korzystam z zadnej jego metody, wywolany jest jedynie konstruktor, dla pewnosci podaje tez linka do tej biblioteki. 

https://github.com/sheppard30/MsUart

Link do komentarza
Share on other sites

(edytowany)

Jeśli masz ochotę to zerknij na kilka moich zmian. 

https://github.com/sheppard30/Czujnik-wilgotnosci---nadajnik/pull/1

Pewnie nie wszystkie są ważne. Mam niestety tą przypadłość, że zawsze muszę coś zmienić po swojemu.

NewFile1.thumb.png.579dd18758c8fa3ab6f60478c2d1a7f7.png

Szpilki w kanale 2 (słabo widoczne) to początek bitu. 

00001110

No i wyrabia się z palcem w nosie. Docelowo możesz pewnie znacznie obniżyć taktowanie.

Edytowano przez etet100
Link do komentarza
Share on other sites

(edytowany)

@etet100 dzięki wielkie, sporo fajnych patentów które sobie użyję. Postanowiłem jednak zmienić architekturę aplikacji, ponieważ uważam że użycie w tym konkretnym przypadku Timera było błędem a raczej było totalnie niepotrzebne. Jakie zadanie ma ten mikrokontroler? 

1. Odczytać dane z pinu analogowego

2. Wysłać te dane

Wszystko w interwale, np. kilku sekundowym a docelowo około godzinnym. I tutaj nie ma potrzeby używania Timera czy przerwań ponieważ:

1. Nie muszę reagować na żadne zewnętrzne sygnały.

2. Nie muszę wykonywać w "tle" w równych odstępach czasowych żadnych operacji, które są niezależne od innych

i wszystko można prosto ogarnąć delayem.

Co innego teraz na odbiorniku, gdzie postanowiłem użyć Atmegi 16A, która ma dużo pinów (potrzebuję do klawiatury i wyświetlacza). Taka klawiatura musi "nasłuchiwać" cały czas więc tutaj napewno Timer może się przydać.

Natomiast to co mnie ciekawi jeszcze przy tym Attiny13a i mojej aplikacji, to konieczność podania delay'a na początku przed 'while'. Bez tego ucina bity jeżeli od razu cośbyłoby wysyłane. 

Edytowano przez Sheppard25
Link do komentarza
Share on other sites

(edytowany)

Ja mam inne zdanie. To się aż prosi o użycie timera. Zwłaszcza jeśli nie bardzo potrzebny do czegoś innego. Taka asynchroniczna komunikacja jest zwykle krytyczna czasowo a żaden delay nie da równych odstępów. Po to powstały timery i przerwania żeby ich używać.

A co do ucinania czegoś... szczerze nie zauważyłem. 

    rf.init();
    rf.send(0b01110000);

    while (1)
    {
        // rf.send(0b01110000);
        // _delay_ms(500);
    }

Niczego nie obcina. Robię restart i oscyloskop ładnie łapie ten pierwszy bajt.

Edytowano przez etet100
Link do komentarza
Share on other sites

Przy Manchesterze te równe odstępy chyba nie są krytyczne, te pare mikrosekund nie zrobi różnicy. Niemniej skoro twierdzisz, że prosi się o jego użycie to użyłbyś go tak jak w moim oryginalnym rozwiązaniu do wysyłania bitów Manchester w równych interwałach czy jakoś inaczej? 

Link do komentarza
Share on other sites

(edytowany)

Dla samej satysfakcji i wprawy warto to zrobić. Na delayach to robią w przedszkolu (pół żartem oczywiście). Przy przerwaniach dochodzą pewne problemy (wyzwania), które lepiej poznać teraz, niż przy większych projektach.

Ten czas jakoś tam istotny jednak jest. Ale faktem jest, że prędkości są minimalne, to i spore odchyłki nie będą miały znaczącego wpływu.
Nie wiem czy czytałeś ten dokument
https://ww1.microchip.com/downloads/en/AppNotes/Atmel-9164-Manchester-Coding-Basics_Application-Note.pdf

A kod wygląda całkiem ok. Zawsze coś można poprawić ale podstawa wydaje mi się solidna.

Tą ATMEGE16 bym jeszcze przemyślał. Nie bardzo sobie wyobrażam co ty zrobisz z tyloma liniami. To jest duże i nieporęczne.

Edytowano przez etet100
Link do komentarza
Share on other sites

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.