Arduino och 4*7 segment display

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
UndCon
Inlägg: 79
Blev medlem: 15 januari 2010, 00:07:10

Arduino och 4*7 segment display

Inlägg av UndCon »

Jag har kopplat in en 7segments display med 4 tecken samt kolon och DP
(från en kabelvision dekoder)

Den har gemensamma kopplingar för segmenten och jag har 5 VCC kopplade på PWM så jag kan dimma dem vid behov.

Det funkar att tex räkna 0-9 mm men jag tänkte försöka programmera så den kan räkna från 9999 och neråt.

Hur kan man gå tillväga för tal som skall visas (9999) och då tända resp segment och visa rätt siffra?

en funktion som tänder rätt segment vid 0-9 har jag redan och den anropar jag så här

Kod: Markera allt

showDigit(9);
så visas 9


Jag funderade på om jag inte skulle använda modulo för att få reda på om talet har 4 siffror

Kod: Markera allt

void displayNumber(int myNumber){

//testa först om talet är 1000 eller högre
if(myNumber % 1000) {
// nu vet vi att talet har fyra siffror, tänd 1a siffran och visa rätt nummer
}

//sedan vidare till hundratal
if(myNumber % 100) {
// nu vet vi att talet har tre siffror, tänd 2a siffran och visa rätt nummer
}

//sedan vidare till tiotal
if(myNumber % 10) {
// nu vet vi att talet har 2 siffror, tänd 2a siffran och visa rätt nummer
}

//sedan vidare till ental

// nu vet vi att talet bara har 1 siffra, tänd 1a siffran och visa rätt nummer
showDigit(9);
}



eller skall man testa talet så här

Kod: Markera allt


if(myNumber > 999){
//talet är större än 999 - då skall vi tända 1a siffran
digitalWrite(gnd_4, 1); //sätter GND HIGH (tänder displayen)
int myCalculatedNumber = myNumber-999;
showdigit(myCalculatedNumber)
}
OSV - med de andra 3....


Tacksam för svar...


pst - jag vet att man kan / borde använda shift register - men jag tror det går/borde gå att lösa så här med...


/N
Senast redigerad av UndCon 23 januari 2011, 15:10:24, redigerad totalt 1 gång.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Arduino och 4*7 segment display

Inlägg av jesse »

Det verkar som om vi ska dela upp problemet i två avdelningar här:

1) hur man omvandlar ett heltal till BCD.siffror
2) hur man kommunicerar med displayen

så att vi inte blandar ihop dessa.
Vilket av dem har du problem med , eller är det båda?
en funktion som tänder rätt segment vid 0-9 har jag redan och den anropar jag så här
showDigit(9); så visas 9
Var visas nian? I vilken av de fyra platserna? Vilket av segmenten är "rätt" segment, och hur anger du det? Du måste ju kunna välja var nånstans du ska visa siffran?
Kan du visa mer än en siffra på displayen samtidigt? Hur gör du då?

Angående punkt (1) ovan så finns det färdiga lösningar. Antingen skriver man ut siffrorna direkt som de "produceras" vid omvandlingen, eller så lägger man den som en sträng i RAM-minnet för att sedan skicka ut siffrorna.

Så här ser mitt program ut för att omvandla ett heltal (32 bitar) till ascii med decimalpunkt:

Kod: Markera allt

char uint_to_string(uint32_t value, uint8_t punkt) {
	char p = UASTR;
	punkt = UASTR-1-punkt;
	siffror[(uint16_t)--p] = '\0';
	do {
		char ch = value % 10 + '0';
		//  if (ch > '9') ch += 'a' - '9' - 1;
		siffror[(uint16_t)--p] = ch;
		value /= 10;
		if (p == punkt) siffror[(uint16_t)--p] = POINT;
	} while (value || p > punkt-2 );
	for (uint8_t i = 0; i<p; i++) siffror[i] = ' ';
	return p;
}
Resultatet hamnar i strängen siffror[].

