Forum: Mikrocontroller und Digitale Elektronik Programm vom Atmega 16 auf Atmega 1284P


von Steffen H. (stef_fen)


Lesenswert?

Hallo Zusammen,

ich möchte gerne mein Programm vom Atmega 16 auf dem Atmega 1284P 
verwenden da er 2 16Bit Timer und 2 8 Bit Timer hat. Der Timer 1 liest 
über den ICP Pin ein PWM Signal von einer RC-Fernsteuerung ein und der 
Timer 3 soll ein PWM Signal erzeugen und damit einen Mosfettreiber 
steuern.

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
//Pinbelegung
11
#define MosfetDriver1_PORT  PORTD  //OC2
12
#define MosfetDriver1_DDR  DDRD
13
#define MosfetDriver1_DB  PB6
14
#define MosfetDriver2_PORT  PORTC
15
#define MosfetDriver2_DDR  DDRC
16
#define MosfetDriver2_DB  PC0
17
#define Stick_PORT      PORTD  //ICP1
18
#define Stick_PIN      PIND
19
#define Stick_DDR      DDRD
20
#define Stick_DB      PD6
21
#define Taster1_PORT    PORTC  
22
#define Taster1_PIN      PINC  
23
#define Taster1_DDR      DDRC
24
#define Taster1_DB      PC0
25
#define Taster2_PORT    PORTC
26
#define Taster2_PIN      PINC
27
#define Taster2_DDR      DDRC
28
#define Taster2_DB      PC1
29
#define LEDRot_PORT      PORTB
30
#define LEDRot_DDR      DDRB
31
#define LEDRot_DB      PB0
32
#define LEDGruen_PORT    PORTB
33
#define LEDGruen_DDR    DDRB
34
#define LEDGruen_DB      PB1
35
36
//Variablendeklaration
37
uint16_t eeunten EEMEM;          //fuer EEPROM
38
uint16_t unten;              //fuer EEPROM
39
uint16_t eeoben EEMEM;          //fuer EEPROM
40
uint16_t oben;              //fuer EEPROM
41
uint16_t eebrake EEMEM;          //fuer EEPROM
42
uint16_t brake;              //fuer EEPROM
43
int flanke;                //fuer Stick
44
uint16_t flankeStart;          //fuer Stick
45
volatile uint16_t stick;        //fuer Stick (volatile = Global gueltig)
46
float deltaStick;            //fuer Stick
47
float rechenwert;            //fuer Stick
48
int sollwert;              //fuer Stick
49
volatile uint8_t currentOverload = 0;  //fuer currentOverload
50
uint16_t voltage;            //fuer voltage
51
uint16_t overTemperature;        //fuer overTemperature
52
int lcdpwm;                //fuer LCD
53
char Buffer[20];            //fuer LCD
54
55
ISR(TIMER1_CAPT_vect) {
56
  if (flanke==0) {
57
    flankeStart = ICR1;
58
    TCCR1B &= ~(1<<ICES1); // fallende Flanke zur Auswertung des ICP
59
    flanke = 1;
60
  }
61
  else {
62
    stick = ICR1 - flankeStart;
63
    flanke = 0;
64
    TCCR1B |= (1<<ICES1); // steigende Flanke zur Auswertung des ICP
65
  }
66
  TIFR1 = ( 1 << ICF1 );  
67
}
68
69
ISR(ANA_COMP_vect) {
70
  if bit_is_clear(ACSR, ACO) {
71
    currentOverload = 1;
72
  }
73
  else {
74
    currentOverload = 0;
75
  }
76
}
77
78
void PWM_Mosfet(void) {
79
  /*Initialisierung fuer PWM ausgeben an Mosfet Treiber
80
  PWM = Prozessorgeschwindigkeit / (Prescaler * 256)
81
  PWM = 8000000 / (8 * 256) = 3906,25Hz = 3,9kHz*/
82
  MosfetDriver1_DDR |= (1 << MosfetDriver1_DB);  //Motor OC2 = Ausgang
83
  OCR3A = 0;                    //von 0 bis 256 einstellbar
84
  TCCR3A |= (1 << COM3A1);            //normaler Modus
85
  TCCR3A |= (1 << WGM31) | (1 << WGM30);      //fast PWM
86
  TCCR3B |= (1 << CS31);              //Prescaler Clock/8
87
}
88
89
void PWM_Empfaenger(void) {
90
  TCCR1B |= (1<<ICES1);        //steigende Flanke zur Auswertung des ICP
91
  TCCR1B |= (1<<CS11) | (1<<CS10);  //Quelle für Timer/Counter = CPU-Takt/64
92
  TIMSK1 |= (1<<ICIE1);        //Capture Interrupt Enable
93
  Stick_DDR &= ~(1<<Stick_DB);    //Impuls von Fernsteuerung ICP1 = Eingang
94
  Stick_PORT |= (1<<Stick_DB);    //Pullup aktiviert
95
}
96
97
void Strommessung(void) {
98
  ACSR |= (0 << ACD);            //Comparator ein
99
  ACSR |= (1 << ACBG);          //interne Referenzspannung (1,3 Volt)
100
  ACSR |= (1 << ACI);            //kann fuer Abfragen genutzt werden
101
  ACSR |= (1 << ACIE);          //löst Interrupt aus
102
  ACSR |= (0 << ACIC);          //verbindet Comparatorausgang mit Counter 1
103
  ACSR |= (0 << ACIS1) | (0 << ACIS0);  //Interrupt auslösen bei jedem Flankenwechsel
104
}
105
106
void StickWay(void) {
107
  if(!(Taster1_PIN & (1 << Taster1_DB))) {
108
    LEDGruen_PORT |= (1 << LEDGruen_DB);
109
    LEDRot_PORT |= (1 << LEDRot_DB);
110
    while(1) {
111
        _delay_ms(3000);
112
        unten = stick + 2;            //incl. Korrekturfaktor
113
        lcdpwm = unten;
114
        lcd_clear();
115
        itoa(lcdpwm, Buffer, 10);
116
        lcd_string(Buffer);
117
        eeprom_write_word (&eeunten, unten);
118
        _delay_ms(3000);
119
        LEDRot_PORT &= ~(1 << LEDRot_DB);
120
        _delay_ms(3000);
121
        oben = stick - 2;            //incl. Korrerkturfaktor
122
        eeprom_write_word (&eeoben, oben);
123
        _delay_ms(3000);
124
        LEDGruen_PORT &= ~(1 << LEDGruen_DB);
125
        break;
126
    }
127
  }  
128
}
129
130
void OptionalBrake (void) {
131
  if(!(Taster2_PIN & (1 << Taster2_DB))) {
132
    LEDGruen_PORT |= (1 << LEDGruen_DB);
133
    LEDRot_PORT |= (1 << LEDRot_DB);
134
    brake = eeprom_read_word (&eebrake);
135
    if (brake == 1) {
136
      brake = 0;
137
    }
138
    else {
139
      brake = 1;
140
    }
141
    eeprom_write_word (&eebrake, brake);
142
    _delay_ms(3000);
143
    LEDRot_PORT &= ~(1 << LEDRot_DB);
144
    LEDGruen_PORT &= ~(1 << LEDGruen_DB);
145
  }
146
}
147
148
void EepromRead(void) {
149
  unten = eeprom_read_word (&eeunten);
150
  oben = eeprom_read_word (&eeoben);
151
  brake = eeprom_read_word (&eebrake);
152
  unten = 1100;
153
  oben = 1900;
154
  deltaStick = oben - unten;
155
  if (deltaStick == 0) {
156
    while(1) {
157
      LEDRot_PORT |= (1 << LEDRot_DB);
158
      LEDGruen_PORT |= (1 << LEDGruen_DB);
159
    }
160
  }
161
  deltaStick = 512 / deltaStick;
162
}
163
164
void WaitForUserReady(void) {
165
  LEDGruen_PORT &= ~(1 << LEDGruen_DB);
166
  LEDRot_PORT |= (1 << LEDRot_DB);
167
  while(stick != unten);
168
  MosfetDriver2_PORT |= (1 << MosfetDriver2_DB);
169
  LEDRot_PORT &= ~(1 << LEDRot_DB);
170
  LEDGruen_PORT |= (1 << LEDGruen_DB);
171
}
172
173
void InputOutput(void) {
174
  MosfetDriver2_DDR |= (1 << MosfetDriver2_DB);  //SD Pin IR2184 Mosfet Treiber
175
  Taster1_DDR &= ~(1 << Taster1_DB);        //Taster 1
176
  Taster1_PORT |= (1 << Taster1_DB);        //Pullup fuer Taster 1
177
  Taster2_DDR &= ~(1 << Taster2_DB);        //Taster 2
178
  Taster2_PORT |= (1 << Taster2_DB);        //Pullup fuer Taster 2
179
  LEDRot_DDR |= (1 << LEDRot_DB);          //Rote LED
180
  LEDGruen_DDR |= (1 << LEDGruen_DB);        //Gruene LED
181
}  
182
183
void ADC_Init(void) {
184
  uint16_t result;
185
  ADMUX = (1<<REFS1) | (1<<REFS0);    //interne Referenzspannung (2,56V)
186
  ADCSRA = (1<<ADPS2) | (1<<ADPS1);     // Frequenzvorteiler, Dummyreadout
187
  ADCSRA |= (1<<ADEN);                  // ADC aktivieren
188
  ADCSRA |= (1<<ADSC);                  // eine ADC-Wandlung 
189
  while (ADCSRA & (1<<ADSC)) {      // auf Abschluss der Konvertierung warten
190
  }
191
  result = ADCW;
192
}
193
 
