Archiv verlassen und diese Seite im Standarddesign anzeigen : STM32F100/ Capture Compare Unit
Hallo,
ich bin bei Konfiguration TIM2 als Compare Capture Timer.
Genau diesen Timer habe ich ausgewählt, weil:
"These Timers (TIM1, TIM2, and TIM3) are capable of handling quadrature (incremental) encoder signals and the digital outputs from 1 to 3 hall-effect sensors. Page 19"
SUPER!!! Genau das brauche ich, denn ich einen incremntal-Drehgeber steuern möchte.
Also dieser Timer - soweit ich richtig verstanden habe- kann als Capture Compare Unit verwendet werden.
Er besitzt 4-Chanels jeweils Counter und Compare/Capture_Register (CCR).
Wird es funktionieren, wenn ich:
1) Den Counter von CH-2 stelle ich so ein, dass er 65535 up-countet (16-Bit). sein PSC stelle ich auf 24 ein, somit ist der Counter_Clock 1MHz (24/24).Demzufolge countet der Counter pro 1µs. so braucht er ca. 65536*1µ= 65ms.
2) Der Capture Eingang ist über Signalleitung mit dem Geber_Pulssignal verbunden. Den konfiguriere ich so, dass er die Steigende Flanke captures. Hinter her stelle den PSC auf 4. So werden 4 steigende Flanken gecaptured, ist der Psc Voll danach wird den Counter-Stand ausgelesen und in CCR kopiert.
3) 1und 2 widerhole ich für den zweiten CH nämlich CH_3 mit dem Unterschied, dass der Capture die Fallende Flanke erwischen soll.
4) am Ende habe ich zwei Value (Zeit der 4-Steigende Flanke und Zeit der 4_Fallende Flanke), die werden durch den Copmare vergleichen und den sich daraus ergebenden Wer wird durch Interrupt im Main Program abgegeben.
So der Counter zählt ganz normal.
Der Capture beobachtet den Eingagnssignal(bei dem soll ich nur einstellen was soll er erfassen (steigende oder fallende) oder gibt noch was einzustellen?)
und der Compare vergleicht die Werte die sich im CCR befinden.
Den Code habe ich Wie geschrieben:
Hier ist die Konfiguration des Counters:
TIM2_Configuration.TIM_CounterMode= TIM_CounterMode_Up;
TIM2_Configuration.TIM_Prescaler= 24;// 24 MHz dividiert durch 24MHz ist 1MHz
TIM2_Configuration.TIM_Period=65535;// Counter zählt bis 65535
TIM2_Configuration.TIM_ClockDivision= 0X0;
TIM2_Configuration.TIM_RepetitionCounter= 0x0;
TIM_TimeBaseInit(TIM2,&TIM2_Configuration);
Hier sind die Configuration für Input Capture:
Input_Capture.TIM_Channel= TIM_Channel_2;// an ch_2 von Tim_2 ist der Drehsignal angeschlossen
Input_Capture.TIM_ICPolarity= TIM_ICPolarity_Rising;// bei Steigender Flanke wird erfasst
Input_Capture.TIM_ICSelection = TIM_ICSelection_DirectTI;
Input_Capture.TIM_ICPrescaler = TIM_ICPSC_DIV4;// jede Vier Flanke
Input_Capture.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &Input_Capture);
TIM_Cmd(TIM2, ENABLE);// Der Counter von Tim2 wird eingeschaltet
Hier ist die CC_Interrupt
TIM_ITConfig(TIM2, TIM_IT_CC2, ENABLE);
Schließlich kommt die nested vector Tabelle.
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel= TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init(&NVIC_InitStructure);
Ich bin jedem sehr DANKBAR, der mir weiter helfen kann.
LG.
RP6conrad
14.07.2011, 21:37
Ich verstehe eigentlich das Problem nicht. Diese Timer konnen so konfiguriert werden das ein kwadratuur encoder eingelesen werd. Der counter wird dan eindeutig die Flanken zaehlen und abhangig das A oder B erst kommt in die richtige Richtung zaehlen. So hat der Counter immer die exacte Position von Drehgeber. Einen Input Capture muss nicht gemacht werden. Ich habe diese Function schon getestet mit das Discovery board, und das functioniert. Für eine Geschwindigkeitsmessung kan ess Sinn machen von die Abstand zwischen Zwei Flanken zu erfassen. In Prinzip muss das auch moglich sein, aber dan mussen sie eine extra Timer verwenden. Das ist dan eine standard ICP Ablauf. Functioniert auch bei mir, aber standard wird oder die Steigende Flanke, oder die Fallende flanke captiert. Zwie moglichkeiten um beide zu captieren : Zwei Kanalen verwenden (ein Timer hat 4 Kanalen) oder das register in ISR selbst togglen.
Sie mussen naturlich auch noch die ISR programmieren. Da werd bei jeden capture ein TIM2_IRQHandler aufgerufen. In diesen ISR muss dan getestet werden in welches Kanal das passiert ware. Forbild von so einen ISR (steht bei mir in die c-file: stm32f10x_it.c (IAR compiler)
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_CC3) == SET) //stijgende flank : stroom> 10 mA
{
kanaal[i]= TIM_GetCapture3(TIM2)-ICP_old;
ICP_old=TIM_GetCapture3(TIM2);
/* Clear TIM3 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
}
if(TIM_GetITStatus(TIM2, TIM_IT_CC4) == SET) //dalende flank : stroom< 10 mA
{
kanaal[i]= TIM_GetCapture4(TIM2)-ICP_old;
ICP_old=TIM_GetCapture4(TIM2);
/* Clear TIM4 Capture compare interrupt pending bit */
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4);
}
}
[QUOTE=RP6conrad;518054]Ich verstehe eigentlich das Problem nicht.
Das Problem liegt an :
1) Den Capture: ich bin nicht sicher ob es so funktioniert, und ob ich es richtig eingestellt habe?.
a)wie wird die Flanke erfasst? soweit ich weiss, er beobachtet den Einganssignal und reagiert auf bestimmten Event. und er tut das abgesehn wie schnell/langsma läuft der Counter
b)wird die steigende Flanke mit dieser Zeile Erfasst?
Input_Capture.TIM_ICPolarity= TIM_ICPolarity_Rising;
2)Den Counter: mir ist nicht sicher ob Autoreload laufen soll? Ich glaube nicht, denn ich will nur wissen bei welchem Stand war er Bei Erfassung einer Flanke
TIM2_Configuration.TIM_Period=65535;
er zählt bis 65535 und dann fängt von null an
TIM2_Configuration.TIM_RepetitionCounter= 0x0;
3)Den Compare: wie lasse ihn einen Interrupt auslösen, wenn die Zwei Werte verglieschen hat?
löst der CC1 einen Interrupt aus, wenn er zwei Values verglischen hat?
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE)
4)Bestimmung die Werte: wie werden die Werte dem Compare zugewiesen?
Timer2 hat 4 Chanels.
CH-1 möchte ich für das erste Eingangssignal zur verfügung stellen
CH-2 für das Zweite Eingagnssignal
CH-3 möchte ich als Ausgangsbit, womit ich ein Led toggle. (optional)
wie kann ich die Werte von den Capturs an einzigen Compare leiten.
Ich bitte um Hilfe, Orientierung.
Vielen Dank
RP6conrad
15.07.2011, 10:31
a)wie wird die Flanke erfasst?
Bei eine richtige Einstellung lauft das automatisch ab. Sobald eine Flanke erkannt ist, wird die Zaehlerstand von TIM2 in eine Register kopiert. Der Zaehler lauft weiter, eine IRQ wird ausgelost.
b)wird die steigende Flanke mit dieser Zeile Erfasst?
Das ist eine foreinstellung von diesen "Input capture channel". Nur zwei optionen, oder er soll reagieren auf eine Positive Flanke, oder eine negative.
2)Den Counter: mir ist nicht sicher ob Autoreload laufen soll?
Normalerweise lauft den timer einfach weiter, bei 0xFFFF fangt er dan wieder an bie 0x0000. Er kan auch eine Interrupt generiert werden, wenn sie das wunschen (wieder eine Foreinstellung).
3)Den Compare: wie lasse ihn einen Interrupt auslösen, wenn die Zwei Werte verglieschen hat?
Das ist ihre eigene Verantwortung : in den ISR (Interrupt Sub Routine) konnen sie das programmieren das bei Erfassung von beide Interrupts, eine Variable gesetzt werd. Der CC1 lost nur eine Interrupt aus bei eine steigende Flanke an Pin A0.2, und das jedesmal. Was passiert an CC2 ist abhangig was dort die Foreinstellung ist. CC2 ist normalerweise an eine andere Eingangpin gekuppelt (A0.3 ?). Den CC2 lost dan nur ein Interrupt aus bein eine Flanke an pin A0.3.
4)Bestimmung die Werte: wie werden die Werte dem Compare zugewiesen?
CC1 : bein eine Flanke an pin A0.2 wird die Zaeherstand von TIM2 abgelegt in register TIM_GetCapture1(TIM2)
CC2 : bei eine Flanke an pin A0.3 wird die Zaehlerstand von TIM2 abgelegt in register TIM_GetCapture2(TIM2)
An der Pin von CH3 passiert nicht, da auch nichts foreingestellt/ programmiert ist. Wie soll diese LED eigentlich reagieren ?
Hier meine code für eine ICP von CCH3/4 von TIM2 : durch eine Foreinstellung reagiert CC3 uaf eine Fallende flanke von A0.2, CC4 auf eine steigende flanke von A0.2 (remap von pins)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_10;
GPIO_Init(GPIOA, &GPIO_InitStructure); //Pin A10=USART Rx,Pin A2 = Input capture TIM2 CH3
/* ² configuration: Input Capture mode ---------------------
The external signal is connected to TIM2 CH3 pin (PA.2)
The Rising edge is used as active edge,
The TIM2 CCR2 is used to compute the frequency value
------------------------------------------------------------ */
TIM_ICInitTypeDef TIM_ICInitStructure; //alleen voor input capture
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 23;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/*Input capture channel 3 configuration*/
TIM_ICInitStructure.TIM_Channel = TIM_Channel_3;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//PA.2
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
TIM_ICInitStructure.TIM_ICFilter = 0x0;
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/*Input capture channel 4 configuration*/
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;
TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_IndirectTI;//Alternate function PA.2
TIM_ICInit(TIM2, &TIM_ICInitStructure);
/* TIM enable counter */
TIM_Cmd(TIM2, ENABLE);
/* Enable the CC3//CC4 Interrupt Request */
TIM_ITConfig(TIM2, TIM_IT_CC3, ENABLE);
TIM_ITConfig(TIM2, TIM_IT_CC4, ENABLE);
/* Setup the microcontroller system. Initialize the Embedded Flash Interface,
initialize the PLL and update the SystemFrequency variable. */
SystemInit();
/* PCLK1 = HCLK/4 */
/* TIM2 clock enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA, GPIOB and GPIOC clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
Hallo,
Ich danke dir sehr Herzlich RP6Conrad für deine Hilfe.
Ich hätte noch paar Fragen und Zwar bezüglich der AFIO.
Ich möchte den User_Button als Inputcapture einstellen, somit wenn ich das Button drucke wird an Input_capture logisch 1 generiert, und dementsprechend läuft der Capture.
Der Pin dieses Buttons ist als WKUP eigestellt, jetzt sollte ich ihn so umstellen, dass er als TIM2_CH0 funktioniert.
Ich habe die folgenden Sätze im RM008 gelesen, die ich nicht ganz gut verstanden habe, und möchte gerne deine Meinung/ Bestätigung einholen:
1) "For alternate function inputs, the port must be configured in input mode (floating, pull-up or Pull down) and the Input pin must be driven externally"
Da der User_Button ist nicht externally getrieben sonder innen, wird das nicht akzeptable, dass der User_Butto als Input capture vorgenommen wird, RICHTIG?????
2) "If you configure a port bit as alternate function Output, this disconnects the Output Register and connects the pin to the out signal of an on_chip peripheral"
Hier wird nur der Output_Register deaktiviert, aber der Inputregister bleibt doch aktive, Richtig? oder wird sowohl als auch deaktiviert????
3) gibt Methode, womit ich mit dem Board "STM32 value line Discovery" den Capture/copmare Funktion teste??? ich muss unbedingt ein Eingagnstriger für den Inputcapture, ich habe Zuhause keine Möglichkeit ein Signal einzuspeisen. Deswegen bin ich darauf gekommen dass der User_button selbst als Eingangssignal einzustellen.
RP6conrad
16.07.2011, 10:10
1) "For alternate function inputs, the port must be configured in input mode (floating, pull-up or Pull down) and the Input pin must be driven externally"
Kan gemacht werden mit der User Button : Diese Button ist verbunden an Pin A0 mit eine Pull down. Ohne betatigung hat der eingang damit 0V, oder logisch 0, betaetigt hat her 3.3V, oder logisch ein. Das wird gemeint mit "Externaly driven". Er muss naturlich als Eingang configuriert werden, und den TIM2 CH1 muss activiert werden.
2) "If you configure a port bit as alternate function Output, this disconnects the Output Register and connects the pin to the out signal of an on_chip peripheral"
Eine pin configuriert als "Alternate Function Output" wird dan nur gesteurt durch die "On chip peripheral" wie PWM, DAC, USART, I2C.... Sie konnen dan nicht mehr die Ausgangen beinflussen direct aus ihre Program. Nach meine Meinung gibt noch immer die Moglichkeit um die Pins ab zu fragen als Eingang.
3) gibt Methode, womit ich mit dem Board "STM32 value line Discovery" den Capture/copmare Funktion teste???
Muss gehen mit der User button und TIM2 CH1 (pin A0). Zum debuggen verwende ich gerne die USART und ein Terminal program auf PC. Damit kan ich in jeden Punkt von mein Program eine variable ausgeben nach PC. Naturlich brauchen sie dan noch ein level converter (MAX232) und eine seriele port auf den PC. Alternativ konnen sie ein Debugger verwenden. Bei den IAR compiler ist das standard moglich. Damit kan auch jeden variable/register ausgelesen werden, obwohl dan der Controller gestoppt werd. Sehr hilfreich fur mich ware auch al die Forbild-Programme von STM32 Std lib, mit eingebunden bei den IAR compiler. Diese sind eigenlich fur ein andere Board gemacht (Eval board STM32..), aber perfect zu verwenden mit kleine Anpassungen. Auch die LEDS an pin C8/C9 sind zu verwenden ! Das standard Program von das discovery board selbst ist nicht so hilfreich : unheimlich fiele "Defines", machen das schwierig zu verstehen.
Hallo;
Ich werde bald verrückt
Ich verstehe nicht wo steckt meinen Fehler.
fast(90%) Jede Zeile verstehe ich, und bin ich sogar sicher dass es so richtig aber 1% falsch reicht um den Programm wahnsinnig zu machen.
Ich brauche jede kleine Hinweise, Tipp, Orientierung bitte....!
/* Includes */
#include <stddef.h>
#include "stm32f10x.h"
/* ---------------------------Private typedef -------------------------------*/
TIM_TimeBaseInitTypeDef TIM2_Configuration;
NVIC_InitTypeDef NVIC_InitStructure;
TIM_OCInitTypeDef Output_Compare;
TIM_ICInitTypeDef Input_Capture;
GPIO_InitTypeDef GPIO_Inity;
/*Variable*/
uint32_t Interrupt_Counter = 0;
/*# ************************************************** *****************************/*/
void RCC_Configuration(void)
{
/* TIM2clock= SystemCoreColock, enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* ALTERNATE FUNCTION ENABLE*/
RCC_APB1PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* GPIOC clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
}
/************************************************** *****************************/
void GPIO_Setup ()
{
/* LEDs pin (PC.08 and 09) configuration */
GPIO_Inity.GPIO_Pin =GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Inity.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
/* TIM2 PA.0 configuration*/
GPIO_Inity.GPIO_Mode =GPIO_Mode_AF_PP;// soll ich PULL-Down oder Pull up werwenden wenn der
// Eingang als Pull-Down Konfiguriert?
// Der AF weil bei dieser Pin wir der Alternate Function verwendet
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Inity.GPIO_Pin =GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_Inity);
GPIO_Init(GPIOC, &GPIO_Inity);
}
/************************************************** ******************************/
void TIM2_SETUP ()
{
/*----Time_Base_Counter-----*/
TIM2_Configuration.TIM_CounterMode= TIM_CounterMode_Up;
TIM2_Configuration.TIM_ClockDivision= 0;
TIM2_Configuration.TIM_Period=65535;
TIM2_Configuration.TIM_Prescaler=1;
TIM_TimeBaseInit(TIM2,&TIM2_Configuration);
/*----Input_Capture Mode CH1----*/
Input_Capture.TIM_ICSelection = TIM_ICSelection_IndirectTI;// hier verstehe ich der Unterschied
// zwischen Direct und Indirekt nicht
// wirklich, aber ich verwende Direct weil ich
// kein remaping durchführe
Input_Capture.TIM_ICPolarity= TIM_ICPolarity_Rising;
Input_Capture.TIM_ICPrescaler = TIM_ICPSC_DIV1;
Input_Capture.TIM_Channel= TIM_Channel_1;
Input_Capture.TIM_ICFilter = 0;
TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);// dieze Zeile verstehe ich überhaupt nicht
TIM_ICInit(TIM2, &Input_Capture);
TIM_Cmd(TIM2, ENABLE);
/*----Enable the Capture Compare Interrupt Request-----*/
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
}
/************************************************** ******************************/
void NVIC_SETUP ()
{
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannel= TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/************************************************** ******************************/
void delayLoop()
{
volatile uint32_t delayCount = 1000000;
while (delayCount > 0)
{
delayCount--;
}
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++*/
int main (void)
{
RCC_Configuration();
GPIO_Setup();
TIM2_SETUP();
while (1)
{
if(INT_Counter ==1)
{
GPIOC->BSRR = GPIO_Pin_8; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_8; // LED Off
delayLoop();
GPIOC->BSRR = GPIO_Pin_8; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_8; // LED Off
delayLoop();
GPIOC->BSRR = GPIO_Pin_9; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_9; // LED Off
delayLoop();
}
}
return 0;
}
void TIM2_IRQHandler (void)
{
// Interrupt Flag muß per Software gelöscht werden
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
INT_Counter++;
}
Ich danke Ihnen.
RP6conrad
16.07.2011, 15:13
/*Variable*/
uint32_t Interrupt_Counter = 0;
Diese soll als "volatile" declariert werden, da er in einen Interrupt gaendert wird.
/* TIM2 PA.0 configuration*/
GPIO_Inity.GPIO_Mode =GPIO_Mode_AF_PP;// soll ich PULL-Down oder Pull up werwenden wenn der
// Eingang als Pull-Down Konfiguriert?
Soll ich als Eingang declarieren, ein AF_PP ist eher ein Ausgang für PWM und solche zu steuern. Bei mir functioniert die ICP beim Eingang declariert als GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
Input_Capture.TIM_ICSelection = TIM_ICSelection_IndirectTI;// hier verstehe ich der Unterschied
// zwischen Direct und Indirekt nicht
// wirklich, aber ich verwende Direct weil ich
// kein remaping durchführe
Ein Timer channel ist normalerweise fast an einen Pin zugewiesen. TIM2 CH1 ist standaard verbunden an pin A0. Da gibt noch eine moglichkeit diese TIM2 CH1 auf einen andere pin zu acivieren : pin A15. Da ist dan eine "REMAP", wird activiert ueber "Indirect"
TIM_SelectInputTrigger(TIM2, TIM_TS_TI1FP1);// dieze Zeile verstehe ich überhaupt nicht
Verwende ich nicht beim Input cature. Wird genutzt beim "external clock" configuration. Diese info steht in die TIM library. :
/**
* @brief Configures the TIMx Internal Trigger as External Clock
* @param TIMx: where x can be 1, 2, 3, 4, 5 or 8 to select the TIM peripheral.
* @param TIM_ITRSource: Trigger source.
* This parameter can be one of the following values:
* @param TIM_TS_ITR0: Internal Trigger 0
* @param TIM_TS_ITR1: Internal Trigger 1
* @param TIM_TS_ITR2: Internal Trigger 2
* @param TIM_TS_ITR3: Internal Trigger 3
* @retval None
Welche compiler verwenden sie ?
Hallo,
Danke für die schnelle Antwort.
ich habe Ihren Hinweise befolgen, was Sie oben erwähnt haben, aber leider immer erfolglos.
Langsam langsam verzweifle ich an das Bord. es muss irgendwie an das Bord liegen. weil das Code soll fehlerlos laufen oder?
Ich verwende den Atolic/TrueSTUDIO STM32 Lite 2.1.0 (STMicroelectronics ST-Link_V2_USBdriver).
Danke.
/* Includes */
#include <stddef.h>
#include "stm32f10x.h"
/* ---------------------------Private typedef -------------------------------*/
TIM_TimeBaseInitTypeDef TIM2_Configuration;
NVIC_InitTypeDef NVIC_InitStructure;
//TIM_OCInitTypeDef Output_Compare;
TIM_ICInitTypeDef Input_Capture;
GPIO_InitTypeDef GPIO_Inity;
/*---------------------------Global Variable---------------------------------*/
volatile uint32_t INT_Counter = 0;
/************************************************** *****************************
# * Function Name : RCC_cONFIGURATION
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void RCC_Configuration(void)
{
/* TIM2clock= SystemCoreColock, enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* ALTERNATE FUNCTION ENABLE*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* GPIOC clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
}
/************************************************** *****************************
# * Function Name : GPIO_SETUP
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void GPIO_Setup ()
{
/* LEDs pin (PC.08 and 09) configuration */
GPIO_Inity.GPIO_Pin =GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Inity.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
/* TIM2 PA.0 configuration*/
GPIO_Inity.GPIO_Mode =GPIO_Mode_IN_FLOATING;// soll ich PULL-Down oder Pull up werwenden wenn der
//Eingang als Pull-Down Konfiguriert?
//Der AF weil bei dieser Pin wir der Alternate Function verwendet
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Inity.GPIO_Pin =GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_Inity);
GPIO_Init(GPIOC, &GPIO_Inity);
}
/************************************************** *****************************
# * Function Name : TIM2_SETUP
# * Description : Timer2 as Output/Compare
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void TIM2_SETUP ()
{
/*----Time_Base_Counter-----*/
TIM2_Configuration.TIM_CounterMode= TIM_CounterMode_Up;
TIM2_Configuration.TIM_ClockDivision= 0;
TIM2_Configuration.TIM_Period=65535;
TIM2_Configuration.TIM_Prescaler=1;
TIM_TimeBaseInit(TIM2,&TIM2_Configuration);
/*----Input_Capture Mode CH1----*/
Input_Capture.TIM_ICSelection = TIM_ICSelection_DirectTI;// hier verstehe ich der Unterschied
// zwischen Direct und Indirekt nicht
//wirklich, aber ich verwende Direct weil ich
// kein remaping durchführe
Input_Capture.TIM_ICPolarity= TIM_ICPolarity_Rising;
Input_Capture.TIM_ICPrescaler = TIM_ICPSC_DIV1;
Input_Capture.TIM_Channel= TIM_Channel_1;
Input_Capture.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &Input_Capture);
TIM_Cmd(TIM2, ENABLE);
/*----Enable the Capture Compare Interrupt Request-----*/
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
}
/************************************************** *****************************
# * Function Name : Configure the nested vectored interrupt controller.
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void NVIC_SETUP ()
{
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannel= TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/************************************************** *****************************
# * Function Name : delayloop
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void delayLoop()
{
volatile uint32_t delayCount = 1000000;
while (delayCount > 0)
{
delayCount--;
}
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++*/
int main (void)
{
RCC_Configuration();
GPIO_Setup();
TIM2_SETUP();
NVIC_SETUP();
while (1)
{
if(INT_Counter ==1)
{
GPIOC->BSRR = GPIO_Pin_8; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_8; // LED Off
delayLoop();
GPIOC->BSRR = GPIO_Pin_8; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_8; // LED Off
delayLoop();
GPIOC->BSRR = GPIO_Pin_9; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_9; // LED Off
delayLoop();
}
}
return 0;
}
void TIM2_IRQHandler (void)
{
// Interrupt Flag muß per Software gelöscht werden
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
INT_Counter++;
}
RP6conrad
16.07.2011, 23:13
Ich habe mal ihre code mit den IAR compiler in meines Discovery board versucht. Das scheint zu functionieren. Jeden mal das ich den user button drucke, erhoht die variable "INT_count", und die LEDS fangen an zu blinken Ich habe nur kleine aenderungen gemacht wegend andere compiler. Moglich sind andere systemfiles auch noch wichtig (Clock Init).
Ich kopîere das nochmal hierein.
/* Includes */
#include <stddef.h>
#include "stm32f10x.h"
/* ---------------------------Private typedef -------------------------------*/
TIM_TimeBaseInitTypeDef TIM2_Configuration;
NVIC_InitTypeDef NVIC_InitStructure;
//TIM_OCInitTypeDef Output_Compare;
TIM_ICInitTypeDef Input_Capture;
GPIO_InitTypeDef GPIO_Inity;
/*---------------------------Global Variable---------------------------------*/
volatile uint32_t INT_Counter = 0;
volatile uint32_t delayCount;
/************************************************** *****************************
# * Function Name : RCC_cONFIGURATION
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void RCC_Configuration(void)
{
/* TIM2clock= SystemCoreColock, enable */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* GPIOA clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
/* ALTERNATE FUNCTION ENABLE*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
/* GPIOC clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
}
/************************************************** *****************************
# * Function Name : GPIO_SETUP
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void GPIO_Setup ()
{
/* LEDs pin (PC.08 and 09) configuration */
GPIO_Inity.GPIO_Pin =GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Inity.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
/* TIM2 PA.0 configuration*/
GPIO_Inity.GPIO_Mode =GPIO_Mode_IN_FLOATING;// soll ich PULL-Down oder Pull up werwenden wenn der
//Eingang als Pull-Down Konfiguriert?
//Der AF weil bei dieser Pin wir der Alternate Function verwendet
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Inity.GPIO_Pin =GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_Inity);
GPIO_Init(GPIOC, &GPIO_Inity);
}
/************************************************** *****************************
# * Function Name : TIM2_SETUP
# * Description : Timer2 as Output/Compare
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void TIM2_SETUP ()
{
/*----Time_Base_Counter-----*/
TIM2_Configuration.TIM_CounterMode= TIM_CounterMode_Up;
TIM2_Configuration.TIM_ClockDivision= 0;
TIM2_Configuration.TIM_Period=65535;
TIM2_Configuration.TIM_Prescaler=1;
TIM_TimeBaseInit(TIM2,&TIM2_Configuration);
/*----Input_Capture Mode CH1----*/
Input_Capture.TIM_ICSelection = TIM_ICSelection_DirectTI;// hier verstehe ich der Unterschied
// zwischen Direct und Indirekt nicht
//wirklich, aber ich verwende Direct weil ich
// kein remaping durchführe
Input_Capture.TIM_ICPolarity= TIM_ICPolarity_Rising;
Input_Capture.TIM_ICPrescaler = TIM_ICPSC_DIV1;
Input_Capture.TIM_Channel= TIM_Channel_1;
Input_Capture.TIM_ICFilter = 0;
TIM_ICInit(TIM2, &Input_Capture);
TIM_Cmd(TIM2, ENABLE);
/*----Enable the Capture Compare Interrupt Request-----*/
TIM_ITConfig(TIM2, TIM_IT_CC1, ENABLE);
}
/************************************************** *****************************
# * Function Name : Configure the nested vectored interrupt controller.
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void NVIC_SETUP ()
{
/* Enable the TIM2 global Interrupt */
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriori ty=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannel= TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd= ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/************************************************** *****************************
# * Function Name : delayloop
# * Description : .
# * Input : None
# * Output : None
# * Return : None
# ************************************************** *****************************/
void delayLoop()
{
delayCount = 1000000;
while (delayCount > 0)
{
delayCount--;
}
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++*/
int main (void)
{
RCC_Configuration();
GPIO_Setup();
TIM2_SETUP();
NVIC_SETUP();
while (1)
{
if(INT_Counter >1)
{
GPIOC->BSRR = GPIO_Pin_8; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_8; // LED Off
delayLoop();
GPIOC->BSRR = GPIO_Pin_8; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_8; // LED Off
delayLoop();
GPIOC->BSRR = GPIO_Pin_9; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_9; // LED Off
delayLoop();
}
}
return 0;
}
//steht bei mir in eine ander file : STM32F10x_it.c
void TIM2_IRQHandler (void)
{
// Interrupt Flag muß per Software gelöscht werden
TIM_ClearFlag(TIM2, TIM_FLAG_CC1);
//TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
INT_Counter++;
}
Ha der Atollic compiler auchj eine debugger ?
Fiel erfolg !!
Hallo,
vielen Dank nochmal für Ihre Mühe. Sie haben mir sehr viel geholfen.
Ja, der Atolic hat schon Debugger.
Den Code werde ich gleich testen.
Danke.
das ist ein Rätzel, den ich nie im Leben verstehen würde.
es funktioniert nicht!
bei Debugg gehts rein in der If_schleife aber die LEDS leuchten nicht obwohl er bei LED-On steht.
Bei meinem Versuch er konnte überhaupt die If_schleife nicht ausführen.
wenn ich andere Programme bedugge, dann leuchten die Leds ganz normal. nur bei diesem Code leuchten sie nicht.
Ich hab das Programm (Toggle LED) aus dem EXamble genommen und debuggert. Es hat supper funktioniert.
Step by step habe ich das Programm erweitert und bei jede Erweiterung habe das Programm erneut debugg um ich sicher zu sein dass die neue erweiterung hat die Funktion von Blinken_Leds nicht beeinflüssen.
1) habe ich NVIC und Inputcapture hingeschrieben. debuggert--> LEDs leuchten.ok!
2)danach die VOLTEILE, debuggert---> LEDS leuchten.ok!
3)RCC-Configuration hingefügt, debuggert-->LEDs leuchten. Ok!
4) dann das GPIO-MODE habe ich von IPD zu In_Floating geändert,debuggert--->LEDS leuchten nicht!! ok das ist Normal.
Was ich annormal finde, dass ich den GPIO-MODE auf IPD zurücksetze und trotzdem leuchten die LEDS nicht. warum?
mehr als diese 4 schritte habe ich and das Programm von LED-Toggle nicht geändert und sie leuchten nicht mehr obwohl sie besitzen den Orginalen Zustand.
was könnte dahinten stecken????
Danch habe ich die RCC von AFIO deaktiviert, trotzdem leuchten die LEDS nicht mehr.
/* Includes */
#include <stddef.h>
#include "stm32f10x.h"
NVIC_InitTypeDef NVIC_InitStructure; <-- das ist die erste 'Änderung, LEDs leuchten noch
TIM_ICInitTypeDef Input_Capture;
GPIO_InitTypeDef GPIO_Inity;
volatile uint32_t INT_Counter = 0;<-- zwite Erweiterung, LEDS leuchten noch
volatile uint32_t delayCount;
void RCC_Configuration(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); <-- dritte, LEDS leuchten
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);<-- vierte, LEDS leuchten nicht mehr
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
}
void delayLoop()
{
volatile uint32_t delayCount = 1000000;
while (delayCount > 0)
{
delayCount--;
}
}
void GPIO_Setup ()
{
GPIO_InitTypeDef GPIO_Inity;
GPIO_Inity.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Inity.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Inity.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_Inity);
GPIO_Inity.GPIO_Pin = GPIO_Pin_1;
GPIO_Inity.GPIO_Mode = GPIO_Mode_IPD;
GPIO_Inity.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_Inity);
}
int main (void)
{
uint8_t read_A0 = 0;
SystemInit();
GPIO_Setup();
while (1)
{
read_A0 =GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0);
if(read_A0)
{
GPIOC->BSRR = GPIO_Pin_8; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_8; // LED Off
delayLoop();
GPIOC->BSRR = GPIO_Pin_9; // LED On
delayLoop();
GPIOC->BRR = GPIO_Pin_9; // LED Off
delayLoop();
}
}
return 0;
}
RP6conrad
17.07.2011, 10:50
GPIO_Inity.GPIO_Pin = GPIO_Pin_1;
GPIO_Inity.GPIO_Mode = GPIO_Mode_IPD;
Jetzt steht hier Pin A1 auf IPD. Pin A0 wird nicht mehr initialisiert. Kan das die Ursache sein ?
Nein, das ist nicht die Ursache.
Übrigens in dem orginalen Programm (Toggle-LED), das in Exsamble stheht, ist der PA1 als GEPIO-Pin für Port A eingestellt, und nicht Pin0.
das hat mir aufgefallen, denn laut der Pinlayout (Datasheet) ist der User_Button mit PA.0 verbunden.
Das Heisst wenn ich im Programm den Pin 1 als GPIO-Pin für User-Button eingebe soll die LEDS nicht leuchten.
Tatsach ist, dass sie tortz der Änderung von pin0 auf Pin1 und von pin1 auf pin0 leuchten.
Ist nicht wahnsinnig????
ich bin Verrückt geworden.
Ist das Programm 100% prommlemlos bei dir gelaufen????
Bei mir das programm meldet kein Fehler bei Debugging, aber die LEDS leuchten nicht wenn der User Butoon gedruckt wird.
Sogra es geht rein in der schleife liest den Befehl das die LEDS einschalten aber die Leds leuchten nicht.
RP6conrad
17.07.2011, 12:15
Es ist scheinbar so, das die Init von portA nicht immer functioniert. Ich habe auch schon erfahren, das beim debuggen und download, nicht alle register von µ gereset werden. Nach eine hard reset (abklemmen Spannung) hat der µ dan wel functioniert.
Bei den debugger konnen sie auch schon sehen oder den Eingang A0 hoch oder niedrig ist. Auch die initialisierung von Ports kann hier angesehen werden. Bei mir ist das program problemlos gelaufen. Ich habe wel die Abfrage "INT_count==1" gaendert in "INT_count>0", jetzt functioniert das auch bei mehrmals drucken.
EDIT :
Ich habe beim zweite Versuch auch das problem das die LEDS nicht leuchten !! Jetzt habe ich wel ein Fehler gefunden in die Init von Ports :
/************************************************** *****************************/
void GPIO_Setup ()
{
/* LEDs pin (PC.08 and 09) configuration */
GPIO_Inity.GPIO_Pin =GPIO_Pin_8 | GPIO_Pin_9;
GPIO_Inity.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
/* TIM2 PA.0 configuration*/
GPIO_Inity.GPIO_Mode =GPIO_Mode_AF_PP;// soll ich PULL-Down oder Pull up werwenden wenn der
// Eingang als Pull-Down Konfiguriert?
// Der AF weil bei dieser Pin wir der Alternate Function verwendet
GPIO_Inity.GPIO_Speed =GPIO_Speed_50MHz;
GPIO_Inity.GPIO_Pin =GPIO_Pin_0;
GPIO_Init(GPIOA, &GPIO_Inity);
GPIO_Init(GPIOC, &GPIO_Inity);
}
Da wird erst eine structure fur Port C gefullt, und dan wieder ueberschrieben für Port A !! Damit wirden Port A und Port C als AF_PP definiert !! Einfach die Zeile "GPIO_Init(GPIOA, &GPIO_Inity);" nach oben verschieben, unten den declarierung von der Structure von Port A !! Dann hat er es bei mir wieder functioniert.
Doch du hast Recht.
Dein letztes Tipp war echt Goldig.
Es funktioniert endlich!!!!!!!!!!!!
Man! wie sollte ich als Anfänger darauf kommen???
Ohne dein Tipe werde ich es nicht entdecken.
Vielen Dank.
Um diese harte Lektion nicht zu vergessen, möchte ich gerne den Grund dafür verstehen.
Kannst du bitte das erkklären?
LG
RP6conrad
18.07.2011, 09:35
Das intialisieren von µ ist eigentlich bestimmte register fullem mit die richtige Dateien. Um das zu erleichteren hat ST schone Librarys geschrieben, womit al diese Initialisierungen gemacht werden konnen. Fast alle Functionen nutzen dabei "Structures". Ein Structure ist ein Datensatz in C, welche man selbst zusammenstellen kan. Beispiel : In die TIM library ist diesen Structure programmiert :
/**
* @brief TIM Time Base Init structure definition
* @note This sturcture is used with all TIMx except for TIM6 and TIM7.
*/
typedef struct
{
uint16_t TIM_Prescaler; /*!< Specifies the prescaler value used to divide the TIM clock.
This parameter can be a number between 0x0000 and 0xFFFF */
uint16_t TIM_CounterMode; /*!< Specifies the counter mode.
This parameter can be a value of @ref TIM_Counter_Mode */
uint16_t TIM_Period; /*!< Specifies the period value to be loaded into the active
Auto-Reload Register at the next update event.
This parameter must be a number between 0x0000 and 0xFFFF. */
uint16_t TIM_ClockDivision; /*!< Specifies the clock division.
This parameter can be a value of @ref TIM_Clock_Division_CKD */
uint8_t TIM_RepetitionCounter; /*!< Specifies the repetition counter value. Each time the RCR downcounter
reaches zero, an update event is generated and counting restarts
from the RCR value (N).
This means in PWM mode that (N+1) corresponds to:
- the number of PWM periods in edge-aligned mode
- the number of half PWM period in center-aligned mode
This parameter must be a number between 0x00 and 0xFF.
@note This parameter is valid only for TIM1 and TIM8. */
} TIM_TimeBaseInitTypeDef;
Um diesen Structure zu nutzen machne wir erst eine "Variable Name" das diesen Structure hat : 'TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;"
Was men jetzt macht bei Init ist diese Structure erst fullen mit die richtige Daten, und dan wird mit eine Function " TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);" diesen Structure genutzt um alle Register zu setzen.
Wen wir noch eine 2den Timer intialisieren mochte, konnen wir die gleiche "Variable Name" nutzen, und ein zweite mal diesen Structuren mit daten fullen.
Die Daten von erste Mal werden dan ueberschrieben, aber das ist unwichtig, da wir schon alle Daten in register kopiert sind bei aufrufen von " TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);"
Die Reihenfolge ist naturlich sehr wichtig !! So, erst die Structure fullen mit Daten, dan die Init Function aufrufen, dan wen notwendig wieder fullen mit Daten für eine Zweite Timer, und dan wieder die Init Function aufrufen. Ich hffe das ich jetzt en bischen Klarheit geschafft haben in diese Materie.
Vielen Danke für die Erklärung.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.