Forum: Mikrocontroller und Digitale Elektronik Brushless Regler Umbau


von Morgy (Gast)


Lesenswert?

Hallo alle zusammen
ich habe auf www.ulrichradig.de unter  Homepage » AVR » AVR BLMC den 
Regler für Brushless Motoren gefunden und will den nach/umbauen.
Nachdem ich die letzten 3 Tage intensiv die Tutorials zum AVR hier 
gelesen habe und den Code
1
/*----------------------------------------------------------------------------
2
 Copyright:      Ulrich Radig (mail@ulrichradig.de)
3
 Author:         Ulrich Radig
4
 Remarks:        
5
 known Problems: none
6
 Version:        23.06.2011
7
 Description:    Brushless Motor Controller for ATmega48/88/168
8
 
9
 Dieses Programm ist freie Software. Sie können es unter den Bedingungen der 
10
 GNU General Public License, wie von der Free Software Foundation veröffentlicht, 
11
 weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder 
12
 (nach Ihrer Option) jeder späteren Version. 
13
14
 Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, 
15
 daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, 
16
 sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT 
17
 FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. 
18
19
 Sie sollten eine Kopie der GNU General Public License zusammen mit diesem 
20
 Programm erhalten haben. 
21
 Falls nicht, schreiben Sie an die Free Software Foundation, 
22
 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 
23
------------------------------------------------------------------------------*/
24
25
#include <avr/interrupt.h>
26
#include <avr/io.h>
27
#include <util/twi.h>
28
29
//Motoradresse
30
#define MOTOR_ADR 0x70
31
32
//PHASE1 (U)
33
#define UH_DDR  DDRB |= (1<<3);
34
#define UH_ON  TCCR2A |= (1<<COM2A1);
35
#define UH_OFF  TCCR2A &= ~(1<<COM2A1);
36
37
//PHASE1 (U)
38
#define UL_DDR  DDRB |= (1<<1);
39
#define UL_ON  PORTB |= (1<<1);
40
#define UL_OFF  PORTB &= ~(1<<1);
41
42
43
//PHASE2 (V)
44
#define VH_DDR  DDRD |= (1<<5);
45
#define VH_ON  TCCR0A |= (1<<COM0B1);
46
#define VH_OFF  TCCR0A &= ~(1<<COM0B1);
47
48
//PHASE2 (V)
49
#define VL_DDR  DDRB |= (1<<2);
50
#define VL_ON  PORTB |= (1<<2);
51
#define VL_OFF  PORTB &= ~(1<<2);
52
53
54
//PHASE3 (W)
55
#define WH_DDR  DDRD |= (1<<3);
56
#define WH_ON  TCCR2A |= (1<<COM2B1);
57
#define WH_OFF  TCCR2A &= ~(1<<COM2B1);
58
59
//PHASE3 (W)
60
#define WL_DDR  DDRC |= (1<<3);
61
#define WL_ON  PORTC |= (1<<3);
62
#define WL_OFF  PORTC &= ~(1<<3);
63
64
65
#define PHASE_ALL_OFF  UH_OFF;UL_OFF;VH_OFF;VL_OFF;WH_OFF;WL_OFF;
66
67
#define SENSE_U    ADMUX = 0;
68
#define SENSE_V    ADMUX = 1;
69
#define SENSE_W    ADMUX = 2;
70
71
#define SENSE_H    (ACSR&(1<<ACO))
72
73
#define START_PWM   5
74
75
volatile unsigned long i2c_timeout = 0;
76
volatile unsigned char rx_pwm = 0;
77
volatile unsigned char rotor_state = 0;
78
volatile unsigned char rotor_run = 0;
79
80
//############################################################################
81
void next_commutate_state (unsigned char startup)
82
//############################################################################
83
{
84
  switch (rotor_state)
85
  {
86
    case (0):
87
      if(!SENSE_H || startup)
88
      {
89
        WH_OFF;
90
        UH_ON;
91
        SENSE_W;
92
        rotor_state = 1;
93
        TCNT1 = 1;
94
      }
95
      break;
96
97
    case (1):
98
      if(SENSE_H || startup)
99
      {
100
        VL_OFF;
101
        WL_ON;
102
        SENSE_V;
103
        rotor_state = 2;
104
        TCNT1 = 1;
105
      }
106
      break;
107
108
    case (2):
109
      if(!SENSE_H || startup)
110
      {
111
        UH_OFF;
112
        VH_ON;
113
        SENSE_U;
114
        rotor_state = 3;
115
        TCNT1 = 1;
116
      }
117
      break;
118
  
119
    case (3):
120
      if(SENSE_H || startup)
121
      {
122
        WL_OFF;
123
        UL_ON;
124
        SENSE_W;
125
        rotor_state = 4;
126
        TCNT1 = 1;
127
      }
128
      break;
129
130
    case (4):
131
      if(!SENSE_H || startup)
132
      {
133
        VH_OFF;
134
        WH_ON;
135
        SENSE_V;
136
        rotor_state = 5;
137
        TCNT1 = 1;
138
      }
139
      break;
140
141
    case (5):
142
      if(SENSE_H || startup)
143
      {
144
        UL_OFF;
145
        VL_ON;
146
        SENSE_U;
147
        rotor_state = 0;
148
        TCNT1 = 1;
149
      }
150
      break;
151
  }
152
}
153
154
//############################################################################
155
//back EMF zero crossing detection
156
ISR (ANALOG_COMP_vect) 
157
//############################################################################
158
{
159
  if(rotor_run == 200) next_commutate_state (0);
160
  
161
  rotor_run++;
162
  if(rotor_run > 200)
163
  {
164
    rotor_run = 200;
165
  }
166
}
167
168
//############################################################################
169
ISR (TIMER1_OVF_vect)
170
//############################################################################
171
{  
172
  next_commutate_state (1);
173
  rotor_run = 0;
174
  OCR2A = START_PWM;
175
  OCR2B = START_PWM;
176
  OCR0B = START_PWM;
177
}
178
179
//############################################################################
180
ISR (TWI_vect)
181
//############################################################################
182
{  
183
  switch (TWSR & 0xF8) //TW_STATUS 
184
  {  
185
    //Adresse empfangen
186
    case TW_SR_SLA_ACK:  
187
      TWCR |= (1<<TWINT);
188
      return;
189
      
190
    //Daten empfangen
191
    case TW_SR_DATA_ACK:
192
      rx_pwm = TWDR;
193
      TWCR |= (1<<TWINT);
194
      i2c_timeout = 0;
195
      return;
196
197
    //Bus-Fehler zurücksetzen 
198
    case TW_NO_INFO:
199
      TWCR |=(1<<TWSTO) | (1<<TWINT); 
200
201
    //Bus-Fehler zurücksetzen   
202
    case TW_BUS_ERROR:
203
      TWCR |=(1<<TWSTO) | (1<<TWINT); 
204
  }
205
  //Reset TW
206
  TWCR =(1<<TWEA) | (1<<TWINT) | (1<<TWEN) | (1<<TWIE);
207
}
208
209
//############################################################################
210
//Hauptprogramm
211
int main (void) 
212
//############################################################################
213
{
214
  //Watchdog on
215
  WDTCSR = (1<<WDCE) | (1<<WDE);
216
  
217
  //Motordriver output
218
  UH_DDR;
219
  VH_DDR;
220
  WH_DDR;
221
  UL_DDR;
222
  VL_DDR;
223
  WL_DDR;
224
    
225
  //PWM for UH, VH and WH (>32KHz)
226
  TCCR0A |= (1<<COM0B1|1<<WGM01|1<<WGM00);
227
  TCCR0B |= (1<<CS00);
228
  
229
  TCCR2A |= (1<<COM2A1|1<<COM2B1|1<<WGM21|1<<WGM20);
230
  TCCR2B |= (1<<CS20);
231
  
232
  //TIMER1 for start commutation or Back EMF lost
233
  TCCR1B |= (1<<CS11);
234
  TIMSK1 |= (1<<TOIE1);
235
236
  PHASE_ALL_OFF;
237
  
238
  //Comperator init for back EMF
239
  ADCSRB  |= (1<<ACME);
240
  DIDR1  |= (1<<AIN0D);
241
  ACSR  |= (1<<ACIE);
242
    
243
  //I2C Init
244
  TWAR = MOTOR_ADR & 0xFE;
245
    TWCR = (1<<TWINT)|(1<<TWEA)|(1<<TWEN)|(1<<TWIE);
246
  
247
  //Interrupts enable
248
  sei();
249
  
250
251
  while(1)
252
  {  
253
    asm("wdr");
254
    if(rx_pwm > START_PWM)
255
    {
256
      ACSR |= (1<<ACIE);
257
      TIMSK1 |= (1<<TOIE1);
258
      
259
      if(rotor_run == 200)
260
      {
261
        OCR2A = rx_pwm;
262
        OCR2B = rx_pwm;
263
        OCR0B = rx_pwm;
264
      }
265
      i2c_timeout++;
266
      
267
      if(i2c_timeout>100000)
268
      {
269
        rx_pwm = 0;
270
      }
271
    }
272
    else
273
    {
274
      PHASE_ALL_OFF;
275
      ACSR&=~(1<<ACIE);
276
      TIMSK1 &= ~(1<<TOIE1);
277
    }
278
  }
279
}
studiert und denke nun, dass ich halbwegs verstehe, was was macht.
Die Schaltung habe ich auf nem Breadboard nachgebaut, jedoch ohne 
Steuerung per I2C.
Generell will ich den Regler umbauen, dass er per PPM (also Modellbau 
Standard) geregelt werden kann, aber das komtm erst noch.
Jetzt will ich erst mal meine Schaltung testen.
Hierfür habe ich im Code den Interrupt ISR (TWI_vect) als auch das I2C 
Init gelöscht und in der void main den timeout entfernt. Soweit ich das 
sehe, wird die Geschwindigkeit des Reglers bzw. die PWM über die 
Variable
volatile unsigned char rx_pwm = 0 geregelt, und um die Schaltung zu 
testen habe ich es abgeändert in volatile unsigned char rx_pwm = 
0b10000000, also Mitte des 8Bit Bereichs, um die Schaltung zu testen und 
der Motor mal mittelschnell dreht.
Der neue Code sieht dementsprechend so aus
1
/*----------------------------------------------------------------------------
2
 Copyright:      Ulrich Radig (mail@ulrichradig.de)
3
 Author:         Ulrich Radig
4
 Remarks:        
5
 known Problems: none
6
 Version:        23.06.2011
7
 Description:    Brushless Motor Controller for ATmega48/88/168
8
 
9
 Dieses Programm ist freie Software. Sie können es unter den Bedingungen der 
10
 GNU General Public License, wie von der Free Software Foundation veröffentlicht, 
11
 weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder 
12
 (nach Ihrer Option) jeder späteren Version. 
13
14
 Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, 
15
 daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, 
16
 sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT 
17
 FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. 
18
19
 Sie sollten eine Kopie der GNU General Public License zusammen mit diesem 
20
 Programm erhalten haben. 
21
 Falls nicht, schreiben Sie an die Free Software Foundation, 
22
 Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. 
23
------------------------------------------------------------------------------*/
24
25
#include <avr/interrupt.h>
26
#include <avr/io.h>
27
#include <util/twi.h>
28
29
//Motoradresse
30
#define MOTOR_ADR 0x70
31
32
//PHASE1 (U)
33
#define UH_DDR  DDRB |= (1<<3);
34
#define UH_ON  TCCR2A |= (1<<COM2A1);
35
#define UH_OFF  TCCR2A &= ~(1<<COM2A1);
36
37
//PHASE1 (U)
38
#define UL_DDR  DDRB |= (1<<1);
39
#define UL_ON  PORTB |= (1<<1);
40
#define UL_OFF  PORTB &= ~(1<<1);
41
42
43
//PHASE2 (V)
44
#define VH_DDR  DDRD |= (1<<5);
45
#define VH_ON  TCCR0A |= (1<<COM0B1);
46
#define VH_OFF  TCCR0A &= ~(1<<COM0B1);
47
48
//PHASE2 (V)
49
#define VL_DDR  DDRB |= (1<<2);
50
#define VL_ON  PORTB |= (1<<2);
51
#define VL_OFF  PORTB &= ~(1<<2);
52
53
54
//PHASE3 (W)
55
#define WH_DDR  DDRD |= (1<<3);
56
#define WH_ON  TCCR2A |= (1<<COM2B1);
57
#define WH_OFF  TCCR2A &= ~(1<<COM2B1);
58
59
//PHASE3 (W)
60
#define WL_DDR  DDRC |= (1<<3);
61
#define WL_ON  PORTC |= (1<<3);
62
#define WL_OFF  PORTC &= ~(1<<3);
63
64
65
#define PHASE_ALL_OFF  UH_OFF;UL_OFF;VH_OFF;VL_OFF;WH_OFF;WL_OFF;
66
67
#define SENSE_U    ADMUX = 0;
68
#define SENSE_V    ADMUX = 1;
69
#define SENSE_W    ADMUX = 2;
70
71
#define SENSE_H    (ACSR&(1<<ACO))
72
73
#define START_PWM   5
74
75
volatile unsigned long i2c_timeout = 0;
76
volatile unsigned char rx_pwm = 0b10000000;
77
volatile unsigned char rotor_state = 0;
78
volatile unsigned char rotor_run = 0;
79
80
//############################################################################
81
void next_commutate_state (unsigned char startup)
82
//############################################################################
83
{
84
  switch (rotor_state)
85
  {
86
    case (0):
87
      if(!SENSE_H || startup)
88
      {
89
        WH_OFF;
90
        UH_ON;
91
        SENSE_W;
92
        rotor_state = 1;
93
        TCNT1 = 1;
94
      }
95
      break;
96
97
    case (1):
98
      if(SENSE_H || startup)
99
      {
100
        VL_OFF;
101
        WL_ON;
102
        SENSE_V;
103
        rotor_state = 2;
104
        TCNT1 = 1;
105
      }
106
      break;
107
108
    case (2):
109
      if(!SENSE_H || startup)
110
      {
111
        UH_OFF;
112
        VH_ON;
113
        SENSE_U;
114
        rotor_state = 3;
115
        TCNT1 = 1;
116
      }
117
      break;
118
  
119
    case (3):
120
      if(SENSE_H || startup)
121
      {
122
        WL_OFF;
123
        UL_ON;
124
        SENSE_W;
125
        rotor_state = 4;
126
        TCNT1 = 1;
127
      }
128
      break;
129
130
    case (4):
131
      if(!SENSE_H || startup)
132
      {
133
        VH_OFF;
134
        WH_ON;
135
        SENSE_V;
136
        rotor_state = 5;
137
        TCNT1 = 1;
138
      }
139
      break;
140
141
    case (5):
142
      if(SENSE_H || startup)
143
      {
144
        UL_OFF;
145
        VL_ON;
146
        SENSE_U;
147
        rotor_state = 0;
148
        TCNT1 = 1;
149
      }
150
      break;
151
  }
152
}
153
154
//############################################################################
155
//back EMF zero crossing detection
156
ISR (ANALOG_COMP_vect) 
157
//############################################################################
158
{
159
  if(rotor_run == 200) next_commutate_state (0);
160
  
161
  rotor_run++;
162
  if(rotor_run > 200)
163
  {
164
    rotor_run = 200;
165
  }
166
}
167
168
//############################################################################
169
ISR (TIMER1_OVF_vect)
170
//############################################################################
171
{  
172
  next_commutate_state (1);
173
  rotor_run = 0;
174
  OCR2A = START_PWM;
175
  OCR2B = START_PWM;
176
  OCR0B = START_PWM;
177
}
178
//############################################################################
179
//Hauptprogramm
180
int main (void) 
181
//############################################################################
182
{
183
  //Watchdog on
184
  WDTCSR = (1<<WDCE) | (1<<WDE);
185
  
186
  //Motordriver output
187
  UH_DDR;
188
  VH_DDR;
189
  WH_DDR;
190
  UL_DDR;
191
  VL_DDR;
192
  WL_DDR;
193
    
194
  //PWM for UH, VH and WH (>32KHz)
195
  TCCR0A |= (1<<COM0B1|1<<WGM01|1<<WGM00);
196
  TCCR0B |= (1<<CS00);
197
  
198
  TCCR2A |= (1<<COM2A1|1<<COM2B1|1<<WGM21|1<<WGM20);
199
  TCCR2B |= (1<<CS20);
200
  
201
  //TIMER1 for start commutation or Back EMF lost
202
  TCCR1B |= (1<<CS11);
203
  TIMSK1 |= (1<<TOIE1);
204
205
  PHASE_ALL_OFF;
206
  
207
  //Comperator init for back EMF
208
  ADCSRB  |= (1<<ACME);
209
  DIDR1  |= (1<<AIN0D);
210
  ACSR  |= (1<<ACIE);
211
212
  //Interrupts enable
213
  sei();
214
  
215
216
  while(1)
217
  {  
218
    asm("wdr");
219
    if(rx_pwm > START_PWM)
220
    {
221
      ACSR |= (1<<ACIE);
222
      TIMSK1 |= (1<<TOIE1);
223
      
224
      if(rotor_run == 200)
225
      {
226
        OCR2A = rx_pwm;
227
        OCR2B = rx_pwm;
228
        OCR0B = rx_pwm;
229
      }
230
    }
231
    else
232
    {
233
      PHASE_ALL_OFF;
234
      ACSR&=~(1<<ACIE);
235
      TIMSK1 &= ~(1<<TOIE1);
236
    }
237
  }
238
}
Den Code ab ich im aktuellen AVRStudio 6.2 als C Projekt erstellt und 
buildet, ohne Fehler.
Dann Tools->Device Programming hab ich mein AVRDragon ausgewählt, wird 
auch problemlos erkannt. Signature und Target Voltage wird ohne Probleme 
ausgelesen.
Da die Schaltung von U. Radig mit 12 MHz läuft und bei ISP Clock steht 
"lower than 1/4 of", habe ich hier 2,5MHz eingegeben.
Unter Oszillation calibration kann ich nur 8MHz einstellen.
Dann habe ich die Hex File ins Flash kopiert, was auch wunderbar 
geklappt hat, und auch auslesbar ist.
Allerdings, wie Ihr richtig vermutet, der Motor dreht nicht :(
Ich benutz zum testen einen DIAMAND AL2730, den ich noch rumliegen hab, 
und angetrieben wird das ganze mit einem 12V Bleiakku.
Aber nach dem Resetten nichts. Lediglich die P-Kanal Mosfets werden 
SAUHEISS!
Meine Vermutung ist, dass ich entweder die char rx_pwm falsch 
interpretiert bzw. gesetzt habe, oder ich beim rauslöschen der I2C was 
falsch gemacht habe.
Kann mir jemand helfen, dass der Motor zumindest mal mit fester Drehzahl 
läuft?
Danke im voraus
Morgy

: Bearbeitet durch User
von Morgy (Gast)


Lesenswert?

Ach ja
Wenn sich jemand fragt warum ich das nich einfach debugge:
Ich arbeite zum ersten mal mit dem  Dragon, und das Studio meinte, dass 
dieses Board debugging nich unterstützt.
Stimmt das???
Oder hab ich da was falsch eingestellt?

von Oliver S. (oliverso)


Lesenswert?

Ich sach mal, schlechtes Kama...

Du möchtest, das dir jemand Code eines Dritten repariert, den du 
kaputt-verändert und dann noch sinnloserweise komplett in den Beitrag 
kopiert hast?

Viel Erfolg...

Oliver

von ?!? (Gast)


Lesenswert?


von ??!? (Gast)


Lesenswert?


von Morgy (Gast)


Lesenswert?

Nicht jeder verwendet I2C zur Ansteuerung, und ich habe lediglich das 
externe auslesen gegen einen festen Wert getauscht, ich denke das kann 
man nachvollziehen, wenn man kurz drüberschaut.
Alternativ könnte man sagen, wie man ein AVRDragon zum Debuggen 
verwendet.
Wenn man keine Lust hat zu helfen oder es nicht kann, wäre es nice, wenn 
man einfach NIX schreibt, statt dauernd solche Kommentare.
Ich hab mir 3 Tage Mühe gegeben und Tutorials studiert, andere hauen den 
Code rein und heulen "macht mal"

von Morgy (Gast)


Lesenswert?

Und es heisst Kharma

von ?!? (Gast)


Lesenswert?

Morgy schrieb:
> Und es heisst Kharma

http://de.wikipedia.org/wiki/Kharma
Wer's mag :-)

von Morgy (Gast)


Lesenswert?

Bitte einfach Hilfe zur Aufgabe
Früher wurde einem in diesem Forum geholfen
Heut muss man Glück haben dass Post 2 kein dummer Kommentar ist

von Name (Gast)


Lesenswert?

Der "dumme" Beitrag gibt dir aber vielleicht Hinweise, warum du keine 
Hilfe bekommst.

Aber du hast recht. Früher war es hier besser. Da hätte ein 
Hilfesuchender die Kritik angenommen und nicht als dumm abgetan.

von Asdf (Gast)


Lesenswert?

Warum setzt Du micht einfach mal die Brenngeschwindigkeit runter, prüfst 
das Brenne und lässt erst mal eine LED auf dem Board blinken, um zu 
prüfen dass der uC richtig und mit der richtigen Geschwindigkeit (fuses 
richtig gesetzt?) läuft?

von Schimanski (Gast)


Lesenswert?

Stell beide Codes als Anhang mit der richtigen Dateiendung rein.

von Carsten R. (kaffeetante)


Lesenswert?

Morgy schrieb:
> Lediglich die P-Kanal Mosfets werden
> SAUHEISS!

Geschieht das auch wenn der Motor nicht angeschlossen ist?

von Morgy (Gast)


Lesenswert?

Danke asdf für die Idee, mit der ich rausgefunden habe, dass der Pin 17 
am uC vermutlich am Arsch ist, da die anderen 5 Ausgänge blinken, dieser 
aber komplett leuchtet. Daher wird der N Kanal an U dauernd geschaltet.
@ Carsten ja aber das warum ist wohl jetzt auch gefunden.
Und danke an Schimanski, ich hab mich schon gefragt wie man das am 
besten macht.
Die letzten 3 Beiträge waren einfach, hilfreich und die Autoren mussten 
vermutlich nicht mal den Code anschauen dazu.
FETTES FETTES DANKE!!!

Und @ Name(Gast)
Ich hätte anders reagiert, wenn das das erste mal gewesen wäre, dass so 
n Kommentar zurückkommt.
Aber ich bin seit Jahren in dem Forum und wie ich sagte, früher hat man 
wesentlich mehr Kommentare im Stil der letzten 3 Beiträge erhalten, die 
kurz und hilfreich sind.
Wenn ich aber in den letzten 2 Jahren um Hilfe gebeten habe, waren die 
ersten 5 Beiträge IMMER unhilfreich, weil die Leute, die helfen wollen 
und können, nach den Witzbolden in einen Beitrag schauen.

Ich will nicht undankbar sein, ehrlich nicht.
Aber wenn jemand nichts dazu sagen möchte, soll ers lassen.
Und wenn jemand helfen möchte, aber nicht kann, soll er nach mehr Infos 
fragen.
Jedenfalls danke an die letzten 3 Beitragsersteller

von Carsten R. (kaffeetante)


Lesenswert?

Ich muß aber zugeben, daß ich bei dem Eingangsbeitrag auch fast 
Augenkrebs bekommen habe. ;-)

