文档
STM32F407VET6 Black Board 代码例程
本文档覆盖 HAL 库、标准库,并特别包含 F407 特色功能:FPU 浮点运算、DSP 库、SDIO、DCMI 摄像头。
一、STM32CubeIDE / HAL 库例程
1.1 系统时钟 168MHz + FPU 使能
/* main.c - F407 168MHz 初始化 + FPU */
#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)); // CP10/CP11 完全访问
/* HSE 8MHz → PLL → 168MHz */
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 = 8; // HSE ÷ 8 = 1MHz
RCC_OscInitStruct.PLL.PLLN = 336; // × 336 = 336MHz
RCC_OscInitStruct.PLL.PLLP = 2; // ÷ 2 = 168MHz (SYSCLK)
RCC_OscInitStruct.PLL.PLLQ = 7; // ÷ 7 = 48MHz (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; // 168MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // 42MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // 84MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5WS); // 5等待周期!
}
int main(void)
{
HAL_Init();
SystemClock_Config();
// ... 外设初始化 ...
while (1);
}
1.2 FPU 浮点运算性能对比
/* 对比 FPU 硬浮点与软浮点性能 */
#include "main.h"
#include <math.h>
/* 务必在 Project Settings 中开启 FPU:
菜单 Project → Properties → C/C++ Build → Settings →
MCU Settings → Floating-point unit: FPv4-SP-D16
Floating-point ABI: Hardware implementation (-mfloat-abi=hard)
*/
void FPU_Demo(void)
{
volatile float a = 3.14159265f;
volatile float b = 2.71828183f;
volatile float result;
volatile uint32_t start, elapsed;
/* 硬件 FPU 测试:100万次浮点运算 */
start = DWT->CYCCNT;
for (uint32_t i = 0; i < 1000000; i++)
{
result = sinf(a) * cosf(b) + sqrtf(a * b);
}
elapsed = DWT->CYCCNT - start;
// 在 168MHz 下,通常约 200-300ms 完成
printf("FPU test: %lu cycles, result=%.6f\r\n", elapsed, (double)result);
}
1.3 SDIO + FATFS 读写 SD 卡
/* SDIO 4线模式 + FATFS */
#include "main.h"
#include "fatfs.h"
FATFS fs; // 文件系统对象
FIL fil; // 文件对象
UINT bw, br;
void SD_Card_Test(void)
{
FRESULT res;
char buf[64];
/* 挂载文件系统 */
res = f_mount(&fs, "", 1);
if (res != FR_OK) {
printf("Mount failed: %d\r\n", res);
return;
}
/* 创建并写入文件 */
res = f_open(&fil, "test.txt", FA_CREATE_ALWAYS | FA_WRITE);
if (res == FR_OK) {
f_puts("Hello from STM32F407 SDIO!\r\n", &fil);
f_puts("SD card works perfectly.\r\n", &fil);
f_close(&fil);
printf("File written OK\r\n");
}
/* 读取文件 */
res = f_open(&fil, "test.txt", FA_READ);
if (res == FR_OK) {
f_read(&fil, buf, sizeof(buf) - 1, &br);
buf[br] = '\0';
f_close(&fil);
printf("Read: %s", buf);
}
f_mount(NULL, "", 1); // 卸载
}
1.4 DCMI + OV7725 摄像头(快照)
/* DCMI 接口抓取一帧到内存 */
#include "main.h"
DCMI_HandleTypeDef hdcmi;
DMA_HandleTypeDef hdma_dcmi;
/* 帧缓冲:QVGA RGB565 = 320×240×2 = 153600 字节 */
#define FRAME_SIZE (320 * 240 * 2)
__attribute__((section(".bss"))) uint8_t frameBuf[FRAME_SIZE];
void DCMI_Init(void)
{
/* 使能时钟 */
__HAL_RCC_DCMI_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
hdcmi.Instance = DCMI;
hdcmi.Init.SynchroMode = DCMI_SYNCHRO_HARDWARE;
hdcmi.Init.PCKPolarity = DCMI_PCKPOLARITY_RISING;
hdcmi.Init.VSPolarity = DCMI_VSPOLARITY_HIGH; // 根据摄像头调整
hdcmi.Init.HSPolarity = DCMI_HSPOLARITY_HIGH;
hdcmi.Init.CaptureRate = DCMI_CR_ALL_FRAME;
hdcmi.Init.ExtendedDataMode = DCMI_EXTEND_DATA_8B; // 8位数据模式
hdcmi.Init.JPEGMode = DCMI_JPEG_DISABLE;
HAL_DCMI_Init(&hdcmi);
/* DMA 配置:DCMI → 内存 */
hdma_dcmi.Instance = DMA2_Stream1;
hdma_dcmi.Init.Channel = DMA_CHANNEL_1;
hdma_dcmi.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_dcmi.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_dcmi.Init.MemInc = DMA_MINC_ENABLE;
hdma_dcmi.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_dcmi.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_dcmi.Init.Mode = DMA_CIRCULAR; // 循环模式连续抓帧
hdma_dcmi.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_dcmi);
__HAL_LINKDMA(&hdcmi, DMA_Handle, hdma_dcmi);
}
void DCMI_StartCapture(void)
{
HAL_DCMI_Start_DMA(&hdcmi, DCMI_MODE_CONTINUOUS,
(uint32_t)frameBuf, FRAME_SIZE / 4);
}
1.5 USB VCP(虚拟串口)
/* USB CDC 虚拟串口 - CubeMX 配置 USB_OTG_FS Device Only → CDC */
#include "main.h"
#include "usbd_cdc_if.h"
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_USB_DEVICE_Init(); // CubeMX 自动生成
while (1)
{
/* CDC_Transmit_FS 发送数据到 PC */
char msg[] = "USB VCP from STM32F407!\r\n";
CDC_Transmit_FS((uint8_t *)msg, sizeof(msg) - 1);
HAL_Delay(1000);
}
}
二、Keil MDK / 标准外设库例程
2.1 168MHz 时钟 + FPU(标准库)
#include "stm32f4xx.h"
void RCC_Configuration(void)
{
/* 使能 FPU */
SCB->CPACR |= ((3UL << 10*2) | (3UL << 11*2));
/* HSE ON */
RCC_HSEConfig(RCC_HSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
/* PLL: 8MHz ÷ 8 × 336 ÷ 2 = 168MHz */
RCC_PLLConfig(RCC_PLLSource_HSE, 8, 336, 2, 7);
RCC_PLLCmd(ENABLE);
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* Flash 5 等待周期 */
FLASH_SetLatency(FLASH_Latency_5);
FLASH_PrefetchBufferCmd(ENABLE);
FLASH_InstructionCacheCmd(ENABLE);
FLASH_DataCacheCmd(ENABLE);
/* 系统时钟切换 */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while (RCC_GetSYSCLKSource() != 0x08);
/* APB 分频 */
RCC_HCLKConfig(RCC_SYSCLK_Div1); // 168MHz
RCC_PCLK1Config(RCC_HCLK_Div4); // 42MHz
RCC_PCLK2Config(RCC_HCLK_Div2); // 84MHz
}
2.2 SysTick 精确延时
/* 使用 SysTick 实现微秒级延时 */
#include "stm32f4xx.h"
volatile uint32_t usTicks;
void SysTick_Init(void)
{
/* SysTick = 168MHz / 1 = 168MHz → 每微秒 168 个 tick */
SysTick_Config(SystemCoreClock / 1000000); // 1μs 中断
}
void Delay_us(uint32_t us)
{
usTicks = us;
while (usTicks != 0);
}
void Delay_ms(uint32_t ms)
{
for (uint32_t i = 0; i < ms; i++)
Delay_us(1000);
}
void SysTick_Handler(void)
{
if (usTicks > 0) usTicks--;
}
2.3 STM32F4 DSP 库 - FFT 示例
/* 需要添加 arm_cortexM4lf_math.lib 到工程 */
#define ARM_MATH_CM4
#include "arm_math.h"
#include <math.h>
#define FFT_SIZE 256
float32_t fftInput[FFT_SIZE * 2]; // 实部+虚部交织
float32_t fftOutput[FFT_SIZE];
arm_cfft_radix4_instance_f32 fftInstance;
void DSP_FFT_Demo(void)
{
float32_t maxValue;
uint32_t maxIndex;
/* 生成测试信号:1KHz 正弦波 */
for (int i = 0; i < FFT_SIZE; i++)
{
fftInput[i * 2] = 100.0f * sinf(2.0f * PI * 1000.0f * i / 10000.0f);
fftInput[i * 2 + 1] = 0.0f; // 虚部
}
/* 初始化并执行 FFT */
arm_cfft_radix4_init_f32(&fftInstance, FFT_SIZE, 0, 1);
arm_cfft_radix4_f32(&fftInstance, fftInput);
/* 计算幅度 */
arm_cmplx_mag_f32(fftInput, fftOutput, FFT_SIZE);
/* 寻找最大频率分量 */
arm_max_f32(fftOutput, FFT_SIZE / 2, &maxValue, &maxIndex);
printf("Peak at bin %lu, magnitude = %.2f\r\n", maxIndex, maxValue);
printf("Frequency ≈ %.1f Hz\r\n", (float)maxIndex * 10000.0f / FFT_SIZE);
}
三、Arduino (STM32duino) 例程
F407 同样支持 STM32duino,在 Board 中选择
Generic STM32F407VET6。
void setup()
{
Serial.begin(115200);
// 注意 F407 的板载 LED 位置因版本不同而异
// 常见版本:PE0/PE1/PB0/PB1
pinMode(PE0, OUTPUT);
pinMode(PE1, OUTPUT);
}
void loop()
{
digitalWrite(PE0, LOW);
digitalWrite(PE1, HIGH);
delay(250);
digitalWrite(PE0, HIGH);
digitalWrite(PE1, LOW);
delay(250);
Serial.println("STM32F407 running on Arduino core!");
}
四、PlatformIO 配置参考
; platformio.ini - F407 Black Board
[env:black_f407ve]
platform = ststm32
board = black_f407ve
framework = arduino
; 或者使用 STM32Cube/HAL 框架
; framework = stm32cube
upload_protocol = stlink
monitor_speed = 115200
; 如需自定义频率
board_build.f_cpu = 168000000L
五、关键配置要点
| 要点 | 说明 |
|---|---|
| FPU 使能 | 代码中 SCB->CPACR 设置 + 编译器选项 -mfloat-abi=hard -mfpu=fpv4-sp-d16 |
| Flash Latency | 168MHz 必须设为 FLASH_LATENCY_5WS,否则 HardFault |
| ART 加速器 | 务必开启预取缓冲和指令/数据缓存 |
| PLLQ | 给 USB/SDIO 提供 48MHz,必须确保 PLLQ 输出精确 48MHz |
| 堆栈大小 | 使用 FATFS、DSP 等库时建议增大堆栈(startup 文件中修改) |