C-kods problem

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

sodjan, ljuset i mörkret.
Tackar!

//Emil
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

Okej, nu har jag skrivit det och kompilator klagar inte.
Men om någon vill så kan den få ögna igenom detta och se ifall jag har tänkt helt fel.

Kod: Markera allt

const unsigned char char_A[] PROGMEM = {0b01111110, 0b10010000, 0b10010000, 0b10010000, 0b01111110};
...................
const unsigned char char_Z[] PROGMEM = {0b10000110, 0b10001010, 0b10010010, 0b10100010, 0b11000010};

const unsigned char char_0[] PROGMEM = {0b01111100, 0b10000010, 0b10000010, 0b10000010, 0b01111100};
..................
const unsigned char char_9[] PROGMEM = {0b01100000, 0b10010000, 0b10010000, 0b10010000, 0b01111110};

const unsigned char char_UT[] PROGMEM = {0b01110000, 0b10001010, 0b01110000}; // !
..................
const unsigned char char_HPI[] PROGMEM = {0b01000100, 0b00101000, 0b00010000}; // >

PGM_P char_array[26] PROGMEM = {char_A, char_B, char_C, char_D, char_E, char_F, char_G, char_H, char_I, char_J, char_K, char_L, char_M, char_N, char_O, char_P, char_Q, char_R, char_S, char_T, char_U, char_V, char_W, char_X, char_Y, char_Z};
PGM_P num_array[10] PROGMEM = {char_0, char_1, char_2, char_3, char_4, char_5, char_6, char_7, char_8, char_9};
PGM_P sign_array[22] PROGMEM = {char_UT, char_PRO, char_SLASH, char_VP, char_HP, char_VHP, char_HHP, char_VKP, char_HKP, char_LIKA, char_FT, char_PLUS, char_MINUS, char_PUNKT, char_KOLON, char_UL, char_APOSTROF, char_DL, char_STJ, char_UPI, char_VPI, char_HPI};

