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.
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
Lesezeichen