Sida 1 av 2

Multiplexning av LED-display

Postat: 18 januari 2011, 07:08:01
av hadoque
Hej
Jag håller på med mitt första PIC-project där jag använder en PIC24FJ64GA004 och C30.
I projektet använder jag 5 st 7-segments displayer. LEDs från displayerna är parallellt kopplade till 8 st portar på PICen. Katoden på varje display är kopplad till en N-MOSFET vars gate är kopplad till en port.
Jag har skrivit en funktion som tar ett tecken och ett displaynummer och som tänder rätt LEDs och kopplar till angiven MOSFET.
Detta funkar precis som det ska om jag statiskt tänder en display, men när jag försöker cykla flera displayer blir allt jättekonstigt.
Mellan varje displaytändning gör jag en liten paus med en for loop, och om jag jag gör en så lång paus så att jag ser varje cykel kan jag se att det är allsköns kombinationer av LEDs som tänds, samt att det ofta är flera displayer som tänds samtidigt.
Jag har uppenbarligen missat något viktigt här. Kan någon ge mig en hint?
Här är koden till funktionen:

Kod: Markera allt

//*** function dispFig ***
//*** Takes a character ((-2)-9), a display number
//*** and wether a dot should be displayed or not. 
//*** -1 is a minus sign and -2 is no LEDs lit.
//*** All displays are reset before setting the new display.
void dispFig(int figure, int displayNo, int dot)
{
    //pins to segments
    //RB8 = g
    //RB7 = f
    //RB6 = e
    //RB5 = d
    //RC5 = c
    //RC4 = b
    //RC3 = a
    //RA2 = dp
    //DISP1-5 = RB9, RC6-9


    //resetting all displays ground connections
    _RB9 = 0;
	_RC6 = 0;
	_RC7 = 0;
	_RC8 = 0;
	_RC9 = 0;


    switch (displayNo)
    {
    case 1:
        _RB9 = 1;
        break;
    case 2:
        _RC6 = 1;
        break;
    case 3:
        _RC7 = 1;
        break;
    case 4:
        _RC8 = 1;
        break;
    case 5:
        _RC9 = 1;
        break;
    default:
        break;
    }


    //sets the different display leds
    switch (figure)
    {
    case -1: //-sign
    {
        _RB8 = 1;
        _RC3 = _RC4 = _RC5 = _RB5 = _RB6 = _RB7  = 0;
        break;
    } //empty, no leds lit
    case -2:
    {
        _RC3 = _RC4 = _RC5 = _RB5 = _RB6 = _RB7 = _RB8 = 0;
        break;
    }
    case 0:
    {
        _RB8 = 0;
        _RC3 = _RC4 = _RC5 = _RB5 = _RB6 = _RB7  = 1;
        break;
    }
    case 1:
    {
        _RC3 = _RB5 = _RB6 = _RB7 = _RB8 = 0;
        _RC4 = _RC5 = 1;
        break;
    }
    case 2:
    {
        _RC5 =_RB7 = 0;
        _RC3 = _RC4 = _RB5 = _RB6 = _RB8 = 1;
        break;
    }
    case 3:
    {
        _RB6 = _RB7 = 0;
        _RC3 = _RC4 = _RC5 = _RB5  = _RB8 = 1;
        break;
    }
    case 4:
    {
        _RC3 = _RB5 = _RB6 = 0;
        _RC4 = _RC5 = _RB7 = _RB8 = 1;
        break;
    }

    case 5:
    {
        _RC4 = _RB6 = 0;
        _RC3 = _RC5 = _RB5  = _RB7 = _RB8 = 1;
        break;
    }

    case 6:
    {
        _RC4 =  0;
        _RC3 =  _RC5 = _RB5 = _RB6 = _RB7 = _RB8 = 1;
        break;
    }

    case 7:
    {
        _RB5 = _RB6 = _RB7 = _RB8 = 0;
        _RC3 = _RC4 = _RC5 = 1;
        break;
    }
    case 8:
    {
		_RB5 = _RB6 = _RB7 = _RB8 = _RC3 = _RC4 = _RC5 = 1;
        break;
    }
    default:
    {
        break;
    }
    }


    if (dot)
        _RA4 = 1;
    else
        _RA4 = 0;




    return;
}

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 10:02:38
av sodjan
Vad har do gjort för att felsöka ?

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 10:28:02
av Icecap
Om inte jag har missuppfattat något har du verkligen missat något!

Jag har löst det på följande sätt:

Kod: Markera allt

