单片机实现PWM LED灯亮度调节及Proteus仿真项目详解
作者:Katie
日期:2025-03-31
目录
-
PWM与LED亮度调节原理
2.1 PWM控制原理
2.2 LED亮度调节原理 -
硬件电路设计
4.1 单片机与LED驱动电路
4.2 Proteus仿真环境搭建 -
软件实现方案
5.1 定时器PWM配置思路
5.2 亮度调节控制逻辑
1. 项目背景与简介
在现代嵌入式系统中,利用单片机实现PWM(脉宽调制)控制是调节LED灯亮度的常用方法。通过改变PWM信号的占空比,可以调整LED的平均电流,从而实现从全亮到全灭的亮度变化。为了验证设计的正确性,本项目不仅在实际硬件平台上实现了LED亮度调节程序,同时利用Proteus仿真软件构建虚拟电路进行仿真验证。
2. PWM与LED亮度调节原理
2.1 PWM控制原理
PWM是一种通过改变脉冲宽度来调制信号平均值的方法。其基本原理为:在固定周期内保持高低电平,通过改变高电平持续时间(占空比)实现对平均电压的控制。公式为:
其中,占空比越高,LED点亮时间越长,平均电流越大,亮度越高。
2.2 LED亮度调节原理
LED的亮度与其通过的平均电流成正比。通过PWM信号控制LED,可以实现以下效果:
-
占空比为0%:LED熄灭;
-
占空比为50%:LED亮度约为一半;
-
占空比为100%:LED全亮。
在本项目中,我们采用固定频率(例如1KHz)的PWM信号,通过调整占空比实现亮度调节。
3. 系统设计方案
3.1 项目需求与功能描述
本项目主要功能需求:
-
利用单片机内置定时器模块产生PWM信号;
-
通过软件控制改变PWM信号占空比,实现LED亮度调节;
-
通过Proteus仿真软件构建虚拟电路,实现仿真验证;
-
利用USART调试接口输出当前PWM参数,便于调试。
3.2 系统整体架构
系统主要分为:
-
PWM生成模块:利用定时器产生固定频率PWM信号,动态更新占空比;
-
LED驱动模块:通过单片机GPIO口输出PWM信号,驱动LED灯;
-
调试反馈模块:利用USART输出调试信息;
-
Proteus仿真平台:构建虚拟电路,包括单片机、LED、限流电阻、供电电源等,验证设计正确性。
4. 硬件电路设计
4.1 单片机与LED驱动电路
硬件部分选用常见的STM32F103系列单片机,连接LED驱动电路示意如下:
-
PWM输出引脚:选用STM32的PA0作为PWM输出口;
-
LED连接:LED通过限流电阻与PA0连接,LED的另一端接地(或根据具体电路设计接电源);
-
供电:单片机及LED均由稳定电源供电(例如5V或3.3V)。
4.2 Proteus仿真环境搭建
在Proteus中进行仿真时:
-
添加STM32F103C8T6芯片模型;
-
在芯片引脚上接入LED及限流电阻;
-
配置电源模块(如5V稳压电源);
-
添加虚拟串口模块(如虚拟终端),连接到USART引脚(PA9/PA10,用于调试输出,可选);
-
配置时钟参数与仿真参数,确保与代码匹配。
5. 软件实现方案
5.1 定时器PWM配置思路
通过单片机内部定时器(如TIM2)生成PWM信号:
-
设定预分频器、自动重装载寄存器(ARR)及比较寄存器(CCR);
-
频率公式为:
-
占空比计算公式:
-
本项目中设定固定PWM频率(如1KHz),通过修改CCR值改变占空比,达到调节LED亮度的目的。
5.2 亮度调节控制逻辑
-
定义全局变量记录当前占空比(0~100%);
-
通过软件接口(如按键或预设程序)改变占空比;
-
在主循环或定时任务中调用“Set_LED_Brightness”函数,更新PWM比较寄存器;
-
利用USART输出当前占空比及调试信息,便于调试与验证。
6. 详细代码实现
下面给出基于STM32F103的示例代码,整合了系统初始化、PWM配置及LED亮度调节逻辑,代码中附有详细注释,便于理解。
6.1 整合代码及详细注释
/***********************************************************************
* 文件名称:PWM_LED_Brightness_Control.c
* 项目名称:单片机实现PWM LED灯亮度调节及Proteus仿真
* 文件描述:本文件实现了利用单片机内部定时器产生PWM信号,
* 并通过动态改变PWM占空比调节LED亮度的功能。程序中
* 包含系统初始化、PWM配置、LED亮度调节函数及USART调试输出。
* 同时提供了在Proteus仿真平台下进行电路仿真的指导说明。
* 作者 :Katie
* 日期 :2025-03-31
*
* 说明:
* 1. 采用STM32F103系列单片机,通过TIM2生成PWM信号输出到PA0。
* 2. LED通过限流电阻连接到PA0,PWM占空比控制LED亮度(0%:灭,100%:全亮)。
* 3. USART1用于调试信息输出,便于在Proteus虚拟终端观察当前占空比参数。
* 4. Proteus仿真部分请参照文末“Proteus仿真步骤”部分。
***********************************************************************/
#include "stm32f10x.h" // STM32F10x标准外设库头文件
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
/*-----------------------------------------------
宏定义部分:系统参数及外设配置
-----------------------------------------------*/
#define SYSTEM_CORE_CLOCK 72000000UL // 系统核心时钟72MHz
// PWM输出配置:使用TIM2通道1,输出至PA0
#define PWM_TIM TIM2
#define PWM_CHANNEL TIM_OCMode_PWM1
#define PWM_GPIO_PORT GPIOA
#define PWM_GPIO_PIN GPIO_Pin_0
// USART调试接口(使用USART1, TX: PA9, RX: PA10)
#define DEBUG_USART USART1
#define DEBUG_BAUDRATE 115200
// PWM基本参数
#define PWM_FREQUENCY 1000 // PWM频率1KHz(周期1ms)
#define DEFAULT_DUTY_CYCLE 50 // 默认占空比50%
/*-----------------------------------------------
全局变量定义
-----------------------------------------------*/
volatile uint32_t pwmPeriod = 0; // 自动重装载寄存器ARR值
volatile uint32_t pwmPulse = 0; // 比较寄存器CCR值
volatile uint8_t currentDutyCycle = DEFAULT_DUTY_CYCLE; // 当前占空比(%)
/*-----------------------------------------------
函数声明
-----------------------------------------------*/
void System_Init(void);
void GPIO_Init_Config(void);
void USART_Init_Config(void);
void TIM_PWM_Init(void);
void Set_LED_Brightness(uint8_t dutyCycle);
void Delay_ms(uint32_t ms);
void USART_Print(const char* fmt, ...);
/*-----------------------------------------------
函数名称:System_Init
函数功能:系统初始化,配置时钟、GPIO、USART和PWM定时器
-----------------------------------------------*/
void System_Init(void)
{
SystemCoreClockUpdate();
GPIO_Init_Config();
USART_Init_Config();
TIM_PWM_Init();
}
/*-----------------------------------------------
函数名称:GPIO_Init_Config
函数功能:初始化PWM输出和USART引脚
-----------------------------------------------*/
void GPIO_Init_Config(void)
{
// 开启GPIOA时钟(PA0用于PWM,PA9/PA10用于USART)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
// 配置PA0为复用推挽输出(PWM输出)
GPIO_InitStructure.GPIO_Pin = PWM_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(PWM_GPIO_PORT, &GPIO_InitStructure);
}
/*-----------------------------------------------
函数名称:USART_Init_Config
函数功能:初始化USART1,用于调试信息输出
-----------------------------------------------*/
void USART_Init_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
// TX: PA9,复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// RX: PA10,浮空输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = DEBUG_BAUDRATE;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(DEBUG_USART, &USART_InitStructure);
USART_Cmd(DEBUG_USART, ENABLE);
}
/*-----------------------------------------------
函数名称:TIM_PWM_Init
函数功能:初始化TIM2生成PWM信号,用于LED亮度调节
-----------------------------------------------*/
void TIM_PWM_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 不采用预分频,计数器时钟 = 系统时钟
uint32_t timerClock = SYSTEM_CORE_CLOCK;
// 计算ARR值:f_PWM = timerClock / (ARR + 1)
pwmPeriod = (timerClock / PWM_FREQUENCY) - 1;
TIM_TimeBaseStructure.TIM_Period = pwmPeriod;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(PWM_TIM, &TIM_TimeBaseStructure);
// 配置PWM输出模式
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = PWM_CHANNEL;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
// 初始占空比为50%,计算CCR值:CCR = 50% * (ARR + 1)
pwmPulse = (DEFAULT_DUTY_CYCLE * (pwmPeriod + 1)) / 100;
TIM_OCInitStructure.TIM_Pulse = pwmPulse;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(PWM_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(PWM_TIM, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(PWM_TIM, ENABLE);
TIM_Cmd(PWM_TIM, ENABLE);
}
/*-----------------------------------------------
函数名称:Set_LED_Brightness
函数功能:设置LED亮度,通过更新PWM比较寄存器(CCR)改变占空比
参数说明:
dutyCycle - 目标占空比(0~100)
-----------------------------------------------*/
void Set_LED_Brightness(uint8_t dutyCycle)
{
if(dutyCycle > 100) dutyCycle = 100;
currentDutyCycle = dutyCycle;
// 计算新的CCR值
pwmPulse = (dutyCycle * (pwmPeriod + 1)) / 100;
TIM_SetCompare1(PWM_TIM, pwmPulse);
USART_Print("当前占空比: %d%%, ARR=%lu, CCR=%lu\r\n", dutyCycle, pwmPeriod, pwmPulse);
}
/*-----------------------------------------------
函数名称:Delay_ms
函数功能:简单延时函数(非精确,仅用于测试)
-----------------------------------------------*/
void Delay_ms(uint32_t ms)
{
volatile uint32_t i, j;
for(i = 0; i < ms; i++)
for(j = 0; j < 7200; j++);
}
/*-----------------------------------------------
函数名称:USART_Print
函数功能:通过USART输出调试信息,封装printf
-----------------------------------------------*/
void USART_Print(const char* fmt, ...)
{
char buffer[128];
va_list args;
va_start(args, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
uint16_t len = strlen(buffer);
for(uint16_t i = 0; i < len; i++)
{
while(USART_GetFlagStatus(DEBUG_USART, USART_FLAG_TXE) == RESET);
USART_SendData(DEBUG_USART, buffer[i]);
}
}
/*-----------------------------------------------
主函数:程序入口
-----------------------------------------------*/
int main(void)
{
System_Init();
USART_Print("PWM LED亮度调节程序启动...\r\n");
// 在Proteus仿真中可观察到LED亮度随占空比变化
// 这里示例依次改变占空比:0%、25%、50%、75%、100%,各状态保持2秒
while(1)
{
Set_LED_Brightness(0);
Delay_ms(2000);
Set_LED_Brightness(25);
Delay_ms(2000);
Set_LED_Brightness(50);
Delay_ms(2000);
Set_LED_Brightness(75);
Delay_ms(2000);
Set_LED_Brightness(100);
Delay_ms(2000);
}
return 0;
}
7. 代码解读与测试结果
7.1 系统初始化与PWM配置
-
System_Init
调用GPIO、USART和TIM2初始化函数。GPIO配置中将PA0设置为复用推挽输出(PWM输出);USART初始化配置为115200波特率,用于调试信息输出。 -
TIM_PWM_Init
根据系统时钟计算ARR值,设定PWM频率为1KHz,初始占空比50%对应的CCR值由公式计算得出。启动TIM2后PWM信号开始输出。
7.2 LED亮度调节逻辑
-
Set_LED_Brightness
根据输入的占空比参数(0~100%),重新计算CCR值,更新PWM输出。通过USART输出调试信息,便于观察当前占空比、ARR和CCR值。 -
主循环
主函数中依次改变占空比,LED亮度由低至高变化,每个状态保持2秒。通过Proteus仿真可以观察到LED亮度随占空比调整而变化。
7.3 Proteus仿真结果
在Proteus仿真环境中:
-
构建包含STM32F103、LED及限流电阻、供电模块的虚拟电路;
-
配置仿真参数(时钟、供电电压等)与代码一致;
-
通过虚拟终端(USART调试模块)可以实时查看程序输出信息;
-
仿真运行过程中LED亮度随着程序中设置的占空比变化,符合预期效果。
8. Proteus仿真步骤
-
创建工程
在Proteus中新建一个工程,选择STM32F103C8T6芯片模型。 -
添加器件
-
添加STM32F103C8T6、LED、限流电阻、稳压电源(例如5V);
-
添加虚拟串口终端(Virtual Terminal),连接到USART1的TX引脚(PA9)。
-
-
连接电路
-
将STM32的PA0连接到LED的正极,LED负极接限流电阻后接地;
-
配置LED工作电压和电阻值,确保LED正常工作;
-
连接电源,确保单片机和器件获得稳定电源。
-
-
配置仿真参数
设置STM32F103的系统时钟为72MHz,并确保仿真环境电压与代码匹配。 -
编译与加载程序
将上述代码编译生成HEX文件,在Proteus中加载HEX文件到STM32芯片模型上。 -
启动仿真
启动仿真后,通过虚拟终端观察USART输出,同时观察LED亮度变化,验证PWM调节效果。
9. 项目总结与体会
本项目通过单片机利用定时器产生PWM信号实现了LED亮度调节,同时在Proteus仿真环境中验证了设计的正确性。主要体会如下:
-
PWM调制与亮度控制
利用定时器PWM输出调节LED亮度的方法简单高效,通过改变占空比即可实现从全暗到全亮的连续调节。 -
软件调试的重要性
通过USART调试输出,可以实时监控PWM参数(ARR、CCR),便于验证计算公式与实际效果。 -
Proteus仿真验证
利用Proteus搭建虚拟电路进行仿真,有助于在实际硬件实现前排查问题、调试程序,并降低开发风险。 -
模块化设计
系统将硬件初始化、PWM配置、亮度调节及调试输出分为独立模块,便于后续扩展(如添加按键调节、远程控制等功能)。
总体来说,该项目为嵌入式系统中LED亮度调节提供了一个完整参考案例,对初学者了解PWM原理、定时器配置及Proteus仿真方法具有较高的指导意义。
10. 扩展阅读与参考资料
-
《嵌入式系统原理与实践》
-
《STM32微控制器实战开发》
-
STM32F103系列数据手册与参考手册
-
在线技术博客(如CSDN、博客园等)中关于PWM、LED控制及Proteus仿真的相关文章
-
Proteus仿真软件使用指南
结语
本文详细介绍了如何利用单片机实现PWM LED灯亮度调节,并在Proteus仿真中验证设计。文章从项目背景、PWM及LED亮度原理、系统设计、硬件电路设计、软件实现方案、详细代码实现与注释,到Proteus仿真步骤、代码解读及测试结果,全面展示了整个设计流程。
作者:Katie
希望本文能为你在嵌入式系统开发和仿真调试方面提供有益启发,欢迎在实践中不断探索和完善该方案!