ATmega8 UART ovládanie LED

Dobře - zkusíme tohle - uprav následující řádek

volatile unsigned char retezec[100], index, data;

na tohle :

volatile unsigned char retezec[100], index, data, echo_znak;

Řádek

  UDR=data;  // odeslat echo do PC - nemusí být.

uprav na

  UDR=echo_znak;  // odeslat echo do PC - nemusí být.

A do inicializace přidej

  echo_znak='A';

Teď by Ti měl mcu posílat zpátky samý A (na každý znak, ne na celý text). Jakmile pošleš samotný ENTER, mělo by A v odpovědích skončit… Samozřejmě za předpokladu, že proměnné budou v paměti v pořadí, jak jsou definovány.

Ano funguje to presne tak.
odoslem LED on
pride AAAAAAA

odoslem ENTER pride A.

Takže teraz zistim či to mám dobre keď stlačím enter a nepride nič.

Vzhledem k tomu, že se mi nepodařilo přesvědčit překladač, aby za proměnnou retezec dal nějakou další, tak zkus proměnnou index nadeklarovat jako volatile unsigned int.

Stá pozice nemusí být 0.
Nula musí být pouze za koncem řetězce.
Když např do proměnné retezec zapíšeme “abcde”, tak za znakem ‘e’ musí být nula. Co je v dalších členech to nehraje žádnou roli.

Proto je také zbytečné nulovat všechny členy proměnné, jak je to v tvém kódu. Řetězec se nuluje tak, že se zapíše 0 jenom do prvního členu.
A tady není nutné ani to, stačí nastavit index na 0 a staré hodnoty se přepíšou.

Ještě bych podotkl:

**unsigned char retezec[100] **není řetězec (pole znaků) ale pole čísel typu unsigned char.
Když např. na takovou proměnnou použijeme stringové funkce, tak dostaneme různá varování.

Teraz to mám takto:

[code]volatile unsigned char retezec[100], data, echo_znak;

volatile unsigned int index;[/code]

a chová sa to tak isto ako keď som to mal takto:

volatile unsigned char retezec[100], index, data, echo_znak;

To je:

  1. Pošlem AHOJ
  2. Pride AAAAA
  3. Pošlem (prazde) ENTER
  4. Príde A

Ok môžem sa opýtať čo týmto chceme dosiahnuť? Aby keď odošlem len ENTER Neprišlo nič?
Alebo sa tím odstranuje priamo táto chyba:

Začínam sa trocha strácať.

2).Keď programuješ používaš nejaký simulátor ,alebo to skušaš priamo na procesore ako ja?

Jak jsem psal výše, nepodařilo se mi přesvědčit překladač, aby proměnnou řetězec umístil před ostatní. Ať jsem zkoušel, co jsem chtěl, vždy byl řetězec na konci RAM. Zkoušel jsem nakonec použí i unsigned int na index, jenže pravděpodobně optimalizace nebo něco jiného mi to “zhatily”. Nevadi. Nebudu Ti více motat hlavu.
V tuto chvíli, když sahneš mimo rozsah 0-100 prostě saháš do oblasti, která není ničím obsazena. Smyčku

