Forum: Mikrocontroller und Digitale Elektronik AVR ATTiny13A Problem mit Servo + LED-Ansteuerung


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Kai W. (chilibit)


Angehängte Dateien:

Lesenswert?

Hallo liebes Forum,
ich hoffe ihr könnt mir weiterhelfen, da ich nach vielen vergeblichen 
Teststunden nicht mehr weiterweiß. Eigentlich sollte mein Vorhaben recht 
einfach sein...

Ziel: 4x 2xLEDs "zufällig" an/aus-schalten und einen Servo ebenfalls 
"zufällig" einen kurzen hin-und-her-Zyklus (Endstellungen) durchlaufen 
lassen.

Problem: Wenn alle LEDs-Codeabschnitte akiv sind, flackern die LEDs 2-4 
(scheinbar unregelmäßiges 2ms und 3,5 ms-An/aus). LED 1 flackert zwar 
nicht, hat aber einen falschen Takt (8, 18 Sek....) und der Servo wird 
zwar synchron zur LED 3 angesteuert, aber nur mit einem 1ms-Signal 
anstatt eines Zyklus (Soll:1ms, 1 Sek. warten, ~2ms).
Wenn nur der Code für die LED 3 (inkl. Servoaktivierung) aktiv ist, 
funktioniert es.

Vermutung: Da ich den Schaltungsaufbau & myC und Fuses bereits 
erfolgreich mit einem nur 
4-LEDs-"zufällig"-an/ausschalten-lassen-Programm und einem 
Servo-Testprogramm (sekündlich zwischen Endstellungen umschalten) 
verwendet habe, verdächtige ich diese eher nicht.
Ich vermute, dass ich bei meiner Timer-Konstruktion etwas nicht 
beachtet/falsch gemacht habe oder dass es im myC irgendwelche 
Abhängigkeiten gibt, die mir nicht bewusst sind. Das Servosignal 
funktioniert prinzipiell mit 1+16 ms ganz gut. Trotzdem habe ich den 
Verdacht, dass beim Takt/Teiler etc. ggf. etaws nicht stimmt. Mit dem 
Datenblatt habe ich mich zwar bereits recht intensiv bei der 
Timer-Programmierung beschäftig, aber ich hoffe, dass ihr mir noch 
hilfreiche Tipps geben könnt.
MfG
Chilibit

myC: ATTiny 13A

Zu mir: ambitionierter Anfänger, habe aber schon 2 andere Projekte mit 
dem  13A umgesetzt (aber noch nichts mit Servos) ;-)

Servo: no name...

Ich habe Bilder der Fuses, Signalen an den Ausgängen und der Schaltung
angehängt.

Microchip Studio 7.0.2594

Program Memory Usage:  540 bytes   52,7 % Full
Data Memory Usage:  59 bytes   92,2 % Full

Programm:
1
#define F_CPU 9600000  //CPU auf 9,6MHz
2
#include <avr/io.h>
3
#include <stdlib.h>
4
#include <avr/interrupt.h>
5
6
//Augen-Zeitvariablen:
7
uint8_t zeitAugenFst=0;
8
uint8_t zeitAugenEinsSek=0;
9
uint8_t zeitAugenZweiSek=0;
10
uint8_t zeitAugenDreiSek=0;
11
uint8_t zeitAugenVierSek=0;
12
13
//Servo-Code:  
14
  uint8_t phase=0;
15
  uint8_t ZeitZaehlerServo=0;
16
  // Timer ist übergelaufen (alle 0,213ms (=256*0,000833ms)), neue Phase beginnt (?? Irgendwie fehlt hier noch der Faktor 10x um auf 17ms zu kommen?!)
17
  // Jede 8. Phase (~17,1ms) wird PB0=1 gesetzt und dann bei Erreichen des Vergleichswertes (OCR0A in der Main-Schleife löst "ISR(TIM0_COMPA_vect)" aus),s.u., wieder auf 0 gesetzt
18
  ISR(TIM0_OVF_vect)
