Skocz do zawartości
Komentator

Kurs STM32 - #7 - Liczniki (timery) w praktyce, PWM

Pomocna odpowiedź

html_mig_img
Przed nami kolejna część kursu programowania STM32. W tej części poznamy podstawy modułów sprzętowych liczników (timerów).Po odrobinie niezbędnych podstaw teoretycznych wykorzystamy PWM do płynnej regulacji jasności diod świecących (w tym RGB).

UWAGA, to tylko wstęp! Dalsza część artykułu dostępna jest na blogu.

Przeczytaj całość »

Poniżej znajdują się komentarze powiązane z tym wpisem.

Udostępnij ten post


Link to post
Share on other sites

Czujniki HC-SR04:

1. Czy do prawidłowego działania konieczne jest podłączenie pinu TRIG do TIM'era, czy wystarczy do zwykłego pinu I/O?

2. Jeśli do TIM, to czy można obydwa piny (TRIG, ECHO) podłączyć do dwóch kanałów tego samego TIM'era, czy trzeba do różnych TIM'erów ??

Zasada działania:

Pomiar odległości jest rozpoczynany po podaniu na wejście TRIG impulsu trwającego minimum 10 µs – rysunek 4. Powoduje to wyemitowanie przez czujnik fali ultradźwiękowej (8 impulsów o częstotliwości 40 kHz), która po odbiciu się od przeszkody wraca do czujnika. Po wykryciu powracającej fali ultradźwiękowej czujnik wystawia na wyprowadzenie ECHO impuls, którego czas trwania jest proporcjonalny do odległości pomiędzy czujnikiem i przeszkodą.

Datasheet:

https://docs.google.com/document/d/1Y-yZnNhMYy7rwhAgyL_pfa39RsB-x2qR4vP8saG73rE/edit?pli=1

Udostępnij ten post


Link to post
Share on other sites

To zależy co chcesz uzyskać. Większość kodów obsługujących HC-SR04 zadowala się zwykłymi pinami I/O oraz aktywnym czekaniem na odpowiedź. Taki kod na ogół działa, wiec na pierwsze pytanie można odpowiedzieć, że zwykłe I/O wystarczy.

Niestety programowe oczekiwanie ma wiele wad. Po pierwsze jeśli wyłączysz wtedy obsługę przerwań, to możesz zaburzyć pracę całego systemu. Natomiast jeśli tego nie zrobisz, to ew. wystąpienie przerwania może popsuć odczyt.

Znacznie lepszy rezultat można uzyskać wykorzystując moduł timera, albo najlepiej cały sygnał oraz pomiar wykonując sprzętowo. Przerwania nie muszą być wtedy wyłączane, a dokładność pomiaru będzie znacznie wyższa. Układy licznikowe STM32 są niesamowicie elastyczne, więc można je skonfigurować tak, żeby jeden moduł zarówno generował sygnał wyzwalający, jak i mierzył szerokość impulsu będącego odpowiedzą.

Udostępnij ten post


Link to post
Share on other sites

W kursie jest napisane, co trzeba zrobić obsługując TIM2. SysTick jest trochę łatwiejszy, ale w przypadku zwykłych timerów trzeba zresetować flagę przerwania:

    
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
   {
       TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Faktycznie, nie kasowałem flagi, głupi błąd.

Użyłem tego narzędzia do wygenerowania system_stm32f4xx.c

http://www.st.com/web/catalog/tools/FM147/CL1794/SC961/SS1533/PF257927

Nastawy

Rozumiem, że rdzeń powinnien być taktowany 64 MHz, a timer 32MHz.

Prescaler jest teraz ustawiony na 16000-1, period 1 i dostaje przerwania co milisekundę.

Dlaczego ten prescaler musi być 16k, a nie 32k? Na płytce mam kwarc 8Mhz

__________

Komentarz dodany przez: Sabre

Udostępnij ten post


Link to post
Share on other sites

Jak zmierzyć czas trwania impulsu na danym pinie? Jest jakiś odpowiednik funkcji "pulseIn" używanej w arduino?

Udostępnij ten post


Link to post
Share on other sites
Jak zmierzyć czas trwania impulsu na danym pinie? Jest jakiś odpowiednik funkcji "pulseIn" używanej w arduino?

Poczytaj o przerwaniach zewnętrznych. A potem spróbuj połączyć to z timerem.

Szukając programu do obsługi dalmierza HC-SR04, powinieneś znaleźć przykładowy kod.

Tak w skrócie:

Pojawia się określony stan na pinie -> przerwanie -> wyzerowanie timera -> stan pinu zmienia się -> zliczenie impulsów -> przeliczenie ilości impulsów na konkretną wartość czasu.

Udostępnij ten post


Link to post
Share on other sites

Witam,
mam pewien problem. Spróbowałem uruchomić sobie serwo pod PWM. Przerobiłem trochę kod z ćwiczenia ale przez cały czas serwo osiąga maksymalną prawą pozycję i jakby chciało iść dalej, przy tym jeszcze buczy. Kod poniżej:

#include "stm32f10x.h"

void TIM2_IRQHandler()
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5))
GPIO_ResetBits(GPIOA, GPIO_Pin_5);
else
GPIO_SetBits(GPIOA, GPIO_Pin_5);
GPIO_SetBits(GPIOC, GPIO_Pin_0);
}