do { index--; retezec[index]=0; // Index je na konci řetězce, tak ho vynulujeme až do nultého znaku. } while (index>0);

přepiš na

while (index>0) { index--; retezec[index]=0; // Index je na konci řetězce, tak ho vynulujeme až do nultého znaku. }

Vysvětlení :
V okamžiku, kdy budeš mít v řetězci pouze ENTER na pozici 0, bude index=0. Před zahájením této smyčky jsi nahradil ENTER znakem 0, tudíž nevadí, když se smyčka neprovede ani jednou. Pokud budeš mít v řetězci třeba “AB”+ENTER, bude index=2. Při vstupu do vyhodnocování nahradíš ENTER znakem 0, čímž řetězec ukončíš. Po vstupu do této smyčky bude index=2. Provede se první cyklus, kdy se index sníží na 1 a na pozici 1 se uloží 0. Následuje kontrola indexu. V tuto chvíli je index 1, smyčka se zopakuje. Při indexu 0 se smyčka neprovede. V prvním případě by, kdy se kontrola prováděla na konci, to znamenalo, že pokud do smyčky vstupuješ s indexem větším, než 0, vše chodí OK. Pokud jsi však do smyčky již vstoupil s indexem=0, pak se dekrementoval index o 1, jenže protože index je unsigned char, nenastavil se na -1, ale na 255. Proto mohl být problém. To, že WinAVR nasypal proměnnou retezec vždy až na konec, způsobilo, že chyba se neprojevila. Dokonce ani při indexu definovaným jako unsigned int, kdy při dekrementování z 0 na 65535 se chyba neprojevila, protože v simulátoru se při práci s řetězcem index ořízl z 16-ti bitů na 8 (z 0xFFFF se stalo 0x00FF). Možná díky optimalizacím - nevím.

Programy krokuji a ladím v AVR Studiu 4.19+WinAVR (to je zárověň odpověď na Tvůj druhý dotaz). Dá se tam nasimulovat i třeba externí přerušení apod. Nicméně mám vyzkoušené, že simuátor AVR Studia obsahuje množství chyb, které se musí obejít v SW při ladění nebo se obejít nedají vůbec (pak nezbývá, než ladit přímo v mcu). Například - nefunguje freerunning mód AD převodníku, resp. automatický restart AD převodu. Pokud používám přerušení od AD převodníku, lze to obejít tak, že se tam při simulaci přidá instrukce pro nové spuštění AD převodu. Zlobí v něm ještě pár dalších věcí (z hlavy si teď nevzpomenu), ale na prvotní ladění je to dobrý. Jako další krok následuje testování na samotném HW. Tam používám systém štěnic, kdy si do inkriminovaného místa dám třeba rozsvícení LEDky, zobrazení na LCD/LED displeji (pokud je použit), případně i posláním dat přes UART do PC (pokud je k dispozici, což většinou není a pokud je, tak je hrozně pomalý…). Tím zjistím, jestli tam program dorazí nebo ne. Chybu, na kterou jsem se snažil Tě navést odhalíš v simulátoru. AVR Studio je ke stažení třeba přímo ze stránek ATmelu (dneska ve verzi tuším 6.2) nebo pohledat po Internetu, kde bys našel starší. Co vím, tak AVR Studio 5 a výše jsou molochy. Někdo na ně nadává, někdo je chválí. Já jsem je zatím nezkoušel. Mě zatím vyhovuje 4.19 (myslím, že se dá i nakopírovat a spouštět bez instalace).

Jinak, co psal AB je samozřejmě pravda. Řetězcová proměnná není unsigned char retezec[100], ale char retezec[100]. Jenže použití char při čtení z UARTu mi dělalo nějaké problémy, tak jsem použil unsigned. Jinak jsem si prošel celý algoritmus a (jak psal AB) je pravda to, že stačí místo nulování řetězce nastavit index=0. Co se té sté pozice týká, tak tam jsem to myslel tak, že na pozici 99 (stá pozice od 0) musí být nula pro stringové funkce. Tam jsem se do toho trošku zamotal sám, protože jakmile dorazí ENTER, tak před předáním řetězce do stringových funkcí se ENTER nahradí 0, tím se řetězec zakončí. Musel bys tam tu 0 zachovávat pouze v případě, že bys ten ENTER před předáním do stringových funkcí nemazal.

Nemohl jsem si nevšimnout, že jsi odložil sleep_mcu(). Na funkčnost tohoto programu to vliv samozřejmě nemá, ale rozhodně je to šikovná věcička. Pomůže Ti častěji, než si myslíš. Například při eliminaci zákmitů tlačítek.

Já drtivou většinu programuju v AVR Studiu v assembleru, po Cčku sáhnu jenom občas a to pouze, když zpracovávám textové proměnné nebo větší množství dat. K programování pak používám programátor ASIX Presto.

Ano sleep_mcu() som vynechal z dôvodu že mi nešlo zkomprimovať a viac som neriešil čo tam ešte ktomu chýba.

Takže finálni kód je takýto.

[code]#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> //Knihovna přerušení

#define LED_PORT PORTD
#define LED_DDR DDRD
#define LED_PIN PIND

#define LED_1 PD7
#define LED_2 PD6

#define LED_1_ON LED_PORT|=(1<<LED_1) //LED1 zapne.
#define LED_1_OFF LED_PORT&=~(1<<LED_1) //LED1 vzpne.
#define LED_2_ON LED_PORT|=(1<<LED_2) //LED1 zapne.
#define LED_2_OFF LED_PORT&=~(1<<LED_2) //LED1 vzpne.

//*****************************************************************************//

volatile unsigned char retezec[100],index, data;

//*******************************************************************************//

ISR(USART_RXC_vect)
{

data=UDR; // Přečíst přijatý byte
UDR=data; // odeslat echo do PC - nemusí být.

if ((index<98)&&(retezec[0]!=0)) index++;  // Prodloužit retězec pouze v případě, že ještě nejsme na konci a zárověň už je zapsaný první znak řetězce (pozice 0) 
retezec[index]=data;  // Zapsat přijatý byte do řetězce. 

}
//********************************************************************************//

int main(void)
{

/**************************** inicializace uart *****************************/

  UCSRA = (1<<U2X); 

  UBRRH = 0x00;  // nastaveni rychlosti pro krystal 14.7456MHz 

  UBRRL = 191; 

  UCSRB = (1<<RXEN) | (1<<TXEN) | (1 << RXCIE);	//prijem, vyslanie   

  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // ramec dat:  8 datovych, 1 stop bit, bez parity 

  sei();                        //Povol prerušenia. 

//********************************************************************************//

  LED_DDR |= (1 << LED_1) | (1 << LED_2); //PD7 ako výstupný (LED.)  

//***********************************************************************************//

while(1)
{

if (retezec[index]==13) // Pokud je poslední načtený znak ENTER, pak se provede následující část programu 
{ 
   retezec[index]=0;  // Ukončit string pro další zpracování. 
  if (strcmp (retezec, "1 on")==0) LED_1_ON;  // Pokud je řetězec "LED on", LEDku rozsvítí 
  if (strcmp (retezec, "1 off")==0) LED_1_OFF;  // Pokud je řetězec "LED off", LEDku zhasne 
  if (strcmp (retezec, "2 on")==0) LED_2_ON;  // Pokud je řetězec "LED on", LEDku rozsvítí 
  if (strcmp (retezec, "2 off")==0) LED_2_OFF;  // Pokud je řetězec "LED off", LEDku zhasne 

  while (index>0) 
  { 
    index--; 
    retezec[index]=0;  // Index je na konci řetězce, tak ho vynulujeme až do nultého znaku. 
  } 
} 

}
}
[/code]

Tak znova som tu.
Nedalo mi a skúšam ten režim spánku.

Doplnil som #include <avr/sleep.h> a set_sleep_mode(SLEEP_MODE_IDLE); postupoval som podla tochto návodu. svetelektro.com/clanky/programujeme-avr-v-jazyku-c-11-cast-553.html

Funguje to pred tim to odoberalo 24,6mA teraz
14.4mA.
Len chcem vedieť či to mám dobre umiestné.

[code]#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h> //Knihovna přerušení
#include <avr/sleep.h>

#define LED_PORT PORTD
#define LED_DDR DDRD
#define LED_PIN PIND

#define LED_1 PD7
#define LED_2 PD6

#define LED_1_ON LED_PORT|=(1<<LED_1) //LED1 zapne.
#define LED_1_OFF LED_PORT&=~(1<<LED_1) //LED1 vzpne.
#define LED_2_ON LED_PORT|=(1<<LED_2) //LED1 zapne.
#define LED_2_OFF LED_PORT&=~(1<<LED_2) //LED1 vzpne.

//*****************************************************************************//

volatile unsigned char retezec[100],index, data;

//*******************************************************************************//

ISR(USART_RXC_vect)
{

data=UDR; // Přečíst přijatý byte
UDR=data; // odeslat echo do PC - nemusí být.

if ((index<98)&&(retezec[0]!=0)) index++;  // Prodloužit retězec pouze v případě, že ještě nejsme na konci a zárověň už je zapsaný první znak řetězce (pozice 0) 
retezec[index]=data;  // Zapsat přijatý byte do řetězce. 

}
//********************************************************************************//

int main(void)
{

/**************************** inicializace uart *****************************/

  UCSRA = (1<<U2X); 

  UBRRH = 0x00;  // nastaveni rychlosti pro krystal 14.7456MHz 

  UBRRL = 191; 

  UCSRB = (1<<RXEN) | (1<<TXEN) | (1 << RXCIE);	//prijem, vyslanie   

  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // ramec dat:  8 datovych, 1 stop bit, bez parity 

  sei();                        //Povol prerušenia. 

//********************************************************************************//

  LED_DDR |= (1 << LED_1) | (1 << LED_2); //PD7 ako výstupný (LED.)  

//***********************************************************************************//

while(1)
{
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();

if (retezec[index]==13) // Pokud je poslední načtený znak ENTER, pak se provede následující část programu 
{ 
   retezec[index]=0;  // Ukončit string pro další zpracování. 
  if (strcmp (retezec, "1 on")==0) LED_1_ON;  // Pokud je řetězec "LED on", LEDku rozsvítí 
  if (strcmp (retezec, "1 off")==0) LED_1_OFF;  // Pokud je řetězec "LED off", LEDku zhasne 
  if (strcmp (retezec, "2 on")==0) LED_2_ON;  // Pokud je řetězec "LED on", LEDku rozsvítí 
  if (strcmp (retezec, "2 off")==0) LED_2_OFF;  // Pokud je řetězec "LED off", LEDku zhasne 

  while (index>0) 
  { 
    index--; 
    retezec[index]=0;  // Index je na konci řetězce, tak ho vynulujeme až do nultého znaku. 
  } 
} 

}
}
[/code]

set_sleep_mode(SLEEP_MODE_IDLE); stačí jenom jednou během inicializace před hlavní smyčkou. Kromě toho bys tam ještě měl mít sleep_enable();

Ještě zkus přidat do inicializace toto :

ACSR|=(1<<ACD); // Vypnutí napájení analogového komparátoru

Mělo by se to projevit na snížení spotřeby, tak jestli máš změřeno 14,4mA, tak bych rád, jestli bys přidal vypnutí komparátoru a napsal mi sem, jak se to projevilo na spotřebě. Dík.

Ok zajtra teraz niesom doma píšem z mobilu.

Ok. Upravil jsem předchozí zprávu, že Ti tam ještě chybí sleep_enable().

Nazdar.
Tak hodil som to do kódu ,ale odber sa nejak nezmenil teraz je 14,3mA.
Cele to mám na nepájivom poli.

inak nieje rozdiel ani stím sleep_enable(); teraz to mám takto:

[code] /**************************** inicializace uart *****************************/

  UCSRA = (1<<U2X); 

  UBRRH = 0x00;  // nastaveni rychlosti pro krystal 14.7456MHz 

  UBRRL = 191; 

  UCSRB = (1<<RXEN) | (1<<TXEN) | (1 << RXCIE);	//prijem, vyslanie   

  UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);  // ramec dat:  8 datovych, 1 stop bit, bez parity 

//************************************ inicializace **************************//

  ACSR|=(1<<ACD); // Vypnutí napájení analogového komparátoru

  set_sleep_mode(SLEEP_MODE_IDLE); 	// nastav tip režimu spánku.

  sei();                        //Povol prerušenia. 

//********************************************************************************//

  LED_DDR |= (1 << LED_1) | (1 << LED_2); //PD7 ako výstupný (LED.)  

//***********************************************************************************//

while(1)
{
sleep_enable();
sleep_mode();

if (retezec[index]==13) // Pokud je poslední načtený znak ENTER, pak se provede následující část programu 
{ 
   retezec[index]=0;  // Ukončit string pro další zpracování. 
  if (strcmp (retezec, "1 on")==0) LED_1_ON;  // Pokud je řetězec "LED on", LEDku rozsvítí 
  if (strcmp (retezec, "1 off")==0) LED_1_OFF;  // Pokud je řetězec "LED off", LEDku zhasne 
  if (strcmp (retezec, "2 on")==0) LED_2_ON;  // Pokud je řetězec "LED on", LEDku rozsvítí 
  if (strcmp (retezec, "2 off")==0) LED_2_OFF;  // Pokud je řetězec "LED off", LEDku zhasne 

  while (index>0) 
  { 
    index--; 
    retezec[index]=0;  // Index je na konci řetězce, tak ho vynulujeme až do nultého znaku. 
  } 
} 

}
}[/code]