Also mach Dir einen Knoten ins Taschentuch für die Zukunft.
Quellcode als Anhang.

Das erhöht die Übersichtlichkeit allgemein. Den Quellcode, besonders 
wenn er länger ist, schaut man sich ohnehin am Besten mit anderen 
Werkzeugen als einem Browser an. Also wozu erst in den Browser kopieren 
um es dann in eine IDE zurück zu kopieren. Das tut sich keiner an.

Wünsche Dir noch viel Erfolg mit der Gerät ;-)

von STK500-Besitzer (Gast)


Lesenswert?

Carsten R. schrieb:
> Also mach Dir einen Knoten ins Taschentuch für die Zukunft.
> Quellcode als Anhang.

und wenn man schon Quellcode in den Post schreiben will, darf man auch 
gerne die richtigen Tags verwenden, wie sie in der Überschrift des 
Textfeldes beschrieben werden - das sieht einfach besser / leserlicher 
aus.

von Oliver S. (oliverso)


Lesenswert?

Morgy schrieb:
> Aber ich bin seit Jahren in dem Forum

Ja nee, is klar...

Oliver

von Schimanski (Gast)


Lesenswert?

ich wäre weiter gegangen und hätte alle relevanten Dateien des Projekts 
gezippt und angehangen. Dann mus man sich nicht mit fehlenden Includes 
oder so rumärgern.
BTT:
ist denn nun alles In Ordnung, nachdem Du feststellen musstest, das dein 
IC im Eimer ist, hast Du sicher einen neuen eingelötet? gehts denn nun?