if (TIM_GetITStatus(TIM2, TIM_IT_CC1) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC1);
GPIO_ResetBits(GPIOC, GPIO_Pin_0);
}
}

int main(void)
{
GPIO_InitTypeDef gpio;
TIM_TimeBaseInitTypeDef tim;
NVIC_InitTypeDef nvic;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_5;
gpio.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA, &gpio);

gpio.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_Init(GPIOC, &gpio);

TIM_TimeBaseStructInit(&tim);
tim.TIM_CounterMode = TIM_CounterMode_Up;
tim.TIM_Prescaler = 64 - 1;
tim.TIM_Period = 20000 - 1;
TIM_TimeBaseInit(TIM2, &tim);

TIM_ITConfig(TIM2, TIM_IT_Update|TIM_IT_CC1, ENABLE);
TIM_Cmd(TIM2, ENABLE);

TIM_SetCompare1(TIM2,50);

nvic.NVIC_IRQChannel = TIM2_IRQn;
nvic.NVIC_IRQChannelPreemptionPriority = 0;
nvic.NVIC_IRQChannelSubPriority = 0;
nvic.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&nvic);

while (1) {
}
}

Może ktoś zauważy co takiego robię nie tak. Z tego co czytałem o sterowaniu serwami to należy wysyłać impulsy z zakresu 1000 do 2000 us w okresie 20 ms. Jeśli coś źle myślę to proszę mnie poprawić. Serwo zasilane z 5V ale wyjście stm32 ma 3.3V (czy to nie będzie się gryzło?).Wydaje mi się, że coś jest nie tak w obliczeniu wartości prescalera, wypełnienia i okresu, kurde nie mam pojęcia. Dzięki z góry za pomoc 🙂

Udostępnij ten post


Link to post
Share on other sites

Vroobee, jeśli Twoje pytanie nie jest związane bezpośrednio z ćwiczeniami przerabianymi w kursie, to załóż proszę osobny temat, w którym opiszesz swój problem - zachowamy wtedy większy porządek.

Udostępnij ten post


Link to post
Share on other sites

Cześć Koledzy i Koleżanki!

Zaznaczam na wstępie, że jestem zupełnym laikiem w programowaniu STMów 🙂

Mam takie pytania:

1. Skonfigurowałem dwa timery, np. Timer 1 i 2 albo 2 i 3. Jak skonfigurować przerwania dla tych dwóch timerów osobno tak, aby przepełnienie każdego z nich wywoływało oddzielną funkcję?

2. Potrzebuję w trakcie programu wyłączyć timer, zmienić tylko poziom przepełnienia licznika tego timera i z powrotem go uruchomić z tą nową właściwością. I tu chodzi o jak największą szybkość, bo myślę (a może błędnie), że zmiana tego za pomocą edycji struktur 1200 razy na sekundę (bo to musi być z taką prędkością) nie jest zbyt dobrym pomysłem. Jak to zrealizować?

Liczę na Waszą pomoc i wyrozumiałość.

Pozdrawiam.

Udostępnij ten post


Link to post
Share on other sites

Czesc!

