sträng till int, i C?

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
oJsan
EF Sponsor
Inlägg: 1541
Blev medlem: 11 november 2005, 21:36:51
Ort: Umeå
Kontakt:

Inlägg av oJsan »

Om du använder den för att "kolla checksumman" så innebär det ju alltså att du även gör en _egen_ beräkning av checksumman va?
Ett alternativ vore då kanske att köra nibblevis XOR på inkomna byte. Jämför sedan de två nibblarna med asciihexvärdet...
Inte säkert att det blir effektivare, men det kanske är värt att testa... (Ha överseende att jag kanske programmerat fel i huvudet, men jag hoppas att själva idéen kommer fram ändå)

Kod: Markera allt

//Datainläsningen, typ nått sånt här...:
while(incomming_data)
{
	indata = getFromUART();
	xorL = (indata & 0x0F) ^ xorL;
	xorH = (indata >> 4) ^ xorH;
}

//Checksumverifiering:
bool verifyChecksum(char xorL, char xorH, char* hexCS)
{
	return
	(
	  (*(hexCS) == ((xorL < 0x0A) ? (xorL+'0') : (xorL+'A')) )
	   &&
	  (*(hexCS+1) == ((xorH < 0x0A) ? (xorH+'0') : (xorH+'A')) )
	 );
}
sodjan
EF Sponsor
Inlägg: 43267
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Jo, jag vet at det börjar glida lite OT, men programmering och optimimering är intressant... :-)

Även 58 till 88 bytes är rellativt mycket för detta...

Den kortaste PIC rutin jag hittade har 7 (8 med "return") instruktioner :

Kod: Markera allt

ascii2byte 
	swapf hichar,w	;swap hi nibble into result
	btfsc hichar,6	;check if in range 'A'-'F' 
	addlw 0x8F 	;add correction swapf ('1'-'A'+1) 
	addwf lochar,w 	;add lo nibble 
	btfsc lochar,6 	;check if in range 'A'-'F' 
	addlw 0xF9 	;add correction '9'-'A'+1
	addlw 0xCD 	;adjust final result -0x33 
	return 
Notera att inga extra RAM/register används än de två där HEX siffrorna
ligger och där resultatet lagras. Inga temp register alltså...

Det skulle förvåna om man inte kan fixa något liknande i "AVR-språk"...

Men mest av akademiskt intresse eftersom du har en rutin som gör det det vill... :-)
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg av Gimbal »

Ja nu traskar jag vidare, ingen ide att tokpolera en detalj i programmets periferi.
Dags att sparka igång AD-omvandlaren...
Användarvisningsbild
bengt-re
EF Sponsor
Inlägg: 4829
Blev medlem: 4 april 2005, 16:18:59
Skype: bengt-re
Ort: Söder om söder
Kontakt:

Inlägg av bengt-re »

Men det kan vara roligt att optimera också. Sen så lär man sig en hel del på att försöka göra lite trickigare matte med 8 bitars assambler...

Formler som x=(on1/(on1+off1)+k)*k2 är rätt kul att försöka få in i en 8 bitars värld.... Speciellt om man skall ta hänsyn till vad upplösning blir vid extremvärden... Men, man kan spara enormt mycket tid på att optimera sån´t. Skrev om en rutin som i högnivåspråk tog 2,1ms till att gå på 4,2us... Rätt skaplig skilnad och 2ms som jag verkligen behövde dök upp! Sen att man sparde något 120byte kod och 4 register kvittade i detta fallet, men trevlig ändå.

Lönar sig ofta att strunta i högnivåspråk och köra assambler - iaf till kretsar där snabbhet är viktigt och behöver maninte hastigheten kan man ju alltid sänka klockfrekvensen och spara ström istället om det nu inte krockar med lämplig klocka för UART....
Användarvisningsbild
exile
EF Sponsor
Inlägg: 496
Blev medlem: 21 oktober 2005, 23:32:07

Inlägg av exile »

Nja, det är snarrare att dålig "algoritm" som ger dålig resultat...
Samt att den som sitter och programerar har dålig koll på vad som är "bra" samnt "dålig" code för AVR, PIC, ARM ....

exempel:

Kod: Markera allt

unsigned int hexe(unsigned char h,unsigned char l)
{
	if (h & 0x40) h = h - 'A' + 10 + '0';
	h -= '0';
	h <<=4;
	h += l;
	if (l & 0x40) h = h - 'A' + 10  + '0';
	h -= '0';	
	return h;
}
ger

Kod: Markera allt

unsigned int hexe(unsigned char h,unsigned char l)
{
	if (h & 0x40) h = h - 'A' + 10 + '0';
 114:	86 fd       	sbrc	r24, 6
 116:	87 50       	subi	r24, 0x07	; 7
	h -= '0';
	h <<=4;
 118:	82 95       	swap	r24
 11a:	80 7f       	andi	r24, 0xF0	; 240
	h += l;
 11c:	86 0f       	add	r24, r22
	if (l & 0x40) h = h - 'A' + 10  + '0';
 11e:	66 fd       	sbrc	r22, 6
 120:	87 50       	subi	r24, 0x07	; 7
	h -= '0';	
 122:	80 53       	subi	r24, 0x30	; 48
	return h;
}
 124:	99 27       	eor	r25, r25
 126:	08 95       	ret
