Guten Abend zusammen,
ich habe vor kurzem meine ersten Schritte mit dem Arduino uno rev3
gewagt und bin jetzt auf ein Problem gestoßen, für dessen Lösung mir der
Ansatz fehlt.
Grundsätzlich möchte ich gesteuert durch Kommunikation über die serielle
Schnittstelle LEDs anschalten können. Wenn 3 Sekunden nicht der "Befehl"
kommt andere LEDs zu schalten, sollen aktuell noch leuchtende LEDs
ausgeschalten werden.
Ich habe jetzt eine Lösung die genau das tut (es handelt sich dabei um
den ersten "c Code" den ich je geschrieben habe, also habt erbarmen. Man
sieht ihm meine Java Wurzeln vermutlich sehr an):
. Ursprünglich wollte ich es, aus Interesse und weil ich das ganze
primär mache um zu lernen, selber mit dem Timer1 und einem Overflow
Interupt machen.
Das sieht dann bei mir so aus:
1
#include<Wire.h>
2
3
constuint8_tBUFLEN=20;
4
charreadData[BUFLEN];
5
intcurrentIndex=0;
6
7
constchar*INIT_COMMAND="re";
8
constchar*TABLE_LAYOUT_COMMAND="tl";
9
constchar*HIGHLIGHT_BOX_COMMAND="hb";
10
constchar*DELIMITER="|";
11
12
charc;
13
intpin_indices[]={9,8,7,6,5,4,3,2};
14
15
voidsetup(){
16
for(inti=0;i<sizeof(pin_indices);i++){
17
pinMode(i,OUTPUT);
18
}
19
clearReadData();
20
21
TCCR1A=0;
22
TCCR1B=0;
23
TCCR1B|=(1<<CS10);
24
TCCR1B|=(1<<CS12);
25
26
Serial.begin(9600);
27
while(!Serial){
28
// wait
29
}
30
}
31
32
voidresetTimer()
33
{
34
noInterrupts();
35
36
TCNT1=18661;
37
TIMSK1|=(1<<TOIE1);
38
39
interrupts();
40
}
41
42
ISR(TIMER1_OVF_vect)
43
{
44
resetLEDs();
45
TIMSK1&=~(1<<TOIE1);
46
}
47
48
voidresetLEDs()
49
{
50
for(inti=0;i<sizeof(pin_indices);i++){
51
digitalWrite(i,LOW);
52
}
53
}
54
55
voidsetLEDs(byteinput)
56
{
57
for(inti=0;i<sizeof(pin_indices);i++){
58
bytemask=1<<i;
59
60
if(mask&input){
61
digitalWrite(pin_indices[i],HIGH);
62
}else{
63
digitalWrite(pin_indices[i],LOW);
64
}
65
}
66
}
67
68
voidclearReadData(){
69
for(inti=0;i<BUFLEN;i++){
70
readData[i]='\0';
71
}
72
currentIndex=0;
73
}
74
75
voidprocessReadData()
76
{
77
char*token;
78
token=strtok(readData,DELIMITER);
79
80
if(token!=NULL){
81
if(strcmp(token,INIT_COMMAND)==0){
82
Serial.write("bin\n");
83
return;
84
}
85
86
if(strcmp(token,HIGHLIGHT_BOX_COMMAND)==0){
87
token=strtok(NULL,DELIMITER);
88
setLEDs(atoi(token));
89
resetTimer();
90
}
91
}
92
}
93
94
voidloop(){
95
while(Serial&&Serial.available()>0){
96
c=Serial.read();
97
if(c=='\n'){
98
processReadData();
99
clearReadData();
100
}else{
101
readData[currentIndex]=c;
102
103
if(currentIndex<BUFLEN-1){
104
currentIndex=currentIndex+1;
105
}
106
}
107
}
108
}
Allerdings funktioniert das nicht. Die LEDs werden nie ausgeschaltet.
Ich habe dann eine Menge Dinge probiert und kam dann irgendwann auf den
Trichter, dass das vielleicht irgendwie mit der Kommunikation über die
serielle Schnittstelle zu tun hat, da diese wohl auch interrupts benutzt
(?). Ich habe dann eine Variante gebaut, die sowas ähnliches wie die 2.
Variante macht, nur ohne dabei Serial zu benutzen und tatsächlich hat
das dann funktioniert:
1
intcurrentIndex=0;
2
intpin_indices[]={9,8,7,6,5,4,3,2};
3
4
voidsetup(){
5
for(inti=0;i<sizeof(pin_indices);i++){
6
pinMode(i,OUTPUT);
7
}
8
9
TCCR1A=0;
10
TCCR1B=0;
11
TCCR1B|=(1<<CS10);
12
TCCR1B|=(1<<CS12);
13
}
14
15
voidresetTimer()
16
{
17
noInterrupts();
18
19
TCNT1=18661;
20
TIMSK1|=(1<<TOIE1);
21
22
interrupts();
23
}
24
25
ISR(TIMER1_OVF_vect)
26
{
27
resetLEDs();
28
TIMSK1&=~(1<<TOIE1);
29
}
30
31
voidresetLEDs()
32
{
33
for(inti=0;i<sizeof(pin_indices);i++){
34
digitalWrite(i,LOW);
35
}
36
}
37
38
voidsetLEDs(byteinput)
39
{
40
for(inti=0;i<sizeof(pin_indices);i++){
41
bytemask=1<<i;
42
43
if(mask&input){
44
digitalWrite(pin_indices[i],HIGH);
45
}else{
46
digitalWrite(pin_indices[i],LOW);
47
}
48
}
49
}
50
51
voidloop(){
52
delay(1);
53
if(currentIndex%5000==0||currentIndex%7000==0){
54
resetTimer();
55
resetLEDs();
56
setLEDs(currentIndex);
57
}
58
59
currentIndex++;
60
}
Wisst ihr, was in der 2. Variante falsch läuft? Wenn das Problem kein
einfacher Fehler in meiner Logik ist sondern irgendwie damit
zusammenhängt das Serial irgendwie den Timer1 benutzt/manipuliert, dann
reicht mir ein Stubs in die richtige Richtung.
Besten Dank für das Lesen bis hierher.
Schönen Abend noch (:
TrudelStrudel schrieb:> Ich habe jetzt eine Lösung die genau das tut (es handelt sich dabei um> den ersten "c Code" den ich je geschrieben habe, also habt erbarmen. Man> sieht ihm meine Java Wurzeln vermutlich sehr an):
Und scheinbar auch dein erster Forumsbeitrag? Lange Quelltexte gehören
in den Anhang!
Ohje das stimmt wohl.
Interessant, dass mir das bei den "funktionierenden" Varianten nicht
aufgefallen ist.
Aber auch wenn ich das korrigiere funktioniert die 2. Variante, also die
mit Timmer und Serial, nicht.
for (int i = 0; i < sizeof(LED_PINS); i++) {
pinMode(i, OUTPUT);
}
Hier fehlt das auch. Hier ist es drin.
void setLEDs(byte input)
{
for (int i = 0; i < sizeof(LED_PINS); i++) {
byte mask = 1 << i;
if (mask & input) {
digitalWrite(LED_PINS[i], HIGH);
} else {
digitalWrite(LED_PINS[i], LOW);
}
}
lastLEDsOn = millis();
}
Das ist ja hochgradig verwirrend.
Wie konnte das denn bisher funktioniert haben?!
Noch irritierender ist, dass es jetzt noch Korrektur nicht mehr
funktioniert. Aber das schaue ich mir morgen weiter an. Vielen Dank
schon mal.
TrudelStrudel schrieb:> Das ist ja hochgradig verwirrend.> Wie konnte das denn bisher funktioniert haben?!
Ganz einfach, deine Schleife geht von 0-7, deine Pins von 2-9, da gibt
es ein paar Überschneidungen.
Falk B. schrieb :
> Ganz einfach, deine Schleife geht von 0-7,
Das stimmt nicht, sie geht von 0 bis 15
TrudelStrudel schrieb:
> sizeof(pin_indices)
Ist doppelt so groß wie das Array.
Abhilfe:
int pin_indices[] = {9, 8, 7, 6, 5, 4, 3, 2}; // falsch
constexpr byte pin_indices[] {9, 8, 7, 6, 5, 4, 3, 2}; // besser
TrudelStrudel schrieb:> (es handelt sich dabei um> den ersten "c Code" den ich je geschrieben habe,
Das glaube ich dir nicht, denn das ist C++ (auch wenn du das noch nicht
weißt)
TrudelStrudel schrieb:> for (int i = 0; i < sizeof(pin_indices); i++) {> pinMode(i, OUTPUT);> }
Alternativ:
1
constexprbytepin_indices[]{9,8,7,6,5,4,3,2};
2
for(constbytepin:pin_indices)pinMode(pin,OUTPUT);
Dank des "range based for loop" kann es auch keine
Bereichsüberschreitung beim Arrayzugriff geben.
Hallo,
dein Timer 1 wird sicherlich nicht das machen was du denkst. Die Timer
werden für PWM (analogWrite) im Hintergrund voreingestellt. Timer 0 für
millis. Das heißt, möchte man einen Timer selbst konfigurieren, muss man
alle Timerregister löschen oder durch direkte Zuweisung überschreiben.
Nur verodern läuft schief. Dann bleiben die bisherigen gesetzten Bits
erhalten. Ich habe mir angewöhnt erstmal alles zu löschen und dann neu
zu konfigurieren. Dabei kann man ohne Gefahr verodern |=. Ich fange beim
konfigureren immer mit dem stoppen des Timers an, hier Register TCCR1B.
Bsp.
1
#include<util/atomic.h>
2
...
3
4
voidpreSetTimer1(void)// Voreinstellungen, läuft noch nicht los
5
{
6
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
7
{
8
TCCR1B=0;// Resets
9
TCCR1A=0;//
10
TIMSK1=0;//
11
TCNT1=0;//
12
OCR1A=COMPAREvalue;
13
OCR1B=COMPAREvalue/2;
14
TCCR1A=_BV(COM1B0)|_BV(COM1A0);
15
TCCR1B=_BV(WGM12);
16
}
17
}
18
19
voidrunTimer1(constunsignedintprescaler)
20
{
21
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
22
{
23
switch(prescaler){
24
case1:TCCR1B|=_BV(CS10);break;
25
case8:TCCR1B|=_BV(CS11);break;
26
case64:TCCR1B|=_BV(CS11)|_BV(CS10);break;
27
case256:TCCR1B|=_BV(CS12);break;
28
case1024:TCCR1B|=_BV(CS12)|_BV(CS10);break;
29
default:break;
30
}
31
}
32
}
33
34
voidstopTimer1(void)
35
{
36
ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
37
{
38
TCCR1B&=~(_BV(CS12)|_BV(CS11)|_BV(CS10));
39
}
40
}
Edit:
In welchen Modus soll dein Timer überhaupt laufen? Was soll er bewirken?
Hallo,
mach einmal das hier:
In der IDE alle Ausgaben einschalten.
Datei > Voreinstellungen >
- Ausführliche Ausgabe während > beide Haken rein
- Compilerwarnungen > "ALLE"
Zeilennummern und Codefaltung sind auch hilfreich.
Speichern beim Überprüfen und Hochladen würde ich abschalten.
Veit D. schrieb:> Das heißt, möchte man einen Timer selbst konfigurieren, muss man> alle Timerregister löschen oder durch direkte Zuweisung überschreiben.
Macht ihm ja...
Zumindest die wichtigen beiden Kontrollregister.
TrudelStrudel schrieb:> TCCR1A = 0;> TCCR1B = 0;> TCCR1B |= (1 << CS10);> TCCR1B |= (1 << CS12);
Sieht zumindest für mich so aus.
Veit D. schrieb:> In welchen Modus soll dein Timer überhaupt laufen? Was soll er bewirken?
Das würde mich auch interessieren.
Hallo,
das TIMSK1 Register wird nicht gelöscht und mit dem TOIE1 Bit "nur"
verodert. Müßte man testen ob da noch ein Bit gesetzt ist und ob dadurch
etwas stört.
Beim Timersetting habe ich herausgefunden das es der 3s Timer sein soll.
Prescaler 1024 im Normal Modus. Hier wird das Interrupt Bit TOIE1
gelöscht zum abschalten und zusammen mit dem Counter Startwert wieder
gesetzt. Sollte eigentlich keine Probleme machen, auch wenn ich den
Timer stoppen/starten würde. Vielleicht statt gezieltes Bit löschen
TIMSK1 = 0 ganz löschen.
Was man noch ändern sollte wäre
1
while(Serial&&Serial.available()>0){
2
in
3
while(Serial.available()>0){
4
5
undcharclokalmachen.
und statt ständig die Größe ermitteln entweder einmal ermitteln oder
fest einsetzen und überall anwenden.
Ansonsten sehe ich aktuell auch noch nicht das große Problem. Da hilft
nur Sketchrückbau und die Timergeschichte und Einlesegeschichte getrennt
zu testen. Aktuell fällt mir kein Grund ein warum irgendein Timer die
Serielle stören sollte.
Bekommst du mit dem asm Dump auch DWARF Errors?
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 15ee
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 15fa
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 1606
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 1612
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 161e
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 162a
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 1636
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 1642
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 164e
C:\avrToolchain\avr-gcc-10.2.0_mingw64_binutils2.35/bin/avr-objdump:
DWARF error: could not find variable specification at offset 165a
Auch wenn ich den Sketch korrigiere damit er keine Warnungen mehr wirft
kommen genau die gleichen DWARF Errors. Kompiliere ich irgendwas anderes
gibts keine DWARF Errors.
Veit D. schrieb:> das TIMSK1 Register wird nicht gelöscht und mit dem TOIE1 Bit "nur"> verodert. Müßte man testen ob da noch ein Bit gesetzt ist und ob dadurch> etwas stört.
Das Register ist 0.
Arduino fasst das nicht an.
Veit D. schrieb:> Bekommst du mit dem asm Dump auch DWARF Errors?
Nicht getestet.
Aber da der Index fürchterlich aus dem Ruder läuft, sind wir im Bereich
des UB, und darum darf das auch passieren.
Nachtrag
Eine schnelle Suche sagt:
> error::dwarf - dwarf debuginfo quality problems ...> If a script requires such data, but the compiler did not> preserve enough of it, pass-2 errors may result.
Passt also irgendwie schon, die Meldung.
Hallo,
Timer, okay alles klar. Danke.
Die Indexe hatte ich korrigiert, dennoch DWARF Errors. Habe dann solange
alles rausgehauen bis das weg war. Am Ende liegst am Wire.h include.
Irre. Benötigt der TO sowieso nicht.
Getestet:
Du hast recht, nach korrigiertem Index schimpft der 10.2.0, bzw. die
binutils2.35, auch bei mir.
avr-gcc-10.1.0 und die Vorgänger zeigen das "Wire" Problem nicht.
Nagut...
Werde Wire mal (irgendwann) daraufhin untersuchen, wo/ob es da
klemmt.....
Befürchte allerdings, dass eher avr-objdump oder die *.elf Erzeugung
wackelt.
Hallo zusammen.
erstmal vielen Dank für die vielen guten und hilfreichen Tipps.
Nachdem ich jetzt die ganzen Indexgeschichten korrigiert habe, läuft es
auch mit Timer + Serial und ich habe eine Menge gelernt (: