Forum: Mikrocontroller und Digitale Elektronik AVR Atmega 8 - 7 Segment Multiplex mal anders?


von Alexander K. (sascha712)


Lesenswert?

Hallo,

ich steh vor nem kleinem Problem:
Ich möchte gerne meine 7 Segmentanzeige, welche aus drei 7 
Segmentanzeigen besteht betreiben.
Diese betreibe ich ohne Transistoren, direkt über den Mikrocontroller 
ohne widerstände etc.
Aber irgendwie bleibt er immer bei der ersten 7 Segmentanzeige.

Kann jemand so nett sein und kurz über den Code schauen?
1
#include <avr/io.h>
2
#include <util/delay.h>
3
4
int main(void)
5
{
6
  DDRD = 255;  //PORT D auf Ausgang
7
  PORTD = 0;  //0V
8
  DDRB = 255;  //PORT B auf Ausgang
9
  PORTB = 0;      //0v
10
  
11
12
  
13
  
14
  uint8_t Block=1;  //Block = Ziffern nr
15
  
16
  
17
  while(1)
18
  {
19
    
20
    
21
    
22
    if(Block == 1)
23
    {
24
      PORTB = 0b00000001;
25
    }
26
    if(Block == 2)
27
    {
28
      PORTB = 0b00000010;
29
    }
30
    if(Block == 3)
31
    {
32
      PORTB = 0b00000100;
33
    }
34
    
35
    _delay_ms(1);
36
    Block ++;
37
    if(Block == 4)
38
    {
39
      Block = 1;
40
    }
41
    
42
    PORTD = 0;
43
  }
44
}

Wo liegt der Fehler, dass er immer bei der ersten Anzeige bleibt? Meine 
zweite und dritte Segmentanzeige werden gar nicht erst geschaltet. Ich 
hab aber die anzeigen an sich überprüft. Bis auf die gemeinsame Anode, 
welche über PORT B angesprochen wird, sind die LEDs der Anzeigen 
Parallel geschaltet.

MfG Alex

von Fabian (Gast)


Lesenswert?

Zwischen Block und dem ++ darf kein Leerzeichen stehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Fabian schrieb:
> Zwischen Block und dem ++ darf kein Leerzeichen stehen.

Soso ... da kennt sich ja einer ganz besonders gut aus mit C.

Alexander, kann man nicht sagen, wo das Problem liegt.  Der Code
ist nicht sonderlich schön, müsste aber funktionieren.

Insbesondere müsstest du (nachdem das da erstmal funktioniert)
natürlich schnellstens zusehen, wie du das in die Interruptroutine
eines Timers bekommst, damit du die Hauptschleife frei bekommst für
die eigentliche Arbeit.

Was ich nur nicht verstehe ist, warum du im Titel "mal anders"
schreibst.  Das ist doch ganz normales Multiplexen.

von Alexander K. (sascha712)


Lesenswert?

Normalerweise wird Multiplexen ja über den Timer gemacht. Aber ich 
wechsel eifnach den Block nach jeder abgeschlossenen reoutine. Würde 
sich hier vllt jemand bereit erklären mir vllt per icq oder so nen wenig 
unter die arme zu greifen? dann müsste ich nicht immer nen Thread 
aufmachen :D.

von Fabian (Gast)


Lesenswert?

Sorry, da habe ich aus Gewohnheit falsch gedacht...

Dann liegt es wohl daran: "ohne widerstände etc"
Das führt zu einem Überstrom und der Controller startet die ganze zeit 
neu.

von Alexander K. (sascha712)


Lesenswert?

Also ich hab das leerzeichen rgad weggemacht und es geht.
Kanns wirklich daran gelegn habn?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Fabian schrieb:
> Dann liegt es wohl daran: "ohne widerstände etc"

Wenn man mal von Vcc = 5 V und Vf[LED] = 2,2 V ausgeht, müsste der AVR
einen Spannungsabfall von 2,8 V aufbringen.  Die Ausgangsstufen eines
ATmega8 sind laut typischen Werten relativ symmetrisch, d. h.  jeder
der beiden aktiven Transistoren muss je 1,4 bringen, wenn man 1
Segment ansteuert.  Das läuft auf einen Strom von etwa 50 mA hinaus.
Für ein 1:3-Multiplexing ist das im Prizip noch OK, allerdings
überschreitet man die maximalen 40 mA Strombelastbarkeit pro IO-Pin.

Allerdings werden im vorliegenden Fall ja jeweils alle Segmente
angesteuert, damit verschiebt sich das ein wenig: die 8 low-side-
Transistoren sind alle parallel, auf der high-Seite arbeitet
dagegen nur einer.  Der high-side-Transistor sättigt bei ca. 70 mA
(wenn er warm wird, noch etwas eher), die sich dann in je ca. 9 mA
pro Segment aufteilen.