von Oliver S. (oliverso)


Lesenswert?

Da ja der TO anscheinend vollständig auf selber denken verzichtet, dann 
doch noch ein Hinweis in Form einer Frage:

WARUM ist der Pin kaputtgegangen?

(Wenn er denn überhaupt kaputt ist)
Oliver

von Morgy (Gast)


Lesenswert?

@oliver
what the .... hab ich dir getan???
ich hab nur gesagt dass ich auf solche kommentare dankend verzichten 
kann,
da sie NULL zum erfolg beitragen, da wird mir wohl JEDER recht geben
Einen neuen IC hab ich eingelötet ja und dank den LEDs hab ich auch noch 
einen kaputten NPN gefunden.
Jedoch rauchen mir nach wie vor die p Kanäler ab.
Ich werde allerdings hier nicht rum heulen "macht mal", genauso wenig 
wie ich nicht von anfang an gefragt hab " kann mir mal wer erklären was 
der Code macht"
Ich hab versucht soweit wie möglich allein voran zu kommen und werd das 
jetzt auch machen.
Im Vergleich zu den meisten Forennutzern (nicht nur dieses Forum) finde 
ich bin ich relativ unfaul, warum das bei manchen nicht auf Anklang 
findet ist mir ein Rätsel.
Wie gesagt dank den LED bin ich gut voran gekommen und weiss jetzt auch 
was falsch ist.
Mir hat ein langjähriger Elektrotechniker, vermutlich im Halbschlaf, auf 
Anfrage nach P-Kanal-Mosfets eine Ladung IRF540PBF ausgehändigt.
Nachdem ich nun die Datenblätter konsultiert habe, weiss ich warum die 
immer abrauchen...
Werd jetzt neue P-Kanäler holen und mich melden