void LCD_Write_Char(unsigned char x, unsigned char y, char ch)
{	
	unsigned char ch_data[5] = {0, 0, 0, 0, 0};
    PGM_P p;

	if((ch >= 'A') && (ch <= 'Z'))
	{
		memcpy_P(&p, &char_array[ch - 'A'], sizeof(PGM_P));
		strcpy_P(ch_data, p);
	}
	
	else if((ch >= '0') && (ch <= '9'))
	{
		memcpy_P(&p, &num_array[ch - '0'], sizeof(PGM_P));
		strcpy_P(ch_data, p);
	}
	
	else
	{
		switch(ch)
		{		
			case '!': memcpy_P(&p, &sign_array[0], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '%': memcpy_P(&p, &sign_array[1], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '/': memcpy_P(&p, &sign_array[2], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '(': memcpy_P(&p, &sign_array[3], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case ')': memcpy_P(&p, &sign_array[4], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '[': memcpy_P(&p, &sign_array[5], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case ']': memcpy_P(&p, &sign_array[6], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '{': memcpy_P(&p, &sign_array[7], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '}': memcpy_P(&p, &sign_array[8], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '=': memcpy_P(&p, &sign_array[9], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '?': memcpy_P(&p, &sign_array[10], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '+': memcpy_P(&p, &sign_array[11], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '-': memcpy_P(&p, &sign_array[12], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '.': memcpy_P(&p, &sign_array[13], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case ':': memcpy_P(&p, &sign_array[14], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '_': memcpy_P(&p, &sign_array[15], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '´': memcpy_P(&p, &sign_array[16], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '|': memcpy_P(&p, &sign_array[17], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '*': memcpy_P(&p, &sign_array[18], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '^': memcpy_P(&p, &sign_array[19], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '<': memcpy_P(&p, &sign_array[20], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			case '>': memcpy_P(&p, &sign_array[21], sizeof(PGM_P)); strcpy_P(ch_data, p); break;
			
			default: break;
		}
	}
	
	osv..osv..osv
}
Fick göra en switch av tecknen då de inte ligger på rad i ASCII tabellen.

Tack ska ni ha för all hjälp!

//Emil
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

Okej, då ingen säger något så antar jag att den är okej. :)

Men, nu har jag börjat blivig orolig för storleken på programmet.
Hur vet man hur mycket minne det kommer ta?
Såhär ser en rad i .hex filen ut: ":100000000C9437010C9452010C9452010C9452013F" och filen är 6109 byte stor nu.

Harför mig att jag fick svar för detta i en gammal tråd men jag lyckades inte hitta den.

//Emil
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Leta efter Intel Hex
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

Okej, nu hänger jag med.
Det är altså 16st databytes per rad och varje rad är 43 tecken.
Så man kan gångra storleken på hexfilen med 16/43 ≈ 1/3 så får man ett ungefärlig storlek på datat som ska in i µCn.

Tack ska du ha!

//Emil
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Inlägg av thepirateboy »

avr-size kan du använda. Läggs med fördel in i makefilen.


C:\Program\WinAVR\bin>avr-size -C --mcu=atmega88 test.elf
AVR Memory Usage
----------------
Device: atmega88

Program: 304 bytes (3.7% Full)
(.text + .data + .bootloader)

Data: 2 bytes (0.2% Full)
(.data + .bss + .noinit)
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

Hur ska man lägga in den i makefilen?
För skriver jag bara avr-size så vill det sig inte.

//Emil
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Jag tror inte din kod stämmer riktigt. Du ska nog skippa alla anrop till strcpy_P(). Så här hade jag tänkt:

Kod: Markera allt

void LCD_Write_Char(unsigned char x, unsigned char y, char ch)
{   
   unsigned char ch_data[5] = {0, 0, 0, 0, 0};
   unsigned char bytes = 0;
   PGM_P p = NULL;

   if ((ch >= 'A') && (ch <= 'Z'))
   {
      p = &char_array[ch - 'A'];
      bytes = sizeof(char_array[0]);
   }
...

//bla bla
		switch (ch)
		{
			case '!': p = &sign_array[0]; break;
			case '%': p = &sign_array[1]; break;
			...
		}
		if (p)
			bytes = sizeof(sign_array[0]);
//bla bla

	memcpy_P((void*)ch_data, p, bytes);

...

Jag har alltså tänkt att du först bestämmer plats i minnet och hur många bytes som ska kopieras. Sen när alla kollar är gjorda så gör du själva anropet till memcpy_P(). I övrigt vet jag inte om det går att förstå vad jag menar i koden. Fråga om du inte förstår. :)

sizeof(PGM_P) som du hade skrivit blir inte rätt va? Kontrollera.
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Inlägg av Korken »

Jag har ingen aning om min kod funkar än men kompilatorn klagar inte.
Jag gjorde exakt lika som på http://www.nongnu.org/avr-libc/user-man ... _rom_array och där står det att man man ska göra så.
För jag har igenteligen ingenaning om hur detta funkar.

Jag förstår inte helle riktigt din kod.
Sen kör du sizeof alltid på det första elementet fast att vissa element inte har samma storlek.
Fast man kanske ska göra så. Somsagt, jag vet inte. :?

//Emil
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Inlägg av sodjan »

> Men, nu har jag börjat blivig orolig för storleken på programmet.

De flesta verktyg (assemblers, kompilatorer o.s.v) brukar ge en del
statistik som bl.a kodstorlek i "list" eller "map" filen eller liknande.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Korken: Största problemet är att det är olika storleker på teckentabellen. Detta kan lösas på olika sätt och ett av de smartaste är att ange storleken.

Jag har gjort en teckentabell till ett projekt där varje inlägg var:
Längd, Data1, Data2, Data3, Data4, Data5
osv.
Då kunde rutinen enkelt slå upp i tabellen, läsa HUR många bytes som skulle skrivas och vilka de var. Ingen massa jävla "case: break".

Visst, det fyllde tomma bytes i minnet men case: break är inte billigt heller.

På mig verkar det som att du vill göra den mest ineffektiva och långsamma kod som möjligt men det kanske är för att"Jag förstår inte heller riktigt din kod".

Jag vet inte hur mycket minne du har men en komplett teckentabell (karaktär 0-255, 6 bytes/karaktär) fyller 1536 bytes. Då har du en 5*7(8) matris med storleksangivelse, är storleken 0 finns det tecken inte.

Enklare mjukvara än så finns inte, kanske inte världens mest effektiva i kodstorlek men snabbt som fan.

Kod: Markera allt

typedef unsigned char byte;
const byte Teckentabell[6][] PROGMEM = {
  {0,0x00,0x00,0x00,0x00,0x00}, // Index ASCII 0
  {0,0x00,0x00,0x00,0x00,0x00}, // Index ASCII 1
  {0,0x00,0x00,0x00,0x00,0x00}, // Index ASCII 2
  {0,0x00,0x00,0x00,0x00,0x00}, // Index ASCII 3
  {0,0x00,0x00,0x00,0x00,0x00}, // Index ASCII 4
....
  {3,0x00,0x00,0x00,0x00,0x00}, // Index ASCII 32 ' '
  {1,0x7D,0x00,0x00,0x00,0x00}, // Index ASCII 33 '!'
  {3,0xC0,0x00,0xC0,0x00,0x00}, // Index ASCII 34 '"'
....
  };

void LCD_Write_Char(unsigned char x, unsigned char y, char ch)
  {   
  if(Teckentabell[0][ch])
    {
    memcpy_P((void*)ch_data, Teckentabell[1][ch], Teckentabell[0][ch]);
    // eller rättare: skriv ut på displayen, datan finns i Teckentabell[1-5][ch]
    // och antalet bytes i Teckentabell[0][ch]
    };
Senast redigerad av Icecap 17 april 2007, 19:27:15, redigerad totalt 1 gång.
thepirateboy
EF Sponsor
Inlägg: 2109
Blev medlem: 27 augusti 2005, 20:57:58
Ort: Borlänge

Inlägg av thepirateboy »

Så här står det i min makefil

size: ${TARGET}
@echo
@avr-size -C --mcu=${MCU} ${TARGET}
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Icecap: Testade din metod och den verkar ta upp 402 bytes (1514-1112) mer minne. Då körde jag 5 bytes/tecken på alla tecken på båda metoderna. Med din metod gjorde jag en array med 128 tecken. Fast din metod är ju bra mycket snyggare.

Men varför kör du med ett "Längd"-fält? Man kan väl lika gärna köra med 5 bytes överallt. Nollorna antar jag inte gör någon skillnad i Korkens LCD-funktion.

Korken: Gör ett testprogram som endast lagrar en byte i Flash-minnet. Sen försöker du läsa av det och låt en LED blinka om du läser rätt byte. Sen går du vidare med arrayer osv. Förstår du inte exakt hur allt fungerar så ska du absolut inte ta för givet att en så stor kodbit, som du har skrivit, fungerar direkt.

Det jag tror du ska använda är memcpy_P(). Sen verkar det som att du ska använda pekartypen PGM_VOID_P istället för PGM_P som du/jag har använt. Se också memcpy(), för att se hur den funktionen fungerar.

Försök fixa en liten testkod och se vad som händer. Eller posta här, så kan jag/vi kolla på koden.
Användarvisningsbild
Icecap
Inlägg: 26659
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

cykze: saxat från ovan
const unsigned char char_UT[] PROGMEM = {0b01110000, 0b10001010, 0b01110000}; // !
const unsigned char char_HPI[] PROGMEM = {0b01000100, 0b00101000, 0b00010000}; // >
Det används INTE en fast 5*7 matris, det används variabel längd tecken. Därför!
Användarvisningsbild
cykze
EF Sponsor
Inlägg: 1539
Blev medlem: 8 april 2004, 10:40:28
Ort: Uppsala

Inlägg av cykze »

Jag så van med fast teckenbredd från vanliga små LCD:er med inbyggda tecken, det var därför. :)
Skriv svar