// ПР3. Аппаратные таймеры STM32C031C6: прерывания и задержка на таймере
// Плата: NUCLEO-C031C6, Wokwi + STM32duino (HardwareTimer + регистры TIM3)
// Автор: Алексеев Ф.В., ЭФБО-08-23
//
// f_TIM = 48 МГц (APB-предделитель = 1)
// T = (PSC + 1) * (ARR + 1) / f_TIM
// TIM14: PSC = 47999, ARR = 249 -> 250 мс -> мигание с периодом 0,5 с
// TIM16: PSC = 47999, ARR = 499 -> 500 мс -> мигание с периодом 1 с
// TIM17: PSC = 47999, ARR = 999 -> 1000 мс -> мигание с периодом 2 с
// TIM3 : PSC = 47, ARR = 999 -> 1 мс -> функция hwDelay(ms)
// --- Светодиоды, мигающие по прерываниям таймеров ---
#define LED_05S D5 // PB4 — период 0,5 с (TIM14)
#define LED_1S D3 // PB3 — период 1 с (TIM16)
#define LED_2S D2 // PA10 — период 2 с (TIM17)
// --- Светофор, работающий на аппаратной задержке TIM3 ---
#define CAR_R D13 // PA5
#define CAR_Y D12 // PA6
#define CAR_G D11 // PA7
HardwareTimer tim14(TIM14);
HardwareTimer tim16(TIM16);
HardwareTimer tim17(TIM17);
// Измеренные интервалы между прерываниями, мс
volatile uint32_t last14 = 0, last16 = 0, last17 = 0;
volatile uint32_t dt14 = 0, dt16 = 0, dt17 = 0;
// ---------- Обработчики прерываний по переполнению (Update) ----------
void isr14() {
digitalWrite(LED_05S, !digitalRead(LED_05S));
uint32_t t = millis(); dt14 = t - last14; last14 = t;
}
void isr16() {
digitalWrite(LED_1S, !digitalRead(LED_1S));
uint32_t t = millis(); dt16 = t - last16; last16 = t;
}
void isr17() {
digitalWrite(LED_2S, !digitalRead(LED_2S));
uint32_t t = millis(); dt17 = t - last17; last17 = t;
}
// Настройка таймера: PSC, ARR и функция обратного вызова
void setupTimer(HardwareTimer &t, uint32_t psc, uint32_t arr, callback_function_t cb) {
t.pause();
t.setPrescaleFactor(psc + 1); // в регистр PSC запишется psc
t.setOverflow(arr + 1, TICK_FORMAT); // в регистр ARR запишется arr
t.attachInterrupt(cb); // прерывание по событию Update
t.refresh();
t.resume();
}
// ---------- Аналог HAL_Delay() на аппаратном таймере TIM3 ----------
void hwDelayInit() {
RCC->APBENR1 |= RCC_APBENR1_TIM3EN; // тактирование TIM3
TIM3->PSC = 47; // 48 МГц / 48 = 1 МГц
TIM3->ARR = 999; // 1000 тактов = 1 мс
TIM3->EGR = TIM_EGR_UG; // загрузить PSC/ARR из теневых регистров
TIM3->SR = 0; // сбросить флаг UIF
TIM3->CR1 = TIM_CR1_CEN; // запуск счёта
}
void hwDelay(uint32_t ms) {
while (ms--) {
while (!(TIM3->SR & TIM_SR_UIF)) { } // ждём переполнения (1 мс)
TIM3->SR = ~TIM_SR_UIF; // сброс флага
}
}
void cars(bool r, bool y, bool g) {
digitalWrite(CAR_R, r); digitalWrite(CAR_Y, y); digitalWrite(CAR_G, g);
}
void setup() {
Serial.begin(115200);
pinMode(LED_05S, OUTPUT); pinMode(LED_1S, OUTPUT); pinMode(LED_2S, OUTPUT);
pinMode(CAR_R, OUTPUT); pinMode(CAR_Y, OUTPUT); pinMode(CAR_G, OUTPUT);
Serial.print("Timer clock = "); Serial.print(tim16.getTimerClkFreq()); Serial.println(" Hz");
setupTimer(tim14, 47999, 249, isr14);
setupTimer(tim16, 47999, 499, isr16);
setupTimer(tim17, 47999, 999, isr17);
hwDelayInit();
Serial.print("TIM14 PSC="); Serial.print(TIM14->PSC); Serial.print(" ARR="); Serial.println(TIM14->ARR);
Serial.print("TIM16 PSC="); Serial.print(TIM16->PSC); Serial.print(" ARR="); Serial.println(TIM16->ARR);
Serial.print("TIM17 PSC="); Serial.print(TIM17->PSC); Serial.print(" ARR="); Serial.println(TIM17->ARR);
Serial.print("TIM3 PSC="); Serial.print(TIM3->PSC); Serial.print(" ARR="); Serial.println(TIM3->ARR);
}
void loop() {
// Светофор: красный 5 с, красный+жёлтый 2 с, зелёный 5 с, жёлтый 2 с
uint32_t t0 = millis();
cars(1, 0, 0); hwDelay(5000);
cars(1, 1, 0); hwDelay(2000);
cars(0, 0, 1); hwDelay(5000);
cars(0, 1, 0); hwDelay(2000);
Serial.print("Traffic cycle = "); Serial.print(millis() - t0);
Serial.print(" ms (expected 14000); ISR intervals: TIM14 = "); Serial.print(dt14);
Serial.print(" ms, TIM16 = "); Serial.print(dt16);
Serial.print(" ms, TIM17 = "); Serial.print(dt17); Serial.println(" ms");
}
Loading
st-nucleo-c031c6
st-nucleo-c031c6