von Morgy (Gast)


Lesenswert?

Soooo ok hab jetzt richtige P-Kanal Mosfets
Jetzt raucht nix und die LED an den Gates blinken bunt.
An den Ausgängen der Brücken mess ich aber konstant 12V und der Motor 
dreht nicht. Wenn ich an den U,V,W Ausgängen LEDs gegen VCC schalte, 
müsste ich ja, wenn die N-Kanal Mosfet gegen Masse schalten, die LED 
blinken sehen, aber sie bleiben dunkel. Daher vermute ich, dass die 
N-Kanaler nicht schalten. An Gate kommt ja Spannung an(LED gegen Masse 
blinkt wunderschön) und an Drain is Masse, wenn er schaltet sollte sich 
ja was tun.
Wenn ich btw eine Phase des Motors direkt auf GND leg gibts Action, also 
die P Mosfets schalten wie geplant.
Laut Original Schaltplan werden IRFR1205 verwendet, ich habe aber 
momentan P55NF in Verwendung, sind ja auch locker bei 12V betreibbar und 
haben sogar eine geringere Kapazität zum Schalten, sprich der 
Vorwiderstand von 33 Ohm sollte unproblematisch sein, aber kein 
Schalten.
Spasshalber hab ich auch mal die IRF540PBF (sind ja N Kanal) getestet, 
die brauchen aber mehr Ladung zum Schalten und bin deshalb auf 27 Ohm 
runtergegangen, aber auch da keine Reaktion.
Ums zusammenzufassen:
Am Mosfet kommt ein Rechtecksignal vom AVR über 33 / 27 Ohm ans Gate, an 
Source liegt Masse, aber an Drain kommt nix an.
Hat wer ne Idee was da los sein könnte?