Sice to moc nepoužívám, ale co takhle se kouknout do knihovny sleep.h.
Co jsem tak vycetl tak musis vybrat sleep mod a potom to aktivovat
zde je pseudokod

#include <avr/interrupt.h> #include <avr/sleep.h> ... set_sleep_mode(<mode>); cli(); if (some_condition) { sleep_enable(); sei(); sleep_cpu(); sleep_disable(); } sei();
Kde MODE pro Mega8 muze nabyvat hodnot

SLEEP_MODE_IDLE SLEEP_MODE_ADC SLEEP_MODE_PWR_DOWN SLEEP_MODE_PWR_SAVE SLEEP_MODE_STANDBY SLEEP_MODE_EXT_STANDBY

Co ktery mod dela je v datasheetu

Ale veď to v kóde mám rovno pod inicializáciou UARTu.

**set_sleep_mode(SLEEP_MODE_IDLE); // nastav tip režimu spánku. **

sleep_enable(); stačí mít také jenom jednou v inicializaci před hlavní smyčkou. Mě je spíš divný, že to vypadá, že to procesor uspávalo i bez povolení sleep módu. To, že vypnutí AD převodníku bude mít jen malý vliv na snížení spotřeby jsem čekal. Jen jsem byl zvědavý, jak moc se to projeví.