194
uint16_t ADC_Read(uint8_t channel) {
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
  sei();          //erlaubt globale Interrupts
204
  lcd_init();
205
  lcd_clear();
206
  lcd_string("Regler");
207
  PWM_Empfaenger();
208
  PWM_Mosfet();
209
  Strommessung();
210
  InputOutput();
211
  StickWay();
212
  //OptionalBrake();
213
  EepromRead();
214
  WaitForUserReady();
215
  ADC_Init();
216
  
217
  while(1) {  
218
    if(currentOverload == 1) {
219
      OCR3A = 0;
220
      MosfetDriver2_PORT &= ~(1 << MosfetDriver2_DB);
221
      WaitForUserReady();
222
    }
223
    overTemperature = ADC_Read(1);
224
    if (overTemperature >= 250) {
225
      OCR3A = 0;
226
      MosfetDriver2_PORT &= ~(1 << MosfetDriver2_DB);
227
      WaitForUserReady();  
228
    }
229
    else {
230
      voltage = ADC_Read(0);
231
      if (voltage <= 125)
232
      {
233
        break;
234
      }
235
      rechenwert = stick - unten;
236
      rechenwert = rechenwert * deltaStick;
237
      sollwert = rechenwert;
238
      if(stick >= oben) {
239
        sollwert = 512;  
240
      }
241
      if(stick <= unten) {
242
        sollwert = 0;
243
      }
244
      if (voltage <= 250) {
245
        if (sollwert >= 127) {
246
          sollwert = 127;
247
        }
248
      }
249
      OCR3A = sollwert;
250
    }
251
  }
252
  while(1) {
253
    OCR3A = 0;
254
    MosfetDriver2_PORT &= ~(1 << MosfetDriver2_DB);
255
    LEDGruen_PORT &= ~(1 << LEDGruen_DB);
256
    LEDRot_PORT |= (1 << LEDRot_DB);
257
  }
258
  return 0;
259
}

