Forum: Mikrocontroller und Digitale Elektronik Atmega 16 PWM über Komparator unterbrechen


von Steffen H. (stef_fen)


Lesenswert?

Hallo Zusammen,

ich möchte mittels eines Stromsensors der am Komparator Eingang AIN1 des 
Atmega 16 angeschlossen ist die PWM ausschalten und damit die Mosfets 
vor Überstrom schützen. Dazu habe ich erst mal anstatt des Stromsensors 
einen Spannungsteiler bestehend aus 10k und einem 10k Poti an den AIN1 
Eingang geschaltet. Als Referenzspannung dienen die internen 1,3 Volt. 
Zum Test schaltet der Komparator eine LED. Aber wie kann ich jetzt die 
PWM unterbrechen? Wenn ich in der ISR ANA_COMP_vect den Befehl OCR2 = 0 
reinschreibe zuckt der Motor auch mal ganz kurz aber dann läuft er ganz 
normal weiter.

Vielen Dank. Gruß Steffen
1
//Bibliotheken einbinden
2
#define F_CPU 8000000
3
#include <avr/eeprom.h>
4
#include <avr/interrupt.h>
5
#include <avr/io.h>
6
#include "lcd-routines.h"
7
#include <stdlib.h>
8
#include <util/delay.h>
9
10
//Variablendeklaration
11
uint16_t eeunten EEMEM;  //fuer EEPROM
12
uint16_t unten;      //fuer EEPROM
13
uint16_t eeoben EEMEM;  //fuer EEPROM
14
uint16_t oben;      //fuer EEPROM
15
int flanke;        //fuer PWM
16
uint16_t flankeStart;  //fuer PWM
17
volatile uint16_t pwm;  //fuer PWM (volatile = Global gueltig)
18
char Buffer[20];    //fuer LCD
19
int lcdpwm;        //fuer LCD
20
float i;        //fuer Rechnung
21
float j;        //fuer Rechnung
22
int k;          //fuer Rechnung
23
24
ISR(TIMER1_CAPT_vect)
25
{
26
  // Initialiserung fuer PWM einlesen vom Empfänger
27
  if (flanke==0)
28
  {
29
    flankeStart = ICR1;
30
    TCCR1B &= ~(1<<ICES1); // fallende Flanke zur Auswertung des ICP
31
    flanke = 1;
32
  }
33
  else
34
  {
35
    pwm = ICR1 - flankeStart;
36
    flanke = 0;
37
    TCCR1B |= (1<<ICES1); // steigende Flanke zur Auswertung des ICP
38
  }
39
  TIFR = ( 1 << ICF1 );  
40
}
41
42
ISR(ANA_COMP_vect)
43
{
44
  //Intialisierung fuer Strommessung
45
  if bit_is_clear(ACSR, ACO)
46
  {
47
    PORTB &= ~(1<<PB1);  //LED ein
48
    //OCR2 = 0;
49
  }
50
  else
51
  {
52
    PORTB |= (1<<PB1); //LED aus  
53
  }
54
}
55
56
void PWM_Mosfet(void)
57
{
58
  /*Initialisierung fuer PWM ausgeben an Mosfet Treiber
59
  PWM = Prozessorgeschwindigkeit / (Prescaler * 256)
60
  PWM = 8000000 / (8 * 256) = 3906,25Hz = 3,9kHz*/
61
  DDRD |= (1 << PD7); // Motor (OC2 => PD7) = Ausgang
62
  OCR2 = 0; // von 0 bis 255 einstellbar
63
  TCCR2 |= (1 << COM21); // normaler Modus (für invertierenden Modus | (1 << COM20))
64
  TCCR2 |= (1 << WGM21) | (1 << WGM20); // fast PWM
65
  TCCR2 |= (1 << CS21); // Prescaler Clock/8
66
}
67
68
void PWM_Empfaenger(void)
69
{
70
  //Initialisierung fuer PWM einlesen vom Empfänger
71
  TCCR1B |= (1<<ICES1); // steigende Flanke zur Auswertung des ICP
72
  TCCR1B |= (1<<CS11) | (1<<CS10); //Quelle für Timer/Counter = CPU-Takt/64
73
  TIMSK |= (1<<TICIE1); //Capture Interrupt Enable
74
  DDRD &= ~(1<<PD6); // Impuls von Fernsteuerung (ICP1 => PD6) = Eingang
75
  PORTD |= (1<<PD6); //Pullup aktiviert
76
}
77
78
void Strommessung(void)
79
{
80
  //Initialisierung fuer Strommessung
81
  ACSR |= (0 << ACD);
82
  ACSR |= (1 << ACBG); //interne Referenzspannung (1,3 Volt)
83
  ACSR |= (1 << ACI);
84
  ACSR |= (1 << ACIE);
85
  ACSR |= (0 << ACIC);
86
  ACSR |= (0 << ACIS1) | (0 << ACIS0);
87
}
88
89
void Knueppelweg(void)
90
{
91
  //Initialisierung fuer Knueppelweg
92
  lcd_clear();
93
  lcd_string("Regler");
94
  lcd_setcursor( 0, 2);
95
  lcd_string("V2.0");
96
  _delay_ms(1000);
97
98
  //Werte ermitteln
99
  if(!(PINB & (1 << PB0)))
100
  {
101
    PORTB |= (1 << PB1);
102
    _delay_ms(1000);
103
    while(1) //fuer untere Knueppelposition
104
    {
105
      lcd_clear();
106
      lcd_string("down:");
107
      lcd_setcursor(0, 2);
108
      lcdpwm = pwm * 8;
109
      itoa(lcdpwm, Buffer, 10);
110
      lcd_string(Buffer);
111
      _delay_ms(50);
112
      if(!(PINB & (1 << PB0)))
113
      {
114
        unten = pwm;
115
        unten += 2; // Korrekturfaktor
116
        eeprom_write_word (&eeunten, unten); //schreiben
117
        lcd_clear();
118
        lcd_string("its:");
119
        lcd_setcursor(0, 2);
120
        itoa(unten, Buffer, 10);
121
        lcd_string(Buffer);
122
        _delay_ms(3000);
123
        break;
124
      }
125
    }
126
    _delay_ms(1000);
127
    while(1) //fuer obere Knueppelposition
128
    {
129
      lcd_clear();
130
      lcd_string("up:");
131
      lcd_setcursor(0, 2);
132
      lcdpwm = pwm * 8;
133
      itoa(lcdpwm, Buffer, 10);
134
      lcd_string(Buffer);
135
      _delay_ms(50);
136
      if(!(PINB & (1 << PB0)))
137
      {
138
        oben = pwm;
139
        oben -= 2; //Korrekturfaktor
140
        eeprom_write_word (&eeoben, oben); //schreiben
141
        lcd_clear();
142
        lcd_string("its:");
143
        lcd_setcursor(0, 2);
144
        itoa(oben, Buffer, 10);
145
        lcd_string(Buffer);
146
        _delay_ms(3000);
147
        PORTB &= ~(1 << PB1);
148
        break;
149
      }
150
    }
151
  }
152
  lcd_clear();  
153
}
154
155
void Knueppelstellung(void)
156
{
157
  //Kontrolliert ob der Knueppel beim ersten Start in der Nullposition ist
158
  while(1)
159
  {
160
    if (pwm == unten)
161
    {
162
    break;
163
    }
164
  }
165
  PORTC |= (1 << PC0);
166
}
167
168
void Ein_Ausgaenge(void)
169
{
170
  //Initialisierung fuer Ein-/Ausgaenge
171
  DDRB &= ~(1 << PB0); //Taster (PB0) = Eingang
172
  PORTB |= (1 << PB0); //Pullup
173
  DDRB |= (1 << PB1); //Gelbe LED (PC6) = Ausgang
174
  DDRC |= (1 << PC0); //SD/ Pin IR2184 Mosfet Treiber (PC0) = Ausgang
175
}  
176
177
void ADC_Init(void) 
178
{
179
  //Initialisierung fuer Spannungsmessung
180
  uint16_t result;
181
 
182
  // interne Referenzspannung als Refernz für den ADC wählen:
183
  ADMUX = (1<<REFS1) | (1<<REFS0);
184
  ADCSRA = (1<<ADPS2) | (1<<ADPS1);     // Frequenzvorteiler, Dummyreadout
185
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
186
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
187
  while (ADCSRA & (1<<ADSC)) {         // auf Abschluss der Konvertierung warten
188
  }
189
  result = ADCW;
190
}
191
 