#define NUMBER_DIGITS 5

byte Buffer[NUMBER_DIGITS]; // Avsätt en buffer där varje byte motsvarar ett displaymodul. I detta fall 5 bytes.
* Startat en timer-interrupt på 70Hz * antal tecken, i detta fall alltså 350Hz.

#define DIGIT_0 RB9
#define DIGIT_1 RC6
#define DIGIT_2 RC7
#define DIGIT_3 RC8
#define DIGIT_4 RC9
#define SEG_A   RC3
#define SEG_B   RC4
#define SEG_C   RC5
#define SEG_D   RB5
#define SEG_E   RB6
#define SEG_F   RB7
#define SEG_G   RB8
#define SEG_DP  RA2

// All skrivning till displayen görs vid att lägga rätt data i buffern, utläsningen sker då i timer-interrupten.

Timer_ISR:
static byte Counter, Show;
; Gör allt som behövs för att rensa interrupt-flagga och så, ger lite tid till att döda ghosting
  DIGIT_0 = 0; Nolla alla siffror
  DIGIT_1 = 0; Nolla alla siffror
  DIGIT_2 = 0; Nolla alla siffror
  DIGIT_3 = 0; Nolla alla siffror
  DIGIT_4 = 0; Nolla alla siffror
  Show = Buffer[Counter++];
  if(Counter >= NUMBER_DIGITS) Counter = 0;
  if(Show & 0x01) SEG_A = 1;
  else SEG_A = 0;
  if(Show & 0x02) SEG_B = 1;
  else SEG_B = 0;
  if(Show & 0x04) SEG_C = 1;
  else SEG_C = 0;
  if(Show & 0x08) SEG_D = 1;
  else SEG_D = 0;
  if(Show & 0x10) SEG_E = 1;
  else SEG_E = 0;
  if(Show & 0x20) SEG_F = 1;
  else SEG_F = 0;
  if(Show & 0x40) SEG_G = 1;
  else SEG_G = 0;
  if(Show & 0x80) SEG_DP = 1;
  else SEG_DP = 0;
  switch(Counter)
    { // Remember that it's counted up
    case 0: DIGIT_4 = 1; break;
    case 1: DIGIT_0 = 1; break;
    case 2: DIGIT_1 = 1; break;
    case 3: DIGIT_2 = 1; break;
    case 4: DIGIT_3 = 1; break;
    }
Det är en klumpig rutin då segmenter och siffror är klumpigt monterat, man kan helt säkert rensa ut i det hela men den fungerar ganska säkert.

I buffern är segmenten som följer:
BIT Segment
0 A
1 B
2 C
3 D
4 E
5 F
6 G
7 DP

När timer-interrupten är startat fungerar displayen så att du skriver önskat visning in i buffern och den visas, ingen hokus-pokus.

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 10:50:09
av hadoque
IceCap >> Wow, vilket jobb du lade ner. Tack för hjälpen. Jag är helt ny på det här, så jag måste smälta koden och förstå alltihopa innan jag testar den...

sodjan >> Jag har dubbelkollat att jag har fått rätt segment till rätt port, men eftersom jag kan tända en enskild siffra på korrekt display, så stämmer ju det.
Efter det är det enda jag kommit på att göra långa pauser mellan skiftningarna och det visar ju att nåt skumt händer (fel LEDs tänds, flera displayer tänder samtidigt).
När jag läser Icecaps kod så ser jag ju att det är en mer direkt aproach som säkert funkar bättre. Jag undrar dock ändå om det är något grundläggande fel i min kod, som jag inte har fattat....

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 11:33:45
av sodjan
> ...men eftersom jag kan tända en enskild siffra på korrekt display, så stämmer ju det.

Är det gjort med liknande kod ?
D.v.s med de där "_RC3 = _RC4 = _RC5 = _RB5 = _RB6 = _RB7 = 1;" o.s.v ?

Men annars är det väl bara att fortsätta felsöka !?
Skala ner koden och verifiera allt som du gör så att det
fungerar så som du tror o.s.v.

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 11:59:28
av hadoque
Ja, jag använder den bifogade koden för att visa en siffra korrekt på en av displayerna.
Med bifogade funktionen:

Funkar, visar sjua på andra displayen:

Kod: Markera allt

int main()
{
    init();

    while (1)
    {
   dispFig(7, 2, 0);
    }
    return 0;
}
Funkar inte, visar en spegelvänd sexa utan bottensegment på de två första displayerna:

Kod: Markera allt