von Carsten R. (kaffeetante)


Lesenswert?

Schalten die Fets denn, wenn Du sie manuell mit Spannung versorgst?
Ist der Schaltplan, abgesehen von den anderen Fets, 100 % identisch mit 
dem Original?

von Morgy (Gast)


Lesenswert?

Also wenn ich mit dem 33 Ohm am Gate auf Vcc geh passiert gar nix, was 
mich wundert weils ja a) Gleichspannung ist und b) nagelneue N Kanal 
Mosfets sind.
Der Schaltplan unterscheidet sich nur in 2 Dingen 1. Die Widerstände an 
SCK und SDL fehlen und die Pins sind unbelegt und 2. ich hab den DIP 
Atmega328 genommen und die Pins entsprechend getauscht, da SMD aufm 
breadboard immer doof ist.
Und wie erwähnt halt  andere Mosfets mit niedrigerer Eingangskapazität

von Carsten R. (kaffeetante)


Lesenswert?

Wenn zwischen VCC und dem Source des Fets wirklich Spannung anliegt 
müßte er schalten, es sei denn er ist irgendwie seltsam angeschlossen 
oder alle sind defekt (unwahrscheinlich).

Du hast ja schon Vcc gegen Gnd getestet. War das beim Source des N-Fets 
oder an einer anderen Stelle abgegriffen?

