STM32F103C8T6 从点灯到深入指南

第一部分:硬件准备

1.1 所需硬件

  • STM32F103C8T6最小系统板(蓝色小板)
  • ST-Link V2下载器(或板载ST-Link的Nucleo板)
  • USB数据线
  • LED和220Ω电阻(如板载LED可省略)
  • 杜邦线若干

1.2 引脚对应关系

STM32F103C8T6常用引脚:
LED        -> PC13(板载LED,大部分板子都有)
串口1 TX  -> PA9
串口1 RX  -> PA10

第二部分:环境搭建

2.1 软件安装

  1. STM32CubeIDE官网下载
  2. STM32CubeMX:(已集成在IDE中)
  3. 驱动:安装ST-Link USB驱动

2.2 第一个工程:LED闪烁

步骤1:使用STM32CubeMX创建工程
1. 打开STM32CubeIDE → New STM32 Project
2. 选择MCU型号:STM32F103C8Tx
3. 配置系统核心:
   - SYS → Debug: Serial Wire
   - RCC → HSE: Crystal/Ceramic Resonator
4. 配置GPIO:
   - PC13 → GPIO_Output(如用板载LED)
5. 时钟配置:设置HCLK为72MHz
6. 生成代码
步骤2:编写LED闪烁代码
// 在main.c的while循环中添加
while (1)
{
  // 方法1:使用HAL库函数
  HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  HAL_Delay(500);  // 500ms延迟
  
  // 方法2:直接寄存器操作(更快)
  // GPIOC->ODR ^= GPIO_PIN_13;
  // HAL_Delay(500);
}

第三部分:深入外设学习

3.1 GPIO深入 - 按键控制LED

电路连接
按键 → PA0(外部中断)
LED  → PC13
代码实现
// 1. CubeMX配置:
// PA0 → GPIO_EXTI0,上升沿触发

// 2. 回调函数实现
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == GPIO_PIN_0)
  {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  }
}

// 3. 消抖处理(软件消抖)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  static uint32_t last_time = 0;
  uint32_t current_time = HAL_GetTick();
  
  if (current_time - last_time > 50)  // 50ms消抖
  {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    last_time = current_time;
  }
}

3.2 定时器 - 精确计时/PWM呼吸灯

定时器中断实现精确闪烁
// 1. CubeMX配置:
// TIM2 → 时钟源Internal Clock
// 预分频:7200-1,自动重载值:5000-1
// 72MHz/7200 = 10kHz,5000/10kHz = 0.5s

// 2. 开启定时器中断
HAL_TIM_Base_Start_IT(&htim2);

// 3. 中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
  if (htim->Instance == TIM2)
  {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
  }
}
PWM呼吸灯
// 1. CubeMX配置:
// TIM3 Channel1 → PA6,PWM Generation CH1
// 预分频:72-1,自动重载值:100-1
// PWM频率 = 72MHz/(72*100) = 10kHz

// 2. 启动PWM
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);

// 3. 呼吸灯效果
uint8_t brightness = 0;
int8_t direction = 1;

while (1)
{
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, brightness);
  brightness += direction;
  
  if (brightness == 0 || brightness == 100)
    direction = -direction;
  
  HAL_Delay(10);
}

3.3 串口通信 - 调试信息输出

串口配置
// 1. CubeMX配置:
// USART1 → Asynchronous
// Baud Rate: 115200
// Word Length: 8bit
// PA9: USART1_TX, PA10: USART1_RX

// 2. 重定向printf(在main.c中添加)
#include <stdio.h>

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif

PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
  return ch;
}

// 3. 使用printf调试
printf("System Start!\r\n");
printf("LED State: %d\r\n", HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13));

3.4 ADC - 电位器读取

ADC单次转换
// 1. CubeMX配置:
// ADC1 → IN0 (PA0)
// Resolution: 12bit
// Scan Conversion Mode: Disabled
// Continuous Conversion Mode: Disabled

// 2. 读取ADC值
uint32_t adc_value = 0;

HAL_ADC_Start(&hadc1);
if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
{
  adc_value = HAL_ADC_GetValue(&hadc1);
}
HAL_ADC_Stop(&hadc1);

// 3. 转换为电压值
float voltage = (adc_value * 3.3) / 4095.0;
printf("ADC Value: %ld, Voltage: %.2fV\r\n", adc_value, voltage);

第四部分:综合项目

项目1:智能呼吸灯

// 功能:ADC控制PWM呼吸频率
while (1)
{
  // 读取电位器值控制呼吸速度
  HAL_ADC_Start(&hadc1);
  HAL_ADC_PollForConversion(&hadc1, 100);
  uint32_t adc_val = HAL_ADC_GetValue(&hadc1);
  HAL_ADC_Stop(&hadc1);
  
  // ADC值映射到延时时间(10-100ms)
  uint32_t delay_time = 10 + (adc_val * 90) / 4095;
  
  // 呼吸灯效果
  for(int i=0; i<100; i++)
  {
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, i);
    HAL_Delay(delay_time);
  }
  for(int i=100; i>0; i--)
  {
    __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, i);
    HAL_Delay(delay_time);
  }
}

项目2:串口命令控制LED

// 串口接收回调
char rx_buffer[32];
uint8_t rx_index = 0;

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  if (rx_buffer[0] == '1')
  {
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
    printf("LED ON\r\n");
  }
  else if (rx_buffer[0] == '0')
  {
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
    printf("LED OFF\r\n");
  }
  else if (rx_buffer[0] == 't')
  {
    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    printf("LED Toggled\r\n");
  }
  
  // 继续接收
  HAL_UART_Receive_IT(&huart1, (uint8_t*)rx_buffer, 1);
}

// 在主函数初始化中开启接收中断
HAL_UART_Receive_IT(&huart1, (uint8_t*)rx_buffer, 1);

第五部分:调试技巧

5.1 常用调试方法

  1. LED指示:不同状态用不同闪烁模式
  2. 串口打印:printf输出变量值
  3. 逻辑分析仪:观察GPIO波形
  4. 调试器:单步执行、断点、查看变量

5.2 故障排除

// 检查时钟是否配置正确
SystemCoreClockUpdate();
printf("System Clock: %ld Hz\r\n", SystemCoreClock);

// 检查外设时钟是否使能
if (__HAL_RCC_GPIOA_IS_CLK_ENABLED())
  printf("GPIOA Clock Enabled\r\n");

// 检查引脚配置
GPIO_InitTypeDef GPIO_InitStruct = {0};
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

第六部分:进阶学习路径

下一步建议

  1. 学习DMA:实现ADC+UART的数据传输
  2. I2C/SPI:连接OLED、传感器
  3. FreeRTOS:多任务管理系统
  4. USB:实现USB虚拟串口
  5. CAN总线:工业通信

实用工具

  • STM32CubeMonitor:实时数据可视化
  • Wireshark:分析串口/USB数据
  • VOFA+:串口波形显示工具

快速参考命令

# 常见问题:
1. 程序不运行? → 检查BOOT0/BOOT1引脚
2. 无法下载? → 检查ST-Link连接
3. 串口无输出? → 检查波特率、TX/RX接线
Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