Zastanawia mnie jedna rzecz - zadanko pierwsze z miganiem diody. Zaklada ono iz zegar procka chodzi z predkoscia 64MHz. Ale w przypadku NUCLEO-F103RB zegar kreci sie z predkoscia 72MHz. Zatem konfiguracja:

 tim.TIM_Prescaler = 64000 - 1;
tim.TIM_Period = 1000 - 1;

powoduje miganie szybsze niz co 1 sec. Czy cos pokombinowalem tutaj??🙂

Niestety nie mozna ustawic prescalera na 72kHz zatem zmodyfikowalem period - jak sobie liczylem to wartosc 1125 (-1) wydaje sie byc poprawna.

Pozdrawiam

Udostępnij ten post


Link to post
Share on other sites

W przypadku płytki Nucleo częstotliwość zegara to 64MHz, a nie 72MHz - co z resztą jest wyraźnie napisane w treści artykułu. Dlatego opisane ustawienia są poprawne.

Udostępnij ten post


Link to post
Share on other sites

Dziekuje za odpowiedz ale dalej cos mi nie pasuje 🙂

Plytke nucleo dostalem razem w pakiecie rozszerzonym zamowionym do tego kursu. Na opakowaniu samej plytki STM32F103RBT6 64 PIN jest opis zawartosci - ARM Cortex M3 72Mhz. Jest to rowniez potwierdzone w drugiej lekcji tego kursu (Podstawowe Informacje o STM32).

Sprawdzalem tez procedure SetSysClock (odpalana podczas startupu w ResetHendler) i nie ma tam w ogole opcji do wybrania 64MHz.

Zatem zastanawiam sie dlaczego zalozeniem w kursie sa wlasnie 64Mhz skoro opiera sie on na ukladzie taktowanym 72Mhz.

Po za tym miganie diody sprawdzilem z zegarkiem w reku i na powyzszym przykladzie nie dziala - znaczy miga za szybko 🙂

dziekuje i pozdrawiam

Udostępnij ten post


Link to post
Share on other sites

72MHz to maksymalna częstotliwość dla układów stm32f103. Wbrew pozorom maksymalna prędkość to nie jedyna dozwolona i można używać też innych. Co więcej w przypadku taktowania mikrokontrolera z wbudowanego generatora RC, maksymalna częstotliwość taktowania nie wynosi 72MHz, ale właśnie 64MHz. Ta informacja jest w dokumentacji procesora, ale mniej wyeksponowana niż maksymalne 72 - w końcu to już nie brzmi tak dobrze w reklamach.

Płytki Nucleo nie posiadają wlutowanego rezonatora kwarcowego 8MHz - mają je np. Discovery. O ile nic się nie zmieniło, Nucleo ma tylko miejsce na ten element.

Możliwości są więć dwie: wlutować rezonator i używać 72MHz, albo zadowolić się 64MHz z wbudowanego generatora RC.

Domyślnie wygenerowany w OpenSTM32 projekt oraz ten kurs zakładał drugą opcję - czyli mamy wewnętrzny generator RC (HSI) oraz taktujemy procesor 64MHz.

Niestety w kodzie dostarczanym z kompilatorem jest błąd, o czym pisałem w kursie. Co więcej, błąd nadal nie został poprawiony.

Po kolei - najpierw zaglądamy do funkcji SystemInit zdefiniowanej w pliku system_stm32f10x.c. Ta funkcja jest wywoływana przed main. Interesuje nas głównie:

  /* Set HSION bit */
 RCC->CR |= (uint32_t)0x00000001;

Jak widzimy używamy HSI, czyli wbudowanego generatora RC. Na końcu znajdziemy odwołanie do kolejnej, czyli SetSysClock.

Stała PLL_SOURCE_HSI została zdefinowana, więc ustawienia PLL to:

  /* At this stage the HSI is already enabled */

 /*  PLL configuration: PLLCLK = HSI/2 * 16 = 64 MHz */
 RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL));
 RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL16);

Komentarz w kodzie mówi wszystko, więc nie będę powtarzać.

Natomiast co do błędu - przewijamy plik do linii 120 i widzimy:

  uint32_t SystemCoreClock = 72000000;

Ta wartość może być powodem niepoprawnego działania niektórych programów. Powinniśmy ją zmienić na 64000000.

Czy to wytłumaczenie przekonało nieco bardziej skąd używana w kursie wartość 64MHz?

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...