USART - atmega8 textový řetězec

Zdravím, tak přemýšlím nad tím, že zase nevím. Mám tuhle knihovnu [svetelektro.com/Pictures/Microprocesory/avr/8/uart.zip] a podle ní mám tenhle program. Kdy napíšu “Ahoj” vrátí mi to zase “Ahoj”. A právě řeším to, jestli lze nějak udělat dle tý knihovny, že když napíšu “ahoj” vrátí mi to “zdar”. A když napíšu něco jinýho než ahoj, tak mi to vrátí třeba “neplatný příkaz” atd.

#include <avr/io.h>  
#include <util/delay.h>  
#include <avr/interrupt.h>  
  
#include "uart.c"  
  
int main(void){  
  
    char pole[128];  
  

    uart_init(2400);  
  
    sei();        
  
    while(1){  
     
        if(uart_gets(pole)){  
        uart_puts(pole);  
        }     
    }  
  
    return 0;  
}

Pro tohle je “knihovna” hodně honosné pojmenování, ale budiž. V každém případě takhle napsaný program jen tupě přeposílá přijatý byte zpět na UART.

  1. tahle “knihovna” bude fungovat pouze na procesorech ATmega8 a ATmega16.
  2. definovat UART buffer a jeho velikost navrdo v knihovně je přinejmenším nestandartní.
  3. uart_gets(…) čeká, až přijde nějaký znak, pak se teprve vrátí do hlavní smyčky, takže jako ukázka dobrý, ale pro použití v programu je naprosto k ničemu, protože zablokuje program až do příjmu nějakého bytu.
  4. Inicializace portu zahrnuje inicializaci přerušení - registr UDR se čte v přerušení a pak následně i v uart_gets(…) - to taky není správně… Navíc už zavoláním přerušení RXC se tento příznak shodí a tím pádem uart_gets(…) se nikdy neukončí.

Pokud chceš na UARTu odpovídat podle přijatého slova/textu, je třeba nejdřív tento text přijmout celý a podle jeho obsahu připravit a odeslat odpověď.

Jinak si myslím, že jsi tohle ani nezkoušel přeložit, protože parametr funkce uart_gets(…) je unsigned char a ty mu předáváš char *.

Já jsem našel takovýhle program, ale tomu nerozumím, tak jestli to jde nějak zjednodušit.Tupě dělat něco, když nevíš co, je k ničemu.Každopádně přeložim, nahraju funguje to, ale překladač mi vyhlásí uporornění a to taky nevím proč a jestli si toho všímat:

led_rozsvec.c:143: warning: passing argument 1 of ‘strncmp’ discards qualifiers from pointer target type
led_rozsvec.c:146: warning: passing argument 1 of ‘strncmp’ discards qualifiers from pointer target type
led_rozsvec.c:150: warning: passing argument 1 of ‘strncmp’ discards qualifiers from pointer target type
led_rozsvec.c:154: warning: passing argument 1 of ‘strncmp’ discards qualifiers from pointer target type
led_rozsvec.c: In function ‘__vector_11’:
led_rozsvec.c:172: warning: array subscript has type ‘char’
led_rozsvec.c:177: warning: array subscript has type ‘char’
led_rozsvec.c:178: warning: passing argument 1 of ‘strncpy’ discards qualifiers from pointer target type
led_rozsvec.c:178: warning: passing argument 2 of ‘strncpy’ discards qualifiers from pointer target type

#include <avr/io.h>
#define F_CPU 8000000
#include <stdio.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <string.h> // funkce pro praci s řetězci strncmp(), strncpy()
#define DELKA_ZPRAVY 16 // maximalni delka zpravy

int usart_putchar(char var, FILE *stream); // odesila znaky na UART

static FILE mystdout = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE);
volatile char nova_zprava=0; // indikuje prichod nove zpravy
volatile char zprava[DELKA_ZPRAVY]; // tady bude uložena celá přijatá zpráva
volatile char docasne[DELKA_ZPRAVY]; // sem se postupně ukládají přicházející znaky

