V programu jsem našel ještě další chybu, takže by Ti to takhle nikdy nefungovalo, neboť řetězec i přes zápis dat z USARTu zůstává trvale prázdný. Chyba je v rutině obsluhy přerušení. To byla malá nápověda a pokud na ní nepřijdeš, tak se k ní vrátíme později a vysvětlím Ti co a jak. Abys mne správně pochopil - nechci Ti psát tupě funkční kód. Vidím, že se snažíš Cčko naučit, tak se Tě snažím navést. A teďka k jednotlivým bodům :
- Musíš si především uvědomit, jaký je obsah jednotlivých proměnných v okamžiku, kdy se mcu dostane do dané části programu.
Jaký je tedy stav :
mcu se dostane do zpracování řetězce v tuto chvíli :
if (retezec[index]==13) // Pokud je poslední načtený znak ENTER, pak se provede následující část programu
Tedy v okamžiku, kdy v proměnné retezec na pozici index je hodnota 13 => ENTER.
Následují tyto akce :
retezec[index]=0; // Ukončit string pro další zpracování.
Do proměnné retezec na pozici index se místo hodnoty 13 zapíše hodnota 0 (nikoliv znak ‘0’). Je to z toho důvodu, že řetězce se v Cčku ukončují právě nulou.
V tuto chvíli je tedy v proměnné retezec to, co jsi poslal po USARTu, ale už bez toho znaku ENTER. Následuje kontrola načteného textu a akce.
V proměnné index je pozice právě toho ukončovacího znaku (té 0) za řetězcem.
V původním kódu je toto :
do
{
retezec[index]=0; // Index je na konci řetězce, tak ho vynulujeme až do nultého znaku.
index--;
}
while (index>0);
Tedy - do řetězce na pozici index dám ukončovací znak a index snížím o 1. Pokud je index>0, akci opakuju. No jo, jenže jakmile je index nula, tak se akce pro retezec[0] už neprovede a v řetězci zbyde první znak a délka řetězce na konci nebude 0 znaků, ale 1 znak. Z toho důvodu bylo nutné přehodit pořadí příkazů => nejdřív odečíst 1 od proměnné index, pak zapsat 0 do řetězce a pak teprve provést kontrolu index na 0. Výsledek je toto :
do
{
retezec--index]=0; // Index je na konci řetězce, tak ho vynulujeme až do nultého znaku.
}
while (index>0);
V tomto okamžiku je na konci výsledek takový, že řetězec obsahuje 0 znaků a index=0.
Ale POZOR ! Když napíšeš retezec[index–]=0; místo **retezec–index]=0; ** nebude to fugnovat správně. Rozdíl je v tom umístění – (platí i pro ++).
Pokud napíšeš --X, provede se nejdřív dekrementace X a pak teprve operace s proměnnou.
Pokud napíšeš X–, provede se nejdřív operace s proměnnou X a pak teprve dekrementace.
Tedy:
A=0;
X=5;
A=++X; není totéž jako A=X++;
V případě A=++X; se provede : X=X+1; A=X; => výsledek je A=6, X=6
V případě A=X++; se provede : A=X; X=X+1; => výsledek je A=5, X=6
-
sleep(); je správně sleep_cpu();. Je to funkce pro uspání procesoru. Najdi si sleep modes a co vlastně dělá. V drtivé většině programů není nutné, aby mcu běžel trvale, ale může se v každém cyklu nekonečné smyčky po provedení všech akcí uspat. Procesor se ze sleepu budí jakýmkoliv povoleným přerušením. Vetšinou to bývá přerušení od timeru, ale třeba i externím přerušením (obsluha tlačítek nebo nějakého čidla) atd.
3)Direktiva #define Ti pomáhá při spoustě různých definic.
a) LED_ON ani LED_OFF nic nevolá (nejsou tam () závorky).
b) Deklaraci funkcí
[code]void LED_ON()
{
PORTD |= (1 << PD7); // zapni LED
}
[/code]
máš špatně - jaké jsou parametry funkce ? To překladač neví.
Ale vraťme se k direktivě #define :
Místo LED_ON dosaď to, co máš v direktivě :
#define LED_ON PD7
if (strcmp (retezec, "LED on")==0) LED_ON; // Pokud je řetězec "LED on", LEDku rozsvítí
Výsledek je nesmysl :
if (strcmp (retezec, "LED on")==0) PD7; // Pokud je řetězec "LED on", LEDku rozsvítí
Můžeš tam samozřejmě napsat místo LED_ON volání tvé funkce, ale místo jedné instrukce tam můžeš mít i 3 a více (v závislosti na nastavení optimalizace překladače). Minimálně call+provedení_akce+ret. S optimalizací tam může být jen to provedení akce, ale taky tam může být nasypáno volání podprogramu plus nějaké uschovávání registrů atd. Direktiva #define musí být tedy zapsaná tak, aby výsledný kód byl :
if (strcmp (retezec, "LED on")==0) PORTD |= (1 << PD7); // Pokud je řetězec "LED on", LEDku rozsvítí
Jak tedy bude direktiva vypadat zkus dát dohromady sám.
Direktiva se používá ke spoustě definic. Například :
#define CERVENA_LED PB1
#define ZELENA_LED PB0
#define ZLUTA_LED PB4
#define LED_PORT PORTB
#define LED_PIN PINB
#define LED_DDR DDRB
V programu pak můžeš napsat :
LED_PORT|=(1<<ZLUTA_LED);
Pokud se pak rozhodneš, že žlutou LEDku dáš z PB4 na PB7 (třeba kvůli zjednodušení DPS), tak v programu stačí přesat 1 místo a nemusíš hledat, kde všude jsi v programu napsal PORTB|=(1<<PB4), abys to upravil.
A pro svoje pohodlí můžeš jít ještě dál, když do výše zmíněných definic přidáš :
#define CERVENA_ON LED_PORT|=(1<<CERVENA_LED)
#define CERVENA_OFF LED_PORT&=~(1<<CERVENA_LED)
#define ZELENA_ON LED_PORT|=(1<<ZELENA_LED)
#define ZELENA_OFF LED_PORT&=~(1<<ZELENA_LED)
#define ZLUTA_ON LED_PORT|=(1<<ZLUTA_LED)
#define ZLUTA_OFF LED_PORT&=~(1<<ZLUTA_LED)
V kódu pak můžeš psát :
CERVENA_ON;
ZLUTA_OFF;
Teď Tě nechám ještě přemýšlet nad tou chybou v příjmu dat z UARTu. Je to velmi jednoduhá oprava, nicméně bez ní to fungovat nebude. Abych Tě nasměroval, chyba je podobná té, co byla v nulování řetězce.