MEGA64 - USART - uložený řetězec se v hlavním program ztratí

Dobrý den, prosím Vás zrovna začínám s MCU a chtěl jsem si vyzkoušet komunkaci po RS232 pomocí MEGY64,. Problém mám v přerušení USART0_RX_vect. Při přijmutí stringu z Pc si tento string uložím do proměnné.
Ale jak jde program zpět do halvní smyčky tak v proměnné nic uloženého není. Proto s tím nemohu dále pracovat.

Jde o to, aby nějaký jednoduchý příkaz poslaný z PC, např. rozvítil ledku atd.

Jsem už z toho celkem zoufalý. Předem děkuji za pomoc.

:arrow_right: administrator: přejmenováno z "MEGA64_problém s přerušením od UART"

Problém může být kdekoliv. Hoď sem zdroják.

Zde to je, na MEGA16 mi to chodilo, ale mohla to být jen náhoda sem začátečník. Tak Vážně netuším co s tím.
matice.c (1.56 KB)

Omlouvám se jen je tam chyba v popisku u nastavení rychlosti je to pro 2400BAUDů pro frekvenci 1MHz. Jen , aby ste si nemyslely, že v tom je chyba. Ta je bohužel jinde. :frowning:

Program není moc dobře stavěn. Ve funkci “u_puts” vypusť zpoždění, místo něho ve funkci “u_putc” je vhodnější testovat, jesli je prázdnej UDR registr.

Abys mohl pracovat s řetězcem v mainu, musíš si tam nějak předat informaci, že řetězec je celý. Teprve pak s ním manipulovat.
Ta koncová ‘\0’ ti s řetězcem z PC přijde?

Nejdůležitější na závěr: proměnná použitá v přerušení a zároveň mimo něj musí být “volatile”.

Popravdě s tím “\0” si nejsem jistý, já myslel že se tím končí každý string.

To Volatile vyzkoušel sem dát do toho přerušení jednoduchou volatile proměnnou.
a potom v mainu s ní pracuji a také to nefunguje.

A Předat to tím ymslíte přes pointer?

Jinak díky za to zpoždění.

Proměnná, pomocí které spolupracuje přerušení (= samostatná funkce, nevolaná, nevracející) musí být globální a volatile se píše před její deklaraci.
Tedy globální volatile string (= char] )a ještě jedna další proměnná, do které budeš ukládat informaci o stavu textu.
Nulou je ukončen string v paměti, ale u přenosu si to musíš zabezpečit sám.

Děkuji za radu, ale vyskytla se mi jiná chyba. Ono Když se to vrací z obsluhy toho přerušení od UART, tak program běží zase od začátku main.
A neběží v nekonečné smyčce. Což mi přijde divny.

Divny to pravdu je, dokonce dost nepravděpodobný :slight_smile:.
Trochu jsem tvůj výtvor modifikoval…[code]#include <avr/io.h> //knihovna popisujici MCU
#include <avr/interrupt.h> //knihovna nutna k preruseni

//void u_putc (char data); // pokud je funkce použita až za svou definicí, není prototyp nutný
//void u_puts (char *text);

#define FALSE 0
#define TRUE 1
#define DELKA_BUFFERU 20

char buff[DELKA_BUFFERU];
volatile unsigned rxc = FALSE; // TRUE když je přijat celý řetězec a čeká na zpracování
// volatile: proměnná využita v přerušení i mimo něj

void u_putc(char data)
{
while( !(UCSR0A & 1<<UDRE0) ); // pockat na prazdny UDR
UDR0 = data;
}

void u_puts (char text])
{
unsigned char i=0;

while((i < DELKA_BUFFERU) && (buff* != '\0')) u_putc(buff*);

}

ISR(USART0_RX_vect)
{
static unsigned char index = 0;
char tmp;

tmp = UDR0;
if(!rxc)
{
	// pokud je předchozí řetězec zpracován (rxc == FALSE), bude se přijímat, jinak budou data ztracena
	
	if( (index < DELKA_BUFFERU-2) && (tmp != '!') )
	{
		// v bufferu je místo a přijatý znak není ukončovací (zde vykřičník)
		buff[index++] = tmp;
	}
	else
	{
		// v bufferu už není místo nebo přijat ukončovací znak
		buff[index++] = '\0';	// zapíšem ukončovací nulu
		rxc = TRUE;				// označíme přenos jako kompletní
		index = 0;
	}
}

}

