Forum: Mikrocontroller und Digitale Elektronik Problem mit Zeitmessung mit Atmega8


von Ewald S. (Gast)


Lesenswert?

Dieses Programm hat mir ein Kollege geschrieben, leider ist er nicht 
mehr für mich greifbar und ich selbst habe fast keine Ahnung von 
Mikrokontrollern und kann auch fast kein Englisch. Es reicht zwar um ein 
wenig in „C“ abzuschreiben und kleine Änderungen vorzunehmen. Ich kann 
mit dem Atmel-Studio 6 Programmänderungen in den Kontroller schreiben.
Das Prg. ist die Steuerung/Regelung eines Schrittmotors, der den 
Originalmotor eines  Filmprojektors ersetzt. Dies funktioniert soweit 
sehr gut.  Zähler0/ INT0 wird vom 25 Hz Videosignal eine Kamera 
gestartet und über INT1 über ein Signal des Filmtransporters gestoppt. 
Dieser Zählerstand, in dem Prg. „abstand“ genannt, darf max. +- 2 bis 5 
Punkte des „soll_abstand“ sein. Die Regelung (wenn ich es so nennen 
darf) erfolgt in den Zeilen 123 bis 136, in dem die Taktfrequenz des 
Schrittmotorstreibers verändert wird.
Das Problem: Wird ohne Regelung gefahren, in dem ich INT0 sperre, läuft 
der Schrittmotor ohne Schrittausfälle, nur Videosignal und 
Projektorsignal triften leider auseinander. Mit Regelung „ruppelt“ der 
Schrittmotor, kann aber am Ausgang PB1 mit dem Oszi nichts erkennen. 
Darauf habe ich den Ausgang PD7 als Prüfausgang geschaltet, darin ist zu 
erkennen, dass in der Funktion ISR(INT1_vect) PD7 gelegentlich auf Hi 
geht.
Meine große Bitte: Programm überschauen und Fehler melden. Übrigens, die 
Funktionen zur Seriellen Übertragung habe ich gemacht um den „abstand“ 
am Pc abzulesen, wird aber nicht während des normalen Ablaufs verwendet.
Vielen Dank im Voraus und bitte keine Hinweise auf das Datenblatt (s.o)
1
1 //Progamm Regler_04.c
2
2 //
3
3 //INT0 = Impulse Master (ca. 25 Hz)
4
4 //INT1 = Impulse Antrieb
5
5 //Zeitmessung/Impulse mit Timer0
6
6 //AVR ATMega8 mit 11,0592 MHz-Quarz
7
7
8
8 //************************************************************************
9
9 #define F_CPU 11059200L
10
10 #include <avr/io.h>
11
11 #include <stdio.h>
12
12 #include <avr/interrupt.h>
13
13 #include <util/delay.h>
14
14
15
15 #undef putchar
16
16 #define putchar my_putchar
17
17 #undef puts
18
18 #define puts my_puts
19
19
20
20 #define bauddivider (unsigned int)(35) //9600 Baud=71 , 19200 Baud =35
21
21 volatile int abstand = 0;
22
22 volatile int start = 0;
23
23 volatile int ueb0 = 0; //Überlaufzähler Zähler0
24
24 volatile int soll_abstand = 200; //Differenz INT0 und INT1
25
25 volatile int topwert = 1658; //Zählerendwert, 1658 ergibt ca. 3333 Hz
26
26 //ICR1=(Takt/(2*Teiler)/Sollfrequenz)-1
27
27 //************************************************************************
28
28 void softstart(int max_topwert)
29
29 {
30
30 int z;
31
31 for(z=6000; z>=max_topwert; z--){ ICR1 = z;_delay_ms(0.2);} //Softstart für Schrittmotor
32
32 }
33
33 //************************************************************************
34
34 void putchar( char c )
35
35 {
36
36 while( (UCSRA & 1<<UDRE) == 0 );
37
37 UDR = c;
38
38 }
39
39
40
40 void puts( char *s )
41
41 {
42
42 while( *s )
43
43 putchar( *s++ );
44
44 }
45
45 //************************************************************************
46
46 void ser_ausgabe(int v0) //Ausgabe auf serielle Schnittstelle
47
47 {
48
48 char fs[20];
49
49 //sprintf(fs,"T0 %5d\r\n",v0);
50
50 sprintf(fs," %5d\\",v0);
51
51 puts(fs);
52
52 }
53
53 //************************************************************************
54
54 ISR (TIMER0_OVF_vect) //Timer0-Überlaufzähler
55
55 {
56
56 ueb0++;
57
57 }
58
58 //************************************************************************
59
59 ISR(INT0_vect) // Zeitmessung Timer0
60
60 {
61
61 abstand=0;
62
62 ueb0=0;
63
63 TCNT0=0;
64
64 TCCR0 |= (1<<CS01) | (1<<CS00); //Timer0 starten 64-Teiler
65
65 PORTD |= (1<<PD7);
66
66 GIFR |= (1<<INTF0)|(1<<INTF1); //INT-Flags löschen
67
67 GICR &= ~(1<<INT0); //INT0 disabled
68
68 GICR |= (1<<INT1); //INT1 enabled
69
69 //GICR &= ~(1<<INT0); //INT0 disabled
70
70 }
71
71 //************************************************************************
72
72 ISR(INT1_vect)
73
73 {
74
74 TCCR0=0; //Timer0 stoppen
75
D:\Filmprojektor\AVRStudio_62\Regler_04\Regler_04.c 2
76
75 PORTD &= ~(1<<PD7);
77
76 abstand=(ueb0*256)+TCNT0;
78
77 GIFR |= (1<<INTF0)|(1<<INTF1); //INT-Flags löschen
79
78 GICR &= ~(1<<INT1); //INT1 disabled
80
79 }
81
80 //************************************************************************
82
81 int main(void)
83
82 {
84
83 DDRD |= (1<<PD7); //Prüfausgang Zählzeit
85
84 DDRB = (1<<PB1); //OC1A auf Ausgang
86
85 DDRB &= ~(1<<PB0) & ~(1<<PB2); //PB0 und PB2 auf Eingang
87
86 PORTB = (1<<PB0) | (1<<PB2); //Pullup Ein an PB0 und PB2
88
87 TCCR1A = (1<<COM1A0); //OC1A PWM aus
89
88 TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10); //
90
89 DDRD &= ~(1<<PD2) & ~(1<<PD3); //Int0 und Int1 auf Eingang
91
90 PORTD &= ~(1<<PD2); //Kein Pullup
92
91 PORTD = (1<<PD3); //Pullup
93
92 MCUCR |= (1<<ISC01) | (1<<ISC11); //Int0 und Int1 auf fallende Flanke
94
93 MCUCR &= ~(1<<ISC00) & ~(1<<ISC10);
95
94 TIMSK |= (1<<TOIE0); //Overflow Timer0 erlauben
96
95 GIFR |= (1<<INTF0)|(1<<INTF1); //INT-Flags löschen
97
96 GICR &= ~(1<<INT0); //INT0 disabled
98
97 GICR &= ~(1<<INT1); //INT1 disabled
99
98 SREG |= (1<<SREG_I); //Globalen Interrupt freigeben
100
99 UBRRL = bauddivider; //set baud rate
101
100 UCSRA = 0; //no U2X, MPCM
102
101 UCSRC = 1<<URSEL^1<<UCSZ1^1<<UCSZ0; //8 Bit
103
102 UCSRB = 1<<RXEN^1<<TXEN; //enable RX, TX
104
103
105
104 while(1)
106
105 {
107
106 //ser_ausgabe(100);
108
107 if (!start)
109
108 {
110
109 if (!(PINB & (1<<PINB0)))
111
110 {
112
111 ICR1=6000;
113
112 }
114
113 else
115
114 {
116
115 ICR1=0;
117
116 }
118
117 }
119
118 if (!(PINB & (1<<PINB2)))
120
119 {
121
120 start=1;
122
121 softstart(topwert);
123
122 }
124
123 if (start)
125
124 {
126
125 //_delay_ms(10);
127
126 if(abstand>(soll_abstand+2)) topwert--;
128
127 if(abstand<(soll_abstand-2)) topwert++;
129
128 if(topwert>1661) topwert=1661;
130
129 if(topwert<1655) topwert=1655;
131
130 ICR1=topwert;
132
131 //_delay_ms(200);
133
132 //ser_ausgabe(abstand);
134
133 _delay_ms(10);
135
134 //ser_ausgabe(ueb0);
136
135 GIFR |= (1<<INTF0)|(1<<INTF1); //INT-Flags löschen
137
136 GICR |= (1<<INT0); //INT0 enabled
138
137 }
139
138 }
140
139 }
141
140 //******Ende Programm Regler_04.c******************************
142
141

