STM32入门学习之定时器PWM输出

1.脉冲宽度调制PWM(Pulse Width Modulation)是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。PWM可以理解为高低电平的占空比,即输出高电平时间与低电平时间的比值。PWM的应用是否广泛,比如在步进电机的控制中,可以通过PWM来控制电机的速度。PWM的原理图如下所示。

 如图中所示,当CNT的值小于ARR时,I/O输出低电平;当CNT的值大于等于ARR时,I/O输出高电平。当CNT的值等于ARR时,CNT的值归零,然后重新向上计数(向上或向下计数可以自行设置)。CNT(TIMx_CNT寄存器是定时器的计数器,该寄存器存储了当前定时器的计数值。)。因此,通过修改自动装载寄存器ARR的值,就可以改变PWM的输出频率。

简单来说,就是设置了自动装载寄存器ARR的值,然后定时器计数CNT,根据CNT与ARR的大小关系,使I/O输出不同的电平。

2.相关寄存器介绍:(寄存器TIMx_CR1、TIMx_PSC、TIMx_ARR、TIMx_SR的介绍请查看:CSDN)

(1)捕获比较模式寄存器(TIMx_CCR1/2):TIMx_CCR1、TIMx_CCR2。

如图所示,第一行为输出时的设置,第二行是输入时的配置。

OCxM是模式设置位,由3位组成,可以控制7种模式。使用PWM模式时,必须设置为110/111。这两种模式的区别是输出的电平极性相反。

CCxS是通道方向的设置位(输入/输出),默认为0,即作为输出使用。

(2)捕获比较使能寄存器(TIMx_CCER):该寄存器控制着各个输入输出通道的开关。

本次实验中只使用到了CC1E位(输入/输出使能位),需要设置为1。

(3)捕获/比较寄存器(TIMx_CCR1~4):TIMx_CCR1、TIMx_CCR2、TIMx_CCR3、TIMx_CCR4。

 在输出模式下,该寄存器的值与定时器的计数值CNT比较,并根据结果使I/O输出高低电平。

(4)刹车和死区寄存器(TIMx_BDTR):该寄存器只有高级定时器需要配置,普通定时器不需要配置此寄存器。本次实验中,实验的普通定时器TIM1,不需要配置此定时器。

如果想要高级定时器正常输出PWM,MOR为必须设置为1。

3.设计思路:首先,使能相应的时钟。然后,配置PA8为复用输出(TIM1_CH1的是和PA8复用的。同时,PA8外接了LED)。其次,设置TIM1的ARR和PSC。最后设置TIM1_CH1的PWM模式和通道方向,使能TIM1的CH1输出。

4.代码:

(1)delay:

