Zpracování řetezce v C

Dobrý den,

rád bych poprosil o pomoc se zpracováním řetezce poslaného přes UART.Netuším jak napsat program v C pro zpracování řetězce. S 1 znakem dokážu pracovat,ale s více znaky netuším jak na to.Potřebuji poslat řetězec př. aaPXXYYZZ kde aaP je hlavička a XX,YY,ZZ jsou čísla v hex pro nastaveni poloh serv.Používám Atmega8 1Mhz 4800bd, používám AVR Studio. V tutoriálech co jsem našel se řeší 1 znak.Děkuji za rady

Zdar.[code]#include <avr/io.h>
#include <stdlib.h> // strtol function

void main(void)
{
//
char retezec] = “aaPFA127B”; // aaPXXYYZZ
long int tmp;
unsigned char x, y, z;

// long strtol ( const char  __nptr, char  __endptr, int __base )
tmp = strtol(&(retezec[3]), NULL, 16);
z = (unsigned char)tmp;
y = (unsigned char)(tmp >> 8);
x = (unsigned char)(tmp >> 16);

for(;;);

}
[/code]

Zbytečně složité (pro začátečníka)

pro tyto případy - kombinace několika typů proměnných- zde ascii znaky + hodnoty v hex přece slouží funkce formátující řetězec.

[code]#include <avr/io.h> //pro funkci printf

unsigned char x, y, z;

printf(“aaP%u%u%u”,x,y,z);
[/code]

Toto ti pošle přes UARt to co potřebuješ - 3 krát %u znamená, že hodnoty x,y a z budou poslány jako unsigned char - tedy vlastně hex

Jsem to pochopil jako že potřebuje zpracovat poslaný řetězec a tak jsem napsal dekódování řetězce.

Nepošle to ta čísla náhodou dekadicky místo šestnáctkově? Pro hex konverzi jsou x a X.

omlouvám se tedy, pro poslání v hex tvaru slouží %c

vím určitě, že %x, nebo %X posílá v ascii znacích hex. zápis- a to malé, nebo velké x udává, jestli to bude v malých nebo velkých písmenech - při x třeba ff a při **X **FF

Díky moc hned to vyzkouším a pochopil jste to správně.Potřebuji aby Atmega přijala z počítače přes UART výše popsany řetezec, kde budou 3 hex čísla 0-FF pro nastaveni polohy 3 serv.

Tak to já jsem to pochopil přesně obráceně, v prvním příspěvku nebyla o PC řeč, tak jsem myslel, že ten řetězec má být poslán z té ATmegy.
Pak je použití fce strtol asi jedinou možnou variantou (atoi asi neuní převést hex. zápis - s písmeny A-f?).

A nebylo by jednodušší posílat z PC přímo hodnoty bez převodu do zápisu v ASCII ? Pokud máš tedy možnost ovlivnit aplikaci v PC.

Omlouvám se moje chyba špatně jsem ten problém popsal. Aplikaci v PC nemám možnost ovlivnit - řeším to na dipl. práci. Je to jejich standartni komunikační protokol, který musím použít.Musím ošetřit i hlavičku(první 3 znaky), aby to reagovalo jen na konkretní a k tomu jsem využil fci strstr(). Těd ještě musím vyladit program, aby procesor přijal celý řetězec a mělo by to chodit snad :unamused:

Na ošetření hlavičky nepotřebuje velkou funkci jako je strstr(). Stačí jednoduchá podmínka:
if(retezec[0] == ‘a’ && retezec[1] == ‘a’ && retezec[2] == ‘P’)…

Nevím jestli toto téma ještě někdo sleduje, ale ještě bych potřeboval trochu pomoct.#include <avr/io.h>

[code]#include <stdlib.h> // strtol function

void main(void)
{
//
char retezec] = “aaPFA127B”; // aaPXXYYZZ
long int tmp;
unsigned char x, y, z;