: Bearbeitet durch User
von Hubert G. (hubertg)


Lesenswert?

Das ganze ist ziemlich unübersichtlich und kaum beschrieben. Da wird 
Hilfe schwer.
Ändere mal in Zeile 21 bis 25 auf volatile unsigned int.
und lösche die Zeilen 66, 77, 95 und 135. Die Interruptflag löschen sich 
von selbst, da kann man sich nur Mist einfangen.

von eProfi (Gast)


Lesenswert?

Erzähle mal mehr über die Vorgängerversionen 1-3.
Haben die besser funktioniert?
Ich würde das ganze anders anpacken, nämlich nicht die Zeit von Int0 bis 
Int1 messen, sondern die Bilder der Kamera und die Bilder des Projektors 
zählen und die Differenz auf Null regeln.

Generell als erstes ein paar Debug-Möglichkeiten vorsehen, z.B. mehr 
LEDs oder ein anderes Display dranhängen.
Oder eine bullet-proof interrupt-driven buffered-Serielle zum PC, damit 
man sorglos Debug-Ausgaben dorthin machen kann.

Vorläufig kann man eine manuelle Eingriffsmöglichkeit schaffen, damit 
man ein Wegdriften korrigieren kann. Vermutlich läuft der "Regler" in 
die untere oder obere Begrenzung (Zeilen 128-129).