Nu behöver ju du inte omvandla till ascii utan det räcker med BCD, och du vill ju inte ha decimalpunkt bland siffororna då den tänds separat?
UndCon
Inlägg: 79
Blev medlem: 15 januari 2010, 00:07:10

Re: Arduino och 4*7 segment display

Inlägg av UndCon »

Tack för hjälpen!

I dagsläget visar jag bara 0-9 på siffra ett(från höger) för det är bara den jag aktiverar

Kod: Markera allt

digitalWrite(gnd_4, 1); //GND till siffra 4
jag byggde om den lite så att jag även kan skicka med vilken siffra som skall vara tänd

Kod: Markera allt

void showDigit(int show_digit, int show_number){//ta emot 1-4 resp 0-9
Då måste jag innan anropet bryta ner talet i delar med if-satsen ovan för att få reda på vilken siffra som skall vara aktiverad och vad den skall visa
Senast redigerad av UndCon 23 januari 2011, 15:11:18, redigerad totalt 1 gång.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Arduino och 4*7 segment display

Inlägg av jesse »

OK, men kan du visa flera siffror samtidigt alltså?

så om du skriver:

Kod: Markera allt

showDigit(1,4)
showDigit(2,8)
showDigit(3,5)
Så står det 485 på displayen sedan? (eller hur är positionerna numrerade?)
UndCon
Inlägg: 79
Blev medlem: 15 januari 2010, 00:07:10

Re: Arduino och 4*7 segment display

Inlägg av UndCon »

hej igen!

exakt så fungerar det nu

Kod: Markera allt

showDigit(1,[b]0[/b]);
  myDelay();
  showDigit(2,[b]4[/b]);
  myDelay();
  showDigit(3,[b]8[/b]);
  myDelay();
  showDigit(4,[b]5[/b]);
  myDelay();

detta scannas nu i loopen med endast 10ms(myDelay) mellan varje nuffra - det ger ett flimmerfritt intryck iaf

om jag kapslar in detta i en while-loop

Kod: Markera allt

int counter=9999;
while(counter >= 0){

  showDigit(2,[b]4[/b]);
  myDelay();
  showDigit(3,[b]8[/b]);
  myDelay();
  showDigit(4,[b]5[/b]);
  myDelay();
  counter--
}
så loopas det från 9999 och neråt - nu måste jag ta counter och bryta ner den i delar - sedan visa det talet på resp display

ungefär så här?

//translates a number into correct digit and number to show

// tar emot counter som myNumber

Kod: Markera allt


void translate(int myNumber)
{
  //här kollar vi 1000
  if(myNumber >999)
  {
    showDigit(1, myNumber/1000);
  }
  myNumber-999;
  
  //här kollar vi 100talet
  if(myNumber >99)
  {
    showDigit(2, myNumber/100);
  }
  myNumber-99;

  //här kollar vi tiotalet
  if(myNumber >9)
  {
    showDigit(3, myNumber/10);
  }
  //återstår endast ental
  myNumber-9;
  showDigit(4, myNumber);
}
Senast redigerad av UndCon 23 januari 2011, 15:08:54, redigerad totalt 1 gång.
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Arduino och 4*7 segment display

Inlägg av jesse »

Använd Code-taggen när du skriver kod i forumet!

Kod: Markera allt

//translates a number into correct digit and number to show

// tar emot counter som myNumber
void translate(int myNumber)
{
      showDigit(1, myNumber/1000);
      myNumber%=1000; // resten
      showDigit(2, myNumber/100);
      myNumber%=100;
      showDigit(3, myNumber/10);
      //återstår endast ental
      myNumber%=10;
      showDigit(4, myNumber);
      }
Denna kod ger inledande nollor. Då behöver du inte if-satserna.

(Vill du ha inledande blanktecken istället för nollor måste du definiera en kod för "blank" som du skickar såvida inte displayvisningsrutinen själv tar bort nollor i början. 0-9 motsvarar ju var sin siffra, men du kan ju ta ett annat tal, t.ex 10.

Ska du visa 0035 i displayen måste du ju skicka 0,0,3,5, men ska du visa bara 35 så måste du ha två blanka innan, t.ex. 10,10,3,5)
UndCon
Inlägg: 79
Blev medlem: 15 januari 2010, 00:07:10

Re: Arduino och 4*7 segment display

Inlägg av UndCon »

Hej!

Nu har du fått kodtaggar till förbannelse ;)

