STM32F411CEU6 BlackPill

元器件
开发板
库存 400

介绍

STM32F411CEU6 最小系统板(BlackPill/WeAct),基于 ARM Cortex-M4 内核,带 FPU 和 DSP,主频 100MHz,512KB Flash、128KB SRAM。板载 25MHz HSE + 32.768KHz LSE 晶振,引出全部 GPIO(36个IO口)。采用 UFQFPN-48 封装,外形紧凑(约 53mm×21mm),Type-C USB 接口,支持 USB OTG FS、3×I2C、5×SPI、3×USART、1×ADC(10通道)、SDIO。是为数不多同时具备高性价比和 USB OTG 的小尺寸 F4 核心板,非常适合可穿戴、USB 设备、四轴飞行器等空间受限的高性能场景。

规格参数

参数
ADC1×12位(10通道)
SRAM128KB
Flash512KB
主频100MHz
内核ARM Cortex-M4 + FPU + DSP
特色所有GPIO均为5V容忍、支持SPI Flash外扩(底板QSPI焊盘)
MCU型号STM32F411CEU6
PCB尺寸53mm×21mm
USB接口Type-C
定时器4×16位通用+2×32位+2×看门狗+1×SysTick
GPIO数量36(全部5V容忍)
板载晶振25MHz HSE + 32.768KHz LSE
烧录方式SWD/串口ISP/USB DFU
调试接口SWD(4线)
通信接口USB 2.0 OTG FS、SDIO、5×SPI/I2S、3×I2C、3×USART

代码例程

STM32F411CEU6 BlackPill 代码例程.md
# STM32F411CEU6 BlackPill 代码例程

本文档涵盖 HAL 库、Arduino、PlatformIO,重点展示 F411 特色:USB OTG、DFU、全 5V 容忍 GPIO、SPI Flash 扩展。

---

## 一、STM32CubeIDE / HAL 库例程

### 1.1 正确的 100MHz 时钟配置(HSE=25MHz)

```c
/* 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 容忍验证)

```c
/* 所有 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 虚拟串口

```c
/* 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 运行时跳转(方便固件更新)

```c
/* 运行时通过软件命令进入 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)

```c
/* 使用 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 闪烁 + 串口

```cpp
// 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 键盘模拟

```cpp
/* 使用 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 容忍)

```cpp
/* 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 配置

```ini
; 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 命令行烧录

```bash
# 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 | 最全外设支持 |

参考资料

暂无参考文献