Charly_cs
11.07.2008, 12:48
Hallo!
Dieses Thema wurde hier schon x-mal besprochen, nur habe ich noch keine Lösung für mein Problem gefunden. Vielleicht weiß ja jemand von euch Rat.
Am Ende soll das eine Motorregelung mit dem ATMega8 werden, doch zunächst möchte ich nur eine Steuerung aufbauen, bei der dem µC vom PC aus ein 10bit Pwmwert geschickt wird, er ihn einstellt und die Umdrehungen im 100ms Takt zählt. Aus einem alten Beitrag habe ich geschlossen, dass es möglich ist Timer, externe Interrupts und die PWM gleichzeitig zu verwenden.
Den Impulsgeber habe ich an den Int0 angeschlossen.
Zum Impulsgeber: 256 Impulse/Umdrehung und der Motor kann bis zu 12k U/min drehen.
Zum Programmablauf:
Im Hauptprogramm wird nur geschaut ob neue Zeichen am UART anliegen um diese dann auszuwerten. Den Timer0 verwende ich für den 100ms-Takt zum Auslesen des Zählers, der mit jedem Int0-Aufruf erhöht wird. Den Zählerstand schreibe ich in eine externe Variable, die bei Bedarf vom Hauptprogramm ausgelesen und an einen externen PC über UART geschickt wird.
Folgendes Problem besteht:
Der Controller startet sich besonders oft bei niedrigen Pwm-Werten neu, jedoch zeitlich nicht vorherzusagen. Wenn ich die Interrupts Timer0 und Int0 ausschalte, funktioniert die Pwmeinstellung wunderbar ohne das sich der µC aufhängt.
Woran kann das liegen? Habe ich bei den Interrupteinstellungen etwas falsch gemacht?
Hier ist mein Programm:
#define F_CPU 16000000
#define UART_BAUD_RATE 19200
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "uart.h"
#include <string.h>
void Pwmstatus(char *);
unsigned long zaehler=0;
unsigned int timer=0;
unsigned long Ergebnis;
int main(void)
{
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
sei();
DDRB |= (1<<PB1) | (1<<PB2); // PWM für Enable1 und Enable2
DDRD |= (1<<PD6) | (1<<PD7); // Für Drehrichtung
PORTD |= (1<<PD6);
PORTD &= ~(1<<PD7);
//Pwm
TCCR1A = (1<<WGM10) | (1<<WGM11) | (1<<COM1A1);
TCCR1B = (1<<CS11) | (1<<CS10);
OCR1A = 0;
//Interrupt0
GIMSK |= (1<<INT0); //INT0 aktiviert
MCUCR |= (1<<ISC01) | (1<<ISC00); //Scharf gestellt auf steigende Flanke
//Timer0
TCCR0 |= (1<<CS01) | (1<<CS00); //Precsaler auf 64
TIMSK |= (1<<TOIE0); //Timer0 aktivieren
TCNT0 = 6; //Timerwert vorstellen auf 6 für 1ms
unsigned int c;
char Eingabe[10];
char Ausgabe[10] = "1001";
int i, asciiwert,Count;
for(;;)
{
c = uart_getc();
if ( c & UART_NO_DATA )
{
for(i=0;i<10;i++) //Dieser Delay von 100ms ist sehr wichtig!!
{
_delay_ms(10);
}
if(strlen(Eingabe)==5)
{
asciiwert = Eingabe[0];
switch (asciiwert)
{
case 'l':
PORTD |= (1<<PD6);
PORTD &= ~(1<<PD7);
Pwmstatus(Eingabe);
Eingabe[0] = '\0';
break;
case 'r':
PORTD |= (1<<PD7);
PORTD &= ~(1<<PD6);
Pwmstatus(Eingabe);
Eingabe[0] = '\0';
break;
case 'g':
itoa(Ergebnis,Ausgabe,10);
i = strlen(Ausgabe);
Ausgabe[i] = '!';
Ausgabe[i+1] = '\0';
uart_puts(Ausgabe);
Eingabe[0] = '\0';
Ausgabe[0] = '\0';
break;
}
}
}
else
{
Count = 0;
while (c != '!')
{
Eingabe[Count++] = c;
c = uart_getc();
}
Eingabe[Count] = '\0';
}
}
return 0;
}
void Pwmstatus(char *buffer)
{
char Buffer[5];
int i;
Buffer[0] = buffer[1];
Buffer[1] = buffer[2];
Buffer[2] = buffer[3];
Buffer[3] = buffer[4];
Buffer[4] = '\0';
i = atoi(Buffer);
OCR1A = i;
}
//Externe Interrupt0 Routine
ISR(INT0_vect)
{
zaehler++;
}
//Timer0 Interruptroutine
SIGNAL (SIG_OVERFLOW0)
{
timer++;
TCNT0=6; //Für 1ms
if(timer == 100)
{
GIMSK &= ~(1<<INT0);
Ergebnis = zaehler;
timer = 0;
zaehler = 0;
GIMSK |= (1<<INT0);
}
}
Vielen Dank!
Grüsse
Charly
Dieses Thema wurde hier schon x-mal besprochen, nur habe ich noch keine Lösung für mein Problem gefunden. Vielleicht weiß ja jemand von euch Rat.
Am Ende soll das eine Motorregelung mit dem ATMega8 werden, doch zunächst möchte ich nur eine Steuerung aufbauen, bei der dem µC vom PC aus ein 10bit Pwmwert geschickt wird, er ihn einstellt und die Umdrehungen im 100ms Takt zählt. Aus einem alten Beitrag habe ich geschlossen, dass es möglich ist Timer, externe Interrupts und die PWM gleichzeitig zu verwenden.
Den Impulsgeber habe ich an den Int0 angeschlossen.
Zum Impulsgeber: 256 Impulse/Umdrehung und der Motor kann bis zu 12k U/min drehen.
Zum Programmablauf:
Im Hauptprogramm wird nur geschaut ob neue Zeichen am UART anliegen um diese dann auszuwerten. Den Timer0 verwende ich für den 100ms-Takt zum Auslesen des Zählers, der mit jedem Int0-Aufruf erhöht wird. Den Zählerstand schreibe ich in eine externe Variable, die bei Bedarf vom Hauptprogramm ausgelesen und an einen externen PC über UART geschickt wird.
Folgendes Problem besteht:
Der Controller startet sich besonders oft bei niedrigen Pwm-Werten neu, jedoch zeitlich nicht vorherzusagen. Wenn ich die Interrupts Timer0 und Int0 ausschalte, funktioniert die Pwmeinstellung wunderbar ohne das sich der µC aufhängt.
Woran kann das liegen? Habe ich bei den Interrupteinstellungen etwas falsch gemacht?
Hier ist mein Programm:
#define F_CPU 16000000
#define UART_BAUD_RATE 19200
#include <stdlib.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "uart.h"
#include <string.h>
void Pwmstatus(char *);
unsigned long zaehler=0;
unsigned int timer=0;
unsigned long Ergebnis;
int main(void)
{
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
sei();
DDRB |= (1<<PB1) | (1<<PB2); // PWM für Enable1 und Enable2
DDRD |= (1<<PD6) | (1<<PD7); // Für Drehrichtung
PORTD |= (1<<PD6);
PORTD &= ~(1<<PD7);
//Pwm
TCCR1A = (1<<WGM10) | (1<<WGM11) | (1<<COM1A1);
TCCR1B = (1<<CS11) | (1<<CS10);
OCR1A = 0;
//Interrupt0
GIMSK |= (1<<INT0); //INT0 aktiviert
MCUCR |= (1<<ISC01) | (1<<ISC00); //Scharf gestellt auf steigende Flanke
//Timer0
TCCR0 |= (1<<CS01) | (1<<CS00); //Precsaler auf 64
TIMSK |= (1<<TOIE0); //Timer0 aktivieren
TCNT0 = 6; //Timerwert vorstellen auf 6 für 1ms
unsigned int c;
char Eingabe[10];
char Ausgabe[10] = "1001";
int i, asciiwert,Count;
for(;;)
{
c = uart_getc();
if ( c & UART_NO_DATA )
{
for(i=0;i<10;i++) //Dieser Delay von 100ms ist sehr wichtig!!
{
_delay_ms(10);
}
if(strlen(Eingabe)==5)
{
asciiwert = Eingabe[0];
switch (asciiwert)
{
case 'l':
PORTD |= (1<<PD6);
PORTD &= ~(1<<PD7);
Pwmstatus(Eingabe);
Eingabe[0] = '\0';
break;
case 'r':
PORTD |= (1<<PD7);
PORTD &= ~(1<<PD6);
Pwmstatus(Eingabe);
Eingabe[0] = '\0';
break;
case 'g':
itoa(Ergebnis,Ausgabe,10);
i = strlen(Ausgabe);
Ausgabe[i] = '!';
Ausgabe[i+1] = '\0';
uart_puts(Ausgabe);
Eingabe[0] = '\0';
Ausgabe[0] = '\0';
break;
}
}
}
else
{
Count = 0;
while (c != '!')
{
Eingabe[Count++] = c;
c = uart_getc();
}
Eingabe[Count] = '\0';
}
}
return 0;
}
void Pwmstatus(char *buffer)
{
char Buffer[5];
int i;
Buffer[0] = buffer[1];
Buffer[1] = buffer[2];
Buffer[2] = buffer[3];
Buffer[3] = buffer[4];
Buffer[4] = '\0';
i = atoi(Buffer);
OCR1A = i;
}
//Externe Interrupt0 Routine
ISR(INT0_vect)
{
zaehler++;
}
//Timer0 Interruptroutine
SIGNAL (SIG_OVERFLOW0)
{
timer++;
TCNT0=6; //Für 1ms
if(timer == 100)
{
GIMSK &= ~(1<<INT0);
Ergebnis = zaehler;
timer = 0;
zaehler = 0;
GIMSK |= (1<<INT0);
}
}
Vielen Dank!
Grüsse
Charly