von Morgy (Gast)


Lesenswert?

War am Source

von uwe (Gast)


Lesenswert?

Tja vieleicht haben dir die Dauerleitenden P-Kanäler halt die N-Kanäler 
kaputtgemacht, denn wo ist denn der Strom Langgeflossen, wenn nicht über 
die N-Kanäler?!

von Carsten R. (kaffeetante)


Lesenswert?

Wenn die FETs bei aktiviertem Gate nicht niederohmig werden sind sie 
entweder nicht korrekt angeschlossen (verkehrt oder gar nicht, z.B. 
schlecht gelötet, schlechter Kontakt, Leitung unterbrochen) oder defekt. 
Letztere ist aber etwas merkwürdig. Ich hätte bei mehreren defekten Fets 
angenommen, daß wenigstens einer davon dauerleitend wird und nicht alle 
dauerhaft hochohmig sind.

Mein Vorschlag wäre:

Einen Fet auszubauen und separat zu testen.

von Morgy (Gast)


Lesenswert?

OK Leute
gute Nachrichten
Motor dreht sich nach Austausch sämtlicher FETs, Transistoren und eines 
verbratenen Widerstandes.
Jetzt liegts an der Software
Ich sag schon ma grosses Danke und ich meld mich wenns Probleme gibt
greetz
Björn

von Morgy (Gast)


Lesenswert?

OK schon gehts los xD
Ich will den Regler ja umbauen auf PPM Regelung.
Geplant war, am ICP das Signal anzulegen, und bei Zustandsänderung den 
Timerwert zu speichern und den grösseren vom kleineren suptrahieren.
Jetzt stellt sich mir nur die Frage, welcher Timer? Timer0, Timer1 und 
Timer2 sind ja schon in Verwendung, 0 und 2 für die PWM der Ausgänge und 
Timer1 für den Anlauf bzw Signalverlust. Beide werden mit prescaler = 1 
und Modus 3 also von 0...255 betrieben, macht bei 12MHz meiner Rechnung 
nach 12000000/255= 47kHz und ne Laufzeit von 0,02ms. Da das PPM Signal 
aber zwischen 1 und 2 ms lang ist, läuft mir der Timer in der Zeit ja 
50-100 mal über und die gespeicherten Werte sind schrott.
Kann ich den Timer1B mit einem anderen Prescaler verwenden als Timer1A?
Oder wäre es besser, für den Anlauf Timer2B zu verwenden und Timer1 für 
die PPM Erkennung?

