文档
STM32F411CEU6 BlackPill 代码例程
本文档涵盖 HAL 库、Arduino、PlatformIO,重点展示 F411 特色:USB OTG、DFU、全 5V 容忍 GPIO、SPI Flash 扩展。
一、STM32CubeIDE / HAL 库例程
1.1 正确的 100MHz 时钟配置(HSE=25MHz)
/* main.c - F411 BlackPill 100MHz 配置 */
/* ⚠️ CubeMX 中必须设置 HSE = 25MHz! */
#include "main.h"
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* 使能 FPU */
SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2));
/* HSE = 25MHz → PLL → 100MHz */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 25; // HSE ÷ 25 = 1MHz
RCC_OscInitStruct.PLL.PLLN = 200; // × 200 = 200MHz
RCC_OscInitStruct.PLL.PLLP = 2; // ÷ 2 = 100MHz (SYSCLK)
RCC_OscInitStruct.PLL.PLLQ = 4; // ÷ 4 = 50MHz (USB/SDIO, 需微调)
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // 100MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; // 50MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; // 100MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3WS); // 3等待周期
}
1.2 GPIO 基础(全 5V 容忍验证)
/* 所有 F411 GPIO 均为 5V 容忍,可直接接 5V 传感器 */
#include "main.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* PC13 - LED (推挽输出) */
GPIO_InitTypeDef GPIO_InitStruct = {0};
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* PA0 - 按键输入(可承受 5V 上拉!) */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
while (1)
{
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
HAL_Delay(50); // 消抖
}
}
}
1.3 USB CDC 虚拟串口
/* CubeMX 配置:USB_OTG_FS → Device Only → CDC Virtual Port Com */
/* 时钟注意:USB 需要 48MHz,确保 PLLQ 输出接近 48MHz */
#include "main.h"
#include "usbd_cdc_if.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USB_DEVICE_Init(); // CubeMX 自动生成
uint32_t counter = 0;
while (1)
{
char buf[64];
int len = snprintf(buf, sizeof(buf),
"BlackPill F411 Uptime: %lu sec\r\n", counter++);
CDC_Transmit_FS((uint8_t *)buf, len);
HAL_Delay(1000);
}
}
1.4 USB DFU 运行时跳转(方便固件更新)
/* 运行时通过软件命令进入 DFU 模式,无需手动跳 BOOT0 */
#include "main.h"
/* 跳转到系统 Bootloader(DFU) */
void JumpToBootloader(void)
{
/* 关闭所有中断 */
__disable_irq();
/* 复位所有外设 */
HAL_RCC_DeInit();
HAL_DeInit();
/* 设置向量表为系统 Bootloader 地址 */
SYSCFG->MEMRMP = 0x01; // 映射系统存储器到 0x00000000
/* 设置 MSP 和跳转 */
uint32_t bootloader_addr = 0x1FFF0000; // F411 系统存储器
__set_MSP(*(volatile uint32_t *)bootloader_addr);
((void (*)(void))(*(volatile uint32_t *)(bootloader_addr + 4)))();
while (1); // 不会执行到此处
}
int main(void)
{
HAL_Init();
SystemClock_Config();
/* 示例:检测某个按键长按则进入 DFU */
// if (isButtonLongPressed()) JumpToBootloader();
while (1)
{
// 正常应用逻辑
}
}
1.5 SPI 扩展 Flash(W25Q64 8MB)
/* 使用 SPI1 与板载或外接 W25Qxx Flash 通信 */
/* PA5(SCK), PA6(MISO), PA7(MOSI), PA4(NSS) */
#include "main.h"
SPI_HandleTypeDef hspi1;
#define FLASH_CS_PIN GPIO_PIN_4
#define FLASH_CS_PORT GPIOA
#define W25Q_CMD_READ_ID 0x9F
#define W25Q_CMD_READ 0x03
#define W25Q_CMD_WRITE_EN 0x06
#define W25Q_CMD_PAGE_PROG 0x02
#define W25Q_CMD_SECTOR_ERASE 0x20
static void MX_SPI1_Init(void)
{
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT; // 软件控制 CS
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4; // 25MHz
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
HAL_SPI_Init(&hspi1);
}
/* 读取 Flash ID */
uint32_t W25Q_ReadID(void)
{
uint8_t cmd = W25Q_CMD_READ_ID;
uint8_t id[3] = {0};
HAL_GPIO_WritePin(FLASH_CS_PORT, FLASH_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, &cmd, 1, 100);
HAL_SPI_Receive(&hspi1, id, 3, 100);
HAL_GPIO_WritePin(FLASH_CS_PORT, FLASH_CS_PIN, GPIO_PIN_SET);
return (id[0] << 16) | (id[1] << 8) | id[2]; // W25Q64 → 0xEF4017
}
/* 读取数据 */
void W25Q_Read(uint32_t addr, uint8_t *buf, uint32_t len)
{
uint8_t cmd[4] = {
W25Q_CMD_READ,
(addr >> 16) & 0xFF,
(addr >> 8) & 0xFF,
addr & 0xFF
};
HAL_GPIO_WritePin(FLASH_CS_PORT, FLASH_CS_PIN, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1, cmd, 4, 100);
HAL_SPI_Receive(&hspi1, buf, len, 1000);
HAL_GPIO_WritePin(FLASH_CS_PORT, FLASH_CS_PIN, GPIO_PIN_SET);
}
二、Arduino (STM32duino) 例程
Board 选择
Generic STM32F411CEU6或WeAct BlackPill F411CE
2.1 LED 闪烁 + 串口
// BlackPill F411 Arduino 基础
void setup()
{
pinMode(PC13, OUTPUT);
Serial.begin(115200);
// USB CDC 串口,直接通过 USB-C 输出
}
void loop()
{
digitalWrite(PC13, LOW); // LED ON
delay(500);
digitalWrite(PC13, HIGH); // LED OFF
delay(500);
Serial.println("BlackPill F411 - Arduino");
}
2.2 USB HID 键盘模拟
/* 使用 Arduino HID 库,BlackPill 变身 USB 键盘 */
#include <HID-Project.h>
void setup()
{
Keyboard.begin();
delay(3000); // 等待电脑识别
}
void loop()
{
// 每隔 5 秒输入一段文字
Keyboard.print("Hello from BlackPill F411!");
Keyboard.press(KEY_RETURN);
Keyboard.release(KEY_RETURN);
delay(5000);
}
2.3 5V 传感器直接读取(得益于全 5V 容忍)
/* 5V 超声波测距模块 HC-SR04 直连(无需电平转换!) */
const int trigPin = PB0;
const int echoPin = PB1;
void setup()
{
Serial.begin(115200);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
// echo 返回 5V 信号,F411 所有 GPIO 5V 容忍,安全!
}
void loop()
{
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = duration * 0.034 / 2.0;
Serial.print("Distance: ");
Serial.print(distance);
Serial.println(" cm");
delay(500);
}
三、PlatformIO 配置
; platformio.ini - BlackPill F411CE
[env:blackpill_f411ce]
platform = ststm32
board = blackpill_f411ce
framework = arduino
; framework = libopencm3 ; 轻量级替代
; framework = stm32cube ; HAL 框架
upload_protocol = dfu ; 通过 USB DFU 烧录,无需 ST-Link!
; upload_protocol = stlink ; 也可用 ST-Link
monitor_speed = 115200
; 自定义编译选项
build_flags =
-D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
-D USBCON
四、dfu-util 命令行烧录
# 1. 进入 DFU 模式:BOOT0 接 3.3V,然后复位或上电
# 2. 检查是否识别
dfu-util -l
# 3. 烧录固件
dfu-util -a 0 -s 0x08000000 -D firmware.bin
# 4. BOOT0 接回 GND,复位即可运行
五、开发建议
| 场景 | 推荐框架 | 理由 |
|---|---|---|
| 快速原型 | Arduino (STM32duino) | 生态丰富,库多,USB CDC 即插即用 |
| USB 设备开发 | STM32Cube HAL | USB 库最完善,CDC/HID/MSC/DFU |
| 低内存场景 | libopencm3 | 超轻量,适合 Bootloader |
| 通用嵌入式 | STM32Cube HAL | 最全外设支持 |