博客
关于我
STM32普通io口模拟pwm输出的三种方法
阅读量:631 次
发布时间:2019-03-14

本文共 3395 字,大约阅读时间需要 11 分钟。

STM32F103RB普通I/O口模拟PWM输出的三种方法

定时器中断产生PWM

如何用I/O口生成PWM?这简单,只需实现高低电平周期性切换即可。确定PWM频率后,这一周期就能被精确量化。频率确定后,想要调整占空比只需设定高电平时间的比例即可。以1kHz的频率为例,周期为1ms。如果我们想实现70%的占空比,那么高电平段的持续时间应为0.7ms。在定时器中断中,我们可以设定每0.1ms触发一次中断,通过计数器记录中断次数。当中断次数达到7次时,就可以切换到低电平状态。

第一种方法代码示例

//#include "stm32f10x.h"

#include "stdio.h"#include "usart.h"#include "tim.h"#include "led.h"#include "misc.h"

void TIM2_NVIC(void);void TIM2_Init(void);unsigned char ucLed;unsigned char ucLck;int main(void){SysTick_Config(72000); // 定时1ms (HCLK = 72MHz)TIM2_Init();TIM2_NVIC();LED_Init();while(1){LED_Disp(ucLed);}}

unsigned int count=0;unsigned int i;

void TIM2_IRQHandler(void){count++;if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){if(count%10){//占空比调整ucLed = (ucLed == 0xFF) ? 0x00 : 0xFF;LED_Disp(ucLed);}}}

这里的i是用于改变占空比的变量,通过让i做延时,使得PWM变化频率变大,产生呼吸灯的效果。通过延时处理,我们可以让占空比变化的频率与实际需求相匹配,避免直接用i++让变化过快或过慢。

第二种方法

比较+周期中断

此种方法通过定时器中的比较通道实现PWM输出。我们可以不使用IO口进行比较操作,而是在中断处理函数中直接设定输出状态。这种方式的配置相对简单,灵活度较高。通过设置定时器的比较值,可以直接控制PWM的占空比。

第二种方法代码示例

//#include "led.h"

#include "misc.h"#include "stdio.h"

void TIM2_Config(uint16_t duty1);unsigned char ucLed;unsigned int Compare2=100;unsigned int ulTick;

int main(void){SysTick_Config(72000); // 定时1ms (HCLK = 72MHz)TIM2_Config(999/4); // 25%占空比TIM_SetCompare2(TIM2, Compare2);LED_Init();while(1){if(ulTick%1000 == 0){Compare2 += 50;if(Compare2 > 999){Compare2 = 100;}TIM_SetCompare2(TIM2, Compare2);}}}

void TIM2_Config(uint16_t duty1){TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_OCInitTypeDef TIM_OCInitStructure;NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_TimeBaseStructure.TIM_Period = 999;  // 1kHzTIM_TimeBaseStructure.TIM_Prescaler = 71;  // 预分频系数TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);TIM_ClearFlag(TIM2, TIM_FLAG_Update);TIM_ITConfig(TIM2, TIM_IT_Update|TIM_IT_CC2, ENABLE);TIM_PrescalerConfig(TIM2, 71, TIM_PSCReloadMode_Immediate);TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Disable;TIM_OCInitStructure.TIM_Pulse = duty1;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;TIM_OC2Init(TIM2, &TIM_OCInitStructure);TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);TIM_Cmd(TIM2, ENABLE);// 中断处理函数void TIM2_IRQHandler(void){    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET){        ucLed = 0x00;        LED_Disp(ucLed);        TIM_ClearITPendingBit(TIM2, TIM_IT_Update);    }    else if(TIM_GetITStatus(TIM2, TIM_IT_CC2) != RESET){        ucLed = 0xff;        LED_Disp(ucLed);        TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);    }}void SysTick_Handler(void){    ulTick++;}

}

通过ulTick控制定时器周期,我们可以在循环中动态调整占空比,实现呼吸灯效果。这种方式简单且灵活,适合需要复杂占空比控制的场景。

第三种方法

系统滴答定时器

第三种方法基于系统滴答定时器(SysTick)。这种方法与第一种方法原理相同,主要通过在中断服务函数中控制I/O口状态切换实现PWM输出。需要注意的是,系统滴答定时器的配置和使用需要遵循特定的规则,建议参考开发板的用户手册或参考资料。

完整工程下载

支持第六个工程(包含两种方法)

作者:江多多 (在校学生) 版权所有,欢迎保留原文链接进行转载! 不忘初心,牢记使命,努力成为一名优秀的嵌入式工程师! (我的第六篇博客)

你可能感兴趣的文章
Quartz中时间表达式的设置-----corn表达式
查看>>
poj 1035
查看>>
POJ 1061 青蛙的约会 (扩展欧几里得)
查看>>
Quartz2.2.1简单使用
查看>>
POJ 1080 Human Gene Functions(DP:LCS)
查看>>
Quant 开源项目教程
查看>>
POJ 1088 滑雪
查看>>
POJ 1095 Trees Made to Order
查看>>
POJ 1113 Wall(计算几何--凸包的周长)
查看>>
poj 1125Stockbroker Grapevine(最短路)
查看>>
Qualitor processVariavel.php 未授权命令注入漏洞复现(CVE-2023-47253)
查看>>
poj 1151 (未完成) 扫描线 线段树 离散化
查看>>
POJ 1151 / HDU 1542 Atlantis 线段树求矩形面积并
查看>>
poj 1163 数塔
查看>>
POJ 1177 Picture(线段树:扫描线求轮廓周长)
查看>>
Qualitor checkAcesso.php 任意文件上传漏洞复现(CVE-2024-44849)
查看>>
POJ 1182 食物链(并查集拆点)
查看>>
POJ 1185 炮兵阵地 (状态压缩DP)
查看>>
POJ 1195 Mobile phones
查看>>
POJ 1228 Grandpa's Estate (稳定凸包)
查看>>