文档
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 Cores(http://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 库