Inledande 0 behövs inte - den koden jag körde tidigare funkade inte så bra...

Jag skall testa din kod och se vad som händer.

EDIT:

Det ger inte heller rätt resultat
nu loopar jag från 0 = och uppåt (då ser man snabbt skillnad från 1 till 2 siffror)

0-9 räknas bra - men när 10 skall visas ser man inte 1:an
(i seriekonsollen ser jag aktuellt värde i loopen(counter)
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Arduino och 4*7 segment display

Inlägg av jesse »

>Inledande 0 behövs inte

Nej, men vad händer om du inte skickar ut ett värde istället för en nolla? Behåller inte displayen den "gamla" siffran då? Så m det står 7312 på displayen och du skriver dit 45 på de två sista positionerna, blir det inte då "7345" ??? Alltså måste du skriva ut "mellanslag"/"inget" på de positionerna? Fast det beror ju helt på hur din rutin för utskrift fungerar.

Det är alltså enklare att alltid skriva fyra siffror (t.e.x 0045) än att maska bort ett visst antal nollor för att få 45.

Det är egentligen bara du som vet hur din funktion showdigit() fungerar i olika situationer.
UndCon
Inlägg: 79
Blev medlem: 15 januari 2010, 00:07:10

Re: Arduino och 4*7 segment display

Inlägg av UndCon »

Självklart - jag har inte postat den koden..

Kod: Markera allt

void showDigit(int show_digit, int show_number){

  if(show_digit == 1){
    // enable gnd
    digitalWrite(gnd_1, 1);
    digitalWrite(gnd_2, 0);
    digitalWrite(gnd_3, 0);
    digitalWrite(gnd_4, 0);
    //call show_number
    showSegments(show_number);
  }
  if(show_digit == 2){
    // enable gnd
    digitalWrite(gnd_1, 0);
    digitalWrite(gnd_2, 1);
    digitalWrite(gnd_3, 0);
    digitalWrite(gnd_4, 0);
    //call show_number
    showSegments(show_number);
  }
    if(show_digit == 3){
    // enable gnd
    digitalWrite(gnd_1, 0);
    digitalWrite(gnd_2, 0);
    digitalWrite(gnd_3, 1);
    digitalWrite(gnd_4, 0);
    //call show_number
    showSegments(show_number);
  }
    if(show_digit == 4){
    // enable gnd
    digitalWrite(gnd_1, 0);
    digitalWrite(gnd_2, 0);
    digitalWrite(gnd_3, 0);
    digitalWrite(gnd_4, 1);
    //call show_number
    showSegments(show_number);
  }
   if(show_digit == 5){
    // enable gnd
    
    digitalWrite(gnd_1, 0);
    digitalWrite(gnd_2, 0);
    digitalWrite(gnd_3, 0);
    digitalWrite(gnd_4, 0);
    digitalWrite(gnd_DP, 1);
    //call show_number
    //showSegments(show_number);
  }
}
den funkar om jag anropar den så här från ex main loop

Kod: Markera allt

    showDigit(1,0);
    myDelay();
    showDigit(2,4);
    myDelay();
    showDigit(3,8);
    myDelay();
    showDigit(4,5);
    myDelay();

Kod: Markera allt

void showSegments(int show_number){
//void showSegments(int show_digit, int show_number){//ta emot 1-4 resp 0-9
  switch (show_number) {
    case 1:
      //Segment=0 + gnd=1 == display segment LIT UP
      digitalWrite(segment_A, 1);
      digitalWrite(segment_B, 0);
      digitalWrite(segment_C, 0);
      digitalWrite(segment_D, 1);
      digitalWrite(segment_E, 1);
      digitalWrite(segment_F, 1);
      digitalWrite(segment_G, 1);
      digitalWrite(colon_DP, 0);
      
      digitalWrite(gnd_DP, 0);

      break;
OSV...

är det lättast att inleda med 0 så gör vi så...
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Arduino och 4*7 segment display

Inlägg av jesse »

0-9 räknas bra - men när 10 skall visas ser man inte 1:an
(i seriekonsollen ser jag aktuellt värde i loopen(counter)
Men det beror väl på att du skriver ut nollan omedelbart efter att du skrivit ut ettan, och då syns ettan i ungefär en tiotusendels sekund , sedan syns nollan.... Du kan alltså inte visa mer än en siffra åt gången med den rutin du har nu.

Kod: Markera allt

   digitalWrite(gnd_1, 0);
Du sätter en bit åt gången, men är inte alla GND-utgångarna på samma port? I så fall kan du ju sätta alla samtidigt?
Nu kör du ju Arduino, och inte "vanlig" AVR, och jag har ingen koll på dess specialfunktioner etc. men att skriva ut alla bitar på en port samtidigt borde väl fungera , typ PORTB = 0b00010000; ?

samma sak med segmenten:

Kod: Markera allt

  digitalWrite(segment_A, 1);
      digitalWrite(segment_B, 0);
      digitalWrite(segment_C, 0);
      digitalWrite(segment_D, 1);
      digitalWrite(segment_E, 1);
      digitalWrite(segment_F, 1);
      digitalWrite(segment_G, 1);
      digitalWrite(colon_DP, 0);
borde kunna ersättas med typ

Kod: Markera allt

SEGMENTPORT = 0b00011110;
Om du vill kunna visa alla siffror "samtidigt" måste du loopa igenom alla fyra positionerna många gånger, och tända dem en och en så snabbt att man inte hinner uppfatta bytet med ögonen.

Fast om du gör det bör du byta ordningen lite på hur du skickar ut data:

visa en siffra:
1) släck alla GND
2) tänd rätt segment
3) tänd rätt GND-bit (nu syns siffran)
4) gör paus en millisekund

