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

本文共 3478 字,大约阅读时间需要 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; // 1kHz
TIM_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输出。需要注意的是,系统滴答定时器的配置和使用需要遵循特定的规则,建议参考开发板的用户手册或参考资料。

完整工程下载

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

作者:江多多 (在校学生)

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

你可能感兴趣的文章
NiuShop开源商城系统 SQL注入漏洞复现
查看>>
NI笔试——大数加法
查看>>
NLog 自定义字段 写入 oracle
查看>>
NLog类库使用探索——详解配置
查看>>
NLP 基于kashgari和BERT实现中文命名实体识别(NER)
查看>>
NLP 模型中的偏差和公平性检测
查看>>
Vue3.0 性能提升主要是通过哪几方面体现的?
查看>>
NLP 项目:维基百科文章爬虫和分类【01】 - 语料库阅读器
查看>>
NLP_什么是统计语言模型_条件概率的链式法则_n元统计语言模型_马尔科夫链_数据稀疏(出现了词库中没有的词)_统计语言模型的平滑策略---人工智能工作笔记0035
查看>>
NLP三大特征抽取器:CNN、RNN与Transformer全面解析
查看>>
NLP学习笔记:使用 Python 进行NLTK
查看>>
NLP度量指标BELU真的完美么?
查看>>
NLP的不同研究领域和最新发展的概述
查看>>
NLP的神经网络训练的新模式
查看>>
NLP采用Bert进行简单文本情感分类
查看>>
NLP问答系统:使用 Deepset SQUAD 和 SQuAD v2 度量评估
查看>>
NLP项目:维基百科文章爬虫和分类【02】 - 语料库转换管道
查看>>
NLP:使用 SciKit Learn 的文本矢量化方法
查看>>
nmap 使用方法详细介绍
查看>>
Nmap扫描教程之Nmap基础知识
查看>>