文章目录
定时器顾名思义就是可以用来定时的,我们可以设置想要的定时时间,然后去做很多事情。STM32的定时器功能很强大,可以用来定时、计数、PWM产生、输入捕获以及定时器中断等。下面就一一介绍一下这些功能。
定时器的计数和定时器的定时功能息息相关,我个人理解为控制计数的数量来控制定时的时间,由于定时器的计数频率和计数量可调,所以可以控制定时器的计时时间。
计数频率和系统时钟、重装载值(arr)和预分频系数(psc)有关。系统时钟在前面关于时钟的学习总结中已经讲解,我们会在主函数的最开始设置系统时钟,STM32单片机的时钟一般设置为最高的72M。预分频系数是指系统时钟经过几分频作为定时器的时钟,预分频系数设置为0的时候就是1分频,也就是不分频,设置为1时候是2分频,3的时候就是4分频,4的时候…总的来说就是PSC+1倍分频。 最大重装载值就是定时器的最大计数值,STM32定时器有一个十六位的计数寄存器,最大计数值就是65535。每次配置定时器都要设置arr和psc,下面给出一段定时器配置的程序。
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=arr;
TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//定时器初始化,配置参数
这段程序中,预分频系数和最大重装载值在调用定时器初始化函数时设置。
这里顺便说一下定时器初始化结构体中的几个常用成员的含义。
和定时器计时功能关系密切的还有一个功能,那就是定时器中断。定时器中断就是在定时器的计数值达到想要的最大计数值时(可以理解为爆表),也就是想要的计时时间后,进入一次中断,在中断中执行特定的代码。
话不多说,还是通过程序来看定时器中断的配置
void TIM2_Int_Init(u16 arr,u16 psc)//定时器2中断初始化 arr为重装载值 psc为分频系数 主函数要进行中断分组
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);//定时器时钟使能
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=arr;
TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);//定时器初始化,配置参数
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);//设置更新中断
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
TIM_ARRPreloadConfig(TIM2,ENABLE);
TIM_Cmd(TIM2,ENABLE);//使能TIM2定时器
}
在这一段程序中,设置了定时器的计数时间,中断的触发方式(更新中断,也就是爆表),以及中断的优先级,以及最重要的使能中断。
有中断就肯定要有中断服务函数
void TIM2_IRQHandler()//定时器中断服务函数
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
利用定时器的输出比较可以产生PWM波,PWM是控制电机速度必不可少的一个东西。STM32一个定时器有四个通道,总共可以产生四路PWM,我们在设置产生PWM时除了要设置基本的定时器的分频系数和重装载值之外,还要设置产生PWM的通道的参数以及调用相关的使能函数。下面还是通过一段程序来展示怎么设置产生PWM。
void TIM3_PWM_Init(u16 arr,u16 psc) // 定时器3 通道2和通道1、3、4输出两路PWM波
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能定时器时钟和GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能定时器时钟和GPIO时钟
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;//配置其为复用推挽输出
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);//配置PA6,PA7口
TIM_TimeBaseInitStruct.TIM_Period=arr;
TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_ClockDivision=0;
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//初始化定时器
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC1Init(TIM3,&TIM_OCInitStruct);//配置定时器输出通道1
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM2;
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;
TIM_OC2Init(TIM3,&TIM_OCInitStruct);//配置定时器输出通道2
TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能重装载寄存器
TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能重装载寄存器
TIM_Cmd(TIM3,ENABLE);//使能整个TIM3
}
在这段程序中,设置了定时器的计数周期和通道1和通道2的输出参数并在其他地方调用输出比较函数产生PWM。

代码如下
TIM3_PWM_Init(20000-1,72-1);
TIM_SetCompare1(TIM3,10000);//PID算法实现;
TIM_SetCompare2(TIM3,10000);//PID算法实现;
这样就可以产生PWM波了!
我们总结一下PWM波的设置步骤
输入捕获也是定时器的一大功能之一,他可以测量脉冲数量和高电平以及低电平时间,话不多说,马上上程序。
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_ICInitTypeDef TIM5_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_ResetBits(GPIOA,GPIO_Pin_0);
TIM_TimeBaseInitStruct.TIM_Period=arr;
TIM_TimeBaseInitStruct.TIM_Prescaler=psc;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseInitStruct);
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn; //TIM5中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
TIM_Cmd(TIM5,ENABLE ); //使能定时器5
设置输入捕获的关键在于输入捕获初始化函数——TIM_ICInit,例程中设置了捕获通道一的上升沿。除此之外,还设置了捕获中断,在中断服务函数中计算高电平时间。代码如下
void TIM5_IRQHandler()
{
if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
定时器的功能非常强大,而且比较复杂,我们可以看出,不管是定时器中断还是产生PWM亦或是输入捕获,都要设置定时器的基本参数,arr和psc以及时钟分频,然后再设置相关的参数,如中断优先级、输入捕获参数、输出比较参数以及使能,这些步骤都是必不可少的,所以我们在使用定时器时一定要细心,否则找错误很麻烦。今天关于定时器的学习总结就写到这里,有错误的地方,请各位在评论区批评指正。
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总
深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal
我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or
我正在寻找一个用ruby演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent
如何学习ruby的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/
深度学习12.CNN经典网络VGG16一、简介1.VGG来源2.VGG分类3.不同模型的参数数量4.3x3卷积核的好处5.关于学习率调度6.批归一化二、VGG16层分析1.层划分2.参数展开过程图解3.参数传递示例4.VGG16各层参数数量三、代码分析1.VGG16模型定义2.训练3.测试一、简介1.VGG来源VGG(VisualGeometryGroup)是一个视觉几何组在2014年提出的深度卷积神经网络架构。VGG在2014年ImageNet图像分类竞赛亚军,定位竞赛冠军;VGG网络采用连续的小卷积核(3x3)和池化层构建深度神经网络,网络深度可以达到16层或19层,其中VGG16和VGG
文章目录1、自相关函数ACF2、偏自相关函数PACF3、ARIMA(p,d,q)的阶数判断4、代码实现1、引入所需依赖2、数据读取与处理3、一阶差分与绘图4、ACF5、PACF1、自相关函数ACF自相关函数反映了同一序列在不同时序的取值之间的相关性。公式:ACF(k)=ρk=Cov(yt,yt−k)Var(yt)ACF(k)=\rho_{k}=\frac{Cov(y_{t},y_{t-k})}{Var(y_{t})}ACF(k)=ρk=Var(yt)Cov(yt,yt−k)其中分子用于求协方差矩阵,分母用于计算样本方差。求出的ACF值为[-1,1]。但对于一个平稳的AR模型,求出其滞