STM32 学习笔记(七)定时器中断:输出比较_stm32 ccr-程序员宅基地

技术标签: # STM32  stm32  学习  单片机  

输出比较

电机相关比较重要。

OC Output Compare(IC 是输入捕获,CC代指这两个单元),用于输出一定频率和占空比的PWM波形。

image-20230425203158414

右下角四个就是CCR。只有通用计时器和高级计时器有,共用一个cnt计数器,高级计数器的前三个ccr寄存器还有死区比较和互补输出功能,可以驱动三相电机。

PWM(Pulse Width Modulation)脉冲宽度调制,在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域。

image-20230429212942091

按一定频率置0置1,可以改变电机综合速度。LED也是,我们人眼看着就觉得灯有亮度,实际上就是按一定频率闪烁就会呈现不同的亮度。

周期Ts,占空比Ton/Ts(置1的时间占总周期比例),频率=周期倒数,分辨率是占空比变化步距。

image-20230429213917384

输入模式:

模式 描述
冻结 CNT=CCR时,REF保持为原状态
匹配时置有效电平 CNT=CCR时,REF置有效电平
匹配时置无效电平 CNT=CCR时,REF置无效电平
匹配时电平翻转 CNT=CCR时,REF电平翻转
强制为无效电平 CNT与CCR无效,REF强制为无效电平
强制为有效电平 CNT与CCR无效,REF强制为有效电平
PWM模式1 向上计数:CNT<CCR时,REF置有效电平,CNT≥CCR时,REF置无效电平 向下计数:CNT>CCR时,REF置无效电平,CNT≤CCR时,REF置有效电平
PWM模式2 向上计数:CNT<CCR时,REF置无效电平,CNT≥CCR时,REF置有效电平 向下计数:CNT>CCR时,REF置有效电平,CNT≤CCR时,REF置无效电平

强制模式比如断开输入的时候。

TIMx_CCER里也可以设置极性。

整体处理逻辑:

image-20230429220013581

image-20230429233415904

频率周期和普通定时器一样,占空比也很好理解。

分辨率就是arr的最小值的倒数。

至于高级计时器,暂时简单了解其区别即可:

image-20230430000755685

两个互补输出可以接到推挽电路上,死区生成电路使得两管切换有一定延迟。

舵机:输入一个角度,舵机停止在固定角度。周期20ms,高电平宽度0.5-2.5ms。

image-20230430002606313

舵机三个角,±极,信号线。(5V)信号线内部有驱动电路,所以可以直接接。

直流电机正向流正向转,反向电流反向转。无法直接驱动,需要依靠 TB6612 芯片驱动。

由两个推挽电路构成,一个H型电路,中间是电机。电流从左上到右下和右上到左下正好流经中间是相反的。

image-20230430004135017

image-20230430004207178

VM:驱动电路。

VCC:控制电路,比如我们32的3.3v。

PWMA PWMB是两个信号端,另外两个引脚可以接任意GPIO口。PWM 控制频率的改变,IN一直保持一个状态即可。

STNDBY 待机控制引脚,接地待机,接VCC工作。

代码:PWM LED呼吸灯

打开TIM GPIO,配置时基单元,配置输出比较单元(CCR值,模式,极性选择,使能输出),配置推挽输出GPIO,启动计数器。

函数:

image-20230430043729585

初始化和赋初值。

image-20230430043819308

强制输出,但是可以被占空比100% 0%替代,所以不常用。

image-20230430050239274

先加载到影子寄存器中。并不会立刻更新ccr。

image-20230430123446162

快速使能,清除ref。

image-20230430123557436

设置输出通道极性,N是互补。这里的设置在初始化时就全做了,这些函数是可以单独修改的。

image-20230430123802337

单独设置输出使能参数。

image-20230430123847995

单独设置输出比较模式。

image-20230430123932130

单独修改ccr寄存器,这个比较重要,比如呼吸灯,占空比是一直改变的。