192
uint16_t ADC_Read(uint8_t channel)
193
{
194
  // Initialisierung fuer Spannungseinzelmessung
195
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F); //Kanal waehlen, ohne andere Bits zu beeinflußen
196
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
197
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung warten
198
  }
199
  return ADCW;
200
}
201
 
202
int main (void)
203
{
204
  lcd_init();
205
  lcd_clear(); 
206
    
207
  PWM_Mosfet();
208
  PWM_Empfaenger();
209
  Strommessung();
210
  sei(); //fuer ISR (gibt den Startschuss fuer Interrupt)
211
  Ein_Ausgaenge();
212
  Knueppelweg();
213
  
214
  unten = eeprom_read_word (&eeunten); //EEPROM lesen
215
  oben = eeprom_read_word (&eeoben);
216
  
217
  Knueppelstellung();
218
  
219
  j = oben - unten; //Knueppelweg Vorberechnung
220
  j = 255 / j;
221
  
222
  ADC_Init(); //Spannungsmessung
223
  uint16_t  spannung; //Spannungsmessung
224
  
225
  while(1) 
226
  {  
227
      i = pwm - unten;
228
      i = i * j;
229
      k = i;
230
      if(pwm >= oben)
231
      {
232
        k = 255;  
233
      }
234
      if(pwm <= unten)
235
      {
236
        k = 0;
237
      }
238
      OCR2 = k;
239
      spannung = ADC_Read(0);
240
      if (spannung <= 250)
241
      {
242
        break;
243
      }
244
  }
245
  while(1)
246
  {
247
    OCR2 = 0;
248
    lcd_init();
249
    lcd_clear();
250
    lcd_string("Akku");
251
    lcd_setcursor( 0, 2);
252
    lcd_string("leer!");
253
    _delay_ms(1000);
254
    PORTC &= ~(1 << PC0);
255
  }
256
  return 0;
257
}