von Carsten R. (kaffeetante)


Lesenswert?

"Bau" dir doch deinen eigenen Soft-timer. Benutze den Überlaufinterrupt 
einer der schnellen Timer zusätzlich um eine Variable hochzuzählen. 
Diese Variable bildet dann das Herzstück deins Soft-Timers. Der braucht 
dann halt etwas Rechenzeit. Aber da er langsam "tickt", ist das nicht 
sooo das Problem.

Nun benutzt du entweder andere Interrupts, z.B.Pin Change für dein 
Eingangssignal sofern die passenden Pins frei (zu bekommen) sind 
(Schaltplan?), die sich mit dem Soft-Timer abgleichen, oder emulierst 
Hardwarefunktionen des Soft-Timers beim Hochzählen, bzw. kombinierst 
beides.

Der Soft-Timer ist natürlich langsamer im Takt. Das begrentzt deine 
Meßgenauigkeit ein wenig. Bei Bedarf ließe sich das eventuell teilweise 
dadurch beheben, daß man beim Capture auch lesend auf den Hardwaretimer 
zugreift und somit die Soft-Ticks wieder feiner auflöst. Diese 
Möglichkeit ist aber nicht immer so einfach gegeben. Dazu bedarf es 
eines Hardwareinterrups zwischen den Soft-Ticks.

: Bearbeitet durch User
von Morgy (Gast)


Lesenswert?

Ich hab spasshalber mal versucht, die Geschwindigkeit über ein Poti zu 
regeln.
Ich hab also zwischen 5V und GND ein 100k Poti angeschlossen und den 
Abgriff an Pin 28 (ADC5)
ADC hab ich meines Wissens nach aktiviert mit

  ADCSRB  |= (1<<ACME);
  ADCSRA  |= (1<<ADEN);
  DIDR1  |= (1<<AIN0D);
  ACSR  |= (1<<ACIE);
  ADMUX   |= (1<<ADLAR);

Wobei die 1., 3. und 4. Zeile vom Originalcode sind und nur wichtig für 
die Rückkommutierung
Auslesen tu ich dann die Variable ADCH, aber die ist unabhängig von der 
Potistellung immer 5.

Auch ein Setzen des Multiplexers

        ADMUX = 5;

hilft nichts.
Hat jemand kurz ne Idee?
Soll generell Übung sein bevors an PPM geht.

von Carsten R. (kaffeetante)


Lesenswert?

Poti richtig angeschlossen? Ausgangsspannung des Potis mit eimen 
Multimeter Prüfen.

Zum Code:

Es zählt nicht nur das Fragment, sondern wie dieses in den bestehenden 
Code eingebunden ist und auch wo. Du hast nur einen ADC. Und der der 
Teilt sich den Multiplexer mit dem Comparator. Der Multiplexer schaltet 
den Comparator mit den Phasen der Ausgangsstufe synchronisiert auf die 
freilaufende Phase. Wenn Du da den ADC zwischendurch nutzen willst mußt 
Du das mit dem Rest des Codes abstimmen.

Aus dem Handbuch des Atmega48/88/168

"It is possible to select any of the ADC7..0 pins to replace the 
negative input to the Analog Comparator.
The ADC multiplexer is used to select this input, and consequently, the 
ADC must be
switched off to utilize this feature."

Und genau das macht der Regler, da er die Phasen abwechselnd überwacht. 
Für das Umschalten benötigt er den Multiplexer.

von Morgy (Gast)


Lesenswert?

Poti is richtig angeschlossen und mit MM geprüft.

In der void main wollte ich ja mit ADMUX = 5 umschalten, dass er den PIN 
5 analog einliesst.
Aber wenn er gegen AIN prüft und nicht gegen Masse (so hab ichs 
verstanden) hab ich ja das Problem dass, solang der Motor dreht und die 
Flanken auswertet, dort immer eine Spannung anliegen wird, die des 
Sternpunktes oder?
Wie lang braucht den der ADC bis er einen Wert ermittelt?
Wäre es möglich, den Bezugspunkt kurzfristig in der void main auf Masse 
zu setzen, den Analogwert einzulesen, und dann wieder auf 
Flankenerkennung zu setzen?
Oder ist der zu langsam dafür?
Bei einem Motor mit (Beispiel) 1800 rpm dauert eine Umdrehung 1/30s und 
es wird 6 mal umgeschaltet, sprich zwischen den Schaltschritten liegen 
5,5ms. Wenn ich direkt nachdem der commutation state geändert wurde den 
Analogwert einlese, müsste es doch gehen oder?

von Carsten R. (kaffeetante)


Lesenswert?

Morgy schrieb:
> die des
> Sternpunktes oder?

Sternpunkt zuzüglich BEMF an der freilaufenden Spule.

Morgy schrieb:
> Wie lang braucht den der ADC bis er einen Wert ermittelt?

