简单了解一下PWM波形就是利用定时器TIM比较器生成,就是根据CNT计时,然后PWM模式的CCR设置一个位置在0~RCC的位置,当CNT计时到CCR持平的位置就值0或者置1。

PWM波形

频率=1/Ts 置高电平的占空比=Ton/Ts 分辨率=占空比变化差距,Ts等于周期,

特别声明一次下:只有惯性系统才可以使用

PWM频率=单片机频率/psc+1/ARR+1

占空比=CCR/ARR+1

PWM分频率=1/ARR+1

下面是配置PWM波形的基本结构图

配置PWM波形是要利用定时器的,所以也要配置定时器的基本结构,这里定时器可以去这个了解一

https://blog.csdn.net/m0_64478952/article/details/123734824?spm=1001.2014.3001.5501

这里还有要知道的是输出比较通到配置的模式分几种。这里标注红色的就是用到的 PWM模式了,

可以看出来PWM1模式和PWM2模式其实就反过来的意思

输出比较模式                                                 REF意思是参考信号

模式

描述

冻结

CNT=CCR时,REF保持为原状态

配置时为有效电平

CNT=CCR时,REF保持为有效电平

配置时为无效电平

CNT=CCR时,REF保持为无效电平

配置时为电平翻转

CNT=CCR时,REF保持为电平反转

强制时为有效电平

CNT与CCR无效,REF强制为无效电平

强制时为有效电平

CNT与CCR无效,REF强制为有效电平

PWM1模式

向上计数:CNT<CCR时,REF置有效电平,CNT>=CCR时,REF置无效电平

向下计数:CNT>CCR时,REF置无效电平,CNT<=CCR时,REF置有效电平

PWM2模式

向上计数:CNT<CCR时,REF置无效电平,CNT>=CCR时,REF置有效电平

向下计数:CNT>CCR时,REF置有效电平,CNT<=CCR时,REF置无效电平

其实输出比较的意思可以看这个文件可以看出来就是进入psc分频,然后CNT开始计数,设定一个重装载得置,在这个置得中间产生一个事件信号,就是设置CCR得值得信号,因为PWM波形一定是要在这个值之内才有意义,不然超过了或者等于的时候,那么占空比是100%就没有意义了。所以这个产生的事件一定是要在这个值的范围内。也就是设置停止位。

接下来就是了解TIM定时器的引脚和比较值通道了。这个通道就是设置PWM输出比较模式的。

可以看一下这个引脚图,PA0对应着TIM2——CH1意思就是定时器2,输出通道1的意思,也就是说用到了PA0的引脚作为PWM生成的话就要配置定时器2和通道1这个功能,否则是不会有效的,这里注意就是只有引脚有标明TIM和CH这些标出才可以使用PWM输出,否则是不行的,往下面看PA1 PA2这些引脚其实都是一样的看定时器看通道,配置相应的就行了,这些都是大同小异的。

这些了解之后就开始配置引脚代码了。

首先配置通常第一步都是打开引脚时钟。

这里用到了定时器以及PA0作为PWM输出引脚所以就对应打开这两个时钟。

这里有注意的时候配置引脚的定时器是复用的功能,所以也要打开AFIO复用功能的时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启定时器2时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);  //打开GPIOA组的时钟

然后配置引脚结构体初始化,这里可以看到这个GPIO_Mode模式配置跟以往的不一样,这里也是用到AF复用的推挽模式,只有这样这个引脚输出PWM的控制权才会复用到定时器的手中。不然是没有PWM的效果的。

    GPIO_InitTypeDef  GPIO_Initstreuture;   //初始化GPIO,同时对应着下面的TIM2和CH1通道GPIO_Initstreuture.GPIO_Mode=GPIO_Mode_AF_PP;   //如果用定时器控制引脚的需要利复用推挽输出,这样控制权才能让定时器控制,才可以有PWM引脚输出GPIO_Initstreuture.GPIO_Pin=GPIO_Pin_0;        //设置GPIO——0引脚GPIO_Initstreuture.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_Initstreuture);      //结构体A组写入寄存器