#ifndef __DELAY_H
#define __DELAY_H#include "stm32f10x.h"void delay_us(uint32_t us);									//ÑÓʱ΢Ãë
void delay_ms(uint32_t ms);									//ÑÓʱºÁÃë#endif
#include "delay.h"void delay_us(uint32_t us)
{uint32_t i;//1.Ñ¡ÔñHCLKʱÖÓ£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµSysTick_Config(72);for(i = 0;i < us;i++){while(!((SysTick->CTRL) & (1 << 16)));		//µÈ´ý¼ÆÊýÍê³É}SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	//Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}void delay_ms(uint32_t ms)
{uint32_t i;//1.Ñ¡ÔñHCLKʱÖÓÔ´£¬²¢ÉèÖõδðʱÖÓ¼ÆÊýÖµSysTick_Config(72000);for(i = 0;i < ms;i++){while(!((SysTick->CTRL) & (1 << 16)));		//µÈ´ý¼ÆÊýÍê³É}SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;	//Ñ¡ÔñSTCLKʱÖÓÔ´£¬²¢Ê§Äܶ¨Ê±Æ÷
}

(2)led:

#ifndef __LED_H
#define	__LED_H#include "stm32f10x.h"void LED_Init(void);#endif
#include "led.h"void LED_Init(void)
{//¶¨Òå¶Ë¿ÚµÄ½á¹¹Ìå:GPIO_InitTypeDef GPIO_InitStruct;//1.ʹÄÜʱÖÓ£ºRCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOA,ENABLE);//2.ÅäÖö˿ڽṹÌåµÄÏà¹ØÐÅÏ¢£º£¨LED1£©GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOD,&GPIO_InitStruct);//ÅäÖÃLED0£ºGPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;GPIO_Init(GPIOA,&GPIO_InitStruct);//³õʼʱ½«LEDµÄ¶Ë¿Ú¶¼ÖÃΪ1£¬¼´Ï¨ÃðGPIO_SetBits(GPIOA,GPIO_Pin_8);GPIO_SetBits(GPIOD,GPIO_Pin_2);
}

(3)pwm:

#ifndef __PWM_H
#define __PWM_H#include "stm32f10x.h"void PWM_Init(u16 arr,u16 psc);#endif
#include "pwm.h"/*±¾´ÎʵÑéÖÐÊÇʹÓÃTIM1Êä³öPWM£¬TIM1ʹÓÃÐèÒª¸´ÓÃPA8ΪÊä³ö*/
void PWM_Init(u16 arr,u16 psc)
{	//¶¨ÒåÏà¹ØµÄ½á¹¹Ì壺GPIO_InitTypeDef GPIO_InitStrcture;TIM_TimeBaseInitTypeDef TIM_InitStructure;TIM_OCInitTypeDef TIM_OCInitStructure;//1.ʹÄÜʱÖÓ£ºRCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOA,ENABLE);//2.ÅäÖÃGPIOA.8½á¹¹ÌåÐÅÏ¢£ºGPIO_InitStrcture.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStrcture.GPIO_Pin = GPIO_Pin_8;GPIO_InitStrcture.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStrcture);//3.ÅäÖÃTIM1½á¹¹ÌåÐÅÏ¢£ºTIM_InitStructure.TIM_Period = arr;TIM_InitStructure.TIM_Prescaler = psc;TIM_InitStructure.TIM_ClockDivision = 0;TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Down;TIM_TimeBaseInit(TIM1,&TIM_InitStructure);//4.ÅäÖÃTIM1_CH1µÄPWMģʽºÍͨµÀ·½Ïò£ºTIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;TIM_OC1Init(TIM1,&TIM_OCInitStructure);//5.ʹÄÜÏà¹Ø¼Ä´æÆ÷£ºTIM_CtrlPWMOutputs(TIM1,ENABLE);			//ʹÄÜÖ÷Êä³öTIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable);	//CH1ԤװÔØʹÄÜTIM_ARRPreloadConfig(TIM1,ENABLE);		//ʹÄÜTIMxµÄARRµÄԤװÔؼĴæÆ÷TIM_Cmd(TIM1,ENABLE);									//ʹÄÜTIM1
}

(4)main:
 

#include "stm32f10x.h"
#include "delay.h"
#include "led.h"
#include "pwm.h"int main(void)
{u8 flag = 1;u16 pwm_value = 0;LED_Init();PWM_Init(899,0);while(1){delay_ms(20);if(flag){pwm_value ++;}else{pwm_value --;}if(pwm_value > 300){//pwm_value = 0;flag = !flag;}if(pwm_value == 0){flag = !flag;}//ÉèÖÃTIM1±È½Ï/²¶»ñͨµÀ¼Ä´æÆ÷µÄÖµ£¬Í¨¹ýÐ޸ĴËÖµ¸Ä±äPWMµÄÕ¼¿Õ±ÈTIM_SetCompare1(TIM1,pwm_value);}
}

5.运行结果:可以看到LED的亮度在自动变化。

 

 6.总结:PWM是通过微控制器的数字输出,控制模拟输出。通常可以利用定时器实现PWM。PWM可以控制I/O输出高低电平的时间,通过I/O输出高低电平的时间,就可以控制外部器件工作/不工作的时间,从而控制其速度或者亮度等。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/40938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【MySQL系列】-回表、覆盖索引真的懂吗

【MySQL系列】-回表、覆盖索引真的懂吗 文章目录 【MySQL系列】-回表、覆盖索引真的懂吗一、MYSQL索引结构1.1 索引的概念1.2 索引的特点1.3 索引的优点1.4 索引的缺点 二、B-Tree与BTree2.1 B-Tree2.2 BTree2.3 B-Tree 与BTree树的区别2.4 那么为什么InnoDB的主键最好要搞成有…

【软件测试】接口测试工具APIpost

说实话&#xff0c;了解APIpost是因为&#xff0c;我的所有接口相关的文章下&#xff0c;都有该APIpost水军的评论&#xff0c;无非就是APIpost是中文版的postman&#xff0c;有多么多么好用&#xff0c;虽然咱也还不是什么啥网红&#xff0c;但是不知会一声就乱在评论区打广告…

【力扣每日一题】2023.8.14 合并二叉树

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 给我们合并两棵二叉树&#xff0c;合并的方式就是把对应位置的节点的值相加&#xff0c;最后把合并后的二叉树的根节点返回出去。 这类二…

一文看尽R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD详解

一文看尽R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD详解 以下六篇文章总结详细&#xff1a; 1. 一文读懂目标检测&#xff1a;R-CNN、Fast R-CNN、Faster R-CNN、YOLO、SSD 2. 【深度学习】R-CNN 论文解读及个人理解 3、R-CNN论文详解 4、一文读懂Faster RCNN 5、学一百遍都…

JAVA基础知识(六)——异常处理

异常 一、异常概述与异常体系结构二、常见异常三、异常处理机制一&#xff1a;try-catch-finally四、异常处理机制二&#xff1a;throws五、手动抛出异常&#xff1a;throw六、用户自定义异常类七、开发中如何选择使用try-catch-finally还是使用throws八、如何看待代码中的编译…

goland插件推荐Rider UI Theme Pack

推荐一个goland配色插件Rider UI Theme Pack&#xff0c;里面自带visual assist配色&#xff0c;配色截图如下&#xff1a; 直接在plugins里面进行搜索或者在插件home page下载后进行安装&#xff0c; 然后按照下图进行设置即可。 此插件还适用于Jetbrains旗下的Clion和Pycharm…

WX1860- ngbe-1.2.5 xdp程序在路由模式下,使用iperf工具测试数据包不转发,用jmeter可以

本地验证时重定向iperf包有出现calltrace错误&#xff0c;经推断&#xff0c;系统PAGE_SIZE<8k时可能出现&#xff08;getconf PAGE_SIZE指令可查看&#xff09;&#xff0c;按下图将ngbe_main.c的2350行ngbe_rx_bufsz改为ngbe_rx_pg_size可修复。其次&#xff0c;需要将加载…

Linux多线程【初识线程】

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; Linux学习之旅 &#x1f383;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f307;前言&#x1f3d9;️正文1、什么是线程&#xff1f;1.1、基本概念1.2、线程理解1.3、进程与线程的关系…

分布式事务与解决方案

一、什么是分布式事务 首先我们知道本地事务是指事务方法中的操作只依赖本地数据库&#xff0c;可保证事务的ACID特性。而在分布式系统中&#xff0c;一个应用系统被拆分为多个可独立部署的微服务&#xff0c;在一个微服务的事务方法中&#xff0c;除了依赖本地数据库外&#…

【深入理解ES6】块级作用域绑定

1. var声明及变量提升机制 提升&#xff08;Hoisting&#xff09;机制&#xff1a;通过关键字var声明的变量&#xff0c;都会被当成在当前作用域顶部生命的变量。 function getValue(condition){if(condition){var value "blue";console.log(value);}else{// 此处…

代码随想录算法训练营第三十六天 | 435. 无重叠区间,763.划分字母区间,56. 合并区间

代码随想录算法训练营第三十六天 | 435. 无重叠区间&#xff0c;763.划分字母区间&#xff0c;56. 合并区间 435. 无重叠区间:eyes:题目总结:eyes: 763.划分字母区间:eyes:题目总结:eyes: 56. 合并区间:eyes:题目总结:eyes: 435. 无重叠区间 题目链接 视频讲解 给定一个区间的…

并发编程系列-Semaphore

Semaphore&#xff0c;如今通常被翻译为"信号量"&#xff0c;过去也曾被翻译为"信号灯"&#xff0c;因为类似于现实生活中的红绿灯&#xff0c;车辆是否能通行取决于是否是绿灯。同样&#xff0c;在编程世界中&#xff0c;线程是否能执行取决于信号量是否允…

8.10 用redis实现缓存功能和Spring Cache

什么是缓存? 缓存(Cache), 就是数据交换的缓冲区,俗称的缓存就是缓冲区内的数据,一般从数据库中获取,存储于本地代码。 通过Redis来缓存数据&#xff0c;减少数据库查询操作; 逻辑 每个分类的菜品保存一份缓存数据 数据库菜品数据有变更时清理缓存数据 如何将商品数据缓存起…

p-级数的上界(Upper bound of p-series)

积分判别法-The Integral Test https://math.stackexchange.com/questions/2858067/upper-bound-of-p-series https://courses.lumenlearning.com/calculus2/chapter/the-p-series-and-estimating-series-value/ 两个重要级数&#xff08;p级数和几何级数&#xff09; ht…

WPF显示初始界面--SplashScreen

WPF显示初始界面–SplashScreen 前言 WPF应用程序的运行速度快&#xff0c;但并不能在瞬间启动。当第一次启动应用程序时&#xff0c;会有一些延迟&#xff0c;因为公共语言运行时&#xff08;CLR&#xff09;首先需要初始化.NET环境&#xff0c;然后启动应用程序。 对于WPF中…

高忆管理:股票T+0交易是什么意思?t+0交易有什么好处?

股票的买卖准则有很多种&#xff0c;T0买卖便是其中之一。那么股票T0买卖是什么意思&#xff1f;t0买卖有什么优点&#xff1f;高忆管理也为大家预备了相关内容&#xff0c;以供参考。 股票T0买卖是什么意思&#xff1f; T0买卖准则是指出资者当天买入的股票能够在当天卖出&am…

SpringBoot 异步、邮件任务

异步任务 创建一个Hello项目 创建一个类AsyncService 异步处理还是非常常用的&#xff0c;比如我们在网站上发送邮件&#xff0c;后台会去发送邮件&#xff0c;此时前台会造成响应不动&#xff0c;直到邮件发送完毕&#xff0c;响应才会成功&#xff0c;所以我们一般会采用多线…

神经网络基础-神经网络补充概念-03-逻辑回归损失函数

概念 逻辑回归使用的损失函数通常是"对数损失"&#xff08;也称为"交叉熵损失"&#xff09;或"逻辑损失"。这些损失函数在训练过程中用于衡量模型预测与实际标签之间的差异&#xff0c;从而帮助模型逐步调整权重参数&#xff0c;以更好地拟合数…

c++--SLT六大组件之间的关系

1.SLT六大组件&#xff1a; 容器&#xff0c;迭代器&#xff0c;算法&#xff0c;仿函数&#xff0c;适配器&#xff0c;空间配置器 2.六大组件之间的关系 容器&#xff1a;容器是STL最基础的组件&#xff0c;没有容器&#xff0c;就没有数据&#xff0c;容器的作用就是用来存…

IO流 详细介绍

一、IO流概述 1.IO&#xff1a;输入(Input读取数据)/输出(Output写数据) 2.流&#xff1a;是一种抽象概念&#xff0c;是对数据传输的总称,也就是说数据在设备间的传输称为流&#xff0c;流的本质是数据传输IO流就是用来处理设备间数据传输问题的。 3.常见的应用&#xff1a…