19
  {
20
    // Servo nur in Phase 0 ansteuern
21
    if (phase==0)
22
    {
23
      PORTB |=(1<<PB0); //Servo-Signal an
24
      
25
      ZeitZaehlerServo = ZeitZaehlerServo+1;  //alle 8 Phasen (17 ms) eins hochzählen
26
      
27
      //Reduziere alle Zeitvariablen um 1 (59 => 0,97Sek)      
28
      zeitAugenFst = zeitAugenFst+1;
29
      
30
    }
31
    
32
    phase = phase+1; // Nächste Phase 1... 2...8 => 0
33
    if (phase > 8)  
34
    {
35
      phase=0;      
36
    }
37
  }
38
39
  // Timer hat Vergleichswert erreicht
40
  ISR(TIM0_COMPA_vect)
41
  {
42
    PORTB &= ~(1<<PB0); //Servo-Signal aus (=>~ 1 - 2 ms)
43
  }
44
  
45
46
47
uint8_t laufZeit=0;
48
uint8_t servoZyklus=0;
49
//Zur Info: Max-Werte für Zeit: 245 (x+10<256), Anzahl: 50
50
//const unsigned char zeitWerteSekundaer[50] = {52, 99, 167, 3, 55, 22, 119, 27, 153, 85, 22, 10, 103, 48, 24, 124, 11, 7, 57, 120, 47, 77, 138, 79, 20, 116, 52, 5, 191, 8, 153, 26, 72, 64, 18, 185, 30, 12, 3, 129, 112, 17, 197, 89, 15, 107, 2, 61, 164, 79};
51
const uint8_t zeitWerteSekundaer[50] = {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2};
52
53
uint8_t zufallsZeitWert();
54
55
int main(void)
56
{      
57
  //Servo-Code
58
    cli(); // Loesche globales Interruptflag
59
    //Setzen der Register fuer 20 ms Timerinterrupt
60
    TCNT0 = 0; //Loesche Timer Counter 0
61
    // Starte Timer 0 im Fast PWM Modus mit Prescaler 256
62
    TCCR0A=0;   //Loesche Timer Counter Controll Register A
63
    TCCR0A |= (1<<WGM01) | (1<<WGM00); //=> Fast PWM
64
    TCCR0B=0;   //Loesche Timer Counter Controll Register B
65
    TCCR0B |= (1<<CS01);  //=>Prescaler 8
66
    //TCCR0B |= (1<<CS02);  //=>Prescaler 256
67
    // Erlaube Interrupts
68
    //Timer/Counter Interrupt Mask Register:
69
    TIMSK0=0;
70
    TIMSK0 |= (1<<OCIE0A) | (1<<TOIE0);
71
    sei();    //Setzen des globalen Interrupt-Enable-Bit
72
    //DDRB   = 0x1f;                    // Eingänge: Reset PB5; Ausgänge: PB0-PB4 (0: Servo; 1-4: LED-Augen 1-4)
73
    DDRB |= (1<<PB4) + (1<<PB3) + (1<<PB2) + (1<<PB1) + (1<<PB0);
74
75
76
77
  while (1) 
78
    {      
79
    //Zeitabfrage Augen 1 bis 4 (Servo mit Auge-3-Anschaltung synchronisiert)    
80
    if(zeitAugenFst>59){ //Sekundentaktgeber
81
      //Sekunden-Taktgeber zurücksetzen
82
      zeitAugenFst = 0; //59 entspricht ca. 1 Sek. (0,97s)
83
      
84
      
85
      //Auge 1: zweite Zeitvariable prüfen (Anzahl an Sekunden)
86
      if (zeitAugenEinsSek>10)
87
      {                
88
        zeitAugenEinsSek--; //Sekundären Zeitzähler reduzieren
89
      }
90
      else
91
      {
92
        //Wenn beide Zeitvariablen abgelaufen sind:
93
        //wenn Auge an, dann ausschalten
94
        if (PINB & (1<<PINB1)) //wenn PinB1 =1
95
        {
96
          //ausschalten
97
          PORTB &= ~(1<<PB1); // PinB1 auf 0 setzen          
98
          //Zeitvariable auf Zufallswert für Aus-Zeit setzen          
99
          zeitAugenEinsSek = 10 + zufallsZeitWert();//Wert aus Zufallsliste beziehen
100
        }
101
        else {
102
          //wenn Auge aus, dann anschalten
103
          PORTB |= (1<<PB1); // PinB1 auf 1 setzen          
104
          //Zeitvariable auf Zufallswert für An-Zeit setzen          
105
          zeitAugenEinsSek = 10+ zufallsZeitWert();//Wert aus Zufallsliste beziehen          
106
        }
107
      }
108
      
109
      
110
      
111
      //Auge 2: zweite Zeitvariable prüfen (Anzahl an Sekunden)
112
      if (zeitAugenZweiSek>10)
113
      {
114
        //Sekundären Zeitzähler reduzieren
115
        zeitAugenZweiSek--;
116
      }
117
      else
118
      {
119
        //Wenn beide Zeitvariablen abgelaufen sind:
120
        //wenn Auge an, dann aus schalten
121
        if (PINB & (1<<PINB2)) //wenn PinB2 =1
122
        {
123
          //ausschalten
124
          PORTB &= ~(1<<PB2); // PinB2 auf 0 setzen
125
          //Zeitvariable auf Zufallswert für Aus-Zeit setzen          
126
          zeitAugenZweiSek = 10+ zufallsZeitWert();//Wert aus Zufallsliste beziehen
127
        }
128
        else {
129
          //wenn Auge aus, dann an schalten
130
          PORTB |= (1<<PB2); // PinB2 auf 1 setzen
131
          //Zeitvariable auf Zufallswert für An-Zeit setzen          
132
          zeitAugenZweiSek = 10+ zufallsZeitWert();//Wert aus Zufallsliste beziehen
133
        }
134
      }
135
   /**/    
136
      //Auge 3: zweite Zeitvariable prüfen (Anzahl an Sekunden+1)
137
      if (zeitAugenDreiSek>10)
138
      {        
139
        zeitAugenDreiSek--; //Sekundären Zeitzähler reduzieren
140
      }
141
      else
142
      {
143
        //Wenn beide Zeitvariablen abgelaufen sind:
144
        //wenn Auge an, dann ausschalten
145
        if (PINB & (1<<PINB3)) //wenn PinB3 =1
146
        {
147
          //ausschalten
148
          PORTB &= ~(1<<PB3); // PinB3 auf 0 setzen
149
          //Zeitvariable auf Zufallswert für Aus-Zeit setzen          
150
          zeitAugenDreiSek = 10+ zufallsZeitWert(); //Wert aus Zufallsliste beziehen
151
        }
152
        else {
153
          //wenn Auge aus, dann anschalten
154
          PORTB |= (1<<PB3); // PinB3 auf 1 setzen
155
          //Zeitvariable auf Zufallswert für An-Zeit setzen          
156
          zeitAugenDreiSek = 10+ zufallsZeitWert(); //Wert aus Zufallsliste beziehen
157
          servoZyklus=0; //Servo aktivieren
158
          ZeitZaehlerServo=0;
159
        }
160
      }  
161
          
162
      
163
      //Auge 4: zweite Zeitvariable prüfen (Anzahl an Sekunden)
164
      if (zeitAugenVierSek>10)
165
      {        
166
        zeitAugenVierSek--; //Sekundären Zeitzähler reduzieren
167
      }
168
      else
169
      {
170
        //Wenn beide Zeitvariablen abgelaufen sind:
171
        //wenn Auge an, dann ausschalten
172
        if (PINB & (1<<PINB4)) //wenn PinB4 =1
173
        {
174
          //ausschalten          
175
          PORTB &= ~(1<<PB4); // PinB4 auf 0 setzen 
176
          //Zeitvariable auf Zufallswert für Aus-Zeit setzen
177
          zeitAugenVierSek = 10+ zufallsZeitWert();//Wert aus Zufallsliste beziehen
178
        }
179
        else {
180
          //wenn Auge aus, dann anschalten          
181
          PORTB |= (1<<PB4); // PinB4  auf 1 setzen 
182
          //Zeitvariable auf Zufallswert für An-Zeit setzen
183
          zeitAugenVierSek = 10+ zufallsZeitWert();//Wert aus Zufallsliste beziehen          
184
        }
185
      }
186
      /* */
187
    }
188
    
189
190
    //Servo-Code:
191
    if (servoZyklus <1) //Anzahl links-rechts-Zyklen des Servos
192
    {
193
    
194
      //Servo-Code
195
      if (ZeitZaehlerServo<59) //<1 Sek. (0,97s)
196
      {      
197
        // Servo nach links fahren        
198
        OCR0A = 148; //74;//37; //62;
199
      }
200
      if (ZeitZaehlerServo>58 && ZeitZaehlerServo<116)
201
      {
202
        // Servo nach rechts fahren
203
        OCR0A = 254;        
204
      }
205
      if (ZeitZaehlerServo>115) //Ein links-rechts-Zyklus durchlaufen
206
      {
207
        //Sekundenzähler zurücksetzen
208
        ZeitZaehlerServo=0;
209
        servoZyklus=servoZyklus+1;
210
      }      
211
    }
212
    
213
    }  //while (1)
214
215
216
  return 0;
217
}
218
219
220
 uint8_t zufallsZeitWert(){
221
   //gibt Zufallswert für Zeit zurück   
222
     if (laufZeit>49){laufZeit=0;}
223
     laufZeit++;
224
     return zeitWerteSekundaer[laufZeit-1];
225
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Bitte beachten, was über **jeder** Texteingabebox hier steht:
1
Antwort schreiben
2
Wichtige Regeln - erst lesen, dann posten!
3
4
  *  ...
5
  *  Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Mein Vorschlag: häng den Code an den nächsten Post einfach als ino Datei 
an und ich lösche den oben raus.


Kai W. schrieb:
> Trotzdem habe ich den Verdacht, dass beim Takt/Teiler etc. ggf. etaws
> nicht stimmt.
Passt die clkdiv8 Fuse?

: Bearbeitet durch Moderator
von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Kai W. schrieb:

> ich hoffe ihr könnt mir weiterhelfen, da ich nach vielen vergeblichen
> Teststunden nicht mehr weiterweiß.

Variablen, die in einem Interrupthandler und in main() genutzt werden, 
sollten als volatile deklariert werden.

Grüßle,
Volker

von Georg G. (df2au)


Lesenswert?

90% RAM Auslastung sind u.U. zu viel. Der Compiler kann Heap/Stack nicht 
korrekt berücksichtigen. Definiere doch die zeitWertesekundaer als 
Progmem und passe die Zugriffe entsprechend an. Das gibt etwas Luft.

von Reinhard R. (reirawb)


Lesenswert?

Hallo Kai,

Kai W. schrieb:
> const uint8_t zeitWerteSekundaer[50] = {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
> 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1,
> 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2};

Die Daten für die Konstante werden in den RAM geschaufelt, lege sie in 
den Flash, dann hast du fast den gesamten RAM frei.

Schau mal hier rein:
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Flash_mit_PROGMEM_und_pgm_read

Etwas weiter unten gibt es auch noch die Beschreibung von "__flash", ist 
IMO einfacher in der Anwendung, nutze ich häufig für Konstanten.

Reinhard

von Kai W. (chilibit)


Angehängte Dateien:

Lesenswert?

Vielen Dank für eure zahlreichen Antworten!
Der Reihe nach:

Da ich nicht weiß, wie ich mit dem Microchip Studio ino-Dateien erzeuge, 
habe ich mal die main.c angehängt. Sorry, ich dachte, dass mein MiniProg 
nicht in die Kategorie "lang" fällt.

Bzgl. des "clkdiv8 Fuse":
Ich habe im ersten Post ein Bild der Fuses angehängt - der LOW.CKDIV8 
ist gesetzt oder was ist gemeint?

volatile:
Alle im Interrupt und main verwendeten Variablen sind jetzt als 
"volatile" deklariert.

RAM/Flash:
Vielen Dank für den Hinweis - ich habe versucht ihn umzusetzen. Wäre 
nett, wenn jemand meine Umsetzung kontrollieren würde.

Ich habe das in der main01.c angehängte Programm auf dem myC getestet 
und bin etwas ratlos, da:
- die LEDs flackern nicht mehr, bleiben aber sehr lange an bzw. aus, 
z.T. gehen sie nur kurz an und direkt wieder aus (was ungefähr der 
vorgesehenen 1 Sek. entsprechen könnte).
- Immerhin Durchläuft der Servo wie geplant einen Links-Rechts-Zyklus, 
wenn die LED 3 angeht.

MfG Kai

von Steve van de Grens (roehrmond)


Lesenswert?

Ich blicke durch den Code nicht durch.

Die Servo-Ansteuerung per Interrupt bin ich so gewohnt, da habe ich 
nichts zu meckern. Aber die Ansteuerung der LEDs würde ich im 
Zustandsautomaten verpacken. Falls dir das nichts sagt, schau dir das 
an: http://stefanfrings.de/multithreading_arduino/index.html

von Georg G. (df2au)


Lesenswert?

Kleinvieh macht auch Mist... warum nicht so? Ist kürzer und schneller.

uint8_t zufallsZeitWert(){     //gibt Zufallswert für Zeit zurück
  laufZeit++;
  if (laufZeit > 49) {laufZeit = 0;}
  return pgm_read_byte (zeitWerteSekundaer[laufZeit]);

Ansonsten scheint die Funktion des Programms ja deutlich näher am Soll 
zu liegen. Das deutet darauf hin, dass der RAM Verbrauch tatsächlich zu 
hoch war.

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Kai W. schrieb:
> Bzgl. des "clkdiv8 Fuse":
> Ich habe im ersten Post ein Bild der Fuses angehängt - der LOW.CKDIV8
> ist gesetzt oder was ist gemeint?

Tja, wenn ich jetzt wüsste, was diese Oberfläche meint? Ich würde das so 
interpretieren, dass CKDIV8 aktiv ist, also auf 0 gesetzt wird. Damit 
wird der Takt der MCU, also auch der Takt, der deren Timer speist, durch 
8 dividiert.

Grüßle,
Volker

: Bearbeitet durch User
von Steve van de Grens (roehrmond)


Lesenswert?

Volker B. schrieb:
> Tja, wenn ich jetzt wüsste, was diese Oberfläche meint?

Sie meint die Fuses im default Zustand, also 1,2 MHz Taktfrequenz.

Die hexadezimale Darstellung unten drunter ist unmissverständlich.

von Volker B. (Firma: L-E-A) (vobs)


Lesenswert?

Steve van de Grens schrieb:
> Volker B. schrieb:
>> Tja, wenn ich jetzt wüsste, was diese Oberfläche meint?
>
> Sie meint die Fuses im default Zustand, also 1,2 MHz Taktfrequenz.
>
> Die hexadezimale Darstellung unten drunter ist unmissverständlich.

...wenn man die ausgewählte MCU kennen würde...

Ah, ok, steht im Titel. Korrigiere:

...wenn man nicht zu faul wäre, das Datenblatt zu suchen... :-)

Grüßle,
Volker

: Bearbeitet durch User
von Steve van de Grens (roehrmond)


Lesenswert?

Volker B. schrieb:
> wenn man die ausgewählte MCU kennen würde.

Siehe links oben im Screenshot Fuses.JPG des Eröffnungsbeitrages. Oder 
im Titel dieser Diskussion.

Die Fuses sind im Datenblatt beschrieben. Ich empfehle das Tool 
https://www.engbedded.com/fusecalc/

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

geh nochmal einen großen Schritt zurück.
Laut deiner Konfig nutzt du den internen 9,6MHz RC.
Zusätzlich ist CKDIV8 Fuse aktiv.
Das heißt dein µC taktet mit 1,2MHz.

Teste einmal ob die 2 Pins sauber takten?
Ungetestet, kompiliert jedoch.
1
#define F_CPU 1200000UL  // 9,6MHz / 8
2
#include <avr/io.h>
3
#include <stdlib.h>
4
#include <avr/interrupt.h>
5
#include <avr/pgmspace.h>
6
7
ISR(TIM0_OVF_vect)      // 292 Hz ???
8
{
9
    PINB = _BV(PB1);    // Toggle
10
}
11
12
ISR(TIM0_COMPA_vect)
13
{
14
    PINB = _BV(PB2); 
15
}
16
17
int main(void)
18
{
19
    DDRB    = _BV(PB1); 
20
    DDRB   |= _BV(PB2); 
21
    TCCR0A  = _BV(WGM01) | _BV(WGM00);  // 8Bit Fast-PWM
22
    TIMSK0  = _BV(TOIE0);   // OVF
23
    TIMSK0 |= _BV(OCIE0A);  // CompareA
24
    OCR0A   = 127;
25
    TCCR0B  = _BV(CS01);    // Timer0 starten, Prescaler 8
26
    sei();   
27
         
28
    while (1) 
29
    { }
30
}
31
32
/*
33
  1 Takt = 833ns
34
  8*256 = 2048 Takte * 833ns = 1,706ms // ein OVF Aufruf
35
*/

Danach überlegst du dir nochmal wie du den Timer konfigurieren musst um 
vernünftig ein Servosignal zwischen 1-2ms zu erzeugen und dabei eine 
Periodendauer von 20ms einzuhalten. Kannst auch auf 10ms Periodendauer 
runtergehen. Das kommt der Auflösung zu Gute bei der Rechnerei.

von Kai W. (chilibit)


Angehängte Dateien:

Lesenswert?

Vielen Dank für Eure Antworten!

Da nun wieder genug RAM zur Verfügung steht, habe ich den LED-Zustand 
mit vier bool-Variablen erfasst, anstatt ihn jedes mal abzufragen. Für 
meinen einfachen Fall genügt aber, denke ich, die einfache 
if-else-Konstruktion oder würdet ihr dringend zu der 
switch-case-Variante raten? Aber danke für den Hinweis auf den 
Zustandsautomaten, werde ich mir merken.

Die Optimierung von Georg G. an der zufallsZeitWert()-Funktion habe ich 
übernommen.

Danke für die Hinweise bzgl. CKDIV8 - das hatte ich nicht 
berücksichtigt.
Ich habe Dein Programm, Veit D., am MCU getestet. Heraus kam eine 
Frequenz von 275 Hz (Signallänge an PB1 bzw. PB2: 1,820ms).
Zugegebener Maßen, verstehe ich das Programm mit den "_BV()"-Ausdrücken 
nicht so ganz und hätte eigentlich eher unterschiedliche Frequenzen an 
den beiden Pins erwartet... Wie auf den Bildern zu sehen ist, trat auch 
eine wiederkehrende Störung auf... diese ist mir aber beim aktuellen 
Programm nicht mehr begegnet.

Nach ein wenig herumrechnen, habe ich mich dann für die folgende 
Variante entschieden:
CKDIV8 deaktiviert (also 9,6 MHz) und den Timer-Prescaler auf 256.
Das ergibt dann 1ms: 37 Takte (1,072ms gemessen), 2ms: 70 Takte 
(nachgemessen & korrigiert => 2,0ms) und einen Zyklus von 
21,6ms(gemessen)

Servo und LEDs werden nun korrekt angesteuert und funktionieren wie 
erwartet... zumindest wenn ich nicht die zufallsZeitWert()-Funktion 
verwende. Wenn ich feste Werte vorgebe, werden diese korrekt umgesetzt. 
Die LEDs, die ihre Zeitwerte über die Funktion beziehen ändern ihren 
Zustand gar nicht oder nur sehr selten. Hat jemand eine Idee, voran das 
liegen könnte? Ich habe den aktualisierten Code angehängt.

MfG Kai

von Axel R. (axlr)


Lesenswert?

bei "pgm_read_byte" fehlt ein "&". Ist zwar kein Arduino, aber siehe 
auch hier
https://stackoverflow.com/questions/31100771/accessing-individual-bytes-in-progmem-on-arduino-avr
oder hier steht das auch:
https://teslabs.com/openplayer/docs/docs/prognotes/Progmem%20Tutorial.pdf
seite 5
Du willst ja nicht die Adresse wissen, sondern den Wert, der sich dort 
verbirgt.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

_BV() ist ein Makro.
avr/sfr_defs.h>
void _BV(bit_number);
Andere Schreibweise statt Bit << schubsen.

Das beide Pins den gleichen Takt haben stimmt. Da hatte ich einen 
Denkfehler. Den OCRA Pin müßte der Timer selbst schalten damit die 
Pulsweite wie Anfangs gedacht verwendet wird. Dann hätte er den 
doppelten Takt. Ist jetzt auch egal.

Übrigens, das Oszi hat links eine Tastenreihe. Damit kann man im 
Bildschirm unten Meßwerte einblenden lassen. Zwecks deiner Frequenz und 
Duty Messung.

Mit Störungen meinst du sicherlich das "Rauschen" auf dem 
Low/High-Pegel?
Das werden Störungen durch schlechte Kontakte/Masse sein. Steckbrett 
usw.

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

habe mich mal rangemacht erstmal den Code aufzuräumen. Damit steigen die 
Chancen das jemand durchblickt. Und du auch um den Fehler zu finden, 
weil die Code Dopplung entfällt.

Dafür müßtest du das aber als Cpp Projekt neu anlegen und wenigstens 
unter
Projekt > Properties >

etwas oberhalb > Configuration: > All Configuration

links Tooolchain:

AVR/GNU C++ Compiler >

Optimization: Level auf (-Os) setzen

C++ Miscellaneous: "other flags" auf -std=c++11 einstellen,
                    Haken bei verbose kannste auch setzen

C kann leider nicht mit der Struktur "struct Auge" umgehen.
Du kannst weiterhin C programmieren, abgesehen von der Struktur.
Wenn das erstmal wie bisher funktioniert kann man weiter schauen ...

von Kai W. (chilibit)


Angehängte Dateien:

Lesenswert?

Vielen Dank für Eure Antworten und Hinweise! Und vielen Dank Veit D., 
dass Du Dir die Mühe gemacht hast, das Programm umzuschreiben. Dadurch 
hast Du für andere User sicherlich ein besseres Beispielprogramm 
erstellt, als mein Anfängerproggi. Zugegeben, mit struct kenne ich mich 
noch nicht aus, aber ich sehe ein, dass es in diesem Anwendungsfall wohl 
Sinn macht. Ich werde Eure zahlreichen Hinweise bei den nächsten 
Projekten versuchen zu berücksichtigen - vielen Dank dafür!

Nach der Ergänzung des fehlenden Adressoperators beim Zugriff auf das 
Array im Flash funktioniert das Programm nun wie erwartet, womit meine 
Frage beantwortet wäre. Ich hänge das endgültige Prog. noch an, falls 
noch anderen Anfängern die struct-Variante zu kompliziert ist.

Abschließend noch der Sinn des Programms:
Wer mag, kann mit seinen Kindern zu Halloween Tischtennisbälle als Augen 
bemalen (Edding, Alufolie als Maske, Klarsichtfolie als Feuchteschutz), 
mit LED versehen und diese dann in einen kugeligen Busch im Vorgarten 
platzieren. Je ein Augenpaar wird dann zufällig an-/ausgeschaltet. Der 
Servo soll dann einen Ast schütteln.

Vielen Dank und viele Grüße
Kai

von Veit D. (devil-elec)


Lesenswert?

Hallo,

Hauptsache ist das es funktioniert.  :-)
Je mehr du programmierst und je mehr Codedopplungen man hat, umso eher 
kommt man dann ins Themengebiet Arrays, Strukturen usw. Das ergibt sich 
dann fließend mit der Zeit. Aber schön ist das du eine Lösung hast.

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.