PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Frequenz messen - Servo ansteuern



Maggus910
15.06.2009, 13:41
Hi,

wir haben ein Projekt am laufen bei dem wir eine Drehzahl in Form einer Frequenz geliefert bekommen und einen Servo dementsprechend ansteuern.

Wir haben als Controlerboard das RN Mini mit dem Atmega 168

Nun habe ich gelesen das man Frequenzen mittels ICP einlesen kann. Wie das genau geht weiß ich zwar noch nicht aber bevor ich mich darin vergrabe habe ich noch eine Frage.

Das PWM Signal für den Servo braucht ja auch ein ICR Register.

Hängen ICP und ICR irgendwie zusammen? Ist das Projekt überhaupt so zu realisieren?

Danke schonmal an alle die sich dem Beitrag annehmen

Ceos
15.06.2009, 14:05
jein, sofern du für in und ausgabe denselben teimer verwendest gehören sie zusamme, aber fnuktionieren dennoch!

du stellst einen timer auf fast PWM, der zählt dann immer hoch, beim überlauf löst er den PWM Pin, wenn du dann einen Wert im OCR register hast und der counter diesen erreicht, setzt er den pin, dann löscht er ihn wieder beim überlauf und so weiter ...

der ICP macht nichts weiter, als dass er bei einer detektierten flanke den aktuellen timerwert in das ICR register schreibt, dass du dann in aller ruhe auswerten kannst, anschliessend setzt du das OCR register damit dein servo aussteuert und lässt den timer seine arbeit machen, bis der nächste ICP kommt .. dir werden aber höchstwahrscheinlich die rechenzyklen ausgehen, also wird da noch einiges an gehirnschmalz hinterherfliessen

Maggus910
15.06.2009, 16:29
So ein Mist...wir waren tierisch happy das der Servo überhaupt geht....es ist nicht so das ich hier einfach nur reinposte weil ich zu faul bin mich drum zu kümmern. Das ist nur nen superkurzfristiges Projekt an der FH...

Ich poste euch mal grade den Code den wir für die Servoansteuerung nutzen...welche Register ich da genau wo verwende weiß ich im Grunde garnicht, der Code wurde nur mit viel ausprobieren angepasst.

Ich würde mich gerne tiefer in de Thematik einarbeiten aber ihr wisst ja selber das das nicht in ein paar Tagen möglich ist....

################################################## #
rncontrol.h

Diese Header-Datei stellt grundlegende Funktionen in C zur Verfügung.
Dominik Wiechard
Bearbeitet von
################################################## #####
*/
#include <avr/io.h>
#include <stdlib.h>
/*-----------------------------------------------------------------------------------*/
/*###Portkonfiguration###*/
/*Pins bzw. Ports als Ein-/Ausgänge konfigurieren*/




void PORTCONFIG(void)
{
//-> alle Pin´s von Port F als Eingänge
DDRB |= (1<<PB1); //PB5 Servo 1 OC1A
DDRC |= (1<<PC0);
}

/*-------------------------------------------------------------------------------------*/
/*###PWM Konfiguration###*/

void PWM_INIT(void)
{
// normale 8-bit PWM aktivieren (nicht invertiert), COM1A1=1 und COM1A0=1-->set 1 upcounting set 0 downcounting

TCCR1A = (1<<COM1A1)|(0<<COM1A0)|(0<<WGM10)|(0<<WGM11);

// Einstellen der PWM-Frequenz (Prescaler = 8-->CS11)

TCCR1B = (0<<CS10)|(1<<CS11)|(0<<CS12)|(0<<WGM12)|(1<<WGM13); // Mode 8 aktiviert

TCNT1H=0x00;
TCNT1L=0x00;

// Interrupts für Timer1 deaktivieren
// Achtung: Auch die Interrupts für die anderen Timer stehen in diesem Register
//TIMSK &= ~0x3c;
TIMSK1=0x00;

ICR1 = 20000;
}

/*-------------------------------------------------------------------------------------*/
/*### ADC-Ansteuerung ###*/

uint16_t adcwert(uint8_t kanal)
{
uint16_t wert = 0; //Variable für Ergebnis deklarieren

ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //Register zur ADC Messung aktivieren

ADMUX = kanal;
ADMUX = (0<<REFS1)|(1<<REFS0);

ADCSRA |= (1<<ADSC); //nach Aktivierung des ADC wird ein Wert eingelesen und verwirft diesen wieder, um den ADC "warmlaufen zu lassen"
while(ADCSRA & (1<<ADSC)) {} //auf Abschluss der Konvertierung warten
wert = ADCW; //ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten Wandlung nicht übernommen.

/* Eigentliche Messung - Mittelwert aus 4 aufeinanderfolgenden Wandlungen */
wert = 0;
for(uint8_t i=0; i<4; i++)
{
ADCSRA |= (1<<ADSC); //eine Wandlung "single conversion" starten
while(ADCSRA & (1<<ADSC)) {} //auf Abschluss der Konvertierung warten
wert = wert + ADCW; //Wandlungsergebnisse aufaddieren
}

ADCSRA &= ~(1<<ADEN); //ADC deaktivieren

wert = wert/4; //Durchschnittswert bilden

return wert;
}

Besserwessi
15.06.2009, 17:58
Dadurch das Kommentare und Code teils nicht zusammenpassen ist der Code schwer zu verstehen. Er hilft einem auch kaum weiter. Es wird genau einer der PWM Modes benutzt die das ICR register als obere Grenze für den Timer nutzen, also die ISP Funktion gerade ausschaltet.

Wenn man nur 1 Senvo hat, könnte man eine den Servo an OC1B hängen und mit MODE15 arbeiten (fast PWM mit OCR1A als TOP wert). Die Frequenzmessung wird dadurch aber schon etwas komplizierter.

Eine Alternative wäre es das PWM Signal nicht ganz in Hardware zuerzeugen, sondern Teilweise in Software. Timer 1 kann dann durchlaufen und dann jeweils ein Interrupt ausgelöst werden wenn die nächste Änderung ansteht. Der Code sollte sehr ähnlich sein, wie man ihn nutzt um sehr viel Servos (z.B. 10) anzusteuern. Bei einem Servo könnte es sogar noch als Quasi Hardware PWM gehen.
Wenn die taktfrequenz günstig liegt, könnte es eventuell auch gehen, den timer bis 2^16 laufen zu lassen und dann eine etwas von 20 ms abweichende Periode hinzunehmen.

Ceos
15.06.2009, 23:26
Wenn man nur 1 Senvo hat, könnte man eine den Servo an OC1B hängen und mit MODE15 arbeiten (fast PWM mit OCR1A als TOP wert). Die Frequenzmessung wird dadurch aber schon etwas komplizierter.
warum das ? ich find die lösung ideal, den timerwert in ne zeit umrechnen muss man so oder so machen!