// long strtol ( const char __nptr, char __endptr, int __base )
tmp = strtol(&(retezec[3]), NULL, 16);
z = (unsigned char)tmp;
y = (unsigned char)(tmp >> 8);
x = (unsigned char)(tmp >> 16);

for(;;);
} [/code]
funguje správně, ale nedaří se mi upravit na to, aby zpracoval řetězec “aaPFA127B”, který bude ukončen znakem CR(Carriage Return- v ASCII kód 13). Nevíte někdo jak tento program upravit na zpravání a přijetí přes UART?Přijetí řetězce přes UART řeším taktofor(r=0;r<10;r++)
[code]{
retezec[r]=uart_getc();

		}[/code]ale je to takové kostrbate. Potřeboval bych, aby po přijetí znaku CR zpracoval tu část řetězce před ním. Mohl by mi prosím Vás někdo pomoci. Děkuji

// načtení řetězce: unsigned char r = 0; do{ retezec[r]=uart_getc(); }while(retezec[r++] != 13); // ... zpracování řetězce
Ten cyklus podmínkou nejspíš jde napsat na 1 řádek (něco jako “while((retezec[r++] =uart_getc())!= 13);”), ale nechce se mi to teď testovat.

Funkce strtol by s entrem na konci snad neměla mít problém a mela by poznat, že už nepatří do čísla. Kdyby to nechodilo, stačí v řetězci najít entr a nahradit ho nulou.

Dorbý den,

potřeboval bych poslat a následně příjmout a dekódovat řetezec znaků přes USART. Řetězec by se měl skládat: první dva znaky určují funkci (např. smaž displej, vypis znak na displej, atp), další dva znaky by měli určovat pozici znaku na displeji a poslední část řetězce by měla určovat znak který bude zobrazen na displeji.

Děkuji za jakoukoluv pomoct

Pokud nebude funkcí a pozic na displeji více jak 256 (což nehrozí pokud jsi to chtěl přenášet pomocí 2 ascii znaků), stačí v obou případech 1B (přenos nemusí probíhat v ascii, stejně dobře projdou i běžná data).
S čím konkrétně je problém? Příjem a vyslání znaku/řetězce tu byl už mockrát. Na dékódování funkce můžeš použít třeba příkaz “switch”. Na zbytku není co dekódovat (pokud přeneseš pozici jako binární číslo místo ascii znaků).

Stačí mi posílat pouze jeden znak nebo příkaz asynchroně přes UART. Všechno chci zobrazit na jednoduchém šestnácti znakovém a dvou řádkovém displeji. Problém je v tom že to posílám bezdrátovým přenosem(868MHz). Doposud jsem pouze posílal jeden znak(bez ovládácích znaků a zabezpečení), ale na displeji se to ukazuje dost zmateně. Některý znak zobrazí například dvakrát jiné třeba vynechá a nebo zobrazí nějakou parazitní blbost přijatou ze vzduchu. Potřebuju tento přenos zabezpečit, navíc mít jistotu že se konkrétní znak zobrazí na určeném místě a ještě bych potřeboval přes UART například smazat displej nebo začít vypisovat znaky na začátek displeje.

Jsem dost špatny programator, ale někdy mám i světlejší chvilky :slight_smile:.

Snad jsem podal dostatečné informace. Budu vděčný za každou radu.

Se zabezpečením přenosu ti neporadím, ale lcd smažeš posláním čísla 1 a na začátek prvního řádku se vrátíš posláním čísla 2.

Zde jsem naprogramoval jednoduchou funkci pro dekódování přijatého řetezce “AAdXYZ”. Program má reagovat pouze na konkrétní hlavičku AA, poté má určit funkci pro ovládání lcd (d= 1-3) a následně buď splnit funkci a nebo napsat znak(Z) na konkrétní pozici (X,Y) na lcd, ale bohužel to vůbec nefunguje. Mohl by mi někdo poradit kde může být chyba?
Děkuji