image-20230430124030903

这个是使能高级定时器会用。

这里选用哪个引脚是有依据的:

image-20230130163347869

PA0是TIM2,CH1的引脚。也可以用AFIO复用其他引脚,避免冲突。

GPIO 要设置成复用功能 AF_PP 方可断开数据寄存器引脚,连接复用功能。

image-20230430171804667

首先我们写一个简单的初始化函数,给定ccr寄存器值,让pwm输出是不会变化的固定值,这样显示的结果是led的亮度随着我们给的ccr值而变亮/暗。

void PWM_Init(void){
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_InternalClockConfig(TIM2);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period=100-1;
    TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    
    //PA0对应定时器2,oc channel1.
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);//防止漏赋初值出错,而且再更改想改的赋值简单一些
    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;
    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse=50;//ccr
    TIM_OC1Init(TIM2,&TIM_OCInitStructure);
    
    TIM_Cmd(TIM2,ENABLE);
}

设置周期100,ccr的值/100就是占空比,当前设置为50%亮度。设置10就是10%亮度。

用 keil 自带示波器看一下a0输出波形:

image-20230501002825514

可以通过 TIM_SetCompare1(TIM2,i); 改变ccr值。

while(1){
    
        for(i=0;i<100;i++){
    
            TIM_SetCompare1(TIM2,i);
            Delay_ms(10);
        }
        for(i=100;i>0;i--){
    
            TIM_SetCompare1(TIM2,i);
            Delay_ms(10);
        }
    }

引脚重映射

image-20230130163347869

如图,TIM2_CH1可以重映射到PA15上。

首先需要开启 AFIO, RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

前面介绍过 AFIO 重映射函数:void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState) ,第一个参数选取什么呢?

数据手册里说:

image-20230501011958981

image-20230501012245153

所以我们选择部分重映像1或完全重映像都行。

然后我们需要取消PA15原来的功能:

image-20230501025047724

第一个:只取消NoJTRST调试的,也就是PB4.

第二个:取消PA15,PB3,PB4这三个JTAG调试端口。

第三个:解除JTAG和SWJ的端口,千万千万千万千万不能用,因为一旦烧录了,我们的板子就再也没法通过stlink下载了。需要用串口处理了。

代码上只是改了GPIO Pin,增加了AFIO重映射。

void PWM_Init(void){
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    GPIO_PinRemapConfig(GPIO_PartialRemap1_TIM2,ENABLE);
    GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    TIM_InternalClockConfig(TIM2);
    
    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
    TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInitStructure.TIM_Period=100-1;
    TIM_TimeBaseInitStructure.TIM_Prescaler=720-1;
    TIM_TimeBaseInitStructure.TIM_RepetitionCounter=0;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStructure);
    
    //PA0对应定时器2,oc channel1.
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_OCStructInit(&TIM_OCInitStructure);//防止漏赋初值出错,而且再更改想改的赋值简单一些
    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OCNPolarity=TIM_OCNPolarity_Low;
    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse=50;//ccr
    TIM_OC1Init(TIM2,&TIM_OCInitStructure);
    
    TIM_Cmd(TIM2,ENABLE);
}

代码:PWM舵机

5V接在stlink上,不要接在面包板上。

和LED呼吸灯相比,可以通过固定的占空比比值来确定旋转角度。

image-20230501033352391

频率:1/20ms=50Hz, 即72M/(arr+1)*(psc+1)=50

ccr和arr+1成一定比例。比如period设置为200-1; psc设置为7200-1; 则ccr按比例可以设为5 10 15 20 25.

当然这样的角度不是很直观,我们可以写一个封装函数,传入角度,转动相应角度。

代码:直流电机

需要用到电机驱动模块。

image-20230514111855619

AN控制方向,随便接GPIO,PWMA接PWM输出。

和之前的输出比较没啥区别,还是我们给定一个ccr参数控制速度。AN的两个GPIO脚要初始化,初始化后一个SetBits一个ResetBits,来控制转向。

