JLC Foundation Board PWM LED Demo | Notes / STM32 | 氵工的博客

JLC Foundation Board PWM LED Demo

发表于 2026-04-02 22:38 1491 字 8 min read

729DHS avatar

729DHS

氵工的博客 - 分享单片机开发、Linux、机器人技术、RL强化学习与嵌入式项目的学习笔记与实践记录。涵盖STM32、FreeRTOS、Rust、R语言等技术的详细教程与调试经验。

Google 未收录此页面? 在 Search Console 中请求编入索引
JLC Foundation Board PWM LED demo, using the onboard PB8 LED.

PWM LED Control Project Documentation

1. Project Overview

This project is an LED brightness control example based on the STM32F407 microcontroller. It uses PWM (Pulse Width Modulation) technology to achieve dynamic LED brightness adjustment. The project is developed using the STM32 HAL library, uses the TIM10 timer to generate PWM signals, controls LED brightness by changing the duty cycle, and implements an LED breathing light effect.

2. Technical Framework

2.1 Hardware Platform

  • Microcontroller: STM32F407
  • Timer: TIM10
  • PWM Output Pin: TIM10_CH1

2.2 Software Architecture

  • Development Environment: STM32CubeMX + VScode
  • Library: STM32 HAL library
  • Code Structure: Standard STM32 HAL project structure

3. Code Structure Analysis

3.1 Header Files

#include "main.h"

Includes the main header file, which defines the basic configuration and function declarations of the STM32 HAL library.

3.2 Variable Definitions

TIM_HandleTypeDef htim10;

Defines the handle for the TIM10 timer, used for timer operations.

3.3 Constant Definitions

static const uint16_t LED_PWM_DUTY_MAX = 60000U;   // PWM maximum duty cycle value
static const uint16_t LED_PWM_DUTY_MIN = 0U;       // PWM minimum duty cycle value
static const uint16_t LED_FADE_STEPS = 70U;        // Breathing light fade steps
static const uint32_t LED_FADE_STEP_MS = 8U;        // Delay time per step (milliseconds)
static const uint32_t LED_PEAK_HOLD_MS = 160U;     // Maximum brightness hold time (milliseconds)
static const uint32_t LED_VALLEY_HOLD_MS = 120U;   // Minimum brightness hold time (milliseconds)

These constants define various parameters for the LED breathing light effect, including PWM duty cycle range, fade steps, and timing parameters.

3.4 Function Prototypes

void SystemClock_Config(void);              // System clock configuration
static void MX_GPIO_Init(void);             // GPIO initialization
static void MX_TIM10_Init(void);            // TIM10 timer initialization
static void LED_SetBrightness(uint16_t duty);      // Set LED brightness
static void LED_GentleFade(uint16_t start_duty, uint16_t end_duty);  // LED fade effect

4. Main Function Implementation

4.1 Main Function