von Karl H. (kbuchegg)


Lesenswert?

Steffen Ha schrieb:

> PWM unterbrechen? Wenn ich in der ISR ANA_COMP_vect den Befehl OCR2 = 0
> reinschreibe zuckt der Motor auch mal ganz kurz aber dann läuft er ganz
> normal weiter.

Logisch.

Dennb nachdem die ISR abgelaufen ist, geht es ja an der unterbrechenden 
Stelle weiter, und das wird dann ja wohl die Hauptschleife in main() 
sein.

In der steht aber
1
  while(1) 
2
  {  
3
      i = pwm - unten;
4
      i = i * j;
5
      k = i;
6
      if(pwm >= oben)
7
      {
8
        k = 255;  
9
      }
10
      if(pwm <= unten)
11
      {
12
        k = 0;
13
      }
14
      OCR2 = k;

womit dein 0-setzen von OCR2 in der ISR nur noch ein Ereignis in der 
Vergangenheit war.

Deine ISR sollte
* ein globales Flag setzen, in dem vermerkt wird, dass der Motor 
abzustellen ist.
* die Hauptschleife berücksichtigt auch noch dieses Flag und entscheidet
  dann was eigentlich gilt. Der Wert, der sich aus der Knüppelposition
  ergeben hat, oder der fixe Wert 0, weil der Analogcomperator eine
  Fehlersituation festgestellt und im globalen Flag dokumentiert hat.
  Und je nachdem wird dann ein entsprechender Wert an OCR2 zugewiesen.

von Karl H. (kbuchegg)


Lesenswert?

PS.
deine vielen Endlos-Schleifen sind .... nicht gut.
Die kann man ruhig auch so umformen, dass man sich nicht aus jeder 
Schleife rausbreaken muss.

Aus
1
void Knueppelstellung(void)
2
{
3
  //Kontrolliert ob der Knueppel beim ersten Start in der Nullposition ist
4
  while(1)
5
  {
6
    if (pwm == unten)
7
    {
8
    break;
9
    }
10
  }
11
  PORTC |= (1 << PC0);
12
}

kann man ganz leicht machen
1
void Knueppelstellung(void)
2
{
3
  while( pwm != unten )
4
    ;
5
6
  PORTC |= (1 << PC0);
7
}

das ist erstens kürzer und zweitens sieht man auch recht eindeutig, was 
die Schleife eigentlich macht. Da steht
  Wiederhole solange, solange pwm nicht gleich unten ist.

Bam, das kann auch der Blindenhund eines Sehbehinderten aus 15 Meter 
Entfernung begreifen, worum es da geht. Und wenn du dann die Variable 
'pwm' noch sinnvoll benennst, denn das ist ja offensichtlich die 
festgestellte Knüppelstellung und auch noch der Funktion einen 
ordentlichen Namen gibst, dann wird der Code selbst dokumentierend ohne 
dass du auch nur einen einzigen Kommentar schreiben musst.
1
void WaitForUserReady()
2
{
3
  while( stick != unten )
4
    ;
5
6
  ENGINE_PORT |= ( 1 << ENGINE_PIN );
7
}

Anstatt des
  ENGINE_PORT |= ( 1 << ENGINE_PIN );
noch eine Abstrahierung, die Auskunft darüber gibt, was hier eigentlich 
mit dem Motor gemacht wird und gut ists.



Und mit den anderen while Schleifen kann man ebenfalls arbeiten. Das 
kann man alles gleichzeitig kürzer UND übersichtlicher schreiben. Deine 
Funktion Knueppelweg ist ein einziger Horror für eine eigentlich 
einfache Funktionalität.

von Steffen H. (stef_fen)


Lesenswert?

Vielen Dank. An der Übersichtlichkeit werde ich noch arbeiten.

>Deine ISR sollte
>* ein globales Flag setzen, in dem vermerkt wird, dass der Motor
>abzustellen ist.

Kann ich das über Bit 4 ACI machen? Muss ich dazu das I-Bit in SREG 
setzen oder mach das schon das sei()?

von Karl H. (kbuchegg)


Lesenswert?

Steffen Ha schrieb:
> Vielen Dank. An der Übersichtlichkeit werde ich noch arbeiten.

Machs gleich!

Die Tatsache, dass du deinen Code nicht mehr überblickst erzählt Bände!
Die Dinge werden nicht besser, in dem du notwendige Arbeiten am Code vor 
dir herschiebst.

> Kann ich das über Bit 4 ACI machen? Muss ich dazu das I-Bit in SREG
> setzen oder mach das schon das sei()?

Wozu so kompliziert?
1
volatile uint8_t currentOverload;
2
3
ISR(ANA_COMP_vect)
4
{
5
  if bit_is_clear(ACSR, ACO)
6
  {
7
    currentOverload = TRUE;
8
  }
9
  else
10
  {
11
    currentOverload = FALSE;
12
  }
13
}
14
15
16
...
17
18
19
int main()
20
{
21
  ...
22
23
  currentOverload = FALSE;
24
25
  ...
26
27
  while(1)
28
  {
29
    if( currentOverload )
30
    {
31
      LED_PORT &= ~(1 << OVERLOAD_LED );
32
      i = 0;
33
    }
34
35
    else
36
    {
37
      LED_PORT |= (1 << OVERLOAD_LED );
38
39
      i = pwm - unten;
40
      i = i * j;
41
42
      if(pwm >= oben)
43
      {
44
        i = 255;  
45
      }
46
      if(pwm <= unten)
47
      {
48
        i = 0;
49
      }
50
    }
51
52
    OCR2 = i;
53
54
    ...

Es ist löblich, wenn du dir überall { } machst. Aber wichtiger wäre es, 
ordentliche Variablennamen zu nehmen. Dieses i hier, das hat eine 
Bedeutung und die Variable hätte sich einen besseren Namen als 'i' 
verdient. Einen Namen, der ihrer Bedeutung besser entspricht. Genauso 
wie 'pwm'. Was ist dieses pwm, was stellt es dar? Das ist die Position 
des Knüppels! Das sollte auch in der Benamung der Variablen rauskommen. 
Das du diese Knüppelposition mit dem Timer feststellst, indem du die 
Pulslänge der eingehenden PWM ausmisst, das ist an dieser Stelle 
uninteressant. Benenne die Dinge danach, was sie (im Umfeld der Aufgabe) 
darstellen und nicht nach technischen Details. Eine Knüppelposition ist 
eine Knüppelposition und keine PWM. In deinem Progamm geht es um Knüppel 
(es sind wohl die KNüppel einer Fernsteuerung gemeint) und Motoren. Aber 
abgesehen von ein paar versteckten Kommentaren kann ich in deinem COde 
diese beiden Wörter überhaupt nirgends entdecken. Dabei sind diese 
beiden Begriffe die Haupt'personen' in diesem Programm. Darum dreht sich 
alles! Stattdessen lese ich i und k und j und ....

von Steffen H. (stef_fen)


Lesenswert?

Eben habe ich das Programm noch mal getestet. Wenn jetzt aber die 
simulierte Stromüberlast auftritt läut der Motor auf der letzen 
Geschwindigkeit weiter. Die LED geht an. Das passt ja soweit, aber der 
Motor sollte ja auch ausgehen.

1
 
2
//Bibliotheken einbinden
3
#define F_CPU 8000000
4
#include <avr/eeprom.h>
5
#include <avr/interrupt.h>
6
#include <avr/io.h>
7
#include "lcd-routines.h"
8
#include <stdlib.h>
9
#include <util/delay.h>
10
11
//Variablendeklaration
12
uint16_t eeunten EEMEM;        //fuer EEPROM
13
uint16_t unten;            //fuer EEPROM
14
uint16_t eeoben EEMEM;        //fuer EEPROM
15
uint16_t oben;            //fuer EEPROM
16
int flanke;              //fuer PWM
17
uint16_t flankeStart;        //fuer PWM
18
volatile uint16_t stick;      //fuer Knueppelposition (volatile = Global gueltig)
19
volatile uint8_t currentOverload;  //fuer Stromsensor
20
char Buffer[20];          //fuer LCD
21
int lcdpwm;              //fuer LCD
22
float i;              //fuer Rechnung
23
float deltaStick;              //fuer Rechnung
24
int k;                //fuer Rechnung
25
26
ISR(TIMER1_CAPT_vect)
27
{
28
  // Initialiserung fuer PWM einlesen vom Empfänger
29
  if (flanke==0)
30
  {
31
    flankeStart = ICR1;
32
    TCCR1B &= ~(1<<ICES1); // fallende Flanke zur Auswertung des ICP
33
    flanke = 1;
34
  }
35
  else
36
  {
37
    stick = ICR1 - flankeStart;
38
    flanke = 0;
39
    TCCR1B |= (1<<ICES1); // steigende Flanke zur Auswertung des ICP
40
  }
41
  TIFR = ( 1 << ICF1 );  
42
}
43
44
ISR(ANA_COMP_vect)
45
{
46
  //Intialisierung fuer Strommessung
47
  if bit_is_clear(ACSR, ACO)
48
  {
49
    currentOverload = 1;
50
  }
51
  else
52
  {
53
    currentOverload = 0;
54
  }
55
}
56
57
void PWM_Mosfet(void)
58
{
59
  /*Initialisierung fuer PWM ausgeben an Mosfet Treiber
60
  PWM = Prozessorgeschwindigkeit / (Prescaler * 256)
61
  PWM = 8000000 / (8 * 256) = 3906,25Hz = 3,9kHz*/
62
  DDRD |= (1 << PD7); // Motor (OC2 => PD7) = Ausgang
63
  OCR2 = 0; // von 0 bis 255 einstellbar
64
  TCCR2 |= (1 << COM21); // normaler Modus (für invertierenden Modus | (1 << COM20))
65
  TCCR2 |= (1 << WGM21) | (1 << WGM20); // fast PWM
66
  TCCR2 |= (1 << CS21); // Prescaler Clock/8
67
}
68
69
void PWM_Empfaenger(void)
70
{
71
  //Initialisierung fuer PWM einlesen vom Empfänger
72
  TCCR1B |= (1<<ICES1); // steigende Flanke zur Auswertung des ICP
73
  TCCR1B |= (1<<CS11) | (1<<CS10); //Quelle für Timer/Counter = CPU-Takt/64
74
  TIMSK |= (1<<TICIE1); //Capture Interrupt Enable
75
  DDRD &= ~(1<<PD6); // Impuls von Fernsteuerung (ICP1 => PD6) = Eingang
76
  PORTD |= (1<<PD6); //Pullup aktiviert
77
}
78
79
void Strommessung(void)
80
{
81
  //Initialisierung fuer Strommessung
82
  ACSR |= (0 << ACD);
83
  ACSR |= (1 << ACBG); //interne Referenzspannung (1,3 Volt)
84
  ACSR |= (1 << ACI);
85
  ACSR |= (1 << ACIE);
86
  ACSR |= (0 << ACIC);
87
  ACSR |= (0 << ACIS1) | (0 << ACIS0);
88
}
89
90
void Knueppelweg(void)
91
{
92
  //Initialisierung fuer Knueppelweg
93
  lcd_clear();
94
  lcd_string("Regler");
95
  lcd_setcursor( 0, 2);
96
  lcd_string("V2.0");
97
  _delay_ms(1000);
98
99
  //Werte ermitteln
100
  if(!(PINB & (1 << PB0)))
101
  {
102
    PORTB |= (1 << PB1);
103
    _delay_ms(1000);
104
    while(1) //fuer untere Knueppelposition
105
    {
106
      lcd_clear();
107
      lcd_string("down:");
108
      lcd_setcursor(0, 2);
109
      lcdpwm = stick * 8;
110
      itoa(lcdpwm, Buffer, 10);
111
      lcd_string(Buffer);
112
      _delay_ms(50);
113
      if(!(PINB & (1 << PB0)))
114
      {
115
        unten = stick;
116
        unten += 2; // Korrekturfaktor
117
        eeprom_write_word (&eeunten, unten); //schreiben
118
        lcd_clear();
119
        lcd_string("its:");
120
        lcd_setcursor(0, 2);
121
        itoa(unten, Buffer, 10);
122
        lcd_string(Buffer);
123
        _delay_ms(3000);
124
        break;
125
      }
126
    }
127
    _delay_ms(1000);
128
    while(1) //fuer obere Knueppelposition
129
    {
130
      lcd_clear();
131
      lcd_string("up:");
132
      lcd_setcursor(0, 2);
133
      lcdpwm = stick * 8;
134
      itoa(lcdpwm, Buffer, 10);
135
      lcd_string(Buffer);
136
      _delay_ms(50);
137
      if(!(PINB & (1 << PB0)))
138
      {
139
        oben = stick;
140
        oben -= 2; //Korrekturfaktor
141
        eeprom_write_word (&eeoben, oben); //schreiben
142
        lcd_clear();
143
        lcd_string("its:");
144
        lcd_setcursor(0, 2);
145
        itoa(oben, Buffer, 10);
146
        lcd_string(Buffer);
147
        _delay_ms(3000);
148
        PORTB &= ~(1 << PB1);
149
        break;
150
      }
151
    }
152
  }
153
  lcd_clear();  
154
}
155
156
void WaitForUserReady(void)
157
{
158
  //Kontrolliert ob der Knueppel beim ersten Start in der Nullposition ist
159
  while(stick != unten);
160
  PORTC |= (1 << PC0);
161
}
162
163
void Ein_Ausgaenge(void)
164
{
165
  //Initialisierung fuer Ein-/Ausgaenge
166
  DDRB &= ~(1 << PB0); //Taster (PB0) = Eingang
167
  PORTB |= (1 << PB0); //Pullup
168
  DDRB |= (1 << PB1); //Gelbe LED (PC6) = Ausgang
169
  DDRC |= (1 << PC0); //SD/ Pin IR2184 Mosfet Treiber (PC0) = Ausgang
170
}  
171
172
void ADC_Init(void) 
173
{
174
  //Initialisierung fuer Spannungsmessung
175
  uint16_t result;
176
 
177
  // interne Referenzspannung als Refernz für den ADC wählen:
178
  ADMUX = (1<<REFS1) | (1<<REFS0);
179
  ADCSRA = (1<<ADPS2) | (1<<ADPS1);     // Frequenzvorteiler, Dummyreadout
180
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
181
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
182
  while (ADCSRA & (1<<ADSC)) {         // auf Abschluss der Konvertierung warten
183
  }
184
  result = ADCW;
185
}
186
 
187
uint16_t ADC_Read(uint8_t channel)
188
{
189
  // Initialisierung fuer Spannungseinzelmessung
190
  ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F); //Kanal waehlen, ohne andere Bits zu beeinflußen
191
  ADCSRA |= (1<<ADSC);            // eine Wandlung "single conversion"
192
  while (ADCSRA & (1<<ADSC) ) {   // auf Abschluss der Konvertierung warten
193
  }
194
  return ADCW;
195
}
196
 
197
int main (void)
198
{
199
  lcd_init();
200
  lcd_clear(); 
201
    
202
  PWM_Mosfet();
203
  PWM_Empfaenger();
204
  Strommessung();
205
  sei(); //fuer ISR (gibt den Startschuss fuer Interrupt)
206
  Ein_Ausgaenge();
207
  Knueppelweg();
208
  
209
  currentOverload = 0;
210
211
  unten = eeprom_read_word (&eeunten); //EEPROM lesen
212
  oben = eeprom_read_word (&eeoben);
213
  
214
  WaitForUserReady();
215
  
216
  deltaStick = oben - unten; //Knueppelweg Vorberechnung
217
  deltaStick = 255 / deltaStick;
218
  
219
  ADC_Init(); //Spannungsmessung
220
  uint16_t  spannung; //Spannungsmessung
221
  
222
  while(1) 
223
  {  
224
    if(currentOverload == 1)
225
    {
226
      PORTB |= (1 << PB1);
227
      k = 0;
228
    }
229
    else
230
    {
231
      PORTB &= ~(1 << PB1);
232
      i = stick - unten;
233
      i = i * deltaStick;
234
      k = i;
235
      if(stick >= oben)
236
      {
237
        k = 255;  
238
      }
239
      if(stick <= unten)
240
      {
241
        k = 0;
242
      }
243
      OCR2 = k;
244
      spannung = ADC_Read(0);
245
      if (spannung <= 250)
246
      {
247
        break;
248
      }
249
    }
250
  }
251
  while(1)
252
  {
253
    OCR2 = 0;
254
    lcd_init();
255
    lcd_clear();
256
    lcd_string("Akku");
257
    lcd_setcursor( 0, 2);
258
    lcd_string("leer!");
259
    _delay_ms(1000);
260
    PORTC &= ~(1 << PC0);
261
  }
262
  return 0;
263
}

von Steffen H. (stef_fen)


Lesenswert?

Eben ist mir noch etwas eingefallen. Ich muss ja in der Main OCR2 = 0 
setzen anstatt k = 0 bei:

1
if(currentOverload == 1)
2
    {
3
      PORTB |= (1 << PB1);
4
      k = 0;
5
    }
6
7
8
 if(currentOverload == 1)
9
    {
10
      PORTB |= (1 << PB1);
11
      OCR2 = 0;
12
    }

von Karl H. (kbuchegg)


Lesenswert?

Schau noch mal GENAU!

Wo ...
1
  while(1) 
2
  {  
3
    if(currentOverload == 1)
4
    {
5
      PORTB |= (1 << PB1);
6
      k = 0;
7
    }
8
    else
9
    {
10
      PORTB &= ~(1 << PB1);
11
      i = stick - unten;
12
      i = i * deltaStick;
13
      k = i;
14
      if(stick >= oben)
15
      {
16
        k = 255;  
17
      }
18
      if(stick <= unten)
19
      {
20
        k = 0;
21
      }
22
      OCR2 = k;
23
      spannung = ADC_Read(0);
24
      if (spannung <= 250)
25
      {
26
        break;
27
      }
28
    }
29
  }
... setzt du den OCR2 neu?

Damit der Motor stoppt, muss OCR2 auf 0 gesetzt werden. Wie genau
realisierst du das in deinem Code?
Oder anders ausgedrückt: Wenn currentOverload anspricht, wie kommt dann
OCR2 eigentlich zu seinem vorgesehenen Wert von 0?

Bei dir: gar nicht.
Du setzt zwar k auf 0, aber .....
... wenn ich mir mal die Einrückung so ansehe
1
    if(currentOverload == 1)
2
    {
3
      ...
4
      k = 0;
5
    }
6
    else
7
    {
8
      ...
9
      OCR2 = k;
10
      ...
11
    }
dann landet dieses k ja nie im OCR2. Das 0-setzen ist im then-Zweig und
die Zuweisung ist im else Zweig.

von Steffen H. (stef_fen)


Lesenswert?

Perfekt. Jetzt funktioniert es. Momentan wertet ja der Timer 1 das 
Signal von der Fernsteuerung aus und der Timer 2 erzeugt das PWM Signal. 
Kann der Timer 1 eigentlich auch beide Aufgaben übernehmen?

Vielen Dank. Gruß Steffen

von Steffen H. (stef_fen)


Lesenswert?

Habt ihr eine Idee wie das mit den Timern ist?

Gruß Steffen

von Steffen H. (stef_fen)


Lesenswert?

Die Frage hat sich leider noch nicht geklärt. Hab ihr eine Idee wie das 
mit den Timern ist? Momentan wertet ja der Timer 1 das Signal von der 
Fernsteuerung aus und der Timer 2 erzeugt das PWM Signal. Kann der Timer 
1 eigentlich auch beide Aufgaben übernehmen?

Vielen Dank. Gruß Steffen

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.