接下来就是配置定时器的时基单元了。这里就没有什么可以讲的,就是根据正常的配置定时器一样。定义结构体初始化,然后设置计数模式,和重装载值以及预分频的值,这里为什么设置频率要设置100-1和36-1呢下面有一个小知识可以讲到。

TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;   //初始化时基单元结构体TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;   //时钟分屏参数,选择哪一个没有很大的问题TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up;   //时钟计数模式,分别由向上计数,向下计数,和三种中央对齐模式TIM_TimeBaseStructure.TIM_Period=100-1;     //频率计数器的值,就是一个周期记多少个数重装载的值TIM_TimeBaseStructure.TIM_Prescaler=36-1;  //预分频器的值TIM_TimeBaseStructure.TIM_RepetitionCounter=0;   //这个是高级定时器,基本通用定时器不用开启TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);    //时基单元结构体写入初始化寄存器

接下来就是这个PWM结构图的基本配置了。首先也是定义Oc通道的结构体,OC通道其实就是CH通道,然后写入结构体成员。有一段注释的是高级定时器的,这里用不到 ,现在配置的是通用定时器的。然后在下就是配置PWM模式,这里配置的是模式1,然后配置极性,再就是打开时使能,这里Pulse其实就是CCR的值,就是这一个位置,让CNT计数到这里的位置,就是占空比的值。这里设置0,是因为等下需要重新修改这个值,因为PWM其实就是一个占空比不断变化的过程,如果只设置一个值,就没有很好的利用PWM的功能。再就写入结构体写入寄存器这里寄存器其实也是有好几个的需要根据配置的引脚打开相应的通道。

    TIM_OCInitTypeDef TIMOC1_Initstruture;      //定义PWM通道TIM_OCStructInit(&TIMOC1_Initstruture);     //结构体成员写入OCS通道//高级定时器用的 //TIMOC1_Initstruture.TIM_OCIdleState=;  //TIMOC1_Initstruture.TIM_OCNIdleState=;//TIMOC1_Initstruture.TIM_OCNPolarity=;//TIMOC1_Initstruture.TIM_OutputNState=;  TIMOC1_Initstruture.TIM_OCMode=TIM_OCMode_PWM1;        //模式TIMOC1_Initstruture.TIM_OCPolarity=TIM_OCNPolarity_High;     //极性    TIMOC1_Initstruture.TIM_OutputState= TIM_OutputState_Enable;    //使能TIMOC1_Initstruture.TIM_Pulse=0;   //脉冲   CCR  //运行时控制CCR需要TIM_SetCompare1这个函数,形成不同的占空比,达到PWM效果TIM_OC1Init(TIM2,&TIMOC1_Initstruture);  //通道1

这里就是四个OC通道对应着CH四个了。

到这里完整的PWM就是差不多了,最后就是打开定时器通道开始工作

TIM_Cmd(TIM2,ENABLE);

接下来就是改变CCR的值也就是Pulse的值,这里也是每个通道对应着一个改变的函数

这里定义一个新的函数方便调用

void PWM_SetCompare3(uint16_t Compare2)
{TIM_SetCompare1(TIM2,Compare2);
}

这里也是每个通道对应一个改变比较值,这个函数意思就是设置比较值,就是CCR的值,这里意思四个通道。参数1很明了了就是设置TIM几定时器几的意思,这里是TIM2。参数2就是一个比较值,这个值可以是参数值。uint16_t,这个数据类型的范围都可以。

上面的大致初始化就我完成了,接下来就是要看看这个电机怎么操作了,电机利用TB16612这个芯片很好用也很方便,驱动电机效果也很好,但是唯一的缺点就是,最近这个热度高,芯片哄抬价格比较高。有点下贵。

用起来很方便,下面附一张接线图,这个可以接两路电机的。分别看下面对应就是了,这个其实就是一个双路H桥直流电机驱动芯片刚好就可以控制正反转。STBY接电源正常工作,接地就是待机状态。