int main(void)
{
  // System initialization
  HAL_Init();
  SystemClock_Config();

  // Peripheral initialization
  MX_GPIO_Init();
  MX_TIM10_Init();

  // Start PWM output
  if (HAL_TIM_PWM_Start(&htim10, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  LED_SetBrightness(LED_PWM_DUTY_MIN);

  // Main loop
  while (1)
  {
    LED_GentleFade(LED_PWM_DUTY_MIN, LED_PWM_DUTY_MAX);
    HAL_Delay(LED_PEAK_HOLD_MS);
    LED_GentleFade(LED_PWM_DUTY_MAX, LED_PWM_DUTY_MIN);
    HAL_Delay(LED_VALLEY_HOLD_MS);
  }
}

The main function first performs system initialization, then configures GPIO and TIM10 timer, and starts PWM output. In the main loop, the LED breathing light mode is achieved through the LED_GentleFade function to create smooth brightness transitions.

4.2 System Clock Configuration

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  // Configure main internal regulator output voltage
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  // Initialize RCC oscillator
  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 = 4;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  // Initialize CPU, AHB, and APB bus clocks
  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_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

The system clock configuration function uses HSE (external high-speed clock) as the PLL clock source and generates a 168MHz system clock through PLL multiplication. It configures clock dividers for CPU, AHB, and APB buses, achieving clock distribution for the entire system.

4.3 TIM10 Timer Initialization

static void MX_TIM10_Init(void)
{
  TIM_OC_InitTypeDef sConfigOC = {0};

  htim10.Instance = TIM10;
  htim10.Init.Prescaler = 0;
  htim10.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim10.Init.Period = 65535;
  htim10.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim10.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  if (HAL_TIM_Base_Init(&htim10) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim10) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = LED_PWM_DUTY_MAX;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim10, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  HAL_TIM_MspPostInit(&htim10);
}

The TIM10 timer initialization function configures the timer’s basic parameters and PWM output channel. Key parameters include:

  • Prescaler: 0
  • Counter Mode: Up counting
  • Auto-reload Value (Period): 65535
  • PWM Mode: PWM1 mode
  • Output Polarity: Active high

4.4 GPIO Initialization

static void MX_GPIO_Init(void)
{
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
}

The GPIO initialization function enables GPIO port clocks to provide clock support for the PWM output pin.

4.5 LED Brightness Setting Function

static void LED_SetBrightness(uint16_t duty)
{
  __HAL_TIM_SET_COMPARE(&htim10, TIM_CHANNEL_1, duty);
}

The LED_SetBrightness function changes the PWM duty cycle by setting the comparison register (CCR) value of TIM10 channel 1, thereby controlling LED brightness. Higher duty cycle means brighter LED; lower duty cycle means dimmer LED.

4.6 LED Fade Effect Function

static void LED_GentleFade(uint16_t start_duty, uint16_t end_duty)
{
  const int32_t delta = (int32_t)end_duty - start_duty;

  for (uint16_t step = 0; step <= LED_FADE_STEPS; ++step)
  {
    const uint16_t duty = (uint16_t)(start_duty + (delta * step) / LED_FADE_STEPS);
    LED_SetBrightness(duty);
    HAL_Delay(LED_FADE_STEP_MS);
  }
}

The LED_GentleFade function implements smooth LED brightness fading. It starts from the initial duty cycle value and gradually changes to the target duty cycle value, with brief delays between each step. By adjusting LED_FADE_STEPS and LED_FADE_STEP_MS parameters, the speed and smoothness of the fade can be changed.

4.7 Error Handler Function

void Error_Handler(void)
{
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
}

The error handler function is called when an error occurs. It disables interrupts and enters an infinite loop to prevent the system from continuing to run.

5. Technical Details

5.1 PWM Principle

PWM (Pulse Width Modulation) is a technique that controls a signal by changing the pulse width. In LED control, the PWM duty cycle (ratio of high-level time to the entire period) determines the LED’s average brightness. Higher duty cycle means brighter LED; lower duty cycle means dimmer LED.

5.2 TIM10 Timer Configuration

TIM10 is a 16-bit timer on the STM32F407 with the following features:

  • 16-bit auto-reload counter
  • Up to 4 independent channels (IC, OC, or PWM)
  • Programmable prescaler
  • Repetition counter

In this project, TIM10 is configured in PWM mode using channel 1 for PWM output. The timer clock is 84MHz (APB2 bus clock), prescaler is 0, and auto-reload value is 65535, so the PWM frequency is: PWM frequency = Timer clock / (Prescaler + 1) / (Auto-reload value + 1) = 84MHz / 1 / 65536 ≈ 1281Hz

5.3 Breathing Light Effect Implementation

The breathing light effect is achieved through the LED_GentleFade function, which fades LED brightness from minimum to maximum and back from maximum to minimum. The fade process is divided into multiple steps with brief delays between each step, creating a smooth brightness change effect.

The number of fade steps and the delay time per step determine the speed and smoothness of the breathing light. More steps and longer delay per step result in a smoother but slower breathing light effect; fewer steps and shorter delays result in a more pronounced but faster effect.

5.4 STM32 HAL Library Usage

This project is developed using the STM32 HAL library, which provides rich functions and structures that simplify peripheral configuration and usage. For example:

  • HAL_Init(): Initialize the HAL library
  • HAL_RCC_OscConfig(): Configure system clock source
  • HAL_RCC_ClockConfig(): Configure system clocks
  • HAL_TIM_Base_Init(): Initialize timer basic functions
  • HAL_TIM_PWM_Init(): Initialize timer PWM functions
  • HAL_TIM_PWM_Start(): Start PWM output
  • __HAL_TIM_SET_COMPARE(): Set timer comparison value

5.5 Code Structure and Comment Standards

This project follows the code structure generated by STM32CubeMX, using specific comment markers for user code areas, such as:

  • /* USER CODE BEGIN Header / and / USER CODE END Header */
  • /* USER CODE BEGIN Includes / and / USER CODE END Includes */
  • /* USER CODE BEGIN 2 / and / USER CODE END 2 */
  • /* USER CODE BEGIN 3 / and / USER CODE END 3 */
  • /* USER CODE BEGIN 4 / and / USER CODE END 4 */

This structure ensures that user code is not overwritten when regenerating code, improving code maintainability.

6. Project Features

  1. Modular Design: LED control functionality is encapsulated in independent functions, making it easy to maintain and extend.
  2. Parameterized Configuration: Constants are used to define breathing light effect parameters for easy adjustment.
  3. Error Handling: Basic error handling mechanism is implemented.
  4. Code Standards: Follows STM32 HAL library code standards and comment style.
  5. Scalability: The code structure is clear, making it easy to add new features or modify existing ones.

7. Application Scenarios

The PWM LED control technology implemented in this project can be applied to various scenarios:

  • LED lighting control
  • Indicator brightness adjustment
  • Decorative lighting effects
  • Backlight brightness adjustment
  • Signal light control

8. Summary

This project demonstrates how to use the STM32F407 timer’s PWM function to achieve LED brightness control and breathing light effects. Through reasonable timer parameter configuration and writing control functions, smooth LED brightness adjustment is achieved. The code structure is clear, follows STM32 HAL library standards, and has good maintainability and scalability. This example can serve as a reference for learning STM32 timer PWM functions and LED control technology.