int main()
{
    long int j;
    init();

    while (1)
    {
   dispFig(7, 2, 0);
for (j = 0; j < 1000; j++)
{
}
	dispFig(8, 1, 0);
for (j = 0; j < 1000; j++)
{
}

    }
    return 0;
}

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 12:02:45
av hadoque
Ja, jag använder den bifogade koden för att visa en siffra korrekt på en av displayerna.
Med bifogade funktionen:

Funkar, visar sjua på andra displayen:

Kod: Markera allt

int main()
{
    init();

    while (1)
    {
   dispFig(7, 2, 0);
    }
    return 0;
}
Funkar inte, visar en spegelvänd sexa utan bottensegment på de två första displayerna:

Kod: Markera allt

int main()
{
    long int j;
    init();

    while (1)
    {
   dispFig(7, 2, 0);
	for (j = 0; j < 1000; j++)
	{
	}
   dispFig(8, 1, 0);
	for (j = 0; j < 1000; j++)
	{
	}

    }
    return 0;
}

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 12:05:58
av sodjan
Det känns som något timing rellaterat vid byte av siffra.
Sådant som port-uppsättning (analoga funktioner o.s.v) är OK ??

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 13:44:02
av Gustav180
Multiplexing av LED är lite trixigt om det inte skall bli "släp" i segmenten. Man ser lite av föregående siffra i nästa display.
Lösningen är att tänd display först släcks helt, sedan lägger du över ny 7S-data för den som skall tändas. Därefter tänder du aktuell display. Då skall släpeffekten vara borta. Koden för detta kan du säkert fixa själv.

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 15:57:50
av Icecap
Största felet i detta är att TS inte har en timer interrupt till att driva multiplexningen, då är det ganska besvärligt att få till det ordentligt.

Men efter vad jag har sett snabbt i programmet stängs siffran inte av, de slås bara på.

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 21:21:32
av hadoque
Ah, jag kom på vad problemet är.
Mitt försök till förklaring (rätta gärna fel!) är att när jag tänder en LED använder jag ett macro (ex _RB5 = 1) för att ändra en bit i ett register. När jag försöker ändra flera bitar samtidigt "hinns" inte hela macrokön med.
Genom att ge lite tid mellan varje macro hinner varje macro att slutföras. Jag började använda __delay32() istället för loopar och testade att göra så här:

Kod: Markera allt

    case 6:
    {
        _RC4 =  0;
		__delay32(100);
        _RC3 = 1; 
		__delay32(100);
		_RC5 = 1;
		__delay32(100);
		_RB5 = 1;
		__delay32(100);
		_RB6 = 1;
		__delay32(100);
		_RB7 = 1;
		__delay32(100);
		_RB8 = 1;
        break;
    }
och på motsvarande sätt med FETarna (ska göra det snyggare förstås). Och det funkade!

Tack alla för snabba svar och hjälp!

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 21:49:33
av sneaky
Detta kan vara värt att läsa angående ovanstående:
http://www.piclist.com/techref/readmodwrite.htm

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 21:57:30
av sodjan
Hur är _RBx macrona definierade ? Är det mot PORTB ?
Om de var mot LATB så skulle det sannolikt fungera utan fördröjningar.
Googla efter "read-modify-write problem" så ser du varför.
T.ex http://marcansoft.com/uploads/readmodifywrite.pdf

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 22:00:15
av sodjan
> Detta kan vara värt att läsa angående ovanstående:
> http://www.piclist.com/techref/readmodwrite.htm

Två saker...

1. Det ska väl vara "nedanstående". :-)

2. Jag såg den sidan men valde att inte ta den som exempel eftersom
den inte nämnder LATx registren (förrutom i en kommentar till texten).

Re: Multiplexning av LED-display

Postat: 18 januari 2011, 22:13:57
av sodjan
Ett par andra kommentarer...

> När jag försöker ändra flera bitar samtidigt "hinns" inte hela macrokön med.

Nej, det är ett totalt missförstånd av vad som händer.
Det har inte ett smack med macrona som sådana att göra.
Du skulle få samma problem även utan macrona.

> Genom att ge lite tid mellan varje macro hinner varje macro att slutföras.

Nej nej nej. Det är totalt fel uppfattat. Det finns ingen "kö" som ska
hinna "slutföras" !

Att lägga till fördröjningar är igen lösning, det är en "quick fix" som
igentligen inte löser grundproblemet. Använd LATx registren istället
så har du helt undvikit RMW problemet och behöver inga fördröjningar.