int main(void){
stdout = &mystdout; // nastavení printf na UART
DDRA = (1<<DDA1) | (1<<DDA2); // indikační LED
UBRRL = 0x33; // baud rate 9600 s clockem 8MHz
UCSRB = (1<<RXEN)|(1<<TXEN); // zapnout vysílač i přijímač
UCSRC = (1<<URSEL) | (1<<UCSZ0) | (1<<UCSZ1); // 8bit přenos, URSEL vybira zapis do UCSRC
UCSRB |= (1 << RXCIE); // povolit přerušení od přijímače
sei(); // globální povolení přerušení

while(1){
if(nova_zprava){ // pokud přišla nová zpráva
// porovnáme obsah zpráv
if(strncmp(zprava,“ahoj”,DELKA_ZPRAVY)==0){
printf_P(PSTR(“Nazdar.\n\r”)); // pošli odpověď
}
else if(strncmp(zprava,“rozsvit”,DELKA_ZPRAVY)==0){
PORTA |= (1<<PORTA1);
printf_P(PSTR(“S radosti.\n\r”)); // pošli odpověď
}
else if(strncmp(zprava,“rozsvit vic”,DELKA_ZPRAVY)==0){
PORTA |= (1<<PORTA1) | (1<<PORTA2);
printf_P(PSTR(“Jak je libo.\n\r”)); // pošli odpověď
}
else if(strncmp(zprava,“zhasni”,DELKA_ZPRAVY)==0){
PORTA &=~((1<<PORTA1) | (1<<PORTA2));
printf_P(PSTR(“Zhasnuto.\n\r”)); // pošli odpověď
}
else{
printf_P(PSTR(“Nerozumim.\n\r”)); // žádná známá zpráva
}
nova_zprava=0; // zpráva je zpracována, budeme čekat na novou
}
}
}

ISR(USART_RXC_vect){
char prijaty_znak;
static char i=0; // pocitadlo znaku v prijimane zprave
prijaty_znak = UDR; // vytáhneme znak co nejdřív z přijímacího bufferu
// pokud nepřišel ukončovací znak a ještě není znaků moc
if((prijaty_znak != ‘\n’) && (prijaty_znak!=‘\r’) && (i<DELKA_ZPRAVY-2)){
docasne[i]=prijaty_znak; // uložíme nově příchozí znak
i++;
}
else{
// pokud je konec zprávy
docasne[i]=‘\0’; // uložíme na konec znak ‘\0’ - konec řetězce
strncpy(zprava,docasne,DELKA_ZPRAVY); // zkopirujeme přijatý text do pole zprava
nova_zprava=1; // dáme vědět hlavní smyčce že má novou zprávu
i=0; // připravíme se na příjem nové zprávy
}
}

int usart_putchar(char var, FILE *stream) {
while (!(UCSRA & (1<<UDRE))); // čekej než se dokončí případná předchozí vysílání
UDR = var; // odešli data
return 0;
}

  1. Když sem vkládáš kód nebo ukázku, tak to uzavři do <code>,</code> - tohle bez odsazování louskat fakt nebudu.
  2. Učíš se a to je dobře, ale asi bys měl začít něčím jednodušším, ideálně od nuly, a postupovat podle datasheetu, abys pochopil co a jak funguje - pak to můžeš skládat do větších celků. Není problém u toho koukat do programu, který víš, co dělá, i když zatím nechápeš proč to tak dělá a postupně se k pochopení propracovat. Samozřejmě se můžeš ptát - když uvidíme snahu, poradíme, vysvětlíme. Tohle je jako bys chtěl jezdit na motorce, ale neumíš ani na kole…


funkce vyžaduje char * a ty mu vkládáš volatile char * - správně to není, vadit to může a nemusí. V tomhle případě buď deklarovat jinak nebo přetypovat.

Index pole by měl být typu int - je lepší ho tak deklarovat.



Warningy je lepší vyřešit a odstranit.

Právě tady jsem na to našel docela dlouhý povídání [http://www.elektromys.eu/clanky/avr_usart1/clanek.html] s příklady a byl tam ten program co jsem sem dával, ale zarazili mě tam ty chyby. Hlavně teda nevim jak pracovat s těma textovými řetězci. Jak vytvářet podmínky, to je zase úplně něco jinýho než práce s čísly.

Jsem něco napsal, tak se chci zeptat. Jestli jsem to dobře pochopil. Pokud chci používat funkce printf, puts, tak si to musím nastavit timhle příkazem a asi se nemá cenu zabívat tím co to znamená.:
static FILE mystdout = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE);
stdout = &mystdout;

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>

#define UART_BAUD_RATE 2400
#define UART_BAUD_REGISTERS (((F_CPU / (UART_BAUD_RATE * 16UL))) - 1)

int usart_putchar(char data, FILE *stream)
{

while (!(UCSRA & (1<<UDRE))); // čekej než se dokončí případná předchozí vysílání
UDR = data;
return 0;
}