visa ett helt tal:
1) visa siffra 1
2) visa siffra 2
3) visa siffra 3
4) visa siffra 4
5) loopa punkt 1-4 100 gånger. (visar talet ca 0.1 sekund) eller 1000 gånger (visar talet 1 sekund)

Nu inser du att du måste ha alla fyra siffrorna sparade någonstans för att snabbt få fram dem hundra eller tusen gånger. Så gör en array med 8-bitars heltal : uint8_t siffra[5]; så kan du använda dem smidigt (Det är en sådan array jag har i mitt kodexempel ovan).

När det funkar och du kan visa riktiga fyrsiffriga tal på displayen så tycker jag du ska börja lära dig interrupt och timers/counters i AVR. Då ordnar du en timer som ger interrupt t.ex. 1000 gånger per sekund. I denna interruptrutin visar du en ny siffra på displayen. För varje gång interruptrutinen anropas visas nästa siffra.... om och om igen i evighet. På så vis fastnar inte main() i en lång loop när ett tal visas på displayen utan är ledigt till annat (kolla knappar t.ex.)

I main() behöver du sedan bara uppdatera de fyra siffrorna i arrayen , så ändras talet på displayen.
UndCon
Inlägg: 79
Blev medlem: 15 januari 2010, 00:07:10

Re: Arduino och 4*7 segment display

Inlägg av UndCon »

Jag kan aktivera fler displayer samtidigt
digitalWrite(gnd_1, 1);
digitalWrite(gnd_2, 1);
digitalWrite(gnd_3, 1);
digitalWrite(gnd_4, 1);

Då skrivs samma siffra på alla 4...då måste jag loopa dessa 4 så snabbt att ögat inte uppfattar det

som det är nu ligger siffrorna sparade i showSegments med en switch som avgör vilken som skall visas

