Sida 2 av 2
Postat: 21 augusti 2006, 21:25:13
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')) )
);
}
Postat: 21 augusti 2006, 21:25:29
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...

Postat: 21 augusti 2006, 22:14:12
av Gimbal
Ja nu traskar jag vidare, ingen ide att tokpolera en detalj i programmets periferi.
Dags att sparka igång AD-omvandlaren...
Postat: 21 augusti 2006, 22:55:26
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....
Postat: 22 augusti 2006, 10:06:41
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

Postat: 22 augusti 2006, 11:02:45
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å...)
Postat: 22 augusti 2006, 11:26:30
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.
Postat: 22 augusti 2006, 11:41:21
av Gimbal
Får erkänna att jag inte ser hur den C koden skulle kunna funka.
Postat: 22 augusti 2006, 12:35:36
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.
Postat: 22 augusti 2006, 13:01:43
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.
Postat: 22 augusti 2006, 13:04:53
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...