static FILE mystdout = FDEV_SETUP_STREAM(usart_putchar, NULL, _FDEV_SETUP_WRITE);

int main(void){

stdout = &mystdout;

UBRRL = UART_BAUD_REGISTERS;
UCSRB = (1<<TXEN);
UCSRC = (1<<URSEL) | (1<<UCSZ0) | (1<<UCSZ1);

while(1)
{

puts("ahoj vole");
printf ("zdar vole\n\n");
_delay_ms(1000);

}

return 0;

}

Jestli chceš umět aspoň trošku programovat (i kdyby jen pro svou zábavu), pak to budeš muset myslet trošku vážně a takovouhle větu nikdy nenapíšeš. Pokud se nechceš zabývat tím, co to znamená, pak se nenaučíš nic…
Na tom serveru elektromyš je spousta dobrých informací, ale i věci, které jsou tak trošku zbytečné. Například ty nesmyslné deklarace některých proměnných jako volatile.


A do <code>,</code> je třeba uzavřít CELÝ kód a ne jenom pár řádek …


Asi by sis měl nastudovat, jaké jsou proměnné a jak se s nimi pracuje. S textovýma řetětězcema se pracuje jako s pointrama, takže i pochopit pointery, které jsou v Cčku velmi silná věc, kterou můžeš použít. Využití programové paměti pro konstanty - zejména ty textové je zbytečné ukládat do RAMky a zabírat jimi místo pro ostatní věci.

Pořád se mi nedaří ten kód sem vložit a ještě jak to kopíruje, tak se ty odsazený úplně rozhodí tady. Už mě to štve proč mi to takhle blbne.
Každopádně jsem se zabýval jen programováním mcu až mě to teď dohnalo k tomu, že vůbec nevím jak se pracuje s textovýma řetězcema atd. Už pomalu si něco studuju. Jen to vždycky zakomponovat do toho mcu.

Práci s textovýma řetězcema použiješ třeba pro různá menu apod. - prostě tam, kde zobrazuješ něco na displej nebo odesíláš data po sériové lince.

Příklad odeslání řetězce po sériové lince :

char TextNaOdeslani[] = "Tenhle text z RAM se odešle po UARTu... \r\n";
volatile char *ZnakProOdeslani;

bool SpustOdesilani( char *_OdesilanyText )
{
    if (UART.Busy) return false;                 // Pokud se zrovna odesílá - oznam neúspěšný start odeslání a konec

    ZnakProOdeslani = _OdesilanyText;            // Zapiš adresu řetězce do pointeru pro odesílání
    if (*ZnakProOdeslani != 0) UART.Busy = true; // Pokud není ukončovací znak, nastav příznak odesílání
    UDR = *ZnakProOdeslani;                      // Do datového registru ulož zapisovaný znak
    ZnakProOdeslani++;                           // Přesuň pointer na další znak
    return true;                                 // Oznam úspěšný start odesílání
}

ISR(TXC_vect)
{
    if (UART.Busy)
    {
        UDR = *ZnakProOdeslani;            // Do datového registru ulož zapisovaný znak
        if (*ZnakProOdeslani==0)
        {
            UART.Busy = false;             // Smaž příznak odesílání
        }
        else
        {
            ZnakProOdeslani++;             // Přesuň pointer na další znak
       }
   }
}

void main(void)
{
.
.
    if (SpustOdesilani(TextNaOdeslani))
    {
        ... úspěšné odeslání ...
    }
    else
    {
        ... neúspěšné odeslání ...
    }
.
.
}

To byl příklad odeslání řetězce, který je v RAM jako proměnná.
Pokud bys odesílal řetězec z programové paměti, musel změnit následující 4 řádky :

char TextNaOdeslani[] = "Tenhle text z RAM se odešle po UARTu... \r\n";
            |
            V
const PROGMEM char TextNaOdeslani[] = "Tenhle text z programové paměti se odešle po UARTu... \r\n";

    if (*ZnakProOdeslani != 0) UART.Busy = true; // Pokud není ukončovací znak, nastav příznak odesílání
          |
          V
    if ((pgm_read_byte(ZnakProOdeslani) != 0) UART.Busy = true; // Pokud není ukončovací znak, nastav příznak odesílání

        UDR = *ZnakProOdeslani;        // Do datového registru ulož zapisovaný znak
          |
          V
        UDR = (pgm_read_byte(ZnakProOdeslani);        // Do datového registru ulož zapisovaný znak

    if (*ZnakProOdeslani==0)
        |
        V
    if (pgm_read_byte(ZnakProOdeslani==0))