vilket blir 10 instruktioner stort
vilket inte är så faligt...

Med lite hand optimering kan jag få det till 8 instruktioner vilket inte är så mycket bättre...

Kod: Markera allt

swap	r24
sbrc	r24, 2
subi	r24, 0x71	; 113
add	r24, r22
sbrc	r22, 6
subi	r24, 0x07	; 7
subi	r24, 0x33	; 51
ret
Noter att alla exempel bygger på sodjan code som han har hitta :)
sodjan
EF Sponsor
Inlägg: 43267
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

Exakt !!
Ett bra exempel på att det går att skriva effektiv kod även med (t.ex) C.
(Om den fungerar alltså, jag har inte analyserat det... :-) )

Det viktiga är att man vet hur processorn (och kompilatorn !) fungerar !
Det finns allt för många som skiver "Windows-kod" till microcontrollers
med "varierande" resultat... :-)

Hur som helst, snyggt var det i alla fall (hoppas att det fungerar också...)
Användarvisningsbild
$tiff
Inlägg: 4941
Blev medlem: 31 maj 2003, 19:47:52
Ort: Göteborg
Kontakt:

Inlägg av $tiff »

Jag stämmer fullständigt in med sodjan.
Många gånger ser man folk som är ovana vid µC som skriver kod som hör hemma någon helt annanstans (då blir man lite mörkrädd). För det mesta klarar de sig undan, eftersom de har processortiden över, men hujedamig vad mycker mer kraft det går att klämma ur en liten 8-bitars propp om man vet hur och vad man skriver!

Det finns åtskilliga appnotes om hur man skriver effektiv C-kod till AVR/PIC, så för den som är intresserad av mer (vilket ni borde vara), är det bara att dammsuga internetet efter dessa.
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg av Gimbal »

Får erkänna att jag inte ser hur den C koden skulle kunna funka.
Användarvisningsbild
exile
EF Sponsor
Inlägg: 496
Blev medlem: 21 oktober 2005, 23:32:07

Inlägg av exile »

Den är ganska enkel...

Vi tar för en nibbel
exempel
unsingend char test(unsingend char ch){
if (ch & 0x40) ch = ch - 'A' + 10 + '0';
ch -= '0';
}

if satsen kollar om siffra eller bokstav genom att titta på den 7biten
0 = 0b00110000
1 = 0b00110001
2 = 0b00110010
3 = 0b00110011
4 = 0b00110100
5 = 0b00110101
6 = 0b00110110
7 = 0b00110111
8 = 0b00111000
9 = 0b00111001
A = 0b01000001
B = 0b01000010
C = 0b01000011
D = 0b01000100
E = 0b01000101
genom att enbart kolla på den 7biten så klarar AVR att göra testet med 1 instruktion... vilket reduserar storleken på den gernerarade koden


om det är en bokstav ch = ch - 'A' + 10 den vanliga omvandlingen + '0' för att vi alltigt drar ifrån '0'.
På så vis sliper vi else satsen och där med alla hopp den förorsakar i onödan.
Gimbal
Inlägg: 8787
Blev medlem: 20 april 2005, 15:43:53

Inlägg av Gimbal »

Aha, där ser man. Listig men svårläst kod, sådan skall man normalt undvika om det inte krävs av minnes eller hastighetsskäl.
Skall prova den i kväll, av minnesskäl.
sodjan
EF Sponsor
Inlägg: 43267
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Får erkänna att jag inte ser hur den C koden skulle kunna funka.

Jag har inte kollat C koden närmare, men jag har just "handkört"
assmembler koden (i C-listan) med "B" "8" och får 184 (decimalt)
vilket är helt korrekt.

Och med exile's förtydligande (och lite mer funderande och studerande
av en ASCII-tabell) så är det ju ganska enkelt.

"0" - "9" är ju enkelt, bara att dra bort "offseten" för nollan.
"A" - "F" flyttas först ner 7 steg så att de ligger direkt efter "9".
Kolla en ASCII tabell så är det ganska tydligt.

"ch - 'A' + 10 + '0'" kan se lite komplicerat ut, men ta en del i taget
så är det ganska klart.

Fört minska med ascii värdet för "A", sedan lägg till 10, sist lägg till
ascii värdet för "0" så att "A" hamnar direkt efter "9"...

D.v.s samma sak som : "ch - 7" (vilket också kompilatorn "såg"...).

Så man kan alltså även skriva det :

Kod: Markera allt

unsigned int hexe(unsigned char h,unsigned char l)
{
   if (h & 0x40) h = h - 7;
   h -= '0';
   h <<=4;
   h += l;
   if (l & 0x40) h = h - 7;
   h -= '0';   
   return h;
} 
vilket är samma sak och kanske lite tydligare...
Skriv svar