void Motor_Init(){
    
    
    //方向控制的引脚:AN设置
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
    
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    PWM_Init();
}

void Motor_SetSpeed(int8_t speed){
    

    if(speed>0){
    
        //方向脚一高一低
        GPIO_SetBits(GPIOA, GPIO_Pin_4);
        GPIO_ResetBits(GPIOA, GPIO_Pin_5);
        TIM_SetCompare3(TIM2,speed);
    }
    else{
    
        GPIO_SetBits(GPIOA, GPIO_Pin_5);
        GPIO_ResetBits(GPIOA, GPIO_Pin_4);
        TIM_SetCompare3(TIM2,-speed);
    }
}

转动时有蜂鸣器般的噪声,可以通过调大频率解决,也就是prescaler和period参数调小点,频率就大了。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/jtwqwq/article/details/130669006

智能推荐

软件测试流程包括哪些内容?测试方法有哪些?_测试过程管理中包含哪些过程-程序员宅基地

文章浏览阅读2.9k次,点赞8次,收藏14次。测试主要做什么?这完全都体现在测试流程中,同时测试流程是面试问题中出现频率最高的,这不仅是因为测试流程很重要,而是在面试过程中这短短的半小时到一个小时的时间,通过测试流程就可以判断出应聘者是否合适,故在测试流程中包含了测试工作的核心内容,例如需求分析,测试用例的设计,测试执行,缺陷等重要的过程。..._测试过程管理中包含哪些过程

政府数字化政务的人工智能与机器学习应用:如何提高政府工作效率-程序员宅基地

文章浏览阅读870次,点赞16次,收藏19次。1.背景介绍政府数字化政务是指政府利用数字技术、互联网、大数据、人工智能等新技术手段,对政府政务进行数字化改革,提高政府工作效率,提升政府服务质量的过程。随着人工智能(AI)和机器学习(ML)技术的快速发展,政府数字化政务中的人工智能与机器学习应用也逐渐成为政府改革的重要内容。政府数字化政务的人工智能与机器学习应用涉及多个领域,包括政策决策、政府服务、公共安全、社会治理等。在这些领域,人工...

ssm+mysql+微信小程序考研刷题平台_mysql刷题软件-程序员宅基地

文章浏览阅读219次,点赞2次,收藏4次。系统主要的用户为用户、管理员,他们的具体权限如下:用户:用户登录后可以对管理员上传的学习视频进行学习。用户可以选择题型进行练习。用户选择小程序提供的考研科目进行相关训练。用户可以进行水平测试,并且查看相关成绩用户可以进行错题集的整理管理员:管理员登录后可管理个人基本信息管理员登录后可管理个人基本信息管理员可以上传、发布考研的相关例题及其分析,并对题型进行管理管理员可以进行查看、搜索考研题目及错题情况。_mysql刷题软件

根据java代码描绘uml类图_Myeclipse8.5下JAVA代码导成UML类图-程序员宅基地