void main(void)
{
// USART0, 8N1, 4800Bd + 0.2% @ 1MHz
UCSR0B |= 1<<TXEN0 | 1<<RXEN0 | 1<<RXCIE0;
// Transmitter Enable, Receiver Enable, RX Complete Interrupt Enable
UBRR0L= 12;
// default nastaveni po resetu je 8N1, nic jiného tedy není třeba nastavovat

sei();

for (;;)
{
	if(rxc)
	{
		// přijat kompletní řetězec nebo plný buffer
		u_puts(buff);
		rxc = FALSE;
	}
	
}

}[/code]Za funkčnost ovšem neručim, nemám na čem testovat (nemám m64 a jsem v práci).**

No pěkná modifikace, moc sem tam z toho svého kódu nepoznal teda :slight_smile:
Děkuji mnohokrát hned zítra otestuji. Nezlobte se, že se mnou ztrácíte čas.
Díky!

Tak bohužel kód nefunguje, na terminál to vůbec nic navypíše. Žádnou funkčí chybu jsem nenašel. Jen taková otázečka možná je to blbost, ale ten čip je ATmega64A a v AVR studiu to programuju jako ATmega64, nemohlo by to být v tomhle? Programuju PRESTEM přes SPI.
Popravdě už su z teho poměrně zófalé na mé zkušební ATmega16 mě vše fungovalo i měření teploty pomocí DS18B, měřil sem napětí atd. a teď mi nefunguje nic.

Jen poznámka dodělal sem si do kódu takovou testovací “věc” když se vyvolá to přerušení od UART tak zhasnu ledku na jednom pinu (která před tím svítí) Dám tam zpoždění, aby to bylo okem viditelny, ale jak zkončí obsluha přerušení ledka se rozsvítí. Možná je to hloupost,ale přijde mi opravdu jako by program po ukončení přerušení běžel od začátku main, kde tu ledku rozsvěcuji.

Zkus jednodušší verzi:[code]#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL
#include <util/delay.h>

void main (void)
{
DDRB |= 1<<PB0;
UBRR0L = 12; // 4800 Bd @ 1MHz
UCSR0B |= 1<<RXCIE0 | 1<<RXEN0 | 1<<TXEN0;

sei();

for(;;)
{ 
	//
	PORTB ^= 1<<PB0;
	_delay_ms(500);
} 

}

ISR(USART0_RX_vect)
{
UDR0 = UDR0;
}[/code]Je to odsud https://forum.mcontrollers.com/t/preruseni-uart-atmega8/1938/1 jen upravéné pro m64.
Nemáš ve fuses zapnutý mód kompatibility pro megu103? U nového mcu je defaultně aktivní (pojistka M103C). Už mě to jednou vypeklo (podruhé člověk ví odkud vítr fouká :slight_smile:).

Jen tak mimochodem - vpravo u svých psaníček máš tlačítko “upravit”, to abys nemusel mít monolog na celou stránku když tě po odeslání ještě něco napadne (občas edituju i více než 5x, jako třeba teď).

Tak program funguje bez problémů, ledka bliká. A terminál vrací znak. To předešlé fórum sem si přečetl a problém s WINAVR není mám to nejnovější.
Jen tak mimichodem pokud vypnu tu ledku v tom přerušení a smažu to blikání z FOR tak po návratu z obdsluhy se mi o5 zapne. To je standartní věc?

Tu kompatibilitu s megu103 mám vypnutou v tom sem hledal problém nejdřív.

O tlačítku vím, začnu ho používat díky :slight_smile:

Vlož upravenej kód.

To sem udělal. Jak řikám LEDka bliká a znak to vrací.

