Precyzyjne opóźnienia w połączeniu z trybami oszczędzania energii w STM32, część 1
List. 2. Implementacja funkcji opóźniających umieszczona w pliku sleep.c
#include "check.h"
#include "clock.h"
#include "sleep.h"
#include
#include
#include
#include
#include
#include
/* Licznik dla opóźnień mikrosekundowych,
zwiększany z częstotliwością 1 MHz */
#define US_TIM TIM2
#define US_TIM_IRQn TIM2_IRQn
#define US_RCC_APB1Periph_TIM RCC_APB1Periph_TIM2
#define US_TIM_IRQHandler TIM2_IRQHandler
/* Licznik dla opóźnień milisekundowych,
zwiększany z częstotliwością 2 kHz */
#define MS_TIM TIM3
#define MS_TIM_IRQn TIM3_IRQn
#define MS_RCC_APB1Periph_TIM RCC_APB1Periph_TIM3
#define MS_TIM_IRQHandler TIM3_IRQHandler
static unsigned usCalibration = 0;
void USleep(unsigned count) {
if (count > usCalibration)
count -= usCalibration;
else if (count > 0)
count = 1; /* minimalna możliwa wartość */
else
return; /* count == 0 */
US_TIM->CNT = 0;
US_TIM->CCR1 = count;
US_TIM->CR1 |= TIM_CR1_CEN;
do
__WFE();
while (US_TIM->CR1 & TIM_CR1_CEN);
}
void US_TIM_IRQHandler(void) {
if (TIM_GetITStatus(US_TIM, TIM_IT_CC1)) {
TIM_ClearITPendingBit(US_TIM, TIM_IT_CC1);
US_TIM->CR1 &= ~TIM_CR1_CEN;
__SEV();
}
}
void MSleep(unsigned count) {
if (count > 0) {
MS_TIM->CNT = 0;
MS_TIM->CCR1 = count << 1; /* tyka 2 kHz */ MS_TIM->CR1 |= TIM_CR1_CEN;
do
__WFE();
while (MS_TIM->CR1 & TIM_CR1_CEN);
}
}
void MS_TIM_IRQHandler(void) {
if (TIM_GetITStatus(MS_TIM, TIM_IT_CC1)) {
TIM_ClearITPendingBit(MS_TIM, TIM_IT_CC1);
MS_TIM->CR1 &= ~TIM_CR1_CEN;
__SEV();
}
}
/* #define PWR_REGULATOR_MODE PWR_Regulator_ON */
#define PWR_REGULATOR_MODE PWR_Regulator_LowPower
static unsigned hclkMHz;
void Sleep(unsigned count) {
if (count > 0) {
/* Alarm zgłaszany jest w ostatnim cyklu oscylatora RTC
odpowiadającego sekundzie, w której alarm należy
zgłosić, więc count <= czas uśpienia < count + 1. */
RTC_WaitForLastTask();
RTC_SetAlarm(RTC_GetCounter() + count);
RTC_WaitForLastTask();
do
PWR_EnterSTOPMode(PWR_REGULATOR_MODE, PWR_STOPEntry_WFE);
while (!RTC_GetFlagStatus(RTC_IT_ALR));
RTC_WaitForLastTask();
RTC_ClearITPendingBit(RTC_IT_ALR);
/* Po obudzeniu trzeba przywrócić pracę oscylatorów. */
ClockConfigure(hclkMHz);
}
}
void Standby(unsigned time) {
PWR_WakeUpPinCmd(ENABLE);
RTC_WaitForLastTask();
RTC_SetAlarm(RTC_GetCounter() + time);
RTC_WaitForLastTask();
PWR_EnterSTANDBYMode();
}
int SleepConfigure(unsigned freqMHz) {
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
hclkMHz = freqMHz;
/* Kalibracja 1 us + 120 cykle zegara */
usCalibration = 1U + (120U / freqMHz);
RCC_APB1PeriphClockCmd(US_RCC_APB1Periph_TIM |
MS_RCC_APB1Periph_TIM |
RCC_APB1Periph_PWR |
RCC_APB1Periph_BKP,
ENABLE);
TIM_TimeBaseStructInit(&TIM_TimeBaseStruct);
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_OCStructInit(&TIM_OCInitStruct);
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_Timing;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
/* Konfiguruj licznik mikrosekundowy na 1 MHz. */
TIM_TimeBaseStruct.TIM_Prescaler = freqMHz - 1;
TIM_TimeBaseInit(US_TIM, &TIM_TimeBaseStruct);
TIM_OC1Init(US_TIM, &TIM_OCInitStruct);
TIM_OC1PreloadConfig(US_TIM, TIM_OCPreload_Disable);
NVIC_InitStruct.NVIC_IRQChannel = US_TIM_IRQn;
NVIC_Init(&NVIC_InitStruct);
TIM_ClearITPendingBit(US_TIM, TIM_IT_CC1);
TIM_ITConfig(US_TIM, TIM_IT_CC1, ENABLE);
/* Konfiguruj licznik milisekundowy na 2 kHz. */
TIM_TimeBaseStruct.TIM_Prescaler = freqMHz * 500 - 1;
TIM_TimeBaseInit(MS_TIM, &TIM_TimeBaseStruct);
TIM_OC1Init(MS_TIM, &TIM_OCInitStruct);
TIM_OC1PreloadConfig(MS_TIM, TIM_OCPreload_Disable);
NVIC_InitStruct.NVIC_IRQChannel = MS_TIM_IRQn;
NVIC_Init(&NVIC_InitStruct);
TIM_ClearITPendingBit(MS_TIM, TIM_IT_CC1);
TIM_ITConfig(MS_TIM, TIM_IT_CC1, ENABLE);
/* Konfiguruj licznik sekundowy. */
PWR_BackupAccessCmd(ENABLE);
if (PWR_GetFlagStatus(PWR_FLAG_SB) != RESET) {
/* Mikrokontroler obudził się ze stanu czuwania. Nie ma
potrzeby ponownego konfigurowania RTC - konfiguracja
jest zachowywana po wybudzeniu ze stanu czuwania. */
PWR_ClearFlag(PWR_FLAG_SB);
RTC_WaitForSynchro();
}
else {
/* Mikrokontroler został zresetowany, konfiguruj RTC, aby
był taktowany kwarcem 32768 Hz i tykał z okresem 1 s. */
RCC_LSEConfig(RCC_LSE_ON);
active_check(RCC_GetFlagStatus(RCC_FLAG_LSERDY), 10000000);
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
}
/* Konfiguruj linię 17 EXTI (alarm RTC), aby narastające
zbocze ustawiało rejestr zdarzenia */
EXTI_StructInit(&EXTI_InitStruct);
EXTI_InitStruct.EXTI_Line = EXTI_Line17;
EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStruct.EXTI_LineCmd = ENABLE;
EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Event;
EXTI_Init(&EXTI_InitStruct);
RTC_WaitForLastTask();
RTC_ClearITPendingBit(RTC_IT_ALR);
return 0;
}

Koniec ery defiladowej. Cykl życia technologii na froncie skrócił się do kilku tygodni
Mouser Electronics podpisuje globalną umowę dystrybucyjną z Telit Cinterion dotyczącą rozwiązań IoT
Czym jest czytnik e-booków i jak działa? 