Steht im Datenblatt. Es wird Zeit daß du Dich selbst mal damit gründlich 
befaßt, auch oder gerade weil es eine ziemliche Lektüre ist. Wenn Du dir 
alles vorkauen läßt wird das nichts mit dem Lerneffekt bzw. dann kannst 
Du dir auch ein Gerät kaufen.

Morgy schrieb:
> Bei einem Motor mit (Beispiel) 1800 rpm dauert eine Umdrehung 1/30s und
> es wird 6 mal umgeschaltet,

Das hängt von der Bauart der Motors ab (siehe Polpaarzahl). Pro 
Umdrehung können mehrere vollständige Kommutierungszyklen erforderlich 
sein.

von Morgy (Gast)


Lesenswert?

Klar die Frage war generell ob man zwischen den Schritten den Modus 
umschalten kann oder ob der Modus nur einmalig gesetzt werden kann.

Und vorgekaut hab ich ja noch nix bekommen ^^
OK ich mach mir mal Gedanken wie man das zwischenrein setzt
CU Later

von Carsten R. (kaffeetante)


Lesenswert?

Von der Programlogik wäre es am Einfachsten:

Der Komparatorinterrupt wechselt auch den Kanal. Stattdessen kannst Du 
da die ADC-Messung veranlassen und beim ADC-Interrupt wieder Auf 
Komparator und den korrekten Kanal zurückschalten. Aber ob die Zeit 
reicht hängt vom Motor bzw seiner Drehzahl ab.

Allerdings sind da einige Details zu bachten bei der Umschalterei. Dazu 
mußt du die entsprechenden Kapitel im Datenblatt durchkauen.

von Morgy (Gast)


Lesenswert?

OK hier mal der Grundgedanke zum Softtimer und der Impulsmessung:
1
ISR (TIMER2_OVF_vect)
2
{
3
  softtimer++;
4
  if (softtimer > 940)
5
  {
6
    softtimer = 0;
7
  }
8
}
9
//########################################################################
10
ISR (INT0_vect)
11
{ 
12
  if (messung == 0)
13
  {
14
    softtimer = 0;
15
    messung = 1  ;
16
  }
17
  else
18
  {
19
    periodendauer = softtimer / 47;
20
    messung = 0;
21
  }
22
}
Bei jedem Overflow des Timer2 wird die Variable "softtimer" hochgezählt.
Da Timer2 kein Prescaler hat und bis 255 zählt, ist die Frequenz meines 
Softtimers 12MHz / 255 = 47,058 kHz.
Am INT0 leg ich jetzt mein Signal an, der INT0 Interrupt wird so 
justiert, dass sowohl steigende als auch fallende Flanken erkannt 
werden. Bei steigender Flanke wird der Softtimer resettet, bei fallender 
Flanke wird die Periodendauer berechnet. Da der Softtimer in 1ms von 0 
auf 47 zählt, rechne ich lediglich die Variable "softtimer" / 47.

Jetzt hab ich nur das Problem, dass meine ISR ja so wie sie da steht 
nicht weiss, ob die Flanke steigend oder fallend ist. Es wird lediglich 
die Variable "messung" jeweils gesetzt oder auch nicht, wodurch es aber 
auch möglich wäre, dass die LOW Phasendauer gemessen wird.
Mein Gedanke wäre jetzt, den INT0 Interrupt am Programmstart so zu 
initialisieren, dass er nur auf fallende Flanken reagiert, und dann, 
sobald eine fallende Flanke gekommen ist, bei der ISR den Modus 
umzustellen. Dadurch wäre sichergestellt, dass nur die HIGH Phase 
gemessen wird.

Jetzt wäre aber meine Frage, ob das auch einfacher geht (z.B. ob es 
einen Befehl in der ISR gibt,case oder so, der erkennt, ob es eine 
steigende/fallende Flanke ist? Oder gibt es verschiedene ISR für den 
INT0 für jeweils steigende und fallende Flanken?

Ausserdem die Frage:
Laut Wikipedia und mehreren Modellbauseiten wird bei der Ansteuerung 
eines Servos die HIGH Flanke ausgewertet.
Letzt hat mir jedoch jemand gesagt, dass beim Regler die LOW Phase 
gemessen wird.
Ist da was dran?

Gruss
Björn

von uwe (Gast)


Lesenswert?

> Jetzt hab ich nur das Problem, dass meine ISR ja so wie sie da steht
> nicht weiss, ob die Flanke steigend oder fallend ist.
Was hindert dich denn daran in der ISR nachzugucken was für ein Pegel am 
INT0 Pin anliegt, wenn 1 im PIN Register stehet muß ja wohl ne steigende 
Flanke den IRQ ausgelöst haben.

von Morgy (Gast)


Lesenswert?

Danke
Genau der Gedankenanstoss den ich gebraucht hab.
Die Rechnung sonst kommt hin oder?

von Morgy (Gast)


Lesenswert?

Also
Jetzt funzt alles, Motor rennt und PPM Steuerung auch
Aufm Breadboard konnt ich auch super proggen/debuggen, wenn ich per 
debugwire reingeh
Jetzt hab ich ne Platine geätzt und alles aufgelötet, geht auch, aber 
ich kann jetzt weder auf den AtMEGA schreiben noch debuggen.
Dass bei debugwire der Kondensator am Reset zwingend raus muss, weiss 
ich, aber kann es auch sein, dass der beim normalen ISP stört?

von Carsten R. (kaffeetante)


Lesenswert?

????????????????????????????????????

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.