PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer als Counter zu konfigurieren



kmrish
15.08.2011, 11:29
hallo liebe Leute;

Der Timer ist ein Counter der mit jedem Takt das Spaziealregister um eins erhöht. das ist mir schon klar.
was mir nicht klar ist, wie wird solcher Timer/COUNTER mit dem externen Ereignisse im Zusammenhang gebracht?

also soweit ich weiss, er (counter) soll das externe Ereigniss und nicht der Takt zählen . ok ich verstehe es, dass der Counter einen Taktsignal braucht um er zählen zu können, aber letzendlich will ich das externe Ereigniss zählen.oder? also es muss irgendwie zwei Register vorhanden, ein für Zählen im Bezug auf Taktsystem und anderer für Zählen der Externe Events. oder?

Ich weiss nicht, es fehlt mir irgendwie eine kitte dabei. es fehlt mir was um die Funktion des Timers als Counter richtig zu verstehen.

Ich bitte um Erklärung bitte!!!

021aet04
15.08.2011, 11:36
Welchen Controller verwendest du? Normalerweise gibt es für den aktuellen Zählstand ein Register. Man stellt nur die "Taktquelle" um. Also entweder interner Takt vom Controller oder ein externes Ereignis.

MfG Hannes

kmrish
15.08.2011, 11:44
ICh verwende Advacned Timer (TIM1).
Laut der Datasheet kann man dieser Timer im Encoder Interface Mode treiben lassen.
Weiters steht drinn, dass der Counter countet herauf oder herunter nach der Drehrichtung des Encoders.
das klingt schön für mich bis ich auf diesem Satz gestolppert und zwar Einstellung des TaktCounter.

Ich habe versucht den TIMer wie folgt zu konfigurieren, können Sie bitte einen kurzen Blick daruaf werfen, und mir sagen ob was noch fehtl bzw. falsch ist.

Daanke für Ihre Hilfe.

void TIMX_Encoder (void)

{
//-------------------Encoder-Interface
TIM_EncoderInterfaceConfig(TIM1, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);

//-------------------Configure the TI1 as Input
TI1_Config(TIM1, TIM_ICPolarity_Rising,TIM_ICSelection_DirectTI,0);

//-------------------Configure the TI1 as Input
//TI2_Config(TIM1, TIM_ICPolarity_Rising,TIM_ICSelection_DirectTI,0x0 0);

//-------------------UG
TIM_UpdateRequestConfig(TIM1,TIM_UpdateSource_Regu lar );

//-------------------Timer_Base Unit
TIM1_Configuration.TIM_CounterMode =TIM_CounterMode_CenterAligned3;
TIM1_Configuration.TIM_ClockDivision =0;
TIM1_Configuration.TIM_Prescaler =60;
TIM_TimeBaseInit(TIM1,&TIM1_Configuration);

//-------------------TIM1 Enable
TIM_Cmd(TIM1, ENABLE);

}

kmrish
15.08.2011, 12:06
Die Frequenz der Externen Signale hängt von der Umdrehungszahl pro Sekunde und von der Impulszahl einer Umdrehung.
Der inkrementelle Drehgeber in diesem Projekt gibt 360 Impulse pro Umdrehung. Das heißt wenn der Geber mit 100 Umdrehungen pro Sekunde getrieben wird, dann wird die Frequenz des Ausgangssignals wie folgt berechnet.
f= Umdrehung pro Sekunde * Impulszahl → 360 * 100= 36KHz
Da die max. Impulszahl von dem Hersteller bekanntgegeben und zwar 200KHz dann kann man die max. Umdrehung pro Sekunde wie folgt berechnen.
Umdrehung pro Sekunde = Impulsfrequenz / Impulszahl → 200KHz / 360= 555 U/s.

021aet04
15.08.2011, 13:53
Ich kann dir da leider nicht weiterhelfen, da ich nicht weiß welchen µC du verwendest. Die Berechnung stimmt.

MfG Hannes

kmrish
15.08.2011, 14:07
de Mikrocontroller ist STM32F100RB die auf den Board "STM32 Value Line Discoverye evaluation board" eingebaut.

Arkon
15.08.2011, 14:08
Du kannst, wie 021aet04 (https://www.roboternetz.de/community/members/7714-021aet04) schon anmerkte, den Timer auch auf ein externes Signal reagieren lassen. Bei Atmegas gibt es Register, mit denen du den Prescaler einstellst aber auch den Timer darauf einstellen kannst auf eine steigende oder fallende Flanke an einem Pin zu reagieren und in diesem Fall das dem Timer zugehörige Zählregister inkrementieren lassen.

kmrish
15.08.2011, 14:21
Du kannst, wie 021aet04 (https://www.roboternetz.de/community/members/7714-021aet04) schon anmerkte, den Timer auch auf ein externes Signal reagieren lassen. Bei Atmegas gibt es Register, mit denen du den Prescaler einstellst aber auch den Timer darauf einstellen kannst auf eine steigende oder fallende Flanke an einem Pin zu reagieren und in diesem Fall das dem Timer zugehörige Zählregister inkrementieren lassen.

wozu soll ich den Prescaler einstellen, wenn ich auf den Taktsignal (in diesem Fall externe Signale) keinen Einfluss habe?

Die Frage an diese Stelle ist, kann sich der Counter an die Geschwändigkeit des externen Signals anpassen???? also zählt er so schnell wie sich das Signal ändert?
geht man davon aus, dass der Signalgeber mit 200KHz läuft, nun kann der Counter je 5µs (1/200KHz) um eins erhöht bzw. verringert???? kann man in solchem Fall sowas konfigurieren und wie????

mit dem Prescaler teile ich den Systemcore Clock vor. nun in diesem Mode verwende ich das Taktsystem nicht sonder externe Signale..!

Danke für Hilfe

Arkon
15.08.2011, 14:46
Wenn du den Timer auf ein externes Signal einstellst hat das nichts mit dem Prescaler zu tun. Das wird nur im selben Register eingestellt.

Welchen µC verwendest du denn für diese Aufgabe? Und in welcher Sprache soll programmiert werden?

kmrish
15.08.2011, 14:48
STM32F100RB mit C-Sprache

kmrish
15.08.2011, 14:55
Das Folgende Code habe ich in der STM32F10x_tim.c.

Ich schätzr mal das ist der Code, das ich suche oder? nun statt external Clock Mode ist eigentlich external Signal das sind gleich oder?

/**
* @brief Configures the External clock Mode1
* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
* @param TIM_ExtTRGPrescaler: The external Trigger Prescaler.
* This parameter can be one of the following values:
* @arg TIM_ExtTRGPSC_OFF: ETRP Prescaler OFF.
* @arg TIM_ExtTRGPSC_DIV2: ETRP frequency divided by 2.
* @arg TIM_ExtTRGPSC_DIV4: ETRP frequency divided by 4.
* @arg TIM_ExtTRGPSC_DIV8: ETRP frequency divided by 8.
* @param TIM_ExtTRGPolarity: The external Trigger Polarity.
* This parameter can be one of the following values:
* @arg TIM_ExtTRGPolarity_Inverted: active low or falling edge active.
* @arg TIM_ExtTRGPolarity_NonInverted: active high or rising edge active.
* @param ExtTRGFilter: External Trigger Filter.
* This parameter must be a value between 0x00 and 0x0F
* @retval None
*/
void TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,
uint16_t ExtTRGFilter)
{
uint16_t tmpsmcr = 0;
/* Check the parameters */
assert_param(IS_TIM_LIST3_PERIPH(TIMx));
assert_param(IS_TIM_EXT_PRESCALER(TIM_ExtTRGPresca ler));
assert_param(IS_TIM_EXT_POLARITY(TIM_ExtTRGPolarit y));
assert_param(IS_TIM_EXT_FILTER(ExtTRGFilter));
/* Configure the ETR Clock source */
TIM_ETRConfig(TIMx, TIM_ExtTRGPrescaler, TIM_ExtTRGPolarity, ExtTRGFilter);

/* Get the TIMx SMCR register value */
tmpsmcr = TIMx->SMCR;
/* Reset the SMS Bits */
tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_SMS));
/* Select the External clock mode1 */
tmpsmcr |= TIM_SlaveMode_External1;
/* Select the Trigger selection : ETRF */
tmpsmcr &= (uint16_t)(~((uint16_t)TIM_SMCR_TS));
tmpsmcr |= TIM_TS_ETRF;
/* Write to TIMx SMCR */
TIMx->SMCR = tmpsmcr;
}

Arkon
15.08.2011, 16:52
Mit dem µC kenn ich mich leider nicht aus. Aber wie schon gesagt:

Bei den meisten (allen?) AVRs gibt es ein Register für den Timer um diesen zu konfigurieren. Man hat die Wahl zwischen zwei "Zählweisen"

1. Der Zähler zählt mit dem µC-Takt, evtl. verrechnet mit einem Presceler, hoch, der überwachte Pin für die zweite Zählgeschwindigkeit hat keinen Einfluss
2. Der Zähler zählt bei jeder steigenden oder fallenden Flanke um jeweils 1 hoch, der µC-Takt hat keinen Einfluss auf die Zählgeschwindigkeit

Ich schätze mal, so eine Einstellung dürfte es auch bei deinem µC geben.

021aet04
15.08.2011, 17:25
@Arkon Er verwendet keinen AVR sondern einen ARM. Ds ist nicht die gleiche Technik.

@kmrish: Leider kann ich dir ebenfalls nicht weiterhelfen da ich mit Atmegas/Attinys, also AVR, programmiere.

MfG Hannes

steffen_hh
15.08.2011, 19:30
Die Initialisierung des TIM1 bis TIM5 und TIM8 als Endcoder ( Endcoder-Mode ) ist relativ einfach. Im Kap. 14.3.12 Manual Rev. 11 steht da alles beschrieben.

Hier ein Bsp. für TIM3:

#define ENCODER_TIMER TIM3
#define C_QA GPIO_Pin_6 //- Input Encoder A
#define C_QB GPIO_Pin_7 //- Input Encoder B

void EncoderTimerInit( void )
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;

/* Timer configuration in Encoder mode */
TIM_DeInit(ENCODER_TIMER);
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // No prescaling
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //

TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(ENCODER_TIMER, &TIM_TimeBaseStructure);

TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = ICx_FILTER;
TIM_ICInit(ENCODER_TIMER, &TIM_ICInitStructure);

//-
TIM_EncoderInterfaceConfig(ENCODER_TIMER, TIM_EncoderMode_TI12,
TIM_ICPolarity_Falling, TIM_ICPolarity_Rising);


// Clear all pending interrupts
// TIM_ClearFlag(ENCODER_TIMER, TIM_FLAG_Update);
// TIM_ITConfig(ENCODER_TIMER, TIM_IT_Update, ENABLE);

TIM_Cmd(ENCODER_TIMER, ENABLE);

}

void init_gpio( void )
{
GPIO_InitTypeDef GPIO_InitStructure;
//- andere Portpins für TIM3 ( GPIO 6 und GPIO 7 )
GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);

GPIO_InitStructure.GPIO_Pin = C_QA | C_QB;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);

}

void main( void )
{
u16 wCounter =0;

init_gpio( );
EncoderTimerInit();

//- Bsp. für das lesen des Encoder-Counter
wCounter = ENCODER_TIMER->CNT;


// etc.

}

Das sollte so funktionieren. Musst Du halt noch entsprechend erweitern oder abändern ( Timer und Ports z.B. )

Gruss
Steffen

kmrish
15.08.2011, 22:45
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

da der Counter in beide Richtung zählen soll, soll als CounterMode das " TIM_CounterMode_CenterAligned3 " ausgewählt werden. stimmt??

RM0008 steht seite 344 " the counter counts up and down (Center aligned mode 3, CMS ="11"). "

wenn das richtig ist, soll ich TIM_TimeBaseStructure.TIM_CounterMode verwenden oder soll ich das da verwenden:
void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode)

welche soll ich verwenden um den Counter-Mode einzustellen?

021aet04
16.08.2011, 07:38
Kannst du ein Datenblatt posten nach deem du gehst. Dann könnte ich nachlesen.

MfG Hannes

kmrish
16.08.2011, 11:10
Hallo Lieber 021aet04

Ich danke dir viel mals für deine Bereitschaft mir zu helfen.
Anbei sende ich dir das Referenz Manual (RM0008).

Dieses Datenbaltt besteth aus 1072 Seiten, deswegen möchte ich dir erleichten, die entsprechende Seiten schnell zu finden.

Encoder Inreface Mode findest du ab Seite 301
Center-aligned mode (up/down counting) ab Seit 278
SPI ab Seite 657 (meine Schaltung wird dabei als Slave-Device betrieben)

Vielen Danke für deine Hilfe.
LG
Adam

RP6conrad
17.08.2011, 06:55
So hat er bei mir functioniert mit ein qwadrature encoder !! Beide Eingangen mussen beschaltet sein, und in Fase versetzt. Dan zaehlt den counter hoch oder ab, abhangig welke Flanke erst kommt.

/**
* @brief Configures the TIMx Encoder Interface.
* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
* @param TIM_EncoderMode: specifies the TIMx Encoder Mode.
* This parameter can be one of the following values:
* @arg TIM_EncoderMode_TI1: Counter counts on TI1FP1 edge depending on TI2FP2 level.
* @arg TIM_EncoderMode_TI2: Counter counts on TI2FP2 edge depending on TI1FP1 level.
* @arg TIM_EncoderMode_TI12: Counter counts on both TI1FP1 and TI2FP2 edges depending
* on the level of the other input.
* @param TIM_IC1Polarity: specifies the IC1 Polarity
* This parmeter can be one of the following values:
* @arg TIM_ICPolarity_Falling: IC Falling edge.
* @arg TIM_ICPolarity_Rising: IC Rising edge.
* @param TIM_IC2Polarity: specifies the IC2 Polarity
* This parmeter can be one of the following values:
* @arg TIM_ICPolarity_Falling: IC Falling edge.
* @arg TIM_ICPolarity_Rising: IC Rising edge.
* @retval None
*/
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICP olarity_Rising);
TIM_EncoderInterfaceConfig(TIM4, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising,TIM_ICP olarity_Rising);
/* TIM enable counter */
TIM_Cmd(TIM2, ENABLE);
TIM_Cmd(TIM4, ENABLE);

/* TIM2 + TIM4 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/* GPIOA, GPIOB and GPIOC clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);

//configure TIM2 CH0/CH1 = A0,A1 alternate function for encoder reading
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1| GPIO_Pin_15;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//configure TIM4 CH0/CH1 = B6,B7 alternate function for encoder reading
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 |GPIO_Pin_6 | GPIO_Pin_7;
GPIO_Init(GPIOB, &GPIO_InitStructure);

static int16_t encoder1;
static int16_t encoder2;
encoder1=TIM2->CNT; //actuele waarde van encoder1
encoder2=TIM4->CNT; //actuele waarde van encoder2

kmrish
17.08.2011, 12:54
hallo RP6conrad,

Ich hätte gerne paar Fragen zu deinem Code.

1) zuerst warum hast zwei Timer TIM2 und TIM4 dafür eingesetzt? wolltest du damit Zwie Drehgebers abtasten?
2)ich sehe in deinem Code keine Funktion, womit der Counter in beide Richtung zählt() sowohl heruaf als acu heunter. laut der RM0008 stellt man sowas durch die folgende Funktion:
TIM_CounterModeConfig(TIM1,TIM_CounterMode_CenterA ligned3);
3) braucht man die Funktion TIM-TimeBseStructure nicht__?????
4) soweit ich richtig verstsnden habe der Counter bekommt das Signal TI1FP1 und TI2FP2, und die beide Signalen sind Inputcapture. das heisst mann soll auch das Capture/ Compare unti Teilweise einstellen wie folgt:

TIM_ICInitStructure.TIM_Channel =TIM_Channel_1 |TIM_Channel_2;
TIM_ICInitStructure.TIM_ICPolarity =TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection =TIM_ICSelection_DirectTI;
TIM_ICInitStructure.TIM_ICPrescaler =TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter =0x0;
TIM_ICInit(TIM1, &TIM_ICInitStructure);

5)mit was kann man auf die folgende Frage Antworten:
kann der Counter in eine Sekunde 200.000 Steigende Flanke zählen? bzw. 400.000 steigende und fallende Flanke zählen?

RP6conrad
17.08.2011, 21:16
1. Stimmt, ich habe 2 motoren mit jeden ein kwadrature encoder (ist für eine robby mit differential drive). Damit wirden von beide motoren die exacte position erfasst.
2. Das schone von diese timer ist das alles komplett in harware verlauft. Ihre C-program muss sich da nicht mehr um kummerm ! Nur eine ueberlauf (16 bit counter) sollen sie noch mit eine interrupt abfangen.
3. Tim base Structure brauchen sie in diesen Fall nicht.
4. Auch input capture braucht man nicht. Ein Input Capture macht folgendes : sobald das "Event" (positive flanke, negatieve flanke) passiert, wird die Timer wert in ein Register abgelegt. Den Timer lauft dabei an eine feste Frequenz. Ist forgesehen um Zeiten zwischen zwei "Events" genau zu messen.
5. Habe ich auch keine Wert gefunden, aber 400 kHz soll eigentlich kein Problem sein, da alles in HW verlauft.