// ПР1. Архитектура Cortex-M0+ (STM32C031C6) и конфигурирование МК
// Плата: NUCLEO-C031C6, среда: Wokwi + STM32duino
// Автор: Алексеев Ф.В., ЭФБО-08-23
#include <Arduino.h>
// Внешний светодиод на D13 = PA5 (тот же вывод, что и LD4 на плате)
#define LED_PIN_NUM 5 // номер линии порта A
// ---------- 1. Конфигурирование системы тактирования ----------
// Переопределяем слабую (weak) функцию ядра STM32duino:
// HSI48 -> делитель HSIDIV = 1 -> SYSCLK = 48 МГц, AHB = /1, APB = /1
extern "C" void SystemClock_Config(void) {
RCC_OscInitTypeDef osc = {};
RCC_ClkInitTypeDef clk = {};
osc.OscillatorType = RCC_OSCILLATORTYPE_HSI;
osc.HSIState = RCC_HSI_ON;
osc.HSIDiv = RCC_HSI_DIV1; // 48 МГц / 1
osc.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
HAL_RCC_OscConfig(&osc);
clk.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
clk.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; // источник SYSCLK — HSISYS
clk.SYSCLKDivider = RCC_SYSCLK_DIV1;
clk.AHBCLKDivider = RCC_HCLK_DIV1; // HCLK = SYSCLK / 1
clk.APB1CLKDivider = RCC_APB1_DIV1; // PCLK = HCLK / 1
HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_1); // 1 такт ожидания Flash (> 24 МГц)
}
// ---------- 2. Инициализация GPIO на уровне регистров ----------
void gpioInitRegisters() {
RCC->IOPENR |= RCC_IOPENR_GPIOAEN; // тактирование порта A
GPIOA->MODER &= ~(3U << (LED_PIN_NUM * 2)); // сброс режима PA5
GPIOA->MODER |= (1U << (LED_PIN_NUM * 2)); // 01 — выход общего назначения
GPIOA->OTYPER &= ~(1U << LED_PIN_NUM); // push-pull
GPIOA->OSPEEDR &= ~(3U << (LED_PIN_NUM * 2)); // низкая скорость
GPIOA->PUPDR &= ~(3U << (LED_PIN_NUM * 2)); // без подтяжки
}
inline void ledOn() { GPIOA->BSRR = (1U << LED_PIN_NUM); } // установка бита
inline void ledOff() { GPIOA->BSRR = (1U << (LED_PIN_NUM + 16)); } // сброс бита
void printHex(const char *name, uint32_t v) {
Serial.print(name); Serial.print(" = 0x"); Serial.println(v, HEX);
}
void setup() {
Serial.begin(115200);
delay(100);
gpioInitRegisters();
Serial.println("=== STM32C031C6 / ARM Cortex-M0+ ===");
// ---------- 3. Сведения о ядре (System Control Block) ----------
uint32_t cpuid = SCB->CPUID;
printHex("SCB->CPUID", cpuid);
Serial.print(" Implementer: 0x"); Serial.println((cpuid >> 24) & 0xFF, HEX); // 0x41 = ARM
Serial.print(" PartNo: 0x"); Serial.println((cpuid >> 4) & 0xFFF, HEX); // 0xC60 = Cortex-M0+
Serial.print(" Revision: r"); Serial.print((cpuid >> 20) & 0xF);
Serial.print("p"); Serial.println(cpuid & 0xF);
// ---------- 4. Тактовые частоты ----------
SystemCoreClockUpdate();
Serial.print("SystemCoreClock = "); Serial.print(SystemCoreClock); Serial.println(" Hz");
Serial.print("HCLK = "); Serial.print(HAL_RCC_GetHCLKFreq()); Serial.println(" Hz");
Serial.print("PCLK1 = "); Serial.print(HAL_RCC_GetPCLK1Freq()); Serial.println(" Hz");
printHex("RCC->CR ", RCC->CR);
printHex("RCC->CFGR", RCC->CFGR);
printHex("FLASH->ACR", FLASH->ACR);
// ---------- 5. NVIC и SysTick ----------
Serial.print("SysTick LOAD = "); Serial.print(SysTick->LOAD);
Serial.println(" (1 ms = HCLK/1000 - 1)");
NVIC_SetPriority(TIM3_IRQn, 2); // пример назначения приоритета
Serial.print("NVIC prio TIM3_IRQn = "); Serial.println(NVIC_GetPriority(TIM3_IRQn));
Serial.print("NVIC prio SysTick = "); Serial.println(NVIC_GetPriority(SysTick_IRQn));
// ---------- 6. Регистры порта после настройки ----------
printHex("GPIOA->MODER", GPIOA->MODER);
Serial.println("Blink PA5 (D13) via GPIOA->BSRR ...");
}
void loop() {
static uint32_t n = 0; // выводим состояние только первых 3 периодов
ledOn();
if (n < 3) { Serial.print("LED ON, GPIOA->ODR = 0x"); Serial.println(GPIOA->ODR, HEX); }
delay(500);
ledOff();
if (n < 3) { Serial.print("LED OFF, GPIOA->ODR = 0x"); Serial.println(GPIOA->ODR, HEX); }
delay(500);
n++;
}
Loading
st-nucleo-c031c6
st-nucleo-c031c6