while(1)
{

_delay_ms(500);
	Data[5] = UDR;

if(Data[0]=='A' && Data[1]=='A')

	{switch (Data[2]) {

		case '1': 
			lcd_clrscr();//smaze lcd
			break;
		
		case '2': 
			lcd_home(); //vrati kurzor na zacatek lcd
			break;

		case '3':
			X=Data[3];
			Y=Data[4];
			lcd_gotoxy(X,Y);//presun kurzoru na konkretni pozici 
			lcd_write(Data[5],1);// zapise znak na lcd

			break;
		}

};
return 0;
};
}

No, mohlo to být horší :slight_smile:.
Používat _delay ve spojení s uartem není vhodné. UDR registr je totiž pouze registr a udrží jen 1B. Ten musíš pokaždé vyčíst, jinak o něj přijdeš. Vpodstatě jediné správné řešení (mimo přerušení, které je mnohem vhodnější) je čekání na přijetí bytu neustálou kontrolou flagu RXC.
“Data[5] = UDR;” pouze načte poslední přijatý byte (předtím se jich mohlo několik ztratit) do poslední pozice v poli. Data v nižších pozicíxh se nemění.

Data pro pozici na displeji musí chodit jako data! Kdybys posílal znaky, dělalo by to nesmysly. Třeba znak ‘5’ by posunul pozici na 35 (ascii hodnota číslice 5).

Kód pro megu8:

[code]#include <avr/io.h>
// #include / .h soubor pro LCD/

#define DELKA_POLE 6

int main(void)
{
unsigned char data[DELKA_POLE], i;

// sem patří inicializace uartu

while(1) 
{
	for(i = 0; i < (DELKA_POLE - 1); i++) data* = data*;
		// přesunout data v poli dolů (uvolnit místo pro nový byte, nejstaší zahodit)


	while(!(UCSRA & (1<<RXC)));		// počkat na nový byte
	data[DELKA_POLE - 1] = UDR;		// na poslední místo nový byte
	if(data[0]=='A' && data[1]=='A') 
	{
		switch (data[2])
		{ 
			case '1': 
				lcd_clrscr();
				break; 

			case '2': 
				lcd_home();
				break; 

			case '3': 
				lcd_gotoxy(data[3], data[4]);
				lcd_write(data[5], 1);
				break;

			default:
				break;
		} 
	}
}

}[/code]**

V tomto kódu je třeba dávat pozor aby bajty nepřicházely rychleji, než stačí proběhnout smyčka.
Např při 4800 baud přijde bajt každé cca 2 ms, ale samotný příkaz lcd_clear může trvat 3-4 ms.

Kód jsem předělal podle úpravy a zkouším tam posílat data úplně jednoduše(viz kod níže), ale bohužel se nic neděje. Inicializace USART je určitě v pořádku znak to přijímá v pohodě. Po aplikaci zabezpečení hlavičkou to bohužel nejede. Zkoušel jsem to přes UDR a printf, ale nic se neděje. :frowning:

Mohl by mi někdo napsat kde dělám chybu nebo jak bych měl poslat řetězec šesti znaků?

Předem moc děkuji

while (1)
{

while ( !( UCSRA & (1<<UDRE)) ); // ceka na vyprazdneni zasobniku
UDR = *"AA311A"; //printf ("AA311A");
				
  }

To o UDR registru platí i o vysílání.
Dnes nemám sil na vysvětlování. Přečti si něco o řetězcích v C, jejich uložení v paměti a manipulace s nimi.
Hodnota “11” v posílaném řetězci se pokusí nastavit souřadnice 31,31!

char[7] str = "AA311A"; unsigned char i; for(i=0; i<6; i++) { while ( !( UCSRA & (1<<UDRE)) ); UDR = str*; }
Pro profesionály: cyklus jde samozřejmě napsat jednodušeji, ale pro zdejšího začátečníka bude toto asi pochopitelnější.*