Wstęp
Dla przypomnienia wklejam poniżej opis poszczególnych liczników wraz z ich zastosowaniem oraz opisem sygnałów zegarowych.
Timer
|
Typ
|
Rozdzielczość
|
Dzielnik
|
Kanał
|
Max Zegar Intrerf
|
Max Zegar Timera
|
APB
|
1, 8
|
Zaawansowany
|
16 bit
|
16 bit
|
4
|
SysClk/2
|
SysClk
|
2
|
2, 5
|
Ogólny
|
32 bit
|
16 bit
|
4
|
SysClk/4
|
SysClk, SysClk/2
|
1
|
3, 4
|
Ogólny
|
16 bit
|
16 bit
|
4
|
SysClk/4
|
1
| |
9
|
Ogólny
|
16 bit
|
16 bit
|
2
|
SysClk/2
|
SysClk
|
2
|
10, 11
|
Ogólny
|
16 bit
|
16 bit
|
1
|
SysClk/2
|
SysClk
|
2
|
12
|
Ogólny
|
16 bit
|
16 bit
|
2
|
SysClk/4
|
SysClk, SysClk/2
|
1
|
13, 14
|
Ogólny
|
16 bit
|
16 bit
|
1
|
SysClk/4
|
1
| |
6, 7
|
Podstawowy
|
16 bit
|
16 bit
|
0
|
SysClk/4
|
1
|
CubeMx
Po wybraniu mikrokontrolera należy włączyć wybrane Timery oraz skonfigurować sygnał zegarowy.
Co do Timerów ja wybrałem TIM1, w który ustawiłem tylko źródło sygnału (Clock Source) jako zegar wewnętrzny (Internal Clock). TIM9 skonfigurowany natomiast tak aby generował sygnał PWM na kanale 1 oraz 2. Automatycznie sygnały zostają przypisane do pinów PE5 (CH1) oraz PE6 (CH2)
Rys. 1. Ustawienie TIM9
Jeśli potrzebny jest PWM na czterech kanałów z jednego licznika, wtedy można wykorzystać TIM4. W programie głównym wygenerowane sygnały zostaną przypisane do pinu PD12 z CH1, oraz PD14 z CH2.
PA0, ten do którego jest podłączony przycisk, dostał przerwanie EXTI0 (GPIO_EXTI0). Jeśli wykorzystuje się widok płytki ewaluacyjnej w CubeMx, to ona ma już tą opcje wybraną.
Rys. 2, Konfiguracja wyprowadzenia PA0
Zegar został skonfigurowany, tak aby taktowanie mikrokontrolera było maksymalne dopuszczalne czyli 168 MHz
Kolejnym krokiem jest wybranie pinów wyjściowych, na które będzie przekazywany sygnał z licznika. Ja wybrałem piny do których są podłączone diody wbudowane czyli od PD12 do PD15. Tak jak w przypadku przycisku, mikrokontroler wybrany w widoku płytki Discovery ma już te piny odpowiednio skonfigurowane.
Rys. 3. Konfiguracja pinów z podłączonymi diodami
W następnym kroku należy odpowiednio ustawić timery. W tym celu trzeba przełączyć się na zakładkę Configuration.
Rys. 4. Ustawienie TIM1
Rys. 5. Ustawienie TIM9
Programowanie
Teraz po wygenerowaniu kodu należy dopisać pozostałą część programu.
W pierwszej kolejności należy dopisać funkcje obsługujące odpowiednie wyprowadzenia. Pierwsza część do obsługi sygnału PWM na pinie PD14 wygląda następująco.
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- if(keyclick==0)
- {
- TIM9->CCR2 = 65535/100*1;
- keyclick++;
- }
- else if(keyclick==1)
- {
- TIM9->CCR2 = 65535/100*10;
- keyclick++;
- }
- else if(keyclick==2)
- {
- TIM9->CCR2 = 65535/100*50;
- keyclick++;
- }
- else if(keyclick==3)
- {
- TIM9->CCR2 = 65535/100*99;
- keyclick++;
- }
- else if(keyclick==4)
- {
- keyclick=0;
- TIM9->CCR2 = 0;
- }
- }
Jego zadanie jest proste w momencie kliknięcia przycisku podłączonego do pinu PA0 następuje zwiększenie zmiennej keyclick, po czym następuje wejście do odpowiedniej części instrukcji warunkowej. W tym przypadku nie ma potrzeby stosowania żadnego zabezpieczenie programowego do ochrony przed drganiem styków, ponieważ został on odpowiednio zabezpieczony sprzętowo przez producenta.
W poszczególnych sekcjach zmieniana jest wartość wpisana do rejestru CCR2, w której przechowywana jest wartość jaka ma zostać wyprowadzona jako sygnał PWM.
Druga funkcja ustawia wartości na wyprowadzeniu PD12. Tak aby wartość PWM była dynamicznie zmieniana.
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == htim1.Instance)
- {
- TIM9->CCR1 = PWMval;
- if(PWMval == 0xFFFF)
- {
- PWMval=0;
- }
- else if(PWMval<0xFFFF)
- {
- PWMval++;
- }
- }
- }
Linijka if(htim->Instance == htim1.Instance) sprawdza jakie źródło przerwania zostało wywołane.
Poniżej wklejam części funkcji main, które zostały dopisane, oraz części funkcji ustawienia timerów.
- /* USER CODE BEGIN 0 */
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);
- uint16_t PWMval=0;
- uint8_t keyclick=0;
- /* USER CODE END 0 */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- /* USER CODE END 1 */
- /* MCU Configuration----------------------------------------------------------*/
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
- /* Configure the system clock */
- SystemClock_Config();
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_TIM1_Init();
- MX_TIM9_Init();
- /* USER CODE BEGIN 2 */
- //Wlaczenie timerow
- HAL_TIM_Base_Start_IT(&htim1);
- HAL_TIM_Base_Start_IT(&htim9);
- //Wlaczenie PWM
- HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_1);
- HAL_TIM_PWM_Start(&htim9, TIM_CHANNEL_2);
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_5));
- HAL_GPIO_WritePin(GPIOD, GPIO_PIN_14, HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_6));
- }
- /* USER CODE END 3 */
- }
- /* TIM1 init function */
- void MX_TIM1_Init(void)
- {
- TIM_ClockConfigTypeDef sClockSourceConfig;
- TIM_MasterConfigTypeDef sMasterConfig;
- htim1.Instance = TIM1;
- htim1.Init.Prescaler = 0;
- htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim1.Init.Period = 8399;
- htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- htim1.Init.RepetitionCounter = 0;
- HAL_TIM_Base_Init(&htim1);
- sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
- HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig);
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
- HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
- }
- /* TIM9 init function */
- void MX_TIM9_Init(void)
- {
- TIM_OC_InitTypeDef sConfigOC;
- htim9.Instance = TIM9;
- htim9.Init.Prescaler = 0;
- htim9.Init.CounterMode = TIM_COUNTERMODE_UP;
- htim9.Init.Period = 65535;
- htim9.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- HAL_TIM_PWM_Init(&htim9);
- sConfigOC.OCMode = TIM_OCMODE_PWM1;
- sConfigOC.Pulse = 100;
- sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
- sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
- HAL_TIM_PWM_ConfigChannel(&htim9, &sConfigOC, TIM_CHANNEL_1);
- sConfigOC.Pulse = 30000;
- HAL_TIM_PWM_ConfigChannel(&htim9, &sConfigOC, TIM_CHANNEL_2);
- HAL_TIM_MspPostInit(&htim9);
- }
- /* USER CODE BEGIN 4 */
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- if(keyclick==0)
- {
- TIM9->CCR2 = 65535/100*1;
- keyclick++;
- }
- else if(keyclick==1)
- {
- TIM9->CCR2 = 65535/100*10;
- keyclick++;
- }
- else if(keyclick==2)
- {
- TIM9->CCR2 = 65535/100*50;
- keyclick++;
- }
- else if(keyclick==3)
- {
- TIM9->CCR2 = 65535/100*99;
- keyclick++;
- }
- else if(keyclick==4)
- {
- keyclick=0;
- TIM9->CCR2 = 0;
- }
- }
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
- if(htim->Instance == htim1.Instance)
- {
- TIM9->CCR1 = PWMval;
- if(PWMval == 0xFFFF)
- {
- PWMval=0;
- }
- else if(PWMval<0xFFFF)
- {
- PWMval++;
- }
- }
- }
- /* USER CODE END 4 */