No možno je to obsihnute nejak v knižnici, lebo ani on to sleep_enable v kode nema a ide mu to. Ma tam aj videa. Postupoval som podla neho.

svetelektro.com/clanky/programujeme-avr-v-jazyku-c-11-cast-553.html

Funkce z <avr/sleep.h> fungují takto:

[code]void set_sleep_mode ( uint8_t mode )
// Vyber sleep mód. Defaultně je nastavený IDLE.

void sleep_enable ( void )
// Nastaví bit SE(sleep enable).

void sleep_cpu ( void )
// Vloží instrukci asm “sleep”. Bit SE musí nastavený a doporučuje se nulovat ho po probuzení.

void sleep_disable ( void )
// Nuluje bit SE (sleep enable).

void sleep_mode ( void )
// Nastaví bit SE a uspí procesor. (Stejně jako posloupnost: sleep_enable; sleep_cpu;)

// Takže kód můžeme psát dvěma způsoby:

main()
{
set_sleep_mode(SLEEP_MODE_IDLE );
sei();

while(1)
{
sleep_enable();
sleep_cpu();
sleep_disable(); // po probuzení
}

// nebo:

main()
{
set_sleep_mode(SLEEP_MODE_IDLE );
sei();

while(1)
{
sleep_mode();
sleep_disable();
}

[/code]

To AB: To doporučení nulovat SE po probuzení je někde v datasheetu ? Já, že nastavuju SE na začátku programu v inicializaci a víc s ním nehýbu. A to IDLE sleep mód používám vždy a nikdy jsem s tím neměl problém. Budu se na to muset podívat.

Je to v Avr-libc.

avr-libc.nongnu.org/user-manual/ … sleep.html

Jojo. Našel jsem to i v datasheetu.