Da könnte man ein paar Pins abfragen, um diesen Wert zu ändern.

Den Sinn der Zeilen 66, 77 sehe ich auch nicht, warum soll das Flag der 
anderen ISR gelöscht werden?

Der Grund für das Rattern dürfte das Asynchrone Reinschreiben in das 
Timer-Registers des StepperMotors sein. Es kann dann nämlich sein, dass 
nach einer Frequenz-Änderung der Zähler erst einmal ganz durchzählen 
muss, bis wieder ein Compare auftritt.
Dann kommen halt einige ms keine Impulse. Das sieht man mit einem 
einfachen Oszi nicht so leicht.

Ich weiß jetzt auswenig nicht, ob der Timer des Mega8 ein spezielles 
Register hat, das den Compare-Wert erst bei einem Compare-Ereignis 
übernimmt (double-buffered). Wenn nicht, macht man das in Software, 
indem man eine kleine Timer-ISR hinzufügt, die das synchrone 
Reinschreiben erledigt.

von Ewald S. (Gast)


Lesenswert?

Hallo eProfi,
herzlichen Dank für die Antwort. Leider ist es aber so wie von mir 
geschrieben, ich kann mit den Befehlen für den Kontroller fast nichts 
anfangen. Ich hoffte, dass jemand irgendeinen falschen Befehl findet, 
der gar nicht zum ATmega 8 bzw. zum Programmablauf passt. Warum 
bestimmte Befehle/Funktionen vorhanden sind, weiß ich nicht, das alles 
hat mein Kollege geschrieben.
mfg Ewald

von Hubert G. (hubertg)


Lesenswert?

Füge in dein Programm mal das ein
1
 ISR (TIMER1_COMPA_vect ){
2
  ICR1=topwert;
3
  }
und im main
1
 TIMSK |= (1<<TOIE0)|(1<<OCIE1A); //Overflow Timer0 erlauben, Outputcompare 1A
Zeile 130 löschen

von m.n. (Gast)


Lesenswert?

Ewald S. schrieb:
> Warum
> bestimmte Befehle/Funktionen vorhanden sind, weiß ich nicht,

Dann laß doch die Finger von dem Kram. Jeder Rat hier ist doch nur 
Stochern im Nebel. Um eine Lösung zu finden, braucht man die Kiste auf 
dem eigenen Tisch.

Sag, wo Du ungefähr wohnst, und frage, ob jemand in der Nähe sich dafür 
interessiert.

von Ewald S. (Gast)


Lesenswert?

Hallo Hubert,
Deine Idee scheint zu helfen, ich habe den Projektor 10 Minuten laufen, 
dabei gab es keinen merkbaren Aussetzer. Jedoch viel mir jetzt auf, dass 
INT1 unterschiedlich auf Hi und dann wieder auf Low reagiert. Ich habe 
den Verdacht, dass das Signal am Eingang Pd3/Int1 nicht sauber ist. 
Dieser Eingang wird durch eine Lichtschranke des Projektors angesteuert. 
Ich werde mich morgen wieder melden.
Vielen Dank für eure Geduld.

von Ewald S. (Gast)


Lesenswert?

m.n
Deine Idee ist sehr gut, ich hoffte, wenn ich alle anspreche, kommen 
mehr Ideen zusammen. Wohnort ist Freiburg, vielleicht findet sich hier 
jemand.

von Hubert G. (hubertg)


Lesenswert?

Löschen mal diese Zeile in deinem Programm:
93 MCUCR &= ~(1<<ISC00) & ~(1<<ISC10);

ob es noch Zeile 93 ist musst du selbst sehen.

von Ewald S. (Gast)


Lesenswert?

Hubert G. schrieb:
> Füge in dein Programm mal das ein ISR (TIMER1_COMPA_vect ){
>   ICR1=topwert;
>   }
>
> und im main TIMSK |= (1<<TOIE0)|(1<<OCIE1A); //Overflow Timer0 erlauben,
> Outputcompare 1A
>
> Zeile 130 löschen

Dieser Code löste das Hauptproblem mit den Schrittausfällen

Hubert G. schrieb:
> Löschen mal diese Zeile in deinem Programm:
> 93 MCUCR &= ~(1<<ISC00) & ~(1<<ISC10);
Dies hat scheinbar keinen Einfluss auf irgendetwas.
Ohne die Interruptflag zu löschen wird nicht mehr "geregelt". Sind aber 
nur in den beiden ISR notwendig.

Die Änderungen der Variablen von "int" nach "unsigned int" bewirkte 
nichts.

Herzlichen Dank.
Eine weitere Frage:
Bei Stillstand/ f=0 des OC1A-Frequenzausganges sollte dieser Ausgang auf 
Hi und nicht auf Low sein, wie läßt sich das ohne ext. Beschaltung 
realisieren.
mfg Ewald

von Hubert G. (hubertg)


Lesenswert?

Also funktioniert das ganze jetzt mal grundsätzlich?

Ewald S. schrieb:
> Bei Stillstand/ f=0 des OC1A-Frequenzausganges sollte dieser Ausgang auf
> Hi und nicht auf Low sein, wie läßt sich das ohne ext. Beschaltung
> realisieren.

Die Frage ist hier, wie kann ich diesen Zustand erkennen? Geht das über 
PinB0 oder PinB2 ? Die Funktion der beiden Eingänge ist ja nicht 
beschrieben.

Wie geschieht die Abschaltung? Einfach Strom aus?

von Ewald S. (Gast)


Lesenswert?

Ja, es funktioniert grundsätzlich, ein Test mit Aufnahme steht 
allerdings noch aus, bisher habe ich nur die Abstände und Synchronität 
der beiden Signale an PD2 und PD3 mit dem Oszi verglichen, das 
funktioniert gut mit Deiner Empfehlung.
Der Ausgang PB1/OC1A gibt in Abhängigkeit des ICR1-Wertes ein 
Rechtecksignal aus für den Schrittmotortreiber. in meinem Fall 3333,33 
Hz.
Schrittweite und Übersetzung ergibt 25 Bilder/Sek. Dies nimmt die Kamera 
auch so auf. Die "Regelung" soll den Projektor und die Kamera exakt (+- 
5msec) synchron halten.
PB0 gibt nur eine niedere Frequenz/Drehzahl zum Einfädeln des Films.
PB2 setzt die Variable "start" auf 1, der Schrittmotor wird langsam 
(softstart) über die max. Startdrehzahl auf die Nenndrehzahl gedreht.
Jetzt setzt die Regelung ein.
Das Ausschalten wird wird am Schrittmotortreiber veranlasst, und 
gleichzeitig das Prg. resettet (PC6/Reset).
Jetzt soll der Ausgang PB1 auf Hi bleiben, sonst macht der 
Schrittmotortreiber irgendwelchen Mist. Aber so wie der Code ist, geht 
er auf Low. Ich möchte dies wenn möglich softwaremäßig machen. Sonst 
muss ein Transistor her.
mfg Ewald

von Hubert G. (hubertg)


Lesenswert?

1
88 TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
Hier gehört das |(1<<CS10) weg.

Ab Zeile 107 (wird sich wahrscheinlich schon verschoben haben) gehört 
das dazu, bzw. ergänzt:
1
 if (!start){
2
   if (!(PINB & (1<<PINB0))){
3
     TCCR1B|=(1<<CS10);
4
    ICR1=6000;
5
   }
6
   else{
7
     TCCR1B &=~(1<<CS10);
8
    PORTB |=(1<<PB1);
9
   }
10
 }
11
 if (!(PINB & (1<<PINB2))){
12
   TCCR1B|=(1<<CS10);
13
  start=1;
14
   softstart(topwert);
15
 }
16
   else{
17
    TCCR1B &=~(1<<CS10);
18
    PORTB |=(1<<PB1);
19
    }
Damit sollte PB1 auf high sein wenn kein Takt ausgegeben wird.

von Hubert G. (hubertg)


Lesenswert?

Hab gerade gesehen das es so nicht geht. Es beißt sich mit dem 
Einfädeln.

von Hubert G. (hubertg)


Lesenswert?

1
 if (!start){
2
   if (!(PINB & (1<<PINB0))){
3
     TCCR1B|=(1<<CS10);
4
    ICR1=6000;
5
   }
6
   else{
7
     TCCR1B &=~(1<<CS10);
8
    PORTB |=(1<<PB1);
9
   }
10
 }
11
 if (!(PINB & (1<<PINB2))){
12
   TCCR1B|=(1<<CS10);
13
  start=1;
14
   softstart(topwert);
15
 }
16
 if ((PINB & (1<<PINB0))&&(PINB & (1<<PINB2))&&(!start)){
17
   TCCR1B &=~(1<<CS10);
18
  PORTB |=(1<<PB1);
19
  }
So sollte es funktionieren.

von Ewald S. (Gast)


Lesenswert?

Hubert G. schrieb:
> So sollte es funktionieren.

Macht es auch, super!!!
Herzlichen Dank!
Jetzt muss ich nur noch die Aufnahme-Einstellungen des Camcorders 
anpassen, dann wird die Kiste mit den Super8-Filmen digitalisiert. Die 
Mechanik ist zu 90 %fertig.
Auch an alle Dank, die sich Gedanken gemacht haben und noch nicht 
geschrieben haben.
mfg Ewald S.

von Ewald S. (Gast)


Lesenswert?

Hallo Hubert G.
Wie vorher beschrieben setze ich nach Ausschalten des 
Schrittmotortreibers den Controller durch eine Resettaste auf 0.
Kann man den Reseteingang dauernd auf Low lassen, solange man das Prg. 
"nicht braucht"? Oder hast Du mir auch wieder so eine gute 
Software-Idee. Vom "Ausschalter" des Schrittmotortreibers kann ich 
sowohl Hi als auch Low im Aus-Zustand erhalten. Am Atmega8 sind die 
Anschlüsse PD4 bis PD7 frei.
mfg Ewald S.

von Hubert G. (hubertg)


Lesenswert?

Es ist kein Problem den Reset dauernd auf low zu lassen.

von Ewald S. (Gast)


Lesenswert?

Hubert G. schrieb:
> Es ist kein Problem den Reset dauernd auf low zu lassen.

Danke

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.