Inkrementalgeber/Magnetgeber auswerten
Hallo liebe RoboterNETZ Gemeinde,
momentan möchte ich gern einen Magnetgeber mit der Auflösung von 2 auswerten. Dazu benutze ich den Atmega88p und benutze HTerm um mir die Werte auszugeben. Nur leider funktioniert das noch nicht ganz. :-k
Ich möchte das Ganze so gestalten, dass ich diesem eine Messdauer von bspw. 200ms vorgebe. ( Da sehr geringe Auflösung, aber dann noch recht gut geregelt werden soll, wobei die Programmdauer nicht sehr kritisch ist ) Während der Messdauer soll der 8-Bit Timer 0 also laufen und beide externene Interrupteingänge INT 0 und INT 1 ( sind also 2 Geber ) sollen bei einer steigenden Flanke einen Impuls weiter zählen.
Die 200ms habe ich versucht über einen Prescaler + mehrere Overflows einzustellen. Nur leider zeigt mein H-Term nur Kauderwelsch an, also so als würde es die Zeichen nicht interpretieren können. ( einmal Endekennung '\0' ) Es kommt auch nur ein einziges Mal ein Zeichen und nicht zyklisch wie die While Schleife es eigentlich machen söllte.
( Die Richtungsauswertung kommt erst im nachhinein, wenn wenigstens das funktioniert )
Code:
#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define Baud 9600UL
volatile uint16_t DRZ1, DRZ2;
volatile uint8_t TIM0_Overflow, Drehrichtung1, Drehrichtung2;
void UARTinit(){
UBRR0 = 103; // Baudrate laut Datasheet
UCSR0B = (1<<TXEN0); // Enable Senden
UCSR0C = (1<<UCSZ00) | (1<<UCSZ01); // Setze 8 Bit Datenlänge
// Alles was 0 ist setzt Asynchron Modus, Normal Speed, 1 Stop Bit und keine Paritaet
}
int uart_send( unsigned char c)
{
while (!(UCSR0A & (1<<UDRE0)))
{
// mach nichts
}
//senden
UDR0=c;
return 0;
}
void uart_puts (char *s)
{
while (*s)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
uart_send(*s);
s++;
}
}
ISR(INT0_vect)
{
DRZ1++;
}
ISR(INT1_vect)
{
DRZ2++;
}
ISR(TIMER0_OVF_vect)
{
TIM0_Overflow++;
}
uint16_t Inkrementalgeber(uint16_t* Drehzahl1, uint16_t *Drehzahl2)
{
TCNT0 = 0;
DRZ1 = 0; // Alle Zählerwerte auf 0 zurücksetzen
DRZ2 = 0;
TIM0_Overflow = 0;
TCCR0B |= (1<<CS02) | (1<<CS00); // Frequentvorteiler von 1024 --> 16MHz/1024 = 64us pro Tick UND TImer0 starten
// 200ms/64us = 3125 --> 8 Bit Timer = 255 --> 12 * 255 + 1 * 65 = 3125 --> TIM0_Overflow = 12 und TCNT0 = 65, damit mit 8 Bit Timer und Prescaler 200ms Messzeit erreicht
TIMSK0 |= (1<<TOIE0); // Overflow_Flag enablen
EICRA |= (1<<ISC11) | (1<<ISC01) | (1<<ISC00) | (1<<ISC10); // INT0 und INT1 auf steigende Flanke triggern
EIMSK |= (1<<INT1) | (1<<INT0); // INT1 und INT0 Interrupts enablen
sei(); // Globale Interrupts erlauben
while (1)
{
if (TIM0_Overflow >= 12)
{
if (TCNT0 >=65)
{
break;
}
}
// tue nichts bis 200ms abgelaufen sind
}
TCCR0B &= ~((1<<CS02) | (1<<CS00)); // Timer stoppen
cli(); // Globale Interrupts ausschalten
*Drehzahl1 = DRZ1; // Werteübergabe der Drehzhalen an das Hauptprogramm
*Drehzahl2 = DRZ2;
}
int main(void)
{
uint16_t Drehzahl1, Drehzahl2;
uint8_t KanalA, KanalB;
DDRD &= ~((1<<PIND2) | (1<<PIND3)); // INT0 und INT 1 als Kanaleingänge für beide Inkrementalgeber auswählen
DDRD |= (1<<PIND1); // UART TX als Ausgang
DDRD &= ~(1<<PIND0);
TCCR0A &= ~((1<<WGM00) | (1<<WGM01)); // Normal Operation Mode für Timer0 auswählen
TCCR0B &= ~(1<<WGM02);
char s[30];
uint16_t x;
while (1)
{
Inkrementalgeber(&Drehzahl1 , &Drehzahl2);
Drehzahl1 = 150 * Drehzahl1; // Drehzahl in 1/min = 60s * ( 1000ms / Messdauer[ms] ) * ( Anzahl Flanken / Imp. pro Umdrehung [ Auflösung ] )
Drehzahl2 = 150 * Drehzahl2; // 60s * 1000/200 * DRZ/2 = 150*DRZ
KanalA = Drehzahl1 / 72; // Untersetzung Getriebe einbringen
KanalB = Drehzahl2 / 72;
x=KanalA;
sprintf(s, "Drehzahl 1: %.d 1/min \n", x);
uart_puts( s );
//_delay_ms(200);
x=KanalB;
sprintf(s, "Drehzahl 2: %.d 1/min \n", x);
uart_puts( s );
//_delay_ms(200);
}
}
Vielen Dank schonmal für eure Hilfe!
Grüße,
Bucki