Vorher stand in der Funktion:
1
void PWM_Mosfet(void)
2
{
3
  /*Initialisierung fuer PWM ausgeben an Mosfet Treiber
4
  PWM = Prozessorgeschwindigkeit / (Prescaler * 256)
5
  PWM = 8000000 / (8 * 256) = 3906,25Hz = 3,9kHz*/
6
  DDRD |= (1 << PD7); // Motor (OC2 => PD7) = Ausgang
7
  OCR2 = 0; // von 0 bis 255 einstellbar
8
  TCCR2 |= (1 << COM21); // normaler Modus (für invertierenden Modus | (1 << COM20))
9
  TCCR2 |= (1 << WGM21) | (1 << WGM20); // fast PWM
10
  TCCR2 |= (1 << CS21); // Prescaler Clock/8
11
}
12
13
void PWM_Empfaenger(void)
14
{
15
  //Initialisierung fuer PWM einlesen vom Empfänger
16
  TCCR1B |= (1<<ICES1); // steigende Flanke zur Auswertung des ICP
17
  TCCR1B |= (1<<CS11) | (1<<CS10); //Quelle für Timer/Counter = CPU-Takt/64
18
  TIMSK |= (1<<TICIE1); //Capture Interrupt Enable
19
  DDRD &= ~(1<<PD6); // Impuls von Fernsteuerung (ICP1 => PD6) = Eingang
20
  PORTD |= (1<<PD6); //Pullup aktiviert
21
}

In der ISR(ANA_COMP_vect) scheint auch irgendetwas nicht mehr zu 
stimmen. Muss das jetzt ISR(ANALOG_COMP_vect) heißen? Aber warum? Auch 
bei den Ports defines oben im Programm ist (#define MosfetDriver1_DB 
PB6) z.B. das PB6 nicht mehr lila hinterlegt im Atmel Studio 6.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

