Gast
#1179903
Hallo
ich benutze einen Atmega8 um in Abhängigkeit des ADC-Kanals variable
Impulslängen zu erzeugen. Ich benutze dabei ADC-Interrupt, Timer0 und
Timer1-Interrupt. Der ADC wird alle 1ms ausgelesen (siehe code).
Was ich eigentlich vor habe, ist Impulse zu erzeugen mit Periodendauern
von ca. mindestens 10ms und 500 us maximal. Um dies zu realisieren habe
ich folgenden Code geschrieben und auch getestet. funktioniert
eigentlich super, ABER: Nun hab ich vor die Zeiten zu ändern, sprich ca.
mindestens 15ms bis maximal 2ms (oder 1,5ms). Wie kann man das
kontrolliert machen ohne irgendwelche Prescaler werte einzustellen und
zu messen?
Ich meine, gibt es eine Formel, mit der man es ausrechnen kann? Komme
mit den ganzen Prescalern und Faktoren durcheinander...
Zusatzfrage: Müssen die Variablen S0, S1 auch volatile, da sie sich auch
in der ISR befinden?
Vielen dank schonmal für eure Tipps!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
CODE:
_________________________________________________
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////
//
//
// Possible Impulse Frequence: Min (Period): 8.4ms Max (Period):
400µs
//
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////
#ifndef F_CPU
/* prevent compiler error by supplying a default */
#define F_CPU 1000000UL
#endif
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/io.h>
volatile char pulselength = 0; //Volatile aufgrund von Interrupt..
char S1 = 0;
char S2 = 0;
char Direction = 1;
volatile uint16_t AdcValue = 0;
////////////////////////////////////////////////////////////////////////
/////////////////////
// ADC Conversion read out
////////////////////////////////////////////////////////////////////////
/////////////////////
ISR(ADC_vect)
{
//Nur die MSB werden übernommen//
pulselength = ADCH;
}
////////////////////////////////////////////////////////////////////////
/////////////////////
////////////////////////////////////////////////////////////////////////
/////////////////////
// Timer 0 interrupt ADC Conversion
////////////////////////////////////////////////////////////////////////
/////////////////////
ISR(TIMER0_OVF_vect ) {
ADCSRA |= (1<<ADSC); // ADC Messung Starten
TCNT0 = 130; //130 => jede 1ms ADC-Abfrage
}
////////////////////////////////////////////////////////////////////////
/////////////////////
////////////////////////////////////////////////////////////////////////
/////////////////////
// Timer 2 interrupt Pulse length -> calculate next signal
////////////////////////////////////////////////////////////////////////
/////////////////////
ISR(TIMER2_OVF_vect )
{
//Vorwärtsbetrieb
if (Direction)
{
if ((S1==1) && (S2==1)) { S1 = 0; S2 = 1; } else
if ((S1==1) && (S2==0)) { S1 = 1; S2 = 1; } else
if ((S1==0) && (S2==0)) { S1 = 1; S2 = 0; } else
if ((S1==0) && (S2==1)) { S1 = 0; S2 = 0; }
}
// Rückwärtsbetrieb
else if (!Direction)
{
if ((S2==1) && (S1==1)) { S2 = 0; S1 = 1; } else
if ((S2==1) && (S1==0)) { S2 = 1; S1 = 1; } else
if ((S2==0) && (S1==0)) { S2 = 1; S1 = 0; } else
if ((S2==0) && (S1==1)) { S2 = 0; S1 = 0; }
}
if (S1) { PORTD |= (1<<PD1); } else { PORTD &= ~(1<<PD1); }
if (S2) { PORTD |= (1<<PD2); } else { PORTD &= ~(1<<PD2); }
TCNT2 = pulselength; //Zählregister
}
////////////////////////////////////////////////////////////////////////
/////////////////////
////////////////////////////////////////////////////////////////////////
/////////////////////
// Initialisierung
//
////////////////////////////////////////////////////////////////////////
/////////////////////
void init() {
//::::::Port Configuration:::::://
//PortD Data Direction Register:
//Ouputs: PD0 = Hall1_R, PD1 = Hall2_R, PD2 = Hall1_L, PD3 = Hall2_L
DDRD |= (1 << PD0) | (1 << PD1) | (1 << PD2) | (1 << PD3);
//Inputs: PD4 = Open, PD5 = Close, PD6 = SetHall_High, PD7 =
SetHall_Low
DDRD &= ~((1 << PD4) | (1 << PD5) | (1 << PD6) | (1 << PD7));
// Init Timer 0
TCCR0 = ( 1 << CS01 ); // Teiler: 8 //1ms ADC Value messung
TIMSK = ( 1 << TOIE0 ); // Overflow Interrupt einschalten
TCNT0 = 130; // init Wert: Zähle 125 bis ersten overflow (1ms)
// Init Timer 2
TCCR2 = ( 1 << CS21 ); //prescaler 8
TIMSK |= (1 << TOIE2); // Overflow Interupt einschalten
//OCR2=200; // Vergleichsregister
TCNT2= pulselength; //200 // Zählregister
//ADC Configuration
////////////////////////////////////////////////////////////////////////
///////////
ADMUX = 0; // Kanal waehlen (ADC0)
ADMUX |= (0<<REFS1) | (1<<REFS0) | (1<<ADLAR); // AVCC als
Referenzspannung nutzen, left adjustet ADC Register (ADLAR)
ADCSRA |= (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0) | (1<<ADIE);
ADCSRA &= ~((1<<ADPS2)|(1 << ADFR));
//// First Read Out um den ADC warmlaufen zu lassen
////////////////////////////////
ADCSRA |= (1<<ADSC); // Start
ADC-Wandlung
while ( ADCSRA & (1<<ADSC) ) { // Warten bis ADC
Wandlung fertig ist
;
}
}
////////////////////////////////////////////////////////////////////////
/////////////////////
////////////////////////////////////////////////////////////////////////
/////////////////////
////////////////////////////////////////////////////////////////////////
/////////////////////
// MAIN
////////////////////////////////////////////////////////////////////////
/////////////////////
////////////////////////////////////////////////////////////////////////
/////////////////////
int main()
{
init();
sei(); // Enable Interrupts
while ( 1 ) {}
return 0;
}
____________________________________________________