只要电源线接好,然后PWMA线接PWM信号引脚AIN1,AIN2普通的IO口电平控制正反转就行了。

那下面就是配置一下IO口吧,就是配置一下A4和A5作为AIN1和2的两个输入引脚就好了。然后

void Motor_Init(void)
{GPIO_InitTypeDef led_Init;           //定义初始化结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);led_Init.GPIO_Mode=GPIO_Mode_Out_PP;         //模式,带上拉电阻的推挽输出led_Init.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;      //引脚led_Init.GPIO_Speed=GPIO_Speed_50MHz;          //速度GPIO_Init(GPIOA,&led_Init);     }

下面就配置一下控制电机正反转和改变CCR的值就好了

void MOtor_Setspeed(int8_t speed)
{if(speed>=0){GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare1(speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare1(-speed);}}

然后全部代码

#include "stm32f10x.h"
uint6_t num=0,num1;void MOtor_Setspeed(int8_t speed);
void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
void Motor_Init(void);
void key_Init(void);
unsigned  key_scanf(void);
int main(void)
{ PWM_Init();Motor_Init();key_Init();while(1){num=key_scanf();       //这个就是一个按键,按一次调一下速度if(num == 1){   num1+=20;if(num1>100){   num1=-100;}}   MOtor_Setspeed(num1);}}void PWM_Init(void)
{RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //开启定时器2时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //打开GPIOA组的时钟//    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);  //从映射引脚
//  GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2 ,ENABLE); //引脚重映射分配部分重映射,先打开重映射TIM2的功能
//  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//因为重映射刚好也JTD端口,所以也需要去掉。看到数据手册,TIM2,通道一部分重映射是PA15.所以初始化就可以把端口改位15,在引脚定刚好是PA15 PB3,PB4GPIO_InitTypeDef  GPIO_Initstreuture;   //初始化GPIO,同时对应着下面的TIM2和CH1通道GPIO_Initstreuture.GPIO_Mode=GPIO_Mode_AF_PP;   //如果用定时器控制引脚的需要利复用推挽输出,这样控制权才能让定时器控制,才可以有PWM引脚输出GPIO_Initstreuture.GPIO_Pin=GPIO_Pin_0;        //设置GPIO——0引脚GPIO_Initstreuture.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_Initstreuture);      //结构体A组写入寄存器TIM_InternalClockConfig(TIM2);  //内部时钟,但是不配置也可以,因为是一直开启的TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;   //初始化时基单元结构体TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;   //时钟分屏参数,选择哪一个没有很大的问题TIM_TimeBaseStructure.TIM_CounterMode= TIM_CounterMode_Up;   //时钟计数模式,分别由向上计数,向下计数,和三种中央对齐模式TIM_TimeBaseStructure.TIM_Period=100-1;     //频率计数器的值,就是一个周期记多少个数重装载的值TIM_TimeBaseStructure.TIM_Prescaler=36-1;  //预分频器的值TIM_TimeBaseStructure.TIM_RepetitionCounter=0;   //这个是高级定时器,基本通用定时器不用开启TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);    //时基单元结构体写入初始化寄存器//PWM频率 =72Mhz/(psc+1)/(arr+1)=1kz。PWM占空比=CRR/(arr+1)=50%。PWM分辨率=1/(arr+1)=1%。这是公式,需要根据不同需求改变不同的参数    TIM_OCInitTypeDef TIMOC1_Initstruture;      //定义PWM通道TIM_OCStructInit(&TIMOC1_Initstruture);     //结构体成员写入OCS通道//高级定时器用的    //TIMOC1_Initstruture.TIM_OCIdleState=;  //TIMOC1_Initstruture.TIM_OCNIdleState=;//TIMOC1_Initstruture.TIM_OCNPolarity=;//TIMOC1_Initstruture.TIM_OutputNState=;  TIMOC1_Initstruture.TIM_OCMode=TIM_OCMode_PWM1;        //模式TIMOC1_Initstruture.TIM_OCPolarity=TIM_OCNPolarity_High;     //极性    TIMOC1_Initstruture.TIM_OutputState= TIM_OutputState_Enable;    //使能TIMOC1_Initstruture.TIM_Pulse=0;   //脉冲   CCR  //运行时控制CCR需要TIM_SetCompare1这个函数,形成不同的占空比,达到PWM效果TIM_OC1Init(TIM2,&TIMOC1_Initstruture);  //通道1TIM_Cmd(TIM2,ENABLE);     //定时器开始工作}void PWM_SetCompare1(uint16_t Compare)
{TIM_SetCompare1(TIM2,Compare);}void Motor_Init(void)
{GPIO_InitTypeDef led_Init;           //定义初始化结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);led_Init.GPIO_Mode=GPIO_Mode_Out_PP;         //模式,带上拉电阻的推挽输出led_Init.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;      //引脚led_Init.GPIO_Speed=GPIO_Speed_50MHz;          //速度GPIO_Init(GPIOA,&led_Init);     }void MOtor_Setspeed(int8_t speed)
{if(speed>=0){GPIO_SetBits(GPIOA,GPIO_Pin_4);GPIO_ResetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare1(speed);}else{GPIO_ResetBits(GPIOA,GPIO_Pin_4);GPIO_SetBits(GPIOA,GPIO_Pin_5);PWM_SetCompare1(-speed);}}void key_Init(void)
{GPIO_InitTypeDef key_Init;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);key_Init.GPIO_Mode=GPIO_Mode_IPU;key_Init.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_13;key_Init.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOC,&key_Init);
}
/*   函数名:按键扫面函数
*    参数  :无
*    返回值:num 按键值当按键按下时返回值1按键1,返回2值按键2,没有按键按下的时候返回值0
*/
unsigned  key_scanf(void)
{unsigned char num=0;if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_1) == 0)  //判断按键是否按下{   Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_1) == 0);//判断按键是否按下Delay_ms(20);num=1;}if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13) == 0){   Delay_ms(20);while(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13) == 0);Delay_ms(20);num=2;}return num;
}

上面arr 设置100-1   arr设置36-1就是因为驱动电机,电机是一个线圈磁铁,如果频率太低,会产生刺激耳朵的声音,可以计算一下的  单片机的频率72000000/100-1/36-1=20khz,是一个高频来的,正常人的耳朵频率范围是20~20khz。其实20khz已近是听不到的了。所以设置为20khz就是避免电机产生刺激的声音,这只是一个小知识,如果不在意的话。完成可以随别设置。

而且arr设置100刚好CCR设置为0加到100刚好就是PWM的占空比就是CCR/ARR+1,可以看出20/100=0.2,40/100=0.4,60/100=0.6 80/100=0.8 100/100=1 这个分辨率就是20%,等于1的时候就是满转速,-负的时候就是电机反转

笔记:STM32——PWM波形生成以及控制电机相关推荐

  1. stm32电机控制定时器1_STM32通过PWM控制电机速度

    做STM32智能小车的实验中会用到定时器PWM输出,来改变直流电机的转速.分享本文了解如何通过PWM实现对电机速度的控制. PWM控制电机速度的基本原理 PWM(Pulse Width Modulat ...

  2. STM32学习笔记(六)丨TIM定时器及其应用(输入捕获丨测量PWM波形的频率和占空比)

    本篇文章包含的内容 一.输入捕获 1.1 输入捕获简介 1.2 输入捕获通道的工作原理 1.3 输入捕获的主从触发模式 1.4 输入捕获和PWMI结构 二.频率的测量方法 2.1 测频法 2.2 测周 ...

  3. STM32 PWM控制电机寄存器配置

    脉冲宽度调制PWM,实现对电机速度的控制. 1.PWM输出原理 假定定时器工作在向上计数 PWM模式,CNT为当前计数值,CCRx为捕获/比较寄存器CCRx的值(预装载值).当 CNT<CCRx ...

  4. STM32循迹小车系列教程(一)—— 使用PWM控制电机

    本章节主要讲解直流减速电机控制原理,电机驱动电路,以及如何使用PWM控制直流减速电机 前言 1.软件准备:STM32CubeMx.Keil5_ MDK 2.硬件准备:STM32F103C8T6核心板. ...

  5. STM32——用PWM控制电机

    最近在研究电机,于是想写一篇文章来记录我的学习历程.下面是用PWM来驱动电机,涉及的电机驱动是L298N. 大概的思路:初始化连接电机的IO口,配置定时器的PWM模式,配置电机IO口的电平. 代码如下 ...

  6. STM32输出PWM波形以及实现LED呼吸灯

    目录 一.PWM的简介 1.PWM的定义 2.PWM的优点 3.PWM的几种控制方法 (1)等脉宽PWM法 (2)随机PWM (3)SPWM法 4.PWM的主要参数 (1)PWM占空比 (2)PWM的 ...

  7. pwm波如何控制电机代码_PWM波控制720电机

    详细方案四:pwm与720电机控制 电机硬件分析 什么是电机? 电机(俗称"马达")是指依据电磁感应定律实现电能转换或传递的一种电磁装置.它的主要作用是产生驱动转矩,作为用电器或各 ...

  8. STM32 HAL库PID控制电机 第二章 TB6612FNG芯片驱动GB37-520电机

    STM32 HAL库PID控制电机 第二章 TB6612FNG芯片驱动GB37-520电机(HAL库) 1 电路图 2 TB6612简介 TB6612是双驱动,可同时驱动两个电机 STBY:接单片机的 ...

  9. 一个定时器生成多路PWM波形的原理和方法成都自动化开发

    在很多工程应用中,需要使用到PWM波(脉宽调制),例如电机调速.温度控制调整功率等.本文讲述怎么利用单片机的一个定时器生成多路PWM波形. 一般的,PWM的周期t1是一个固定值,如1ms,10ms,1 ...

最新文章

  1. 非常全面的AutoML资源,看这个就够了!
  2. todomvp 谷歌的MVP实例
  3. PLSQL_统计信息系列10_统计信息过旧导致程序出现性能问题
  4. 2019年第十届蓝桥杯 - 省赛 - Java研究生组 - A. 立方和
  5. JDK1.6历史版本的下载
  6. Shell编程:awk使用总结
  7. mybatis中使用SqlSessionManager进行insert操作
  8. Intellij IDEA 通过数据库表逆向生成带注释的实体类文件超级详细步骤,附详细解决方案
  9. Python的web相关及Django简介
  10. 左拥快手右抱抖音,丁磊直播究竟图什么?
  11. 什么是程序化交易?如何快速入门?
  12. [操作系统]进程同步 Reader-Writer问题 共享缓冲区问题 面包师问题 吸烟者问题
  13. windows 多开微信
  14. Android下的弹幕的简单实现
  15. python应用——用python实现对excel的查找替换
  16. Windows自带的输入法全角/半角如何切换?
  17. MySQL内置函数中的日期和时间函数详解
  18. PS学习笔记 day1
  19. Google如何增加外链?谷歌外链自动化靠谱吗?
  20. 第17课:转型的分类(图文篇)

热门文章

  1. 江苏省专精特新小巨人企业奖励政策及申报条件重点介绍,补贴50万
  2. PTA:修理牧场(哈夫曼算法)
  3. 易中天讲座免费在线学习 免费下载
  4. 不要把5G压力都留给运营商,华为自动驾驶网络是个聪明的方法
  5. 速领电商:怎么制作视频短片
  6. 装修鸿蒙瓷砖选择,我家110平新房,简单装修花16万,还是地板的瓷砖最有档次!...
  7. python发邮件,添加附件
  8. android 仿微信demo————注册功能实现(服务端)
  9. springboot+mysql+基于Android的校园综合服务App平台的设计 毕业设计-附源码181042
  10. Maven-3.maven知识点