Bitte lies die Datenblätter der beiden Controller und schau mal in die 
Device-Files. Dort haben sich sicher Namen und Positionen von Registern 
und Bits geändert. Das ist immer so, wenn man von einem (alten) 
kleineren Chip auf einen (neueren) großen portiert.

von Steffen H. (stef_fen)


Lesenswert?

Aber warum wird bei den Ports defines oben im Programm (#define 
MosfetDriver1_DB PB6) z.B. das PB6 nicht mehr lila hinterlegt im Atmel 
Studio 6? Wenn ich den Device Atmega 16 auswähle ist es wieder so, 
ändere ich ihn wieder zurück ist er schwarz.

von Karl H. (kbuchegg)


Lesenswert?

Entscheidend ist nicht, ob das Syntax-Highlighting deines Editors ein 
bestimmtes Wort, auf welches es konditioniert wurde, lila, grün blau 
oder rot einfärbt, entscheidend ist, ob der µC den Portpin hat und ob 
der Compiler ihn kennt.

von nix (Gast)


Lesenswert?

Steffen Ha schrieb:
> das PB6 nicht mehr lila hinterlegt im Atmel
> Studio 6

Ich verwende den Atmega1284P nun schon ein halbes Jahr und bin ebenfalls 
vom 16er gewechselt...bei mir markiert er sie auch nicht mehr, ABER es 
funktioniert trotzdem:)

von Steffen H. (stef_fen)


Angehängte Dateien:

Lesenswert?

Jetzt habe ich mal nur den oberen Teil des Programmes, also das einlesen 
des PWM Signals von der Fernsteuerung getestet.

Beim Atmega 16 habe ich eine Taktfrequenz von 8MHz (externem 
Quarzoszillator) und einem Prescaler von 8:

((8*10^6 Hz) / 8)^-1 = 1us * 1900 (zeigt das Display an) = 1900us = 
1,9ms was der oberen Knüppelposition der Fernsteuerung entspricht.

Beim Atmega 1284P habe ich auch eine Taktfrequenz von 8MHz (externem 
Quarzoszillator) und einem Prescaler von 8):

Da zeigt mir das Display aber nur 238 * 1us wären ja nur 238us.

Auch die Zeit für das _delay_ms kommt mir viel länger vor und die 
Einstellungen für die Fuses die mir das Atmel Studio im Vergleich zum 
Atmega 16 bietet sind auch komisch. Beim internen Oszillator steht nur 
etwas von kHz aber nicht von MHz.

von Karl H. (kbuchegg)


Lesenswert?

Schalte die CKDIV8 Fuse aus.


Es hilft nichts:
Du MUSST die jeweiligen Datenblätter STUDIEREN. Auch wenn dir das nicht 
gefällt.

von Electronics'nStuff (Gast)


Lesenswert?

Und es gibt einen praktischen Knopf auf deiner Tastatur, der nennt sich 
"PrtScn" oder ähnlich.

Dann musst du deinen Bildschirm nicht mehr fotografieren.

von Steffen H. (stef_fen)


Lesenswert?