文章浏览阅读1.4k次。myelipse里有UML1和UML2两种方式,UML2功能更强大,但是两者生成过程差别不大1.建立Test工程,如下图,uml包存放uml类图package com.zz.domain;public class User {private int id;private String name;public int getId() {return id;}public void setId(int..._根据以下java代码画出类图

Flume自定义拦截器-程序员宅基地

文章浏览阅读174次。需求:一个topic包含很多个表信息,需要自动根据json字符串中的字段来写入到hive不同的表对应的路径中。发送到Kafka中的数据原本最外层原本没有pkDay和project,只有data和name。因为担心data里面会空值,所以根同事商量,让他们在最外层添加了project和pkDay字段。pkDay字段用于表的自动分区,proejct和name合起来用于自动拼接hive表的名称为 ..._flume拦截器自定义开发 kafka

java同时输入不同类型数据,Java Spring中同时访问多种不同数据库-程序员宅基地

文章浏览阅读380次。原标题:Java Spring中同时访问多种不同数据库 多样的工作要求,可以使用不同的工作方法,只要能获得结果,就不会徒劳。开发企业应用时我们常常遇到要同时访问多种不同数据库的问题,有时是必须把数据归档到某种数据仓库中,有时是要把数据变更推送到第三方数据库中。使用Spring框架时,使用单一数据库是非常容易的,但如果要同时访问多个数据库的话事件就变得复杂多了。本文以在Spring框架下开发一个Sp..._根据输入的不同连接不同的数据库

随便推点

EFT试验复位案例分析_eft电路图-程序员宅基地

文章浏览阅读3.6k次,点赞9次,收藏25次。本案例描述了晶振屏蔽以及开关电源变压器屏蔽对系统稳定工作的影响, 硬件设计时应考虑。_eft电路图

MR21更改价格_mr21 对于物料 zba89121 存在一个当前或未来标准价格-程序员宅基地

文章浏览阅读1.1k次。对于物料价格的更改,可以采取不同的手段:首先,我们来介绍MR21的方式。 需要说明的是,如果要对某一产品进行价格修改,必须满足的前提条件是: ■ 1、必须对价格生效的物料期间与对应会计期间进行开启; ■ 2、该产品在该物料期间未发生物料移动。执行MR21,例如更改物料1180051689的价格为20000元,系统提示“对于物料1180051689 存在一个当前或未来标准价格”,这是因为已经对该..._mr21 对于物料 zba89121 存在一个当前或未来标准价格

联想启天m420刷bios_联想启天M420台式机怎么装win7系统(完美解决usb)-程序员宅基地

文章浏览阅读7.4k次,点赞3次,收藏13次。[文章导读]联想启天M420是一款商用台式电脑,预装的是win10系统,用户还是喜欢win7系统,该台式机采用的intel 8代i5 8500CPU,在安装安装win7时有很多问题,在安装win7时要在BIOS中“关闭安全启动”和“开启兼容模式”,并且安装过程中usb不能使用,要采用联想win7新机型安装,且默认采用的uefi+gpt模式,要改成legacy+mbr引导,那么联想启天M420台式电..._启天m420刷bios

冗余数据一致性,到底如何保证?-程序员宅基地

文章浏览阅读2.7k次,点赞2次,收藏9次。一,为什么要冗余数据互联网数据量很大的业务场景,往往数据库需要进行水平切分来降低单库数据量。水平切分会有一个patition key,通过patition key的查询能..._保证冗余性

java 打包插件-程序员宅基地

文章浏览阅读88次。是时候闭环Java应用了 原创 2016-08-16 张开涛 你曾经因为部署/上线而痛苦吗?你曾经因为要去运维那改配置而烦恼吗?在我接触过的一些部署/上线方式中,曾碰到过以下一些问题:1、程序代码和依赖都是人工上传到服务器,不是通过工具进行部署和发布;2、目录结构没有规范,jar启动时通过-classpath任意指定;3、fat jar,把程序代码、配置文件和依赖jar都打包到一个jar中,改配置..._那么需要把上面的defaultjavatyperesolver类打包到插件中

VS2015,Microsoft Visual Studio 2005,SourceInsight4.0使用经验,Visual AssistX番茄助手的安装与基本使用9_番茄助手颜色-程序员宅基地

文章浏览阅读909次。1.得下载一个番茄插件,按alt+g才可以有函数跳转功能。2.不安装番茄插件,按F12也可以有跳转功能。3.进公司的VS工程是D:\sync\build\win路径,.sln才是打开工程的方式,一个是VS2005打开的,一个是VS2013打开的。4.公司库里的线程接口,在CmThreadManager.h 里,这个里面是我们的线程库,可以直接拿来用。CreateUserTaskThre..._番茄助手颜色

推荐文章

热门文章

相关标签