No tak omlouvám se Všem, teda hlavně piityymu tu pojistku sem měl nastavenou špatně. Já totiž jak už si nevěděl rady tak semd ělal všechno komplet od začátku a zapoměl jí vypnout. Teď vyzkouším jak se to chová dál.
.
.
.
Tak ten tvůj prvotní kód začíná fungovat, jen je tam nějak špatně udělaná detekce délky toho “buff” páč mi to odešle až po 16znacích.

Možná by se mohl v přerušení přijmout celý řetězec.
Jako ukončovací znak stringu jsem nastavil Enter kvůli snadnému zkoušení z terminálu.

[code]#include <avr/io.h> //knihovna popisujici MCU
#include <avr/interrupt.h> //knihovna nutna k preruseni
//void u_putc (char data); // pokud je funkce použita až za svou definicí, není prototyp nutný
//void u_puts (char *text);

char buff[20];
volatile uint8_t isr_flag; //použitá v main() i ISR(), proto “volatile”

//-----------------------------------------------------------------------------

void u_putc(char data)
{
while( !(UCSR0A & 1<<UDRE0) ); // pockat na prazdny UDR
UDR0 = data;
}

//-----------------------------------------------------------------------------

unsigned int u_getc(void) //příjem znaku
{
while ( !(UCSR0A & (1<<RXC0)) )
;
return UDR0;
}

//-----------------------------------------------------------------------------

void u_puts(char *s ) //zápis stringu do uart
{
while (*s)
u_putc(*s++);
}

//-----------------------------------------------------------------------------

ISR(USART0_RX_vect)
{
unsigned char index;

for (index=0;index<sizeof(buff);index++)
{
buff[index] = u_getc();

     if((buff[index] == 13) || (buff[index] == 10))  //klávesa Enter
     {
        buff[index] = 0; //ukonči string v "buff" nulou
        break;  //vystoupí ze smyčky for
     }

}

isr_flag=1;
}

//-----------------------------------------------------------------------------

int main(void)
{
// USART0, 8N1, 4800Bd + 0.2% @ 1MHz
UCSR0B |= 1<<TXEN0 | 1<<RXEN0 | 1<<RXCIE0;
// Transmitter Enable, Receiver Enable, RX Complete Interrupt Enable
UBRR0L= 12;
// default nastaveni po resetu je 8N1, nic jiného tedy není třeba nastavovat
sei();

for (;:wink:
{
if(isr_flag == 1) // přijat kompletní řetězec nebo plný buffer
{
isr_flag = 0;
u_puts(buff);
}
}
}
[/code]

Tak Mockrát děkuji všem, především piityymu. Bylo to tou pojistkou. Ted už jede všechno jak má. Pittyho kód pro komunikaci funguje na 100%.

To: AB tvůj kód sem již nezkoušel, neměl sem na to sílu :slight_smile: nezlob se, ale také moc děkuji.

A díky taky za upozornění na mé chyby, budu se snažit se jich vyvarovat.

ABeho by fungoval taky, jen s malými odlišnostmi.
Jeho příjem je tzv. blokující - dokud nedojde celý řetězec, program je zastaven. Když používám přerušení, tak obvykle proto, abych toto odstranil :wink:. Ba co víc, není tu pouze blokující příjem, ale blokující přerušení, to mi přijde jako ještě drsnější metoda.
Buffer se bude chovat jako kruhový - pokud bude řetězec delší než pole, přerušení se ukončí, mezitím se v mainu začne zpracování a s příchodem dalšího znaku se kód opět zablokuje a začne přepisování bufferu.
Z toho plyne určité nebezpečí - v době zpracování nemusí řetězec obsahovat ukončující nulu. To samé platí, pokud bude mít zaslaný řetězec délku rovnu délce bufferu.
V cyklu je použit operátor sizeof(). Zde samozřejmě v pořádku, takto jednoduše jde použít pouze pokud jde o pole 1B prvků - to by mohlo v budoucnu začátečníkovi způsobit nepřijemnosti.

Fce na odeslání řetězce je rychlejší, je však životně závislá na přítomnosti ukončující nuly v řetězci. To je naprosto běžné, ovšem zde není její přítomnost zajištěna.