Ich habe mir jetzt erst mal ein kleines Testprogramm gemacht. Die 
Funktion zum einlesen des PWM Signals vom Empfänger funktioniert aber 
nur wenn ich den Teil des PWM Signals für den Mosfet ausklammere. Nehme 
ich den Teil dazu zeigt er mir auf dem Display nur eine Null. Ich habe 
mir das Datenblatt mal angeschaut. Aber ich kann nichts finden.

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
//Pinbelegung
11
#define MosfetDriver1_PORT  PORTD  //OC2
12
#define MosfetDriver1_DDR  DDRD
13
#define MosfetDriver1_DB  PB6
14
#define MosfetDriver2_PORT  PORTC
15
#define MosfetDriver2_DDR  DDRC
16
#define MosfetDriver2_DB  PC0
17
#define Stick_PORT      PORTD  //ICP1
18
#define Stick_PIN      PIND
19
#define Stick_DDR      DDRD
20
#define Stick_DB      PD6
21
22
//Variablendeklaration
23
int flanke;                //fuer Stick
24
uint16_t flankeStart;          //fuer Stick
25
volatile uint16_t stick;        //fuer Stick (volatile = Global gueltig)
26
float deltaStick;            //fuer Stick
27
float rechenwert;            //fuer Stick
28
int sollwert;              //fuer Stick
29
volatile uint8_t currentOverload = 0;  //fuer currentOverload
30
uint16_t voltage;            //fuer voltage
31
uint16_t overTemperature;        //fuer overTemperature
32
int lcdpwm;                //fuer LCD
33
char Buffer[20];            //fuer LCD
34
35
ISR(TIMER1_CAPT_vect) {
36
  if (flanke==0) {
37
    flankeStart = ICR1;
38
    TCCR1B &= ~(1<<ICES1); // fallende Flanke zur Auswertung des ICP
39
    flanke = 1;
40
  }
41
  else {
42
    stick = ICR1 - flankeStart;
43
    flanke = 0;
44
    TCCR1B |= (1<<ICES1); // steigende Flanke zur Auswertung des ICP
45
  }
46
  TIFR1 = ( 1 << ICF1 );  
47
}
48
49
void PWM_Empfaenger(void) {
50
  TCCR1B |= (1<<ICES1);        //steigende Flanke zur Auswertung des ICP
51
  TCCR1B |= (1<<CS11);        //Quelle für Timer/Counter = CPU-Takt/8
52
  TIMSK1 |= (1<<ICIE1);        //Capture Interrupt Enable
53
  Stick_DDR &= ~(1<<Stick_DB);    //Impuls von Fernsteuerung ICP1 = Eingang
54
  Stick_PORT |= (1<<Stick_DB);    //Pullup aktiviert
55
}
56
57
void PWM_Mosfet(void) {
58
  /*Initialisierung fuer PWM ausgeben an Mosfet Treiber
59
  PWM = Prozessorgeschwindigkeit / (Prescaler * 256)
60
  PWM = 8000000 / (8 * 1023) = 3906,25Hz = 3,9kHz*/
61
  MosfetDriver1_DDR |= (1 << MosfetDriver1_DB);  //Motor OC2 = Ausgang
62
  OCR3A = 0;                    //von 0 bis 256 einstellbar
63
  TCCR3A |= (1 << COM3A1) | (1 << WGM31) | (1 << WGM30);      //normaler Modus & fast PWM
64
  TCCR3B |= (1 << WGM32) | (1 << CS31);              //fast PWM & Prescaler Clock/8
65
}
66
67
void InputOutput(void) {
68
  MosfetDriver2_DDR |= (1 << MosfetDriver2_DB);  //SD Pin IR2184 Mosfet Treiber
69
  Taster1_DDR &= ~(1 << Taster1_DB);        //Taster 1
70
  Taster1_PORT |= (1 << Taster1_DB);        //Pullup fuer Taster 1
71
  Taster2_DDR &= ~(1 << Taster2_DB);        //Taster 2
72
  Taster2_PORT |= (1 << Taster2_DB);        //Pullup fuer Taster 2
73
  LEDRot_DDR |= (1 << LEDRot_DB);          //Rote LED
74
  LEDGruen_DDR |= (1 << LEDGruen_DB);        //Gruene LED
75
}
76
77
int main (void) {
78
  sei();          //erlaubt globale Interrupts
79
  InputOutput();
80
  PWM_Empfaenger();
81
  PWM_Mosfet();
82
  lcd_init();
83
  lcd_clear();
84
  lcd_string("Regler");
85
  MosfetDriver2_PORT |= (1 << MosfetDriver2_DB);
86
  _delay_ms(1000);
87
  
88
  while(1) {
89
  lcd_clear();
90
  lcd_string("PWM");
91
  lcd_setcursor(0, 2);
92
  lcdpwm = stick;
93
  itoa(lcdpwm, Buffer, 10);
94
  lcd_string(Buffer);  
95
  _delay_ms(50);
96
  OCR3A = 50;
97
    
98
  }
99
  return 0;
100
}

von Karl H. (kbuchegg)


Lesenswert?

Da kann was nicht stimmen

> #define MosfetDriver1_PORT  PORTD  //OC2
> #define MosfetDriver1_DDR  DDRD
> #define MosfetDriver1_DB  PB6

> #define Stick_PORT      PORTD  //ICP1
> #define Stick_PIN      PIND
> #define Stick_DDR      DDRD
> #define Stick_DB      PD6

Der Eingang vom RC-Empfänger kann nicht am Port D / Pin 6 liegen, wenn 
da gleichzeitig der Ausgang vom Mosfet Driver liegt. (Oder umgekehrt)

Irgendeine der beiden Angaben muss falsch sein.

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.