en 2dimensionell array är kanske bättre...

Kod: Markera allt

byte seven_seg_digits[10][7] = {
    { 1,1,1,1,1,1,0 },  // = 0
    { 0,1,1,0,0,0,0 },  // = 1
    { 1,1,0,1,1,0,1 },  // = 2
    { 1,1,1,1,0,0,1 },  // = 3
    { 0,1,1,0,0,1,1 },  // = 4
    { 1,0,1,1,0,1,1 },  // = 5
    { 1,0,1,1,1,1,1 },  // = 6
    { 1,1,1,0,0,0,0 },  // = 7
    { 1,1,1,1,1,1,1 },  // = 8
    { 1,1,1,0,0,1,1 }   // = 9
};

void sevenSegWrite(byte digit) {
  byte pin = 2;
  for (byte segCount = 0; segCount < 7; ++segCount) {
    digitalWrite(pin, seven_seg_digits[digit][segCount]);
    ++pin;
  }
}

void loop() {
  for (byte count = 10; count > 0; --count) {
   delay(1000);
   sevenSegWrite(count - 1);
  }
  delay(4000);
}


men det får jag inte riktigt att lira heller...
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Arduino och 4*7 segment display

Inlägg av jesse »

Jag kan aktivera fler displayer samtidigt
digitalWrite(gnd_1, 1);
digitalWrite(gnd_2, 1);
digitalWrite(gnd_3, 1);
digitalWrite(gnd_4, 1);
Jo, det förstår jag , men det är ju inte så användbart, såvida du inte bara vill skriva ut talen 777,2222,88,111,9999,0000,44 osv...
Jag vet inte om det fungerar bättre om du lägger alla siffror i en array, men visst ser det snyggare ut. T
anken jag hade var att du använder alla bitar i ett 8-bitars heltal istället för åtta heltal med en bit i varje:

Kod: Markera allt

byte seven_seg_digits[10] = {
    0b1111110,  // = 0
    0b0110000,   // = 1
    0b1101101,   // = 2
    0b1111001,   // = 3
    0b0110011,   // = 4
    0b1011011,   // = 5
    0b1011111,   // = 6
    0b1110000,  // = 7
    0b1111111,  // = 8
    0b1110011   // = 9
};
Men det beror ju på hur displayen är ansluten till porten... Jag antar att det är alla 7 bitarna parallellt på samma port?
men det får jag inte riktigt att lira heller...
och det betyder ???
UndCon
Inlägg: 79
Blev medlem: 15 januari 2010, 00:07:10

Re: Arduino och 4*7 segment display

Inlägg av UndCon »

Om jag aktiverar segment A och GND 1-4 så lyser A på alla 4 samtidigt

När något inte "lirar" så funkar det inte
Användarvisningsbild
jesse
Inlägg: 9240
Blev medlem: 10 september 2007, 12:03:55
Ort: Alingsås

Re: Arduino och 4*7 segment display

Inlägg av jesse »

Jo, det fattade jag, men vad är det som inte fungerar? Var har du stött på problem?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Arduino och 4*7 segment display

Inlägg av sodjan »

> Om jag aktiverar segment A och GND 1-4 så lyser A på alla 4 samtidigt

Ja, det är ju ganska självklart att det blir då, eller hur ?
Men det är det ingen som har föreslagit.

Du får nog ta och luta dig tillbaka lite och fundera. Du har nog inte
alls förstått vad det är som Jesse försöka förklara för dig. Du behöver
en *helt ny* arkitektur i applikationen. Visningen på displayerna ska vara
en egen självgående del (interrupt/timer styrd) som bara kontinuerligt
visar siffror från en buffert där resten av applikationen skriver det
som ska visas. Du kan inte blanda kod som tar fram det som ska visas
med den kod som sedan faktiskt visar siffrorna, då blir det den soppa
som du nu försöker få ordning på (det går, i princip, inte).

Jag tror inte heller att Jesse riktigt fattade att du inte fattade... :-)
Skriv svar