Hallo
Ich möchte mit einem kleinen Attiny 2 x 7 Segment Anzeige ansteuern.
Dazu möchte ich das Array nutzen:
1
charcharArray[]=
2
{// ABCDEFG Segments
3
0b1111110,// 0
4
0b0110000,// 1
5
0b1101101,// 2
6
0b1111001,// 3
7
0b0110011,// 4
8
0b1011011,// 5
9
0b1011111,// 6
10
0b1110000,// 7
11
0b1111111,// 8
12
0b1111011,// 9
13
0b1110111,// 10 "A"
14
0b0011111,// 11 "B"
15
0b1001110,// 12 "C"
16
0b0111101,// 13 "D"
17
0b1001111,// 14 "E"
18
0b1000111,// 15 "F"
19
0b0000000,// 16 Space
20
0b0000001// 17 '-'
21
};
Bei dieser Tabelle liegen alle Ausgänge auf Port A. Ansteuerung damit:
1
PORTA&=~(1<<PINA0);// Schaltet Pin PA0 Segment d AZ1 ein
2
_delay_ms(500);// Pause 500 ms
3
PORTA|=(1<<PINA0);// Schaltet Pin PA0 Segment d AZ1 aus
4
_delay_ms(500);// Pause 500 ms
5
6
PORTB&=~(1<<PINB2);// Schaltet Pin PB2 Segment e AZ1 ein
7
_delay_ms(500);// Pause 500 ms
8
PORTB|=(1<<PINB2);// Schaltet Pin PB2 Segment e AZ1 aus
9
_delay_ms(500);// Pause 500 ms
Wenn ich PIN.. ersetze durch
1
PORTA&=~(0b00001000);// Schaltet Pin PA3 Segment a AZ1 ein
2
_delay_ms(500);// Pause 500 ms
3
//PORTA |= (1<<PINA3); // Schaltet Pin PA3 Segment a AZ1 aus
4
5
PORTA|=(0b00001000);// Schaltet Pin PA3 Segment a AZ1 aus
6
_delay_ms(500);// Pause 500 ms
kann ich ja nur die Werte aus der oberen Tabelle nehmen. Da aber die
Anzeige auf Port A und Port B angeschlossen ist, funktioniert das nicht.
Wie kann ich das machen?
LG Henry
Deine Beispiele machen teilweise nicht richtig Sinn. Du verwendest dein
charArray nirgends in deinem Code!?
Mit der Glaskugelbrille sage ich, Teile deine Liste in 2 Listen (einmal
für PORTA und einmal für PORTB) auf.
In jedem Array dürfen dann nur die Beteiligten Pins jeweils getrennt
nach PORTX stehen.
Dann sind es in Zukunft halt 4 Zugriffe.
Irgendwie so in der Art:
Henry schrieb:> Da aber die Anzeige auf Port A und Port B angeschlossen ist,> funktioniert das nicht.> Wie kann ich das machen?> LG Henry
Dein CharArray muss eben 2 Bytes enthalten (z.B. als unsigned int oder
als struct { unsigned char A,B; } eines für die zu setzenden Ausgänge
auf PortA und eines für die Ausgänge auf Port }B, und der Code donnert
die entweder inklusive der unbenutzten Bits raus, oder maskiert die
benutzten z.B. benutzt bit 0 bis bit 5:
portA = (pinA&0xE0)|CharArray[value].A;
Henry schrieb:> Wie kann ich das machen?
Das wäre etwas, das du dir selber bereits ausgedacht haben solltest,
bevor du dein Projekt hier vorstellst.
Wer von den Lesern deines Beitrages hat denn ein genau gleiches Projekt
wie du selbst, einschließlich einer genau gleichen Schaltung,
Leiterplatte usw.?
W.S.
N. M. schrieb:> Deine Beispiele machen teilweise nicht richtig Sinn. Du verwendest dein> charArray nirgends in deinem Code!?
Ja das stimmt. Verwende das Array nicht.
Habe die Ports so aufgeteilt:
// PA5 - Anode 1
// PA7 - Anode 2
// PA3 - Segment a
// PA2 - Segment b
// PA1 - Segment c
// PA0 - Segment d
// PB2 - Segment e
// PB1 - Segment f
// PB0 - Segment g
Bin gerade dabei den Aufruf der Ports zu machen. Dabei bin ich auf das
Problem gekommen. Habe vorher nur einzelne Segmente zum testen
angesteuert. Wollte als nächstes die Zeichen ansteuern und dann den
Timer dazu.
W.S. schrieb:> Wer von den Lesern deines Beitrages hat denn ein genau gleiches Projekt> wie du selbst, einschließlich einer genau gleichen Schaltung,> Leiterplatte usw.?
Wahrscheinlich keiner, ist klar. Warum kann man bei einem Problem nicht
fragen? Meine Kenntnissevon C sind nicht überdurchschnittlich. Es reicht
halt um eine LED blinken zu lassen. Bitte keine Aussage wie "lies dein C
Buch". Habe dort nachgeschlagen, leider ohne Lösung.
Hänge deine Anzeige an je Ziffer einen PCF-8574.
Dann schick den die Bit-Folge aus deinen Array und das war's. Geht sogar
ohne Array wenn du eine Sub benutzt.
Sub (Text as string, Stelle as integer)
x = bit_array
if Text = "1" then x = 0b1111110
.
.
.
if stelle = 1 then setze_Pcf8574 (027, x)
end sub
' Das ist ein code-Struktur-Aufbau nix zum Abtippen.
Ansonsten gebe ich yesitsme Recht.
yesitsme schrieb:> Ein Schaltplan wäre jetzt schön...
Henry schrieb:> Warum kann man bei einem Problem nicht> fragen?
Fragen ist das beste was du machen kannst. ABER du musst auch soviel
Kontext geben, so das man das Problem verstehen kann.
Mir fallen jetzt mehere Möglichkeiten ein, wie man das jetzt lösen kann.
z.B.: Du speicherst Port und Pin in einem Array und loopst beim Update
der Anzeige da drüber. Ungefähr so:
Habe die Stromaufnahme gemessen.
Der Prozessor nimmt ohne Anzeige ca. 6-10mA
und mit Anzeige max 19mA bei Anzeige einer 8. Als Programm habe ich das
obere genommen, allerdings mit verlängerter Anzeigezeit. Unterschiede in
der Helligkeit der einzelnen Segmente sind nicht zu sehen.
B. W. schrieb:> z.B.: Du speicherst Port und Pin in einem Array und loopst beim Update> der Anzeige da drüber. Ungefähr so:
Dies Möglichkeit gefäält mir. Mal sehen ob ich das so hinkriege.
B. W. schrieb:> Fragen ist das beste was du machen kannst. ABER du musst auch soviel> Kontext geben, so das man das Problem verstehen kann.
Leider reagieren einige Leute hier sehr komisch auf Fragen. Das geht von
Hilfe, über das C-Buch bis hin zu verbalen Beleidigungen.
Danke für deine Hilfe
Henry schrieb:> B. W. schrieb:>> z.B.: Du speicherst Port und Pin in einem Array und loopst beim Update>> der Anzeige da drüber. Ungefähr so:>> Dies Möglichkeit gefäält mir. Mal sehen ob ich das so hinkriege.
das sollte gehen, nur für den Zugriff auf den Port gibt es noch es
Makro: _SFR_IO8(SFRNo);
SFRNo ist dann ein uint8_t.
Henry schrieb:> Leider reagieren einige Leute hier sehr komisch auf Fragen. Das> geht von Hilfe, über das C-Buch bis hin zu verbalen Beleidigungen.
Es könnte vielleicht damit zusammenhängen, daß du im falschen Forum
bist. Hier ist "Projekte & Code". Und die Beschreibung ist:
> Hier könnt ihr eure Projekte, Schaltungen oder Codeschnipsel> vorstellen und diskutieren. Bitte hier keine Fragen posten!
Da du eine Anfängerfrage(!) zum µC hast, gehört sie in "Mikrocontroller
und Digitale Elektronik". Aber eigentlich wäre es besser, wenn du mal
einen Augenblick selber darüber nachdenken würdest. Vielleicht auch
mal ein Tutorial durcharbeiten. Man muß nicht mit jeder Frage, die sich
nicht sofort und auf den ersten Blick beantwortet, gleich in ein Forum
rennen und die Leute dort belästigen.
Heiner schrieb:> @Schlaumeier>> Welche libs soll er denn nehmen??
Ich dachte da an diese Anleitung. ;) Erschien mir irgendwie logisch.
Die benutzen zwar eine 4-Stellige Anzeige aber das ist eh Wurst.
Weil man muss ja die Lib eh initialisieren (sieh ersten Zeilen im Code).
Kleine Anmerkung am Rande.
Ich kenne nicht alle Chips der ATiny-Serie. Aber ich kennen den Atiny-85
sehr gut.
Und der kann keine 7-Segment-Anzeige ohne Hilfs-Chips ansteuern.
Hat ja nur 8 Pins damit erschreckt der keine 7-Segment-Anzeige.
Die braucht nämlich 7 Pins für die LED's und 1 Pin für die Auswahl der
Ziffer ;)
Weshalb ich in meinen Code oben davon ausgegangen bin, das mind. 1
PCF-9574 als Bus-Expander (i2c-Bus) nachgeschaltet ist.
Dann muss der TO nur für jede Ziffer die Bit-Sequenz festlegen, und dann
die Bit-Sequenz in einen Rutsch zum PCF-8574 senden. Die passenden
"Mikro-Leds" (was anders sind da alles nämlich nicht) werden geschaltet
und alles ist gut.
Den Code oben von mir, nur leicht anpassen je nach CHIP und Ansteuerung.
Da ich noch kein Schaltplan gesehen habe, kann ich nicht mehr Infos
geben.
Sein Code ist jedenfalls vielleicht !! Funktionsfähig aber 1000 % zu
lang.
Ich persönlich würde so ne Primitive Sache sogar (s.Code oben) OHNE Libs
machen.
Kleiner Hinweis.
In den besten Buch was ich zum Arduino kenne und habe (20 Euro bei
Amazon, in Prime kostenlos) macht der Autor das über ein Schieberegister
mit > 36 Zeilen Code OHNE Libs. Und das sogar bei einer 4 Stelligen
Anzeige. ;)
https://www.amazon.de/Arduino-Kompendium-Elektronik-Programmierung-Projekte/dp/3966450399
Das ist DAS Buch für Arduino-Anfänger. Hat selbst mir viel neues
gezeigt. Was ich manchmal komplizierter gemacht habe.
Und beschreibt die "üblichen" Komponenten und Module die es für die
Arduinos gibt. Mit Code die ans laufen zu bringen.
Mir war es die Kohle wert. Habe aber in PRIME Probe gelesen. ;)
Benutze einen Attiny 84 auf Steckbrett. Die Belegung der Pins habe ich
bereits oben angegeben.
Man kann das ganze auch gern in einen anderen Bereich verlegen, habe
kein Problem damit.
Ist den Hilfe an bestimmte Bereiche gebunden?
Mit dem Code zu lang geb ich dir vollkommen recht. Er ist noch sehr
umständlich und lang. Es ist der erste Versuch ein laufendes Programm zu
schreiben. Es kommt ja auch noch die Anzeige auf 2 7-Segmend Anzeige
dazu. Da gibt es noch einiges zu tun für mich.
Henry schrieb:> Benutze einen Attiny 84 auf Steckbrett.
Ich habe mir den gerade mal angesehen. Wenn du den DIREKT nutzt, sind
deine Pins weg. ;)
Eine 7-Segment-Anzeige ist nix anders als 7 LED's. Also kannst du sie
auch genau SO ansteuern.
Du braucht für eine also 7 -Segment-Anzeige 7 PIN + 1 Pin je Ziffer.
Also machst du folgendes.
Du schreibst dir eine SUB-Routine. An die übergibst du das Zeichen (Zahl
ist auch ein Zeichen) + die Stelle an der das Zeichen erscheinen soll.
********** Variante mit Zusatz-Chip (PCF-8574 oder Schieberegister)
In der Routine machtst du
If Zeichen = "1" then 010101001 ' Du setzt als alle LEDS auf EIN die du
dafür brauchst.
Als = 16 abfragen.
Dann kommen die Sende-Befehle
If ziffer = 1 then ' der 2 Parameter des Aufrufs
' sende Bit-folge an Chip
end if
Wenn du ein PCF-8574 mit der Passenden Libs hast, brauchst du nur mit
EINER Zeile die ganze Bit-Sequenz zu senden. und VORHER die passende
Ziffer zu aktivieren.
Geht auch mit einen Schieberegister.
*** Variante ohne Zusatzchip.
Machst du es von Hand (also ohne Zwischenchip), Dann machst du
folgendes.
Die selbe SUB mit den selben Aufruf
Aber mit Vorspann.
Aktive Ziffer auswählen.
ALLE Segmente auf AUS.
Dann kommt.
If Zeichen = "1" then
pin_Segment_a = high
pin_Segment b = high
end if
Du musst also für jedes Zeichen NUR die passenden Pins auf high (an)
setzen.
Da du im Vorspann vorher alles aus gemacht hast reicht das völlig aus.
In den Beispiel ist es aber erforderlich das du ALLE Pins vorher
Deklarierst, damit der Atiny weiß was er da dran hängen hat.
Und wie schon erwähnt. Ich halte diese Variante für MIST, weil danach
bei deinen Chip kaum noch Pins für andere Sachen übrig bleiben.
Fertig.
Aber wie sagte man schon vor 2000 Jahren. Viele Wege führen nach Rom ;)
Ich bin grundsätzlich der Meinung man soll die Pins am Chip sparsam
verbrauchen. Weshalb ich IMMER ein Treiberchip für Anzeigen (auch LCD'
Anzeigen) benutze. Für so ne Dummen Anzeige min. 8 Pins opfern geht mir
gewaltig gegen den Strich. Aber jeden da seine.
fertig.
DB 01110111b ;| A | A | ; 100Ah | | |_____| | \__/ |
39
DB 01111100b ;| b | B | ; 100Bh | |/ D \| DIG3 |
40
DB 00111001b ;| C | C | ; 100Ch | ¯¯¯¯¯¯¯¯¯ |
41
DB 01011110b ;| d | D | ; 100Dh | |
42
DB 01111001b ;| E | E | ; 100Eh |
43
DB 01110001b ;| F | F | ; 100Fh |
44
; Digit 1 | Digit 2 | Digit 3 | Digit 4 |
45
; Seg PGFEDCBA |PGFEDCBA |PGFEDCBA |PGFEDCBA |Displ| Adress |Command
46
LED_Inf DB 01111100b ;b : | 1010h | 1xxx
47
DB 01110110b ;H : | 1011h | 20xx
48
DB 01110111b,11110011b ;AP: | 1012h | 30xx
49
DB 01111001b,11110011b ;EP: | 1014h | 40xx
50
DB 01110110b,11110011b ;HP: | 1016h | 50xx
51
DB 01101101b,01111000b,01011100b,01010000b;Stor | 1018h | 60
52
DB 01111100b,00111000b,00000110b,01010100b;bLin | 101Ch | 70
53
DB 01111100b,00111000b,00111111b,00111101b;bLOG | 1020h | 80
54
DB 01000000b,01000000b,11000000b,01000000b;--.--| 1024h | 90
55
DB 01111001b,01010000b,01010000b,01000000b;Err- | 102Ch | A0
56
; 76543210
57
Dis_X DB 00000100b ;Dig.1| 1030h | Digit1
58
DB 00001000b ;Dig.2| 1031h | Digit2
59
DB 00010000b ;Dig.3| 1032h | Digit3
60
DB 00100000b ;Dig.4| 1033h | Digit4
Dann kannst du direkt als Beispiel ein LT-4620HG anschließen und kannst
direkt den Code senden.
Der Chip selber kümmert sich um den Rest.
Habe einfachheitshalber gerade ein Definition Beispiel angehängt.
Er kann softwaremäßig wählbar sowohl Comon Anode oder Katode ansteuern
Helligkeit einstellbar, Scannfrequenz einstellbar, Keine zusätzliche
Komponenten nötig, Direkt mit I²C Ansprechbar.
BCD-DEZ und HEX Anzeige usw.
Dieser IC wurde speziell für 7Seg. LED-Displays wie Typ LT-4620HG
entwickelt(Die in Synthesizer/Keyboard verbaut wurden).
Patrick L. schrieb:> Kannst du auch ein: ES47121P16 Verwenden.
Hast du mal das Datenblatt dazu? Irgendwer hat dazu zwar Werbung
gebucht, aber ansonsten kennt mein Google den nicht.
Da gebe ich dir Recht, konnte diesen IC auch nicht finden.
Mit dem Attiny geht es mir nicht komplexe oder andere Schaltungen.
Möchte einfach einen kleinen IC nur für diese Aufgabe haben. Verwende
sonst meisten einen Atmega 16 oder 328.
Schlaumaier schrieb:> Ich bin grundsätzlich der Meinung man soll die Pins am Chip sparsam> verbrauchen. Weshalb ich IMMER ein Treiberchip für Anzeigen (auch LCD'> Anzeigen) benutze. Für so ne Dummen Anzeige min. 8 Pins opfern geht mir> gewaltig gegen den Strich. Aber jeden da seine.
Ich möchte diesen Chip nur für die Anzeige einsetzen. Hauptsache die
Pins reichen für diese Anwendung. Einen PCF8574 wird nicht rankommen.
Eine Anwendung könnte z.B. eine (Stop) Uhr oder Rundenzähler sein.
Könnte auch 2 bis 3 Anzeigen dieser Art nehmen und damit die Zeit
anzeigen. Eine Verbindung könnte dann mit einem Bus erfolgen. Da nur
dieser Code darauf laufen soll ist die Grösse des Codes eigentlich egal.
Einen PCF8574 benutze ich bereits an einem Display mit 2x16
yesitsme schrieb:> Hast du mal das Datenblatt dazu? Irgendwer hat dazu zwar Werbung> gebucht, aber ansonsten kennt mein Google den nicht.
Ja ich bin dabei ein Artikel hier im Wiki zu verfassen, wie ich diesen
Chip in einer Helligkeitsteuerung verwende.
Der ES47121P16(DIP16) und ES47121S16(SOIC16) sind Kunden IC's die für
versch. Synthi und Keyboards hergestellt wurden. Sie wurden nie
offiziell als IC's bei Distries verkauft, sondern nur im Verbautem
Zustand. Ich selber habe noch welche als Ersatzteile im Lager, so kam
ich auf die Idee diese als LED Displaykontroller in einem "Programmable
Dimmer-Projekt" Kundenauftrag zu verwenden, über welchen ich gerade
ein Artikel für hier im "MC" am schreiben bin.
PS: Der Chip wird sogar immer noch hergestellt, gilt also "noch" nicht
als Obsolete aber wird doch als NRND aufgeführt.
Darf aber als Ersatzteil verkauft werden, da die Verträge mit den
meisten Hersteller von Keyboard, mittlerweile ausgelaufen sind.
Datenblatt kann ich dir per PN zusenden, öffentlich hier Posten muss ich
zuerst Abklären ob ich dies Darf, da dies ja ein OEM Produkt ist. ;-)
Falls aber jemand Interesse hat, ich habe seit über 20 Jahren eine
Stange der DIP16 Version hier im Ersatzteillager liegen, da ich bis
heute noch nie einen, als Ersatzteil gebraucht habe, kam ich auch auf
die Idee ihn bei einem Kleinkundenauftrag einzusetzen und
hier,(Inspiriert durch genau diesen Thread hier) für welche die so etwas
suchen, um das "Basteln" von Einzelstücken zu erleichtern, anzubieten.
Die Vergammeln sonnst hier noch im Lager, da sie scheinbar einfach nicht
kaputtgehen wollen ..LOL...
PS2: Habe beim Durchsehen der Datenblätter übrigens gerade gesehen, dass
es den auch in einer 60V Version für VFD gegeben hat, weis aber noch
nicht ob auch dieser noch hergestellt wird.
Bei Interesse kann ich ja mal bei der Produktion in CH nachfragen.
Patrick L. schrieb:> Kannst du auch ein: ES47121P16 Verwenden.
DU WIE.
Ich kann nur Chips verwenden die ich kenne und die ich bei Reichelt o.s.
bekommen kann.
Beide Bedingungen erfüllt dein Chip nicht.
Henry schrieb:> Ich möchte diesen Chip nur für die Anzeige einsetzen.
Dann benutze doch einfach die "Variante ohne Zusatzchip".
Musst halt nur ALLE Pins extra deklarieren (als Output) und dann
dementsprechend die Pins an/aus schalten.
Auch kein Hexenwert.
Geht nach meiner Variante oder mit Lib und den Link oben.
Patrick L. schrieb:> Sie wurden nie offiziell als IC's bei Distries verkauft, sondern nur im> Verbautem Zustand.
Hmm... Keine Dokumentation und keine Verfügbarkeit... Den Chip muß ich
unbedingt in meiner Schaltung haben...
yesitsme schrieb:> Hmm... Keine Dokumentation und keine Verfügbarkeit... Den Chip muß ich> unbedingt in meiner Schaltung haben...
Verfügbar ist er, und Datenblatt haben die Hersteller die ihn Verbaut
haben (Wie wir z.B.) auch. Habe dir ja angeboten, wenn du Interesse hast
per PN ein Datenblatt zuzusenden. Aber es geht ja hier nicht um einen
Verkaufstread.
Ich wollte nur dem TO oder welchen die ähnliches aufbauen und ev. halt
nicht so Fit im Programmieren sind, oder einfach ein Chip suchen die
komplette 7Seg. Kontroller sind, diesen Chip als Alternative anbieten,
weil er einfach in der Anwendung ist.
Ich muss keine verkaufen, die liegen auch noch gut 10 weitere Jahre im
Lager,
Wollte ja nur ein Tipp zur Vereinfachung geben.
Es ist auch nicht gedacht damit Geld zu verdienen, für das habe ich
definitiv zu wenige im Lager liegen, Der Aufwand würde sich nicht
Rechtfertigen.
Ist echt nur als Hilfe gedacht, weil sie nun einmal da sind,
Ich habe die ja auch nur, weil ich damals gedacht habe "Muss ich ein
paar im Lager haben falls mal einer Hopps geht". Was bis heute nicht
eintraf.
Henry schrieb:> Meine Kenntnissevon C sind nicht überdurchschnittlich.
Das verlangt auch keiner von dir. Und mal ganz generell gesagt, ist es
auch einigemaßen unerheblich, welche Programmiersprache du benutzt.
Weitaus wichtiger ist es, programmieren zu können, also fähig zu sein,
gute und tragfähige Algorithmen zum Lösen eines Problems zu erdenken.
Das Niederschreiben in irgend einer Programmiersprache ist etwas, das
erst danach kommt.
W.S.
Henry schrieb:> ein laufendes Programm zu schreiben.
Und es läuft. Damit ist alles gut.
Natürlich kann man immer alles anders machen aber es wird damit nicht
besser. Vielleicht einfacher oder weniger Schreibarbeit oder schöner
anzusehen für Person x. Alles irrelevant.
Solange die Anzeige hell genug, der Tinny kalt genug und Pinns genug da
sind gibt es keinen Grund was zu ändern.
Vielleicht als Hobby um was zu tun?
Den Code kürzen?
Weniger Flash brauchen?
Ihn schneller machen?
A. H. schrieb:> Vielleicht als Hobby um was zu tun?> Den Code kürzen?> Weniger Flash brauchen?> Ihn schneller machen?
Hobby sagt es am besten. Ansonsten den Code kürzen.
Kann mir auch vorstellen, das alles per Bus übertragen wird. Nur noch
ein Wert/Buchstabe übertragen und der Attiny macht die Darstellung
allein.
Henry schrieb:> das alles per Bus übertragen wird. Nur noch ein Wert/Buchstabe übertragen und> der Attiny macht die Darstellung allein.
Da würde sich I2C anbieten, Die richtigen Pins sind noch frei :-)
Vielleicht immer zwei Zeichen übertragen, dan braucht der Tiny nicht zu
überlegen welches jetzt angezeigt werden soll ;-)
Aber vieleicht vorher das Programm ü+berarbeiten damit auch beide
Anzeigen (gleichzeitig) was zeigen. Dann muß es etwas hektischer werden
(das _delay_ms(500)) muß ganz weg/durch einen zähler ersetzt werden. da
beide Anzeigen <20ms gewechselt werden müssen:
etwa so
Porta wert 1
portb wert1+1an
_delay
portb 1aus
Porta wert 2
portb wert2+2an
-delay und nötige Bearbeitungen (neue Werte holen , etc
portb 2aus
goto etwa so ;-)
Habe das Programm etwas hübscher gemacht. Es wird nur eine Ziffer
angezeigt.
Die beiden Pins für den Bus hatte ich freigelassen, da ich noch nicht
wusste wie ich es genau mache.
1
#define F_CPU 8000000UL // Angabe der Frequenz, wichtig für die Zeit
Du willst die "persistence of vision" ausnutzen. Dazu musst du zwischen
beiden Ziffern hin und herschalten. Idealerweise mit festem Zeittakt, da
sonst eine Ziffer heller leuchtet als die andere oder es flackern kann.
Ich denke ich würde da einen Timer mit Interrupt verwenden. Das Programm
berechnet das dazustellende Muster und schreibt es in einen Buffer. Die
Interrupt routine kopiert den Buffer nur auf die Ports.
Die Interrupt routine könnte so aussehen:
Wollte erst mal beide Ziffern darstellen ohne Timer um es für mich zu
lernen. Da gibt es schon die ersten Fragen dazu. Frequenz muss <10 mS
sein? Wie kann ich das machen das beide Ziffern dargestellt werden bzw,
2 Unterschiedliche Ziffern. Extremfall sollte es durchzählen von 00 bis
99. Ist z.b. gut für eine Stopuhr. Dachte dabei an 2 Schleifen in
einander.
Die Funktion des Timers dabei bin ich noch am lesen.
B. W. schrieb:> Ich denke ich würde da einen Timer mit Interrupt verwenden. Das Programm> berechnet das dazustellende Muster und schreibt es in einen Buffer. Die> Interrupt routine kopiert den Buffer nur auf die Ports.
Das versteh ich noch nicht. Wie soll das gehen?
Für PORTA musst du dir noch überlegen, wie du das Pattern für die Anoden
da noch reinbekommst.
Und für die erstem Tests kannst du updateDisplay() auch so oft wie es
geht in deiner Hauptscheife aufrufen.
... weil ich das gerade für einen ATmega gemacht habe (Multiplexing
einer 7-Segmentanzeige), habe ich das mal adaptiert für den hier
genannten ATtinyx4 (wobei sich mir der Sinn - und ich mache sehr viele
sinnlose Sachen - nicht erschließt, wenn man nach dem Multiplexen nur
noch eine einzige Portleitung frei hat).
Zur Anzeige gebracht wird der Inhalt des Arrays ("Framebuffer")
fb_seg7[2]
wobei hier jedes Bit der 2 Bytes ein Segment der Anzeige repräsentiert.
fb_seg[0] ist das rechte, fb_seg[1] das linke Digit.
Ein Timer1 Interrupt erledigt das Multiplexen, so dass ausschließlich
ein Zugriff auf fb_seg7[x] die Anzeige steuert.
fb_setdez(uint8_t val) und fb_sethex(uint8_t val) beschreibt den
Framebuffer, so dass bspw. ein Aufruf
fb_setdez(18); die Zahl 18 auf der Anzeige erscheinen läßt.
--------------------------------------------------
in mpx_2conc.h werden alle Angaben "zusammengepfriemmelt", die in
Verbindung mit den Portpins stehen.
So sind sprechendere Namen gegeben um einen Portpin als Ausgang zu
definieren:
PA4_output_init();
setzt den Portpin PA4 als Ausgang.
PA4_set(); / PA4_clr(); Setzt bzw. löscht einen Portpin.
PA4_input_init();
würde PA4 als Eingang mit eingeschalteten Pull-Up-Widerstand definieren,
is_PA4()
würde den PA4 Pin einlesen.
Mittels mpx_2conc.h ist es somit sehr einfach möglich, die Zuordnung der
Pins an die Anzeige vorzunehmen:
#define seg_d B1
ordnet das Segment d einer Anzeige dem Portpin B1 zu. Hier darf NICHT
PB1 angegeben werden, da sonst die Verknüpfungen in mpx_2conc.h nicht
richtig funktionieren.
Gruß,
Ralph
Henry schrieb:> Ich möchte mit einem kleinen Attiny 2 x 7 Segment Anzeige ansteuern.
Welcher denn?
Henry schrieb:> Da aber die> Anzeige auf Port A und Port B angeschlossen ist, funktioniert das nicht.
Warum machst Du dann sowas?
Am einfachsten ist die generische Lösung:
Ralph S. schrieb:> weil ich das gerade für einen ATmega gemacht habe
So geht es mir auch.
Nicht multiplexen, aber 2 Ziffern statisch angesteuert an einem ATmega8,
Segmente der 1er und 10er Stelle auf PortD und PortB verteilt wie es
sich ergab:
PD0: G1, PD1: A1, PDC1, PD3: E1, PD4: D1, PD5: C10, PD6: E1, PD7: B1
PB0: B10, PB1: G10, PB2: A10, PB3: F10 PB6: D10, PB7: E10
Nur C der 10er ist also auf dem Port der 1er gelandet. Man muss nur die
7-Segment Ziffernmuster passend codieren, und kann dann x von 0 bis 99
ausgeben:
Ralph S. schrieb:> (wobei sich mir der Sinn - und ich mache sehr viele> sinnlose Sachen - nicht erschließt, wenn man nach dem Multiplexen nur> noch eine einzige Portleitung frei hat).
Jetzt zitiere ich mich mal selbst:
Eine Anwendung habe ich mal gefunden: ein Thermometer an der
7-Segmentanzeige. Thermometer realisiert mittels 10k NTC Widerstand und
Lookup-Table und Interpolation der Stützstellen.
Beim Foto möge man mir verzeihen, ich habe nur eine 4-stellige Anzeige
zur Verfügung gehabt und von daher sind nur 2 der 4 Stellen genutzt.
Peter D. schrieb:> Warum machst Du dann sowas?> Am einfachsten ist die generische Lösung:
Das versteh ich nicht. Hatte bisher nichts damit zu tun.
Ich verwende einen Attiny 84. Ersteinmal hatte ich den rumzuliegen da
ich den mal falsch bestellt habe. Und zweitens reichen die Pins genau
für die Aufgabe aus.
Möchte es versuchen eine grössere Aufgaben in mehrere kleine Teil zu
zerlegen. Es wurde oben schon der I2C Bus angedacht. Ein Master soll die
Aufgaben verteilen und die Ergebnisse zur Anzeige geben. Dachte dabei an
"verteilte Intellegenz". Als Master dachte ich an den Atnega8/32 oder
328 oder sogar an einen SAM. Natürlich nur was dabei mit meinem Wissen
möglich ist.
Wie oben schon erwähnt.
Für LED-Displays (egal welcher Art) ist ein Port-Expander (ich liebe den
PCF-8574) IMMER die beste Lösung wenn das Display von Allein kein Bus
mitbringt.
Selbst bei den Großen AT-MEGA (54 Pins wenn ich das richtig im Kopf
habe) würde ich ein Port-Expander nutzen.
Das hat 2 Gründe.
1. Ich kann das Display ohne KM an Kabel verbinden.
2. Die Ansteuerung ist bedeutet leichter in der Software.
Was heißt der Code wird bedeutend kürzer.
Und wenn man das Display mal tauschen muss, weil z.b. für die
Erweiterung das 2 Zeilen Display nicht mehr ausreicht muss man auch
nicht an der Hauptplatine herum spielen.
Das gilt auch für 7-Segment-Anzeigen. Beispiel : du hast ein 2 Stellige
und merkst das eine 4 Stellige besser wäre. Du hast vorher die Anzeige
und den Port-Expander auf einer Hilfs-Platine montiert.
Du ziehst die Hilfs-Platine ab. Steckst die neue dran, verlegst noch 2
Leitungen für Stelle 3 + 4 und bist fertig. Bisschen im Code
nachgebessert.
Alles in allen ist das so sehr einfacher zu Händeln. Und die abgebaute
Platine. Die kannst du Problemlos ohne viel Theater in ein anderes
Projekt einbauen.
Und ich weiß wovon ich rede. Ich habe in einer meiner
Lieblings-Projekte die 1602 gegen eine 1604 getauscht. Beide hatten
eine Huckpack-Platine mit PCF-8574. Kabel abziehen, neuen dran, FERTIG.
Der größte Aufwand war, und das meine ich bitter ernst, das auf fräsen
des Lochs im Gehäuse wo das größere Display rein sollte. !!
Gerade auf Steckboards wirst du so was lieben lernen. Da gilt : JE
weniger Kabel desto besser. Die wackeln alle wie Hund mit Schwanz und
erzeugen gerne Wackelkontakte.
Da geb ich dir Recht. Mit dem PCF8574 kann viel machen. Es ist immer der
I2C Bus mit dabei. Finde diesen Bus eigentlich sehr gut. Was machst du
aber wenn es den 8574 nicht mehr gibt und es nur noch den MCP23017 gibt.
Ist im Grunde das selbe und hat noch einiges mehr. Das Programm kann man
anpassen, ist klar. Habe auch (Farb) Displays mit Bus gesehen. Ist
wahrscheinlich eine ganz andere Welt. Da gibt es noch viel zu lernen für
mich.
Schlaumaier schrieb:> Für LED-Displays (egal welcher Art) ist ein Port-Expander (ich liebe den> PCF-8574) IMMER die beste Lösung wenn das Display von Allein kein Bus> mitbringt.
Warum kommt von Schlaumaier IMMER der gröbste Unsinn.
Die beste Lösung, kommerziell gerne verwendet, ist ein uC mit
eingebauten Stromquellen und leistungsstarken Multiplexausgangen wie
beim SinoWealth SH79F3212 oder PIC16F1764.
Zweitbeste Lösung für LED Anzeigen ist ein Schieberegister-Treiber mit
Konstantstromausgängen wie DM13 oder TLC5923 oder gleich multiplexfähig
wie MAX7219 oder TB62709.
Aber all die kennt der rückständige Schlaumaier naturlich nicht.
Der PCF8574 ist das dümmste was man machen kann, weil er ein I/O
Expander ist, also universell auch für Eingänge, die man nicht braucht
und das Programmieren erschweren und unnötig teuer ist. Er begrenzt den
Strom nicht selbst sondern braucht pro LED einen Vorwiderstand und
schaltet nur nach Masse, ist für common cathode also ungeeignet Simple
74HC595 wären sind billiger und besser.
Leute, es geht hier doch nicht darum, welche externen Chips die besseren
sind. Der TO wollte eine Multiplexlösung ohne externen Chips.
Wenn er darüber spricht, an dem Tiny84 noch einen I2C Bus zu
realisieren, muß er bei der Anzeige den DP weglassen. Dann hat er 7 Pins
für die Segmente plus 2 Pins fürs multiplexen => in Summe 9. Plus 3 Pins
für Vcc, Gnd und /reset sind 12. Hat er noch genau 2 Pins frei ( und
keinen Dezimalpunkt auf der Anzeige ). Wie gesagt beim Thema bleiben.
Wenn man eine einfache Lösung haben will, nimmt man einen Controller mit
LED Konstantstromausgängen oder einen externen Chips, der das
Multiplexen erledigt (TM1637, Max xxxx).
Beim TO geht's darum das Display ohne Chip zu verwenden und darum wie
das geht. Hieraus kann er etwas lernen.
Danke für deine Worte. Mit dem DP hast du recht, hatte vergessen es zu
sagen.
Habe das Netz durchsucht und einige Infos zum Grund gefunden.
Ich brauche einen Timer, der einfachste reicht aus. Er muss mit ca.5ms
zwischen den beiden Anzeigen umschalten, Die verbleibende Zeit muss er
an sein. Dann muss ich der den Anzeigen jeweils den Inhalt zu ordnen.
Bei 2 Anzeigen sind von 00 bis 99 alles möglich. Die Anzeigen von a bis
f nehme ich erst mal nicht. So muss weiter lesen...
Henry schrieb:> Er muss mit ca.5ms> zwischen den beiden Anzeigen umschalten, Die verbleibende Zeit muss er> an sein. Dann muss ich der den Anzeigen jeweils den Inhalt zu ordnen.
Du hast den Beitrag Beitrag "Re: 7 Segment Anzeige auf verschiedenen Ports"
oben aber schon gelesen, oder?
Da ist der Timer(interrupt), der allerdings mit ca. 1 mS läuft, schon
integriert und alles was du brauchst um die Anzeige zu steuern. Wenn du
den Dezimalpunkt dort nicht brauchst, kannst du den Portpin frei lassen
und diesen Pin dann einfach nicht als Ausgang initialisieren. Somit sind
dann am Controller 2 Portpins frei.
Ralph S. schrieb:> Leute, es geht hier doch nicht darum, welche externen Chips die besseren> sind. Der TO wollte eine Multiplexlösung ohne externen Chips.
PERFEKTE Aussage.
Ich habe den PCF-8574 in Massen (> 20 Stk.) hier liegen. Und Widerstände
(kosten SMD < 1 Cent) bestelle ich eh im 100er Paket.
Also löse ich ALS HOBBY eine Sache lieber mit den was ich habe, als das
ich mir ein Haufen Spezialchips besorge, die den Job sicher besser
erledigen können.
Der PCF-8574 (und sein großer Bruder) sind für mich genau das was auch
in der Beschreibung steht. PORT-EXPANDER. Sie stellen mir also mehr
Pins zu Verfügung bzw. retten meine "Pins on Board" vor der Benutzung.
Ach und nur zu Info.
den MCP23017 habe ich auch 3 x hier liegen.
Und Schieberegister setze ich nur ein, wenn der I2C-Bus überlagert wird,
da die i.r.R. hintereinander geschaltet werden können. Was bedeutet, so
ca. ab der 17 LED setzte ich das dann ein.
Aber wie schon erwähnt. Ich mache das als Hobby. Mit den Dingen die ich
zur Verfügung habe, und die ich preiswert kaufen kann. Und da ich keine
Firma bin, sind Bestellungen bei Mouser oder Farnell auch außen vor. Und
nein, dank der Lästereien hier, vertraue ich hier keinen Mehr, was heißt
ich kann mich auch keiner Sammelbestellung anschließen. SORRY. Also
bastele ich mir den Sache die ich halt bei Reichelt + Co. bekomme.
Und da kostet der PCF-8574 < 1 Euro (jedenfalls in meiner letzten
Bestellung)
Aber jeder baut anders. Ich habe nur meine Gründe gesagt wieso ich es
SO mache.
Ralph S. schrieb:> Du hast den Beitrag Beitrag "Re: 7 Segment Anzeige auf verschiedenen> Ports"> oben aber schon gelesen, oder?
Hallo Ralph
Ja, den Beitrag habe ich gelesen. Bin dabei es zu verstehen. Die zweite
(h) dabei bringt mich etwas durcheinander. Habe bisher kein Programm mit
2 Datein gesehen. Wenn ich es richtig gesehen habe kann ich die Segmente
frei angeben. Timer ist auch drin, habe ich gesehen.
Mit dem PCF8574 hast du vollkommen recht. Es gab hier auch schon eine
Disput wie weit der PCF noch verwendet werden kann. Ist ja nicht mehr
der Jüngste. Die Anwendung ist einfach und schnell. Habe mir die neuen
ICs auch angesehen. Jeder IC hat seine Vor- und Nachteile.
Bin aber dabei die Leistung zu verteilen. Die Attiny sind für diese
kleine Aufgabe sehr gut geeignet. Wenn man es schafft den Master richtig
zu programmieren kann man viele Sachen machen. Mach die ganze Sache auch
nur als Hobby und was ich mir leisten kann. Versuche lieber den IC zum
Leben zu erwecken als mir das blöde Fernsehprogramm anzuschauen. Möchte
meine grauen Zellen auch noch was bieten und nicht durch Langeweile dem
Alk verfallen.
Henry schrieb:> Versuche lieber den IC zum Leben zu erwecken als mir das blöde Fernsehprogramm
anzuschauen. Möchte meine grauen Zellen auch noch was bieten und nicht durch
Langeweile dem Alk verfallen.
Ich auch. ;)
Aber ich habe pay_tv für Arme. Da ist Discovery und History mit drin. Da
lernt man echt viel.
Da aber ich nicht nur Dokus schauen mag, habe ich mit Arduinos
angefangen. Zuerst mit einen Starter-Kit mit UNO damit man mal ein
Anfang hat. Dann schnell zu Nano weil so schön klein. Und als ich
schnell gemerkt habe, was man damit alles machen kann, kamen mir viele
schöne Ideen meine Modellautos (Revell + Co.) mal zu Beleuchten. Ergo
bin ich dabei da Atiny-85 (Das Teil gab es SMD für unter 1 Euro /Stk.
bei Reichelt) einzubauen und jede Menge Beleuchtung einzubauen. Wegen
der Größe wird das nicht Elektronisch korrekt aber es funktioniert, das
ist die Hauptsache. ;)
Wie gesagt. Mir muss was einfallen und dann baue ich es.
Kein Stress, keine Hektik und wenn es mal 5 Monate im Schrank liegt
juckt das auch keinen.
Henry schrieb:> Hallo Ralph> Ja, den Beitrag habe ich gelesen. Bin dabei es zu verstehen. Die zweite> (h) dabei bringt mich etwas durcheinander. Habe bisher kein Programm mit> 2 Datein gesehen.
kein böse gemeintes "Oh jeh":
Kein größeres Programm (in C) wird aus einer einzelnen Datei bestehen
(und kleinere wohl auch nicht).
Wahrscheinlich ohne dass du es bemerkst verwendest du für deine
Programmierung auch mehrere Datei (bspw. durch ein #include
<utils\delay.h>.
Eine "h-Datei" (Header) beinhaltet zum einen Deklarationen vorhandener
Funktionen. Das heißt, es werden allgemein gehaltene Funktionen die in
anderen Programmen auch genutzt werden können, in eine extra Datei
geschrieben (die dann in aller Regel .c heißt). Die Ausarbeitung dieser
Funktion nennt sich "definition". Die Header Datei ihrerseits, die im
Hauptprogramm eingebunden wird, beinhaltet die Deklarationen. Eine
Deklaration ist hierbei die Bekanntgabe, welche Funktionen vorhanden
sind, und die in einem Hauptprogramm verwendet werden können.
Somit ist es möglich, das Hauptprogramm von den ausgelagerten Funktionen
unabhängig voneinander zu compileren. Durch dieses compilieren entsteht
kein lauffähiges Programm, sondern ein sogenannter Object-Code. Erst das
Verbinden von Hauptprogramm und anderen externen Programmteilen (manche
hier, vor allem Arduinonutzer nennen das gerne Lib) erzeugt ein
lauffähiges Programm. Das Verbinden von mehreren Programmteilen zu einem
lauffähigen Programm nennt man "linken", das Programm nennt man Linker.
Im AVR-GCC ist ein Linkerprogramm integriert.
Zum Anderen sind ein einem Headerfile sogenannte "define" und "Macros"
vorhanden.
Im einfachsten Fall kann man bei einem "define" sagen, dass es ein
"suchen und ersetzen" in einem Hauptprogramm ist:
#define laufspeed 200
Egal wo nun im Hauptprorgramm "laufspeed" auftaucht, wird dieses durch
den Wert 200 ersetzt:
_delay_ms(laufspeed);
im Hauptprogramm bedeutet nichts anderes als
_delay_ms(laufspeed);
Der Text eine .h Datei wird genau an der Stelle einefügt, an der diese
mittels
#include "datei.h"
angegeben ist.
---------------------------------------------
In meinem Fall könnte also der komplette Textinhalt des .h - Files auch
an dieser Stelle niedergeschrieben werden. Beim Compilieren meines
Programmes ist also darauf zu achten, dass genau diese Datei sich im
selben Verzeichnis befindet wie das Hauptprogramm.
In meinem Fall gibt es zu meiner h-Datei keine entsprechende .c Datei,
da keine weiteren Funktionen (die hinzugelinkt werden müssten)
existieren.
Hier sind nur Macros angegeben, die erst bei einem Aufruf im
Hauptprogramm Programmcode erzeugen.
Diese Macros gewähren einen einfacheren Umgang mit den I/O Pins des
Controllers und sind fast schon als eine Art Abstraktion anzusehen:
1
#define MASK1 ( 1 << 1 )
2
3
#define PA1_output_init() ( DDRA |= MASK1 )
4
#define PA1_set() ( PORTA |= MASK1 )
5
#define PA1_clr() ( PORTA &= ~MASK1 )
6
#define PA1_input_init() { DDRA &= ~MASK1; PORTA |= MASK1; }
7
#define is_PA1() ( (PINA & MASK1) >> 1 )
Wann immer auch im Programmtext "MASK1" geschrieben wird, steht dort in
Wirklichkeit (1 << 1 ), was einem Zahlenwert von 0x02 entspricht (auch
das hätte man für MASK1 schreiben können.
PA1_output_init() wird somit durch:
DDRA |= (1 << 1);
ersetzt, dieses entspricht dem Initialisieren des Pins PA1 als Ausgang.
PA1_set() wird durch:
PORTA |= (1 << 1);
dieses entspricht dem Setzen eines Portpins auf 1.
Das ganze hat den Vorteil, wenn man dieses einmal für alle Pins eines
Controllers gemacht hat, sich nicht mehr mit der Hardware
auseinandersetzen zu müssen, wie denn ein Port zu initialisieren ist und
wie dieser bspw. auf 1 oder gesetzt werden kann (eine ähnliche
Vorgehensweise habe ich mit allen Controllerfamilien gemacht, die von
mir eingesetzt werden, auch die der STM32 Familie).
Im Weiteren meiner .h Datei nehmen die defines in ihren Deklarationen
etwas "kryptische" Formen an (nur die Deklaration, nicht deren
verwendung):
Sie setzen nun mehrere Defines so zusammen, dass bspw. ein
kseg0_init()
entsteht. Du kannst innerhalb deines Hauptprogramms nun einfach
kseg0_init(); hinschreiben, und der Port an dem die Multiplexleitung 0
angeschlossen ist, wird initialisiert. Schreibst du also bspw. im
Hauptprogramm:
#define kseg0 A5
so wird automatisch PA5 als Anschlussleitung für Multiplexlinie 0
bestimmt. Das Hauptprogramm bedient sich nur dieses kseg0 und nicht den
Hardwarenamen des Controllers.
Würdest du anstelle von A5 bswp. B2 angegeben, so wäre dann
logischerweise B2 die Multiplexleitung (hier müßtest du dann natürlich
den Anschluss der vorher für B2 vorgesehen war ändern).
Für ein erstes Ausprobieren kannst du auch schlicht die .h Datei nehmen,
und deren Inhalt an die Stelle kopieren, an der das "include" auftaucht.
Dieses macht aber den Sourcecode im Hauptprogramm relativ
unübersichtlich
Ralph S. schrieb:> Egal wo nun im Hauptprorgramm "laufspeed" auftaucht, wird dieses durch> den Wert 200 ersetzt:>> _delay_ms(laufspeed);>> im Hauptprogramm bedeutet nichts anderes als>> _delay_ms(laufspeed);
muß natürlich heißen:
_delay_ms(200);
Ralph S. schrieb:> Du hast den Beitrag Beitrag "Re: 7 Segment Anzeige auf verschiedenen> Ports"> oben aber schon gelesen, oder?
Diese generische Lösung hatte ich auch vorgeschlagen. Wird ja nach
SBI/CBI übersetzt, ist also schnell und wenig Code.
Maskieren über mehrere Ports hinweg verleitet dagegen schnell zu
Fehlern.
... in der Datei mpx_2digit_demo.c hat sich ein Fehler eingeschlichen.
Die Funktion
void seg7_allclr(void)
stammt aus einer Version für gemeinsame Kathode (und nicht für
gemeinsame Anode). Sie löscht nicht alle Segmente, sondern sie setzt
alle. Dieses ist der Grund für ein leichtes Hintergrundleuchten der
Digits, korrekt muß sie lauten:
Ralph S. schrieb:> Beim Foto möge man mir verzeihen, ich habe nur eine 4-stellige Anzeige> zur Verfügung gehabt und von daher sind nur 2 der 4 Stellen genutzt.
Ich vermisse die Vorwiderstände, das ist unverzeihlich.
Henry schrieb:> Die Attiny sind für diese> kleine Aufgabe sehr gut geeignet. Wenn man es schafft den Master richtig> zu programmieren kann man viele Sachen machen.
Wenn du den ATtiny wirklich nur als Anzeigentreiber verwenden magst,
wärst du tatsächlich mit einem fertigen externen Anzeigentreiber besser
bedient. Potentielle Bausteine sind hier:
- MAX7219 ( 8 x 8 Segmente)
- TM1637 ( 20pol. , 6 Digits zu je 8 Segmente, 16 Tasten)
- TM1638 ( 28 pol. , 10 Digits zu je 8 Segmente, 24 Tasten)
- TM1651 ( 16 pol. , 4 Digits zu je 7 Segmente, 7 Tasten)
Allen obigen Bausteinen gemein ist, dass sie, wenn sie mit einem Wert
beschrieben wurden, diesen solange anzeigen bis dieser geändert wird.
Daneben kann tatsächlich auf die (ultrabilligen) Schieberegister 74HC595
zurück gegriffen werden. Hier entsteht aber das kleinere Problem (wie
bspw. mit den Chinamodulen, die diese in Verbindung mit
7-Segmentanzeigen einsetzen), dass die serielle Ausgabe auf diesen
Bausteinen dennoch gemultiplext werden muß (sofern nicht jedes einzelne
Schieberegister statisch ein Digit ansprechen soll).
Bspw. können mit 2 kaskadierten Schieberegistern insgesamt 16 Pins
gesteuert werden. Hier wären 8 Pins für die Segmente und 8 Pins für
Multiplexleitungen frei. So könnten hier dann insgesamt nach dieser
Methode 8 Digits angeschlossen werden. Nachteilig bei dieser Methode
ist, dass hierfür innerhalb eines Interrupts die Anzeigen dennoch
gemultiplext werden müssen (was bei einem expliziten Anzeigentreiber
nicht der Fall ist).
Gegen einen Anzeigentreiber realisiert mit einem ATtiny spricht das
Multiplexen an sich und das Fehlen von Kommunikationsschnittstellen. Ein
serielles Protokoll mittels des USI (zudem noch als Slave) ist nicht
wirklich lustig zu realisieren.
------------------------------------------------
Unabhängig davon bin ich am überlegen wie ein proprietärer (nur zu mir
kompatibler) 1-Drahtbus aussehen könnte, damit über diesen bspw. ein
ATtiny von einem anderen Controller aus angesprochen werden könnte.
Dadurch, dass der Controller im Multiplexing beschäftigt ist, ist hier
ein Timing einzuhalten nicht so ganz trivial
Hallo Ralph
Verwende an sich den HT16K33 sehr gern. Hat von Hause aus den I2C bus
drin und kann sehr gut eine Matrix oder Balken ansteuern. Gibt es als
Modul zum aufstecken. Hatte im Netz auch schon eine Laufschrift damit
gesehen. Ist auch leicht zu programmieren. Auch USI gibt es ja im Netz.
Muss mal schauen ob es nicht einen Attiny mit Bus gibt. Kann mich dran
erinnern auch was dazu gesehen zu haben.
Warum kann man die Aufgaben nicht verteilen? Der Master organisiert
alles und die einzelnen Slaves machen die Aufgaben. Dachte dabei an
einen Encoder, Joystick oder Sprachausgabe mittels MP3 oder WAV020. Jede
Platine hat seine spezielle Aufgabe. Im Grunde hat der Master mit der
Anzeige auf einem Farb TFT Graphikdisplay so um 3 bis 5 Zoll schon genug
zu tun.
Es gibt doch viele Baugruppen mit Bus, so wie den INA 219.
Bekomme noch einge Fehlermeldungen.
#define kseg1_init() CONC(P,CONC(kseg1,_output_init()))
#define kseg1_set() CONC(P,CONC(kseg1,_set())
#define kseg1_clr() CONC(P,CONC(kseg1,_clr()))
Die mittlere Zeile verursacht ein
"Error'CONC' undeclared (first use in this function)"
Die anderen habe ich soweit gefunden, Fehlende Klammern oder vergessenes
Semikolon, alles wahrscheinlich übertragungsfehler. Auf diesen kann ich
mir leider keinen Reim machen.
Es wird jetzt ohne Fehler übertragen. Es erfolgt auch eine Anzeige auf
den beider 7-Segment. Allerdings wechseln die Segmente so schnell das
nichts zu erkennen ist.
Habe den DP auskommentiert und die Segmente korrekt zugewiesen.
Da hast du ja ein richtiges Spielzeug programmiert. Eine Ziffer zählt
ständig durch von 0 bis 9. Die andere Ziffer ist so schnell das man die
einzelnen Zahlen nur ahnen kann und nach 99 kommt das umlaufende Segment
als Abschluss. Sieht wirklich gut aus und zeigt die Funktion.
Damit fängt die Arbeit bei mir an, muss es noch verstehen.
Danke
Henry schrieb:> Eine Ziffer zählt> ständig durch von 0 bis 9. Die andere Ziffer ist so schnell das man die> einzelnen Zahlen nur ahnen kann und nach 99 kommt das umlaufende Segment
Dann stimmt noch etwas nicht. Das Demoprogramm zählt kontinuierlich
hoch, Zeitdauer zwischen dem Hochzählen gleich 0,3 Sekunden.
Irgendwo ist da dann noch scheinbar der Wurm drin !
Wenn das zu schnell läuft, kann es sein, dass du irgendwo die Angabe für
F_CPU nicht richtig eingestellt hast.
Kann es sein, dass dein ATtiny auf internem 8 MHz Takt hast aber F_CPU
mit 1000000 deklariert ist?
Gehe einfach mal ganz am Anfang des Programms her und schreibe ein:
#define F_CPU 8000000ul
darüber und schaue, was er dann macht.
----------------------------
Außerdem wollte ich das jetzt einmal probieren, eine "Fernsteuerung" der
Anzeige mittels eines anderen Controllers vorzunehmen.
Einfachkeitshalber habe ich hierfür dann den UART verwendet (mittels
USI) und diesem UART schlicht die Möglichkeit genommen, etwas zu senden.
Der ATtiny ist somit ein reiner Empfänger.
Natürlich habe ich mir jetzt keine Mühe gemacht, ein besonders stabiles
Protokoll zu implementieren.
Des TO's wegen habe ich auch die UART-Funktionen nicht in eine andere
Datei ausgelagert, weil ich nicht weiß, ob er weiß, wie man eine
Sourcedatei zu einem bestehenden Programm hinzulinkt.
Das "Füttern" des ATtiny mittels UART funktioniert. Hierfür mußte jedoch
der Anschluß PA6 frei gemacht werden, an dem bisher das Segment "g"
angeschlossen war, weil auf diesem Anschluß, der Input für das USI ist.
Ist die Schaltung aufgebaut, so erwartet das Programm auf der seriellen
Schnittstelle 3 Zeichen:
1
- 1. Zeichen: 0 => kein dp wird angezeigt
2
1 => dp wird angezeigt
3
- 2. Zeichen: 10er Stelle der Anzeige
4
- 3. Zeichen: 1er Stelle der Anzeige
Sendet ein Host (über UART) bspw. "156" wird auf der Anzeige "5.6"
angezeigt.
Wird ein Leerzeichen anstelle einer der beiden Ziffern gesendet,
schaltet diese das betreffende Digit dunkel:
Mit "1 5" wird auf der Anzeige " .5" dargestellt.
Henry hätte wohl mehr gelernt, wenn er das Programm selbst erstellt
hätte.
So ist seine Eigenleistung gleich Null.
Stichwort „Hilfe zur Selbsthilfe“ 🤷♂️
Das stimmt nicht. Das Programm vorher habe ich selber geschrieben ohne
jede Hilfe. Auch die erste Version stammt von mir allein.
Hilfe zur Sebsthilfe hat dabei eine ganz andere Bedeutung.
Wenn man im Netz so gut wie keine Tuts oder andere Erklärung findet
bleibt einen nichts weiter übrig als zu fragen.
Wenn man eine funktionierenden Code bekommt kann man diesen auseinader
nehmen und genau schauen wie man es macht. Einen Code der nicht
funktioniert und man Tagelang damit verbringt ihn zum laufen zu bekommen
nützt wenig und der Verdruss ist recht gross.
Du hast mit den 8 MHz recht, Asche auf mein Haupt. Gebe sehr oft diese
Daten in eine extra Datei, so auch die Frequenz. Habe es diesmal total
übersehen. Sorry.
Das musste ich noch anpassen:
1
// Zuordnung der Anschluesse der 7-Segmentanzeige zu den Portpins des Controllers
2
#define kseg1 A5 // A3 -A7
3
#define kseg0 A7 // A5 - A5
4
#define seg_a A3 // A1
5
#define seg_b A2 // A4
6
#define seg_c A1 // A7
7
#define seg_d A0 // B1
8
#define seg_e B2 // B0
9
#define seg_f B1 // A2
10
#define seg_g B0 // A6
11
//#define seg_dp B2
Damit laufen die Zahlen recht gemütlich durch.
Du hast es jetzt auch noch mit UART gemacht. Einfach toll. Werde es
höchstwahrscheinlich nicht nehmen, da ich auf den I2C Bus gehen werde.
Die übergabe des Wertes soll dabei vom Master zum Slave gemacht werde.
Werde erst mal den Programm auseinder nehmen uns genau schauen wie es
geht. Scheinbar gefällt des nicht allen
Henry schrieb:> Werde es> höchstwahrscheinlich nicht nehmen, da ich auf den I2C Bus gehen werde.
Hier mußt du dann tatsächlich den Dezimalpunkt komplett weglassen, damit
du wieder 2 Pins frei hast.
Einen I2C-Slave auf einem ATtiny aufsetzen, das ganze noch wenn ein
Timerinterrupt läuft, ist schon recht sportlich.
Mit Bitbanging I2C wirst du da (als Slave) nicht so weit kommen und das
ganze mit USI ist schlicht eine Qual.
Ein einziges Mal habe ich das gemacht gehabt (ATtiny44 als I2C-Slave),
auf dem ist aber kein Multiplex gelaufen und ich erinnere mich noch,
dass ich mir die Haare gerauft habe. Leider finde ich die Datei in
meinen Quellen nicht mehr.
Solltest du das hinbekommen, ist dir mein Respekt gewiss.
Heiner schrieb:> Henry hätte wohl mehr gelernt, wenn er das Programm selbst erstellt> hätte.>> So ist seine Eigenleistung gleich Null.>> Stichwort „Hilfe zur Selbsthilfe“ 🤷♂️
Hier könnte er als erstes einmal lernen, wie das Zusammenspiel von
Compiler, Präprozessor und Linker funktioniert. Das wäre auch sehr
hilfreich, wenn er weiter Programme aus dem Netz adaptieren möchte.
Dieses Zusammenspiel ist elementar und hat erst einmal nichts mit dem
Codieren zu tun. Hier könnte er lernen, wie er das Multiplexing in eine
.c / .h Kombination auslagern kann um sie bei Bedarf wieder zu
verwenden.
Da aber seine Entwicklungsumgebung unbekannt ist, kann man hier nicht so
wirklich helfen. Dem TO sei es aber angeraten sich dieses Zusammenspiel
einmal genauer anzusehen.
Ein steiniger, aber sehr lehrreicher Weg, ist es, das ganze auf der
Console zu tun und mittels Makefiles das zu realisieren.
Schauen wir einmal, was er hier noch so schreiben wird.
Ralph S. schrieb:> Da aber seine Entwicklungsumgebung unbekannt ist, kann man hier nicht so> wirklich helfen. Dem TO sei es aber angeraten sich dieses Zusammenspiel> einmal genauer anzusehen.
Es braucht nichts unbekannt zu sein.
Arbeite mit den Atmel Studio 7, oder vielleicht nennt es sich gerade
anders.
Dann verwende ich einen ICE (früher MK2), für erste Versuche einer
Schaltung ein Breadboard mit 5v Speisung. Ansonsten gern kleine Platinen
um SMD oder anderes zu nutzen. Kein Android oder ähnliches, lieber ganz
normales C. Habe als Prozessot bisher den Attiny84, Attiny2313, Atmega 8
und 32. Habe mir den Raspi angesehen, komme damit überhaupt nicht klar.
Erste Versuche mit einem SAM21 und 32 Bit. Meistens IO Ansteuerung, auch
TFT Farb Graphikdisplay. Habe dazu auch eigene h Datein geschrieben.
Handbuch "C von A-Z" liegt gleich neben den Tasten. Leider bin ich nicht
der Profi der kompexe Programme vollkommen selber schreiben kann. Aus
dieser Not herraus schaue ich gern auf andere Programme und versuche den
Ablauf zu begreiffen. Das erfordert teilweise mehr Wissen um das zu
verstehen. Nutze gern kleine Programme die frei sind um nicht jeden Tag
alles neu zu erfinden.
Schau verstärkt auf den I2C Bus. Der gefällt mir sehr gut. Sorry, bin
schon ein älteres Semester und alles dazu sebst gelernt, nichts
studiert.
So, das sind meine Daten zu dem Thema. Falls noch was unklar, einfach
fragen.
Ralph S. schrieb:> Einen I2C-Slave auf einem ATtiny aufsetzen, das ganze noch wenn ein> Timerinterrupt läuft, ist schon recht sportlich.
Ach, das geht recht gut mit dem USI. Der Master muß allerdings das
Clock-Stretching beherrschen. Aber das muß er immer, wenn der Slave ein
MC ist, der noch andere Tasks ausführt.
Bei längeren Leitungen kann es allerdings nachteilig sein, daß das USI
nicht die im I2C-Standard vorgeschriebenen Filter an den Eingängen hat.
Ich würde daher immer eine CRC über die I2C-Pakete machen.
Hallo!
Peter D. schrieb:>> Ach, das geht recht gut mit dem USI. Der Master muß allerdings das> Clock-Stretching beherrschen. Aber das muß er immer, wenn der Slave ein> MC ist, der noch andere Tasks ausführt.> Bei längeren Leitungen kann es allerdings nachteilig sein, daß das USI> nicht die im I2C-Standard vorgeschriebenen Filter an den Eingängen hat.> Ich würde daher immer eine CRC über die I2C-Pakete machen.
Ich denke nicht, dass der TO mit dem von Dir erwähnten Clock–Stretching
etc zurecht kommt, wenn ich sein Wissen bezgl C und den Prozessoren
betrachte.
Ohne vorgekautes Beispiel wird das nix
SCNR 😉
Grüße Heiner
Heiner schrieb:> Ich denke nicht, dass der TO mit dem von Dir erwähnten Clock–Stretching> etc zurecht kommt
Das Clock-Stretching macht der USI-Slave automatisch und ein korrekt
implementierter Master reagiert darauf automatisch, d.h. hält seinen
SCL-Takt solange an. Der Benutzer muß sich also nicht drum kümmern, man
sieht es nur auf dem Oszi (verlängerte Low-Zeiten).
Peter D. schrieb:> Das Clock-Stretching macht der USI-Slave automatisch
Und wenn alles sauber Programmiert ist löst die USI ein Interrupt aus
wenn das Datenpaket (Oder wen vorhanden der FIFO Puffer voll)
vollständig übertragen ist.
Das selbe gilt übrigens auch beim Master.
Peter D. schrieb:> Heiner schrieb:>> Ich denke nicht, dass der TO mit dem von Dir erwähnten Clock–Stretching>> etc zurecht kommt>> Das Clock-Stretching macht der USI-Slave automatisch und ein korrekt> implementierter Master reagiert darauf automatisch, d.h. hält seinen> SCL-Takt solange an. Der Benutzer muß sich also nicht drum kümmern, man> sieht es nur auf dem Oszi (verlängerte Low-Zeiten).Patrick L. schrieb:> Peter D. schrieb:>> Das Clock-Stretching macht der USI-Slave automatisch>> Und wenn alles sauber Programmiert ist löst die USI ein Interrupt aus> wenn das Datenpaket (Oder wen vorhanden der FIFO Puffer voll)> vollständig übertragen ist.>> Das selbe gilt übrigens auch beim Master.
Na, dann ist ja alles klar 😉
Und Henry kann mit der Implementierung beginnen - wobei ich mich
erinnere, dass schon mal jemand (hier!) versucht hat, eine I2C
Kommunikation von Attiny - Atmega128 (vergeblich?) zu implementieren und
dann wohl am besagten Clock-Stretching gescheitert ist…
Heiner schrieb:> dann wohl am besagten Clock-Stretching gescheitert ist…
Das muss speziell in der USI aktiviert werden.
Default ist Clock-Stretching disabled.
Möglich dass es in dem Thread wo du von Sprichst das Problem war. Kenne
den Thread nicht und kann deshalb auch nix zu sagen ;-)
Das hat alles noch Zeit. Habe erst noch ein paar andere Sachen vor.
Dachte dabei an einen Timer, Watchdoog, ADC und Porterweiterungen mit
Interrupt. Da habe ich noch einiges zu lernen.
Henry schrieb:> Das hat alles noch Zeit. Habe erst noch ein paar andere Sachen> vor.> Dachte dabei an einen Timer, Watchdoog, ADC und Porterweiterungen mit> Interrupt. Da habe ich noch einiges zu lernen.
Schau Dir mal die „Tuts“ von Achim S. (Bei makerconnect zu finden) an,
sind vielleicht interessant für Dich
Und lies ein gutes C Buch 😉
Ich nutze das Buch "C von A bis Z" von Jürgen Wolf. Das wurde mehrfach
hier als gut erwähnt. Brauche ich noch ein anderes.
Deinem Rat werde ich gern folgen.
Heiner schrieb:> (Bei makerconnect zu finden)
Habe mir die Seiten bzw. Tuts angesehen. Konnte leider zu 7-Segment
Anzeige nichts finden. Das mit dem Bus ist sehr interessant.
Also Henry!
Das mit den 7-Segmentanzeigen wurde Dir doch lang und breit HIER schon
erklärt, verstehen musst Du es schon selbst, Kollege!
Etwas Eigenleistung ist schon nötig 🤷♂️
Axel S. schrieb:> gleich in ein Forum rennen und die Leute dort belästigen.
Genau da ist das Problem. Das so mancher offenbar elitärer Kreis hier
sich belästigt fühlt.
:)
Ralph S. schrieb:>> (wobei sich mir der Sinn - und ich mache sehr viele>> sinnlose Sachen - nicht erschließt,
Joh, ok dein Code funktioniert ABER ist unnötig complex (da die Segmente
hier einzeln bearbeitet werden) und daher eher nicht size/speed/power
optimal.
Ich würde z.B. mit dem gezeigten Makro (oder den Code direkt verwenden)
#define WBITM(r,m,v) (((r)&((0xFF)^(m)))|((m)&(v))) // write bit mask
pro Ziffer (oder auch nur pro Wert, also dann 2 statt 4 Aufrufe) zwei
obige Port Anweisungen aufrufen. Für jedes Symbol (1-9, A-F) sind m
(mask) und v (value) für die zwei r (port register) via LUT definiert.
Weiters könnten inaktive Segment Port-Lines Tristate gesetzt werden, für
Power Save hins. der Porttreiber.
Und die Multiplex Freq wird nicht nur für Digits betrachtet/dynamisch
gesetzt sondern hins. der Anzahl der aktiven Segmente. Spart wieder
Power und die Ziffern sind immer alle gleich intensiv hell. Es lassen
sich so auch Anzeigen verwenden und ausgleichen, wo die Segmente bei
gleichen Strom unterschiedlich hell sind.
@Henry:
Vielleicht solltest du dich grundlegender mit bestimmten Techniken
beschäftigen? Ich weiß jetzt nicht, wo genau deine Probleme sind, den
Code zu verstehen, aber ich glaube (nach dem Blick in meine Glaskugel),
das du grundlegendes noch nicht verstanden hast und evtl. "zu hoch"
einsteigst. Du schreibst zwar von Timern und I2C Bus etc., aber ich
glaube du hast bisher einfach Code zusammenkopiert und verwendet (ohne
das Verständnis dafür zu haben).
Um "meinen" Code der 7-Segmentanzeige zu verstehen ist es von zentraler
Bedeutung, den Timerinterrupt zu verstehen und ich habe dir das einmal
vereinfacht. Solltest du das schon wissen was jetzt gleich kommt...
smile, dann war es halt von meiner Seite für umsonst.
Im folgenden Programm wird eine Leuchtdiode mittels Timerinterrupt zum
Blinken gebracht:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define F_CPU 8000000ul
5
6
// 1 << 6 = 0100 0000 bin = Maske fuer Bit Nr. 6 (von 0 an gezaehlt)
7
// ODER Verknuepfungen sind in der Lage ein Bit zu setzen
8
// UND - Verknuepfungen sind in der Lage ein Bit zu loeschen
9
// wird mit der negierten Masek einer ODER Verknuepfung eine
10
// UND - Verknuepfung vorgenommen, so wird das entsprechende Bit
Erklärungen:
-----------------------
F_CPU
-----------------------
Wichtig, sollte nirgendwo ein F_CPU definiert sein muß das in Zeile 4
gemacht werden, weil später beim Initialisieren des Timers genau diese
Angabe benötigt wird.
#define
-----------------------
Zeile 13 bis 17 ordnet der Verwendung der Portpins "sprechende" Namen
zu. led_init() ist aussagekräftiger als ein DDRA |= 0x40; Hier weiß man
sofort, dass der Anschluss initialisiert wird. Bei led_set() / led_clr()
ist es noch klarer. Das Makro sagt hier, dass der Anschlußpin auf 1 oder
0 gesetzt werden soll. Außerdem ist es sehr viel einfacher nur im
#define bspw. den Portpin zu ändern anstelle im gesamten Programm, vor
allen Dingen dann, wenn dieses setzen / rücksetzen mehr als einmal im
Programm benötigt wird.
timer1_init()
-----------------------
ist das Einstellen des Timer1 für seine Verwendung. Timer 1 kann in
mehreren Betriebsarten verwendet werden, hier wird er so eingestellt,
dass er einen automatischen Interrupt generiert. Hierdurch ist es
möglich, unabhängig von einem Main-Programm einen Programmaufruf zu
starten, der nicht explizit aufgerufen wird. Somit ist ein
"automatischer Intervallbetrieb" möglich. Im Vorliegenden Fall wird ein
Compare-Modus (Vergleichsmodus) verwendet. Ein interner 16-Bit breiter
Hardwarezähler wird automatisch hochgezählt. Der Zähler kann von
unterschiedlichen Taktquellen gespeist werden. Im vorliegenden Fall wird
er vom Prozessortakt gespeist (hier dann 8 MHz, die mittels den Fuses
eingestellt sind).
Bei einem 8 MHz Takt entspricht ein Taktzyklus einer Zeit von t = 1 / f
==> 1 / 8 MHz = 0,125 µS
Zeile 52 ist entscheidend dafür, wie häufig mein Interrupt (ISR)
aufgerufen wird und gibt somit den Intervall vor, mit dem
vollautomatisch der Interrupt gestartet wird. OCR1A ist ein 16-Bit
breites Vergleichsregister. Erreicht der Zählerstand in TCNT1 (ebenfalls
16-Bit breit) diesen Wert, wird der Interrupt ausgelöst. Im vorliegenden
Fall ergibt F_CPU / 200 = 8000000 / 200 den Wert 40000. Nach 40000
Zyklen also wird der Interrupt ausgelöst. Da ein Zyklus 0,125 µS lang
ist, erfolgt ein Auslösen nach 40000 * 0,125 µS = 5 mS.
ISR (TIM1_COMPA_vect)
--------------------------
Dieses ist die Interruptroutine, die nun alle 5 mS selbsttätig im
Intervall aufgerufen wird, egal wo sich das Hauptprogramm gerade
befindet.
Hier möchten wir eine LED blinken lassen.
In Zeile 27 wird eine Variable led_cnt als static definiert. Dieses
sorgt dafür, dass der Inhalt dieser Variable beim Beenden der
Interruptfunktion nicht verloren geht und beim nächsten Aufruf verfügbar
ist.
Nach dem 100sten Aufruf (100 x 5 mS = 0,5 S) wird die LED eingeschaltet,
beim 200sten Aufruf wieder ausgeschaltet und die Variable zu 0 gesetzt.
Dieses sorgt jetzt in dem Interrupt dafür, dass die LED blinkt.
main
------------------------
Im main Programm wird lediglich der Timer 1 für den Interrupt
(Intervallbetrieb) sowie der Anschluß der LED initialisiert. Danach
folgt in Zeile 67 eine Endlosschleife while(1);
"Eigentlich" dürfte das Programm nun gar nichts tun, weil in der
Endlosschleife keine Anweisungen stehen. Allerdings wird diese
Endlosschleife im Intervall unterbrochen und die Interruptroutine (mit
dem LED-Blinken) ausgeführt.
------------------------------------------------------
So, sollte ich dich damit gelangweilt haben, tut mir das leid, wenn
nicht, ist es für dich vllt. Interessant diesen Ablauf zu verstehen.
Genau dieses Vorgehen wird bei der Ansteuerung der gemultiplexten
Anzeige verwendet: Der Interrupt bedient die Anschlußleitungen der
7-Segmentanzeigen.
Analog hierzu kann man bspw. den Interruptbetrieb dahingehend
modifizieren, dass man die Blinkdauer der LED aus dem Hauptprogramm
modifizieren könnte:
1
uint8_t led_an = 100;
2
uint8_t led_aus = 200;
3
4
ISR (TIM1_COMPA_vect)
5
{
6
static uint8_t led_cnt = 0;
7
8
led_cnt++;
9
if (led_cnt == led_an) led_set();
10
if (led_cnt == led_aus)
11
{
12
led_clr();
13
led_cnt= 0;
14
}
15
}
16
17
int main(void)
18
{
19
timer1_init();
20
led_init();
21
22
led_an= 10;
23
led_aus= 250;
24
while(1);
25
}
Hier wurden jetzt 2 zusätzliche Variable eingeführt, led_an und led_aus.
Mittels dieser beiden Variablen ist es möglich das Blinkverhalten im
Interrupt zu beeinflussen. Ein bloßes Zuweisen von Werten an diese
Variable im main Programm bestimmt die Pulse- und Pausezeiten der
Leuchtdiode, ohne auf den Port der LED direkt zuzugreifen. Alles
geschieht im Intervall. Analog hierzug gilt im übertragenen Sinne bei
der 7-Segmentanzeige, dass lediglich der Inhalt des Framebuffers
geändert werden muß, das Anzeigen alleine geschieht im Interrupt.
Ralph S. schrieb:> Apollo M. schrieb:>> #define WBITM(r,m,v) (((r)&((0xFF)^(m)))|((m)&(v))) // write bit mask>> ... und du bist dir sicher dass der TO das versteht ?
+ 1 😉
Ralph S. schrieb:> ... und du bist dir sicher dass der TO das versteht ?
Eher so - Ich bin mir jetzt nicht sicher, ob du das verstehst, weil das
war für dich war!
Apollo M. schrieb:> Eher so - Ich bin mir jetzt nicht sicher, ob du das verstehst, weil das> war für dich war!
Ich habe es schon verstanden gehabt, aber um mich gehts hier ja nicht !
Versuche es mal in ein paar meiner Worte zu sagen:
Ralph S. schrieb:> #define MASK (1 << 6)> #define led_init() DDRA |= MASK> #define led_set() PORTA |= MASK> #define led_clr() PORTA &= ~ MASK
Du definierst eine Maske
- Bit 6 von PORT A
- vom DDRA
- PORTA |= - einschalten
- PORTA &= - ausschalten
- Es wird Timer 1 verwendet
- auf 5ms (hab allerdings noch nicht nachgerechnet)
Ralph S. schrieb:> ISR (TIM1_COMPA_vect)> {> static uint8_t led_cnt = 0;> led_cnt++;> if (led_cnt == 100) led_set();> if (led_cnt == 200)> {> led_clr();> led_cnt= 0;> }> }
Die ISR wird unabhängig vom restlichen Programm alle 5 ms aufgerufen.
Das Programm wird danach automtisch an der letzten Stelle weiter
ausgeführt.
In der ISR schaltest du die LED die du in der Maske zugewiesen hast.
Zählvariable ist dabei led_cnt, wird zu Anfang auf 0 gesetzt.
led_cnt zählt bei jedem Durchlauf 1 hoch.
Mit led_cnt == sind Schaltpunkte definiert, 100 ein, 200 aus.
Bei 200 wird auch led_cnt auf 0 gesetzt. Und das ganze beginnt von vorn.
Hoffe das ich es richtig zusammengaêfasst habe.
So was ähnliches verwende ich selbst bei Muktitasking.
1
#define F_CPU 16000000UL // Angabe der Quarzfrequenz, wichtig für die Zeit
Hab gerade gesehen das auch ein paar Fehler drin sind oder anders besser
geht. Habe es nach der Anleitung von Falk gemacht. Es gibt ein Tut dazu
im Wissen. Dazu gibt es dann noch verschiedene Abwandlungen dazu.
Das nächste Programm war eine "Einknopfbedienung" mit Encoder und
Tasterentprellung nach Peter.
Möchte nur damit zeigen das mir ein Interrupt nicht fremd ist.
Apollo M. schrieb:> #define WBITM(r,m,v) (((r)&((0xFF)^(m)))|((m)&(v))) // write bit mask
Das ist mir im Moment zu hoch, muss erst es auseinder nehmen.
Ich folge deinen Erklärungen ganz genau, lese die einzelnen Programme
genau. Meistens sind einige Eigenarten der einzelnen Kollegen drin, die
ich so nicht kenne, aber gut sind. Warum soll man nicht dazu lernen.
Wenn ich meine früheren Codes betrachte und die von heute sind da auch
deutliche Unterschiede drin.
Nimm einafch als Beispiel die Tasterentprellung von Peter. Ich kann
nicht sagen wie es genau funktioniert, Das geht aber auch andern so,
habe eine komplette Erklärung zu liegen, kann es anwenden und anpassen
und es funktioniert. Das ist schon recht kompliziert für mich. Es
fordert aber die grauen Zellen heraus.
Nochmal, lese alles was du schreibst mit sehr grossen Intresse, lerne
gern von andern und bin aus der Zeit nur In und Out zu schalten raus.
Henry schrieb:> So was ähnliches verwende ich selbst bei Muktitasking.>
Na jetzt bin ich aber platt! "Muktitasking" (meinst wohl "Multitasking")
- wenn Du Dich DAMIT beschäftigst bzw "verwendest", dann verstehe ich
aber Deine bisherigen Probleme nicht - oder willst Du hier die Leser
verar**???
Und Dein Hinweis auf Peter's Tastenentprellung (Du meinst wohl "Peda"
Peter Danneger?) - Du verstehst sie zwar nicht, wendest sie aber an -
wow!
Bei dem hier:
((r)&((0xFF)^(m))
könntest du es besser sehen wenn hier stehen würde:
((r) & ~(m))
Zu sehen ist hier eine UND-Verknüpfung mit m. In m wird jedes einzelne
Bit invertiert. Somit werden die Bits in r gelöscht, die durch m
maskiert sind.
Der Hintergrund:
Das ^ Zeichen bedeutet in C eine Exclusive-ODER Verknüpfung. Eine
Exclusive-Oder Verknüpfung nimmt man bspw. auch gerne in FPGAS um
steuern zu können, ob ein einzelnes Bit invertiert wird oder nicht.
Bsp.:
1
Bitnr.: 7 6 5 4 3 2 1 0
2
-----------------------------
3
0xff = 1 1 1 1 _ 1 1 1 1
4
Maske_org = 1 1 0 0 _ 0 0 0 0
5
------------------------------
6
XOR
7
------------------------------
8
Maske_neu = 0 0 1 1 _ 1 1 1 1
9
r_org = 1 1 1 0 _ 1 0 1 0
10
------------------------------
11
UND
12
------------------------------
13
r_neu = 0 0 1 0 _ 1 0 1 0
Wie du oben sehen kannst, werden aus r die oberen beiden Bits (Nr.7 und
Nr. 6) geloescht, alle anderen bleiben unverändert.
--------------------------------------------------
Zu deinen Programmen:
1
void led_blinken1()
2
{
3
led1++;
4
if(led1==300)
5
{
6
PORTA &= ~(1<<PA6); // Schaltet Pin
7
PORTA |= (1<<PA7); // Schaltet Pin
8
}
9
else
10
{
11
if(led1==600)
12
{
13
PORTA |= (1<<PA6); // Schaltet Pin
14
PORTA &= ~(1<<PA7); // Schaltet Pin
15
led1=0;
16
}
17
}
Das ist einfach nicht schön zu lesen und aus den Kommentaren "Schaltet
Pin" wird man später nicht wirklich schlau (zumindest dann nicht, wenn
es etwas komplexer wird als nur LED blinken zu lassen). Dein Programm
stellt einen Wechselblinker dar, welches 2 LEDs im Wechsel blinken läßt.
Schöner (und besser leßbar) sieht es dann so aus (ich nenen die LEDS
jetzt mal leda und ledb weil du den Namen led1 schon für den Zähler
verwendet hast):
1
// statt (1 << PA6) kann man auch (1 << 6) schreiben, da irgendwo in den defines der
2
// Header zum avr_gcc stehen muß: #define PA6 (1 << 6)
3
4
#define leda_set ( PORTA |= (1 << PA6) )
5
#define leda_clr ( PORTA &= ~(1 << PA6) )
6
7
#define ledb_set ( PORTA |= (1 << PA7) )
8
#define ledb_clr ( PORTA &= ~(1 << PA7) )
9
10
void led_blinken1()
11
{
12
led1++;
13
if(led1==300)
14
{
15
leda_clr();
16
ledb_set();
17
}
18
else
19
{
20
if(led1==600)
21
{
22
leda_set();
23
ledb_clr();
24
led1=0;
25
}
26
}
Dieses macht die ganze Sache übersichtliche und wenn das Setzen /
Rücksetzen mehr als einmal benötigt wird, erspart es Schreibarbeit und
erleichtert zudem, an Controller angeschlossene Einheiten besser
abzuändern.
Ralph S. schrieb:> Bei dem hier:>
Deine Geduld (oder Selbstdarstellung) ist bewundernswert
Das weiß doch der Henry alles schon
Aber wenn's Dir ein gutes Gefühl gibt - weiter so!
Heiner schrieb:> Deine Geduld (oder Selbstdarstellung) ist bewundernswert
okay... dann halte ich mich zurück, der TO soll, wenn er ernsthaft
Fragen hat PN schreiben, dann ist hier niemand mehr belästigt !
Ralph S. schrieb:> Heiner schrieb:>> Deine Geduld (oder Selbstdarstellung) ist bewundernswert>> okay... dann halte ich mich zurück, der TO soll, wenn er ernsthaft> Fragen hat PN schreiben, dann ist hier niemand mehr belästigt !
Das hat mit Belästigen nichts zu tun, sondern mit der Bequemlichkeit, ja
fast geistigen Trägheit (no offence!) des TO - wenn er, wie er selbst
schreibt, Multitasking und Peda's Tastenentprellcode verwendet, dann
sollte er auch die hier reingestellten Programme verstehen (auch die,
die er selbst reingestellt hat), OHNE dass man sie ihm Bit für Bit
vorkauen muss - und genau das machst Du.
Nix für ungut!
SCNR
Heiner schrieb:> Das weiß doch der Henry alles schon>> Aber wenn's Dir ein gutes Gefühl gibt - weiter so!
Leider weiss Henry nicht alles. Sonst würde ich nicht diese Fragen
stellen.
Gerade der Anschluss auf 2 Ports bereitet mir grosse Problem. Hatte
bereits einige Programme dazu geschrieben (stehen oben) um Segmente zu
testen.
Leider ist es in diesem Forum Standart geworden mit vielne Worten nichts
zu sagen. Es gibt immer wieder Leute die es einen nicht zutrauen was
allein zu machen. Wie will man einem Anfänger/Amateur die Freude an
erreichten machen wenn man keine Hilfe bekommt. Mit Grundlagen
anzufangen ist schon gut. Doch schnell kommt man zu Problemen die man
kaum allein vernünftig gelöst bekommt.
Henry schrieb:> Habe das Programm etwas hübscher gemacht.
wenn doch überall
Henry schrieb:> switch(number)> {> case 1:> clearsegment();
wenn in jedem case und auch im default clearsegment(); aufgerufen wird,
kannst du es auch einmal vor switch(number) aufrufen, dann muss es nicht
im switch stehen!
MaWin schrieb:> Nicht multiplexen, aber 2 Ziffern statisch angesteuert an einem ATmega8,> Segmente der 1er und 10er Stelle auf PortD und PortB verteilt wie es> sich ergab:
Bist du da noch unter den 200mA/device?
Davon gibt's noch mehr. Direkt und auch PT6xxxx und andere NEC
kompatible für LEDs+VFDs.
Auch mit "mehr-benutzung" von progmem müsste irgendwo liegen. Das fang
ich jetzt auf Anhieb nicht.
Interesse? Dann guck ich demnächst durch und poste es.
Heiner schrieb:> Hallo Ida O> zu Deinem Code - was soll denn: PORTB++;> in Zeile 68 bewirken??> Kommentare wären auch nicht schlecht!
Portb ist mit 0x0F als Ausgang, da waren 4 einzelne LEDs dran, die
einfach nur mit blinkten. Da an der anderen 4 Bits nichts angeschlossen
war habe ich einfach nur PORTB++ gemacht.
Ich hatte mal so nen Splin überall 7-Segment Anzeigen zu verteilen. Da
nahm ich immer einer Anzeige, hab so ein Grunggerüst zusammmengezimmert
und dann irgendwelche Nachrichten für meine Freundin in
"7-Segment-Speak" da drauf laufen lassen.
Da gibt's keine Kommentare zu und jetzt, teilweise Jahre später, fange
ich nicht an das extra zu kommentieren. Wenn noch mehr Fragen
auftauchen, dann erklär' ich es gern.
Heiner schrieb:> Hallo Ida O>> Und generell könnteste das MPX_DIG auch in ein Array schreiben und wie> das andere Array behandeln, dann wäre der Code entsprechend kürzer
Ja, ich weiss, das meinte ich mit "mehr benutzung" von PROGMEM.