PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Atmel Tiny 13V als Controller für einen Dieselmotor



erik1563
01.09.2011, 13:26
Moin Moin!
Bei folgendem Projekt könnte ich eure Hilfe gut gebrauchen: Ich versuche mit Hilfe eines Atmel Tiny13V einen Drehzahlcontroller für einen kleinen Dieselmotor zu bauen. Dazu muss der Atmel einen Servo ansteuern können, der später fürs Gasgeben zuständig ist.
Bisher sieht das Programm so aus:

#include <avr/io.h>#include <avr/interrupt.h>


//#define f_cpu 9,6 MHz // ???


uint8_t y;
volatile uint16_t count, time;


void delay(uint16_t d) // Warteschleife 1/50 Sekunde
{
time=d+1; while(time);
}
unsigned char z;
ISR(TIM0_COMPA_vect) // Servoansteuerung
{
if (count>y) PORTB &= ~(1<<PB4); else PORTB |= (1<<PB4);
if (count < 500) count++; else { count=0; if(time) time--; }
}


int main(void)
{
PORTB |= (1<<PB1);
DDRB = (1<<PB4)|(1<<PB1); // Servoausgang


TCCR0A = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0A |= (0 << COM0A0) | (0 << COM0A1); // ohne OCR-Pin
TCCR0B = (0 << CS02) | (0 << CS01) | (1 << CS00); // prescaler /8
TIMSK0 = (1 << OCIE0A); // Interrupt ein
OCR0A = 12; // 100kHz 9600000/(8*12)
sei();
// y=150; //wieso kann ich y nur hier setzen?


while(1){
y=150; // und nicht hier?

}
return(0);
}



Anmerkung: Das Programm entstammt komplett radbruchs Feder (meinen Danke noch einmal an dieser Stelle).
Der Servo hängt am PB4, mit der Variable y setzt man die Servoposition.
Meine Frage ist nun: Warum kann ich y nur ausserhalb der while(1)-Schleife setzten?
Setze ich y in while(1) fährt der Servo einfach nach ganz links. (Je höher die y-Werte desto weiter "rechts" steht der Servo.)
Da ich mich erst nen knappen Monat mit µC beschäftige bin ich mit meinem Latein am Ende...
Vielen Dank schonmal für eure Hilfe!

radbruch
01.09.2011, 15:33
Hallo

Ich habs mal etwas geputzt:

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t y, p;

ISR(TIM0_COMPA_vect) // Servoansteuerung
{
static uint16_t count=0;
if (count>y) PORTB &= ~(1<<PB4); else PORTB |= (1<<PB4);
if (count < 2000) count++; else { count=0; if(p) p--; }
}

int main(void)
{
DDRB = (1<<PB4)|(1<<PB1); // Servoausgang
PORTB |= (1<<PB1); // und Spannungsversorgung der Schaltung?

TCCR0A = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0A |= (0 << COM0A0) | (0 << COM0A1); // ohne OCR-Pin
TCCR0B = (0 << CS02) | (0 << CS01) | (1 << CS00); // kein prescaler!
TIMSK0 = (1 << OCIE0A); // Interrupt ein
OCR0A = 12; // 100kHz 1200000/12
sei();

y=150;

while(1)
{
p=50; while(p); // eine Sekunde warten
if(y == 150) y=100; else y=150; // neue Position festlegen
}
return(0);
}

Das ist jetzt für 1,2MHz. Das sollte nicht funktionieren, weil die ISR nur 12 Takte Zeit hat und deshalb vermutlich überläuft (=während der Ausführung der ISR tritt schon der nächste Interrupt auf). Sollte dein Tiny wirklich mit 9,6MHz takten, sollte das OCR0A so geladen werden:

OCR0A = 96; // 100kHz 9600000/96

Die ISR hätte dann 96 Takte Zeit zur Ausführung.

Gruß

mic

[Edit]

TCCR0B = (0 << CS02) | (0 << CS01) | (1 << CS00); // kein prescaler!
OCR0A = 12; // 100kHz 9600000/(8*12)
sei();
// y=150; //wieso kann ich y nur hier setzen?


while(1){
y=150; // und nicht hier?
Vermutlich passiert genau hier der Überlauf. Nach while(1) sind die zwölf Takte vorbei (egal welcher Kontrollertakt verwendet wird) und der Kontroller stürzt ins Interruptüberlaufsniwana. Es wird zwar noch irgendwas als Impuls ausgegeben, aber das ist völlig unkontrolliert. Bei der Zuordnung direkt nach sei() erfolgt der Absturz wenigstens mit richtig geladenem y. Ist nur so ein Nachtgedanke.

erik1563
14.09.2011, 12:17
So!
Ein kleines Update meines Projektes:
Ich hab mir mit hilfe des Asuro einen "Simulator" gebaut mit hilfe ich die Programmierung testen will.
Er simuliert ein Signal, wie es von einem Drehzahlsensor stammen könnte, mit variabler Drehzahl.
Nun scheitere ich aber schon seit einer Weile an folgendem:
Um eine Drehzahl errechnen zu können muss ich ja die Impulse pro Zeiteinheit zählen. Ich schaffs aber nicht eine Schleife zu programmieren, die z.B. 1/4 Sekunde gewisse Befehle ausführt (Impulse an einem Beinchen zählen).
Ich hoffe ihr versteht was mein Problem ist...

erik1563
15.09.2011, 13:54
#include <avr/io.h>#include <avr/interrupt.h>


volatile uint8_t y, p;
unsigned char b, c, a;


ISR(TIM0_COMPA_vect) // Servoansteuerung
{
static uint16_t count=0;
if (count>y) PORTB &= ~(1<<PB4); else PORTB |= (1<<PB4); // solange count größer ist als y pb4=1
if (count < 2000) count++; else { count=0; if(p) p--; } //p wird mit 960.0000 /96 = 100khz /2000 =50hz angesteuert (20ms) p wird runtergezählt (p=50 = eine sekunde)
}


int main(void)
{
DDRB = (1<<PB4)|(1<<PB1); // Servoausgang


TCCR0A = (0 << WGM00) | (1 << WGM01); // CTC-Mode
TCCR0A |= (0 << COM0A0) | (0 << COM0A1); // ohne OCR-Pin
TCCR0B = (0 << CS02) | (0 << CS01) | (1 << CS00); // kein prescaler!
TIMSK0 = (1 << OCIE0A); // Interrupt ein
OCR0A = 96; // 100kHz 1200000/12
sei();


y=150;


while(1)
{
p=13;
c=0;
while(p > 0) {
a = PINB;
a = a & 0x08;
if (a !=0){
c++;}
else{
c=c+0;}
}
if (c > 13) { // 50 impulse pro sekunde angestrebt
y--;}
else if (c==13) {
y=y+0;}
else {
y++;}

}
return(0);
}
Hier einmal mein Versuch... egal wieviel Hertz ich an den Eingang anlege, der Servo läuft immer gaaanz langsam runter in seine Nullstellung... verändern der C-Variable ändert auch nichts...