STM32F103C8T6 Blue Pill 代码例程

知识库
知识库文档
/firmware/开发板/STM32F103C8T6 Blue Pill/STM32F103C8T6 Blue Pill 代码例程.md

文档

STM32F103C8T6 Blue Pill 代码例程

本文档提供三种主流开发平台的代码例程:STM32CubeIDE (HAL库)、Keil MDK (标准外设库)、以及 Arduino (STM32duino)。


一、STM32CubeIDE / HAL 库例程

1.1 GPIO 初始化与 LED 闪烁

/* main.c - STM32CubeIDE HAL库 LED闪烁 */
#include "main.h"

void SystemClock_Config(void);
static void MX_GPIO_Init(void);

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_GPIO_Init();

    while (1)
    {
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);  // 翻转 PC13
        HAL_Delay(500);                           // 延时 500ms
    }
}

/* GPIO 初始化 - CubeMX 自动生成 */
static void MX_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOC_CLK_ENABLE();

    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);
}

/* 系统时钟配置 72MHz HSE+PLL */
void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;     // 8MHz × 9 = 72MHz
    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;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;  // APB1 最大 36MHz
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  // APB2 最大 72MHz
    HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}

1.2 USART1 串口通信

/* USART1 发送示例 - PA9(TX) PA10(RX) */
#include "main.h"
#include <stdio.h>

UART_HandleTypeDef huart1;

static void MX_USART1_UART_Init(void)
{
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 115200;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    HAL_UART_Init(&huart1);
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_USART1_UART_Init();

    char msg[] = "Hello from STM32F103 Blue Pill!\r\n";
    while (1)
    {
        HAL_UART_Transmit(&huart1, (uint8_t *)msg, sizeof(msg) - 1, 1000);
        HAL_Delay(1000);
    }
}

1.3 ADC 读取示例

/* ADC1 通道0 (PA0) 读取模拟量 */
ADC_HandleTypeDef hadc1;

static void MX_ADC1_Init(void)
{
    hadc1.Instance = ADC1;
    hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
    hadc1.Init.ContinuousConvMode = ENABLE;           // 连续转换模式
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    HAL_ADC_Init(&hadc1);

    /* 配置通道 */
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ADC_CHANNEL_0;                  // PA0
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; // 采样时间
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

int main(void)
{
    HAL_Init();
    SystemClock_Config();
    MX_ADC1_Init();
    HAL_ADC_Start(&hadc1);

    while (1)
    {
        HAL_ADC_PollForConversion(&hadc1, 100);       // 等待转换完成
        uint32_t adcVal = HAL_ADC_GetValue(&hadc1);   // 读取 ADC 值 (0-4095)
        float voltage = adcVal * 3.3f / 4096.0f;      // 换算为电压
        // 可通过 USART 输出 voltage 值
        HAL_Delay(100);
    }
}

1.4 I2C 通信(OLED SSD1306)

/* I2C1 (PB6-SCL, PB7-SDA) 驱动 SSD1306 OLED */
I2C_HandleTypeDef hi2c1;

static void MX_I2C1_Init(void)
{
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 400000;                   // 400KHz 快速模式
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    HAL_I2C_Init(&hi2c1);
}

/* SSD1306 基础写命令 */
void SSD1306_WriteCmd(uint8_t cmd)
{
    uint8_t buf[2] = {0x00, cmd};  // Co=0, D/C#=0 (命令)
    HAL_I2C_Master_Transmit(&hi2c1, 0x3C << 1, buf, 2, 100);
}

/* SSD1306 初始化序列 */
void SSD1306_Init(void)
{
    HAL_Delay(100);  // 等待上电稳定
    SSD1306_WriteCmd(0xAE); // Display OFF
    SSD1306_WriteCmd(0xD5); SSD1306_WriteCmd(0x80); // 设置振荡频率
    SSD1306_WriteCmd(0xA8); SSD1306_WriteCmd(0x3F); // 设置多路复用比
    SSD1306_WriteCmd(0xD3); SSD1306_WriteCmd(0x00); // 显示偏移
    SSD1306_WriteCmd(0x40); // 起始行
    SSD1306_WriteCmd(0x8D); SSD1306_WriteCmd(0x14); // 电荷泵
    SSD1306_WriteCmd(0x20); SSD1306_WriteCmd(0x00); // 水平寻址模式
    SSD1306_WriteCmd(0xA1); // 段重映射
    SSD1306_WriteCmd(0xC8); // COM扫描方向
    SSD1306_WriteCmd(0xDA); SSD1306_WriteCmd(0x12); // COM引脚配置
    SSD1306_WriteCmd(0x81); SSD1306_WriteCmd(0xCF); // 对比度
    SSD1306_WriteCmd(0xD9); SSD1306_WriteCmd(0xF1); // 预充电周期
    SSD1306_WriteCmd(0xDB); SSD1306_WriteCmd(0x40); // VCOMH
    SSD1306_WriteCmd(0xA4); // 全部点亮关闭
    SSD1306_WriteCmd(0xA6); // 正常显示(非反色)
    SSD1306_WriteCmd(0xAF); // Display ON
}

二、Keil MDK / 标准外设库 例程

2.1 GPIO 初始化(标准库)

/* main.c - StdPeriph 库版本 LED闪烁 */
#include "stm32f10x.h"

void RCC_Configuration(void);
void GPIO_Configuration(void);
void Delay_ms(uint32_t ms);

int main(void)
{
    RCC_Configuration();
    GPIO_Configuration();

    while (1)
    {
        GPIO_ResetBits(GPIOC, GPIO_Pin_13);  // LED ON (低电平亮)
        Delay_ms(500);
        GPIO_SetBits(GPIOC, GPIO_Pin_13);    // LED OFF
        Delay_ms(500);
    }
}

void RCC_Configuration(void)
{
    /* 使能 HSE */
    RCC_HSEConfig(RCC_HSE_ON);
    while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);

    /* 配置 PLL: HSE × 9 = 72MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    RCC_PLLCmd(ENABLE);
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

    /* 设置 Flash 等待周期 */
    FLASH_SetLatency(FLASH_Latency_2);

    /* 切换系统时钟到 PLL */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while (RCC_GetSYSCLKSource() != 0x08);

    /* APB1/APB2 分频 */
    RCC_HCLKConfig(RCC_SYSCLK_Div1);
    RCC_PCLK1Config(RCC_HCLK_Div2);  // APB1 ≤ 36MHz
    RCC_PCLK2Config(RCC_HCLK_Div1);  // APB2 ≤ 72MHz

    /* 使能 GPIOC 时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
}

void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  // 推挽输出
    GPIO_Init(GPIOC, &GPIO_InitStructure);
}

/* 简易延时(非精确) */
void Delay_ms(uint32_t ms)
{
    uint32_t i, j;
    for (i = 0; i < ms; i++)
        for (j = 0; j < 12000; j++);
}

2.2 定时器中断

/* TIM2 定时器中断,1ms 周期 */
#include "stm32f10x.h"

volatile uint32_t systick_ms = 0;

void TIM2_Init(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

    /* TIM2 时钟 = APB1×2 = 72MHz,预分频 72-1 = 1MHz,周期 1000-1 = 1ms */
    TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
    TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);

    /* NVIC 配置 */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

void TIM2_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
        systick_ms++;
        if (systick_ms >= 500)
        {
            systick_ms = 0;
            GPIO_WriteBit(GPIOC, GPIO_Pin_13,
                (BitAction)!GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13));
        }
    }
}

三、Arduino (STM32duino) 例程

使用 STM32duino 需要在 Arduino IDE 中安装 STM32 Coreshttp://dan.drown.org/stm32duino/package_STM32duino_index.json),选择 Board 为 "Generic STM32F103C series"。

3.1 LED 闪烁(Arduino 风格)

// Blue Pill 板载 LED 在 PC13
void setup()
{
    pinMode(PC13, OUTPUT);
    Serial.begin(115200);  // USART1: PA9(TX), PA10(RX)
}

void loop()
{
    digitalWrite(PC13, LOW);   // LED ON (低电平点亮)
    delay(500);
    digitalWrite(PC13, HIGH);  // LED OFF
    delay(500);

    Serial.println("Hello from STM32F103 Blue Pill!");
}

3.2 ADC 读取与串口输出

void setup()
{
    Serial.begin(115200);
    pinMode(PA0, INPUT_ANALOG);  // PA0 模拟输入
}

void loop()
{
    int adcVal = analogRead(PA0);       // 0-4095 (12bit)
    float voltage = adcVal * 3.3 / 4096.0;
    Serial.print("ADC: ");
    Serial.print(adcVal);
    Serial.print("  Voltage: ");
    Serial.print(voltage, 3);
    Serial.println(" V");
    delay(200);
}

3.3 I2C OLED 显示

#include <Wire.h>
#include <Adafruit_SSD1306.h>

#define OLED_ADDR 0x3C
Adafruit_SSD1306 display(128, 64, &Wire, -1);

void setup()
{
    Wire.begin();           // I2C1: PB6(SCL), PB7(SDA)
    display.begin(SSD1306_SWITCHCAPVCC, OLED_ADDR);
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(SSD1306_WHITE);
    display.setCursor(10, 20);
    display.println("STM32duino");
    display.display();
}

void loop()
{
    // 无需循环操作
}

四、开发环境搭建指南

平台 编译工具链 烧录工具 难度
STM32CubeIDE GCC ARM 内置 ST-Link / OpenOCD ⭐⭐
Keil MDK ARMCC 内置 ST-Link ⭐⭐⭐
Arduino IDE GCC ARM STM32duino bootloader / ST-Link
PlatformIO (VSCode) GCC ARM OpenOCD / ST-Link ⭐⭐

推荐组合

  • 初学者:Arduino IDE + STM32duino,快速上手
  • 进阶学习:STM32CubeIDE + HAL 库,官方工具链,CubeMX 图形化配置
  • 工程开发:Keil MDK + 标准外设库 / HAL 库

信息

路径
/firmware/开发板/STM32F103C8T6 Blue Pill/STM32F103C8T6 Blue Pill 代码例程.md
更新时间
2026/5/26