Damit ist natürlich klar, dass die ganze Schaltung ziemlicher Murks
ist, denn je nach der Anzahl der eingeschalteten Segmente leuchten
sie unterschiedlich hell.  Aber dass es Murks ist, wussten man ja
eigentlich schon vorher. ;-)  Außerdem bringt es nicht viel, die
Leistung innerhalb des AVRs zu verheizen statt extern, verheizt
werden muss sie sowieso.

Funktionieren sollte sie aber trotzdem, natürlich sofern das Netzteil
wenigstens die knapp 100 mA liefern kann.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Alexander K. schrieb:
> Kanns wirklich daran gelegn habn?

Nein.  Du kannst da 5 Leerseiten einfügen, es muss trotzdem noch
funktionieren.

Vermutlich hast du vorher einfach nicht den letzten Stand in den
Flash geladen.

von Fabian (Gast)


Lesenswert?

Jörg Wunsch schrieb:
> Fabian schrieb:
>> Zwischen Block und dem ++ darf kein Leerzeichen stehen.
>
> Soso ... da kennt sich ja einer ganz besonders gut aus mit C.

Alexander K. schrieb:
> Also ich hab das leerzeichen rgad weggemacht und es geht.

Das wird uns jetzt Jörg Wunsch mal bitte erklären....

von Fabian (Gast)


Lesenswert?

Füge das Leerzeichen doch noch einmal wieder ein, und prüfe es. 
Ansonsten würde ich Jörg da zustimmen, dass Du wohl nicht vor dem 
flashen compiliert hast etc....

von Fabian (Gast)


Lesenswert?

(Aber ich muss weiterhin gestehen, dass Jörg wohl Recht hat. Es ist zwar 
untypisch dort ein Leerzeichen einzufügen. Aber letztendlich dürfte es 
kein Unterschied machen, da es ja auch nur ein Operator ist...)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Fabian schrieb:
> Das wird uns jetzt Jörg Wunsch mal bitte erklären....

Bitte:
1
$ cat foo.c
2
#include <stdint.h>
3
4
uint8_t x;
5
6
void with_space(void)
7
{
8
  x ++;
9
}
10
11
void without_space(void)
12
{
13
  x++;
14
}
15
$ avr-gcc -Os -mmcu=atmega128 -S foo.c
16
$ cat foo.s
17
        .file   "foo.c"
18
__SREG__ = 0x3f
19
__SP_H__ = 0x3e
20
__SP_L__ = 0x3d
21
__CCP__ = 0x34
22
__tmp_reg__ = 0
23
__zero_reg__ = 1
24
        .text
25
.global with_space
26
        .type   with_space, @function
27
with_space:
28
/* prologue: function */
29
/* frame size = 0 */
30
/* stack size = 0 */
31
.L__stack_usage = 0
32
        lds r24,x
33
        subi r24,lo8(-(1))
34
        sts x,r24
35
/* epilogue start */
36
        ret
37
        .size   with_space, .-with_space
38
.global without_space
39
        .type   without_space, @function
40
without_space:
41
/* prologue: function */
42
/* frame size = 0 */
43
/* stack size = 0 */
44
.L__stack_usage = 0
45
        lds r24,x
46
        subi r24,lo8(-(1))
47
        sts x,r24
48
/* epilogue start */
49
        ret
50
        .size   without_space, .-without_space
51
        .comm x,1,1
52
.global __do_clear_bss

Wo siehst du einen Unterschied zwischen beiden Funktionen?

von Fabian (Gast)


Lesenswert?

Bin ja schon still...... ;-)

von Peter D. (peda)


Lesenswert?

Alexander K. schrieb:
> Ich möchte gerne meine 7 Segmentanzeige, welche aus drei 7
> Segmentanzeigen besteht betreiben.
> Diese betreibe ich ohne Transistoren, direkt über den Mikrocontroller
> ohne widerstände etc.

Dann brauchst Du Dich über komische Effekte auch nicht zu wundern.
Die 3 Transistoren und 8 Widerstände kosten <1€ und bewirken 
Zuverlässigkeit.

Aber vielleicht macht es Dir ja gerade Spaß, wenn es mal funktioniert 
und mal nicht.
Den ADC kannst Du auf jeden Fall vergessen, dessen GND hüpft wild umher.


Peter

von Alexander K. (sascha712)


Lesenswert?

Aber selbst, wenn ich die Anode über transistoren laufen lasse und ich 
widerstände benutze, dann wird der Strom doch trotzdem durch den 
Microcontroller geleitet?
Oder sollte ich jeweils Transistoren für kathode und anode benutzen?

von Karl H. (kbuchegg)


Lesenswert?

Die 8 Portpins, die die Segmente treiben (PORTD), schaffen das noch so 
lala.
Aber der eine Pin, über den der komplette Strom kommen muss (PORTB), der 
schafft es auf keinen Fall. Der bricht zusammen.

von Alexander K. (sascha712)


Lesenswert?

Hmm, nungut, ich hab noch Transistoren rumliegen, dann werd ich die mal 
zwischenhängen.
Das gamze war eig für ne Ladedruck anzeige in einem TurboDiesel gedacht.
Dachte ich hol mir das Signal vom Saugrohrdrucksensor und werte es per 
ADC aus.

Da stehe ich aber leider auch wieder vor dem Problem, das ich bei 
normalem Atmosphärischem druck ca. 4,8 volt (bei 5 volt eingangsspannung 
des Sensors), aber beim unterdruck, sprich der druck, welchen der 
Turbolader aufbaut, deutlich weniger spannung aus dem sensor kriege. wie 
kann ich das signal "invertieren"?

Tut mir leid, das ich so dämliche fragen stelle.. :-/
Der Saugrohrdrucksensor hat 4 anschlüsse. 5volt eingang, Ground, 
Ausgang(welcher dann den Druck anzeigt) und NTC... Was mache ich mit dem 
NTC? muss ich das mit einbeziehen?

Bei der ganzen Geschichte handelt es sich um einen 1,9 TDI (MKB ATD) mit 
101 PS in einem Skoda Fabia.

Ich weis, das es eig unsinnig ist da ne Ladedruckanzeige zu haben. Aber 
es ging mir halt erstmal ums machbare^^

von Karl H. (kbuchegg)


Lesenswert?

Alexander K. schrieb:

> des Sensors), aber beim unterdruck, sprich der druck, welchen der
> Turbolader aufbaut, deutlich weniger spannung aus dem sensor kriege. wie
> kann ich das signal "invertieren"?

Wozu willst du das elektrisch invertieren.
Du hast ein Programm auf dem µC laufen. Der µC kann rechnen!
Nichts einfacher als dort den Zahlenwert von 1024 abziehen und er ist 
invertiert.
Man baut nix in Hardware, was man auch trivial in Software machen kann.

von Alexander K. (sascha712)


Lesenswert?

Ich wollte das per Software machen ;)

Mir fehlt bloß manchmal so dieser Denkanstoss.
.....aber es ist ja wirklich total einfach ....


Danke für eure hilfe. :)

....und tut mir leid, das ich euch hier mit solchen "pille palle" zeug 
nerve ^^

von ... (Gast)


Lesenswert?

Alexander K. schrieb:
> Hmm, nungut, ich hab noch Transistoren rumliegen, dann werd ich die mal
> zwischenhängen.

Aber bittte außer den Basisvorwiderständen auch die Widerstände für die 
LEDs - einen pro Segment - einbauen.

von Peter D. (peda)


Lesenswert?

... schrieb:
> Aber bittte außer den Basisvorwiderständen

Mit npn für die gemeinsamen Anoden brauchts keine Basiswiderstände. Und 
man hat keinen Millereffekt (Geisterdigits).


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Alexander K. schrieb:
> Mir fehlt bloß manchmal so dieser Denkanstoss.

Stichwort: Geradengleichung (sofern der Sensor mit seiner Spannung
linear ist).  Du kalibrierst dir zwei Punkte, durch die du eine
Gerade legst.  Diese ist gekennzeichnet durch Offset (Verschiebung
zur Nulllinie) und Anstieg.  In deinem Falle ist der Anstieg halt
negativ.

von Alexander K. (sascha712)


Lesenswert?

Ja, genau. Doch was ist, wenn der Sensor sich nicht linear verhält?

Ich werde natürlich meinen Laptop mit OBD Kabel und VAG Com verwenden 
und mir den Ladedruck in den Messwertblöcken anzuschauen und dies 
dementsprechend anzugleichen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Alexander K. schrieb:
> Doch was ist, wenn der Sensor sich nicht linear verhält?

Dann kommen Elemente höherer Ordnung dazu: quadratische Annäherung,
kubische, Polnyom n-ten Grades.  Ermittlung der Polynomkoeffizienten
mit der Methode der kleinsten (Fehler-)Quadrate, oder exakt für
N Stützstellen als Polynom (N-1). Grads (wimre ist das Verfahren
dafür von Newton).  Polynomberechnung mit dem Horner-Schema.

Sollten genug Begriffe für Google sein. ;-)

von Alexander K. (sascha712)


Lesenswert?

Okay, danke schön :) ich werd mich dran versuchen^^

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.