目录
前言
本文记录嵌入式开发课程第九周实验作业,学习有关定时器&PWM相关的知识以及运用。
一、实验任务
1、使用STM32F103的Tim2~Tim5其一定时器的某一个通道pin(与GPIOx管脚复用,见下图),连接一个LED,用定时器计数方式,控制LED以2s的频率周期性地亮-灭。
2、接上,采用定时器pwm模式,让 LED 以呼吸灯方式渐亮渐灭,周期为1~2秒,自己调整到一个满意效果。使用Keil虚拟示波器,观察 pwm输出波形。
3、再接上,采用定时器的另外一个通道,编程采集上面的pwm输出信号,获得其周期和脉宽,并重定向输出到串口显示。
二、定时器和PWM
1、定时器介绍
定时器是用来定时的机器,是存在于STM32单片机中的一个外设。STM32总共有8个定时器,分别是2个高级定时器(TIM1、TIM8),4个通用定时器(TIM2、TIM3、TIM4、TIM5)和2个基本定时器(TIM5、TIM6),如下图所示:
这三种定时器的区别在于:高级定时器具有捕获/比较通道和互补输出,通用定时器只有捕获/比较通道,基本定时器没有以上两者。
2、定时器的工作原理
定时器可分为四个大部分,分别是:时钟产生部分,时基单元部分,输入捕获部分,输出比较部分。
(1)时钟产生部分可选择四种时钟源:①内部时钟(CK_INT);②外部时钟模式:外部触发输入(ETR);③内部触发输入(ITRx);④外部时钟模式:外部输入脚(TIx)。
(2)时基单元部分包括三个寄存器:
①计数器寄存器(TIMx_CNT):向上计数、向下计数或者中心对齐计数;
②预分频器寄存器(TIMx_PSC):可将时钟频率按1到65535之间的任意值进行分频,可在运行时改变其设置值;
③自动装载寄存器(TIMx_ARR):如果TIMx_CR1寄存器中的ARPE位为0,ARR寄存器的内容将直接写入影子寄存器;如果ARPE为1,ARR寄存器的那日同将在每次的更新时间UEV发生时,传送到影子寄存器;如果TIM1_CR1中的UDIS位为0,当计数器产生溢出条件时,产生更新事件。
(3)输入捕获部分
IC1、2和IC3、4可以分别通过软件设置将其映射到TI1、TI2、TI3和TI4;
4个16位捕捉比较寄存器可以编程用于存放检测到对应的每一次输入捕捉时计数器的值;
当产生一次捕捉,相应的CCxIF标志位被置1;同时如果中断或DMA请求使能,则产生中断或DMA请求。
如果当CCxIF标志位已经为1,当又产生一个捕捉,则捕捉溢出标志位CCxOF将被置1。
(4)输出比较通道(PWM)
PWM模式有两种:边沿对齐模式和中心对齐模式。
频率和占空比可以进行如下设定:一个自动重载寄存器用于设定PWM的周期;每个PWM通道有一个捕捉比较寄存器用于设定占空时间。
3、PWM介绍
PWM是指脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,也就是说通过调节占空比的变化来调节信号、能量等的变化,占空比就是指在一个周期内,信号处于高电平的时间占据整个信号周期的百分比,例如方波的占空比就是50%。PWM的功能有很多种,比如控制呼吸灯、控制直流电机或者舵机等驱动原件等等,是单片机的一个十分重要的功能。广泛应用在从测量、通信到功率控制与变换的许多领域中。
以单片机为例,我们知道,单片机的IO口输出的是数字信号,IO口只能输出高电平和低电平。假设高电平为5V 低电平则为0V 那么我们要输出不同的模拟电压,就要用到PWM,通过改变IO口输出的方波的占空比从而获得使用数字信号模拟成的模拟电压信号。
我们知道,电压是以一种连接1或断开0的重复脉冲序列被夹到模拟负载上去的(例如LED灯,直流电机等),连接即是直流供电输出,断开即是直流供电断开。通过对连接和断开时间的控制,理论上来讲,可以输出任意不大于最大电压值(即0~5V之间任意大小)的模拟电压。
比方说:占空比为50% 那就是高电平时间一半,低电平时间一半,在一定的频率下,就可以得到模拟的2.5V输出电压 那么75%的占空比 得到的电压就是3.75V。
PWM的调节作用来源于对“占周期”的宽度控制,“占周期”变宽,输出的能量就会提高,通过阻容变换电路所得到的平均电压值也会上升,“占周期”变窄,输出的电压信号的电压平均值就会降低,通过阻容变换电路所得到的平均电压值也会下降,也就是,在一定的频率下,通过不同的占空比 即可得到不同的输出模拟电压。
PWM是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压,当PWM效率越大,响应越快。对于呼吸灯来说,就是高电平的时间占整个周期的比值,占空比越高,LED就越暗。
CCR不断增大意味着低电平占的时间越来越多所以亮度由暗一直到亮。
参考链接:
https://blog.csdn.net/qq_44016222/article/details/123507270
https://blog.csdn.net/as480133937/article/details/103439546
三、用定时器控制小灯周期性闪烁
1、环境搭建
玻珠选择用库函数的方式来建立工程,这就需要我们去下载相关的固件库,这里直接提供玻珠下载的链接,出自江协科技(另:他家B站有关STM32芯片的相关学习视频真的很详细也很好懂),链接里不仅有STM32的,还有51单片机及其他相关知识的资料链接。
资料下载https://jiangxiekeji.com/download.html 根据教程建立新工程后,就可以对代码进行完善了。
2、代码编写
main.c文件:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init();
while (1)
{
PWM_SetCompare1(0);
Delay_ms(2000);
PWM_SetCompare1(100);
Delay_ms(2000);
}
}
PWM.c文件:
#include "stm32f10x.h" // Device header
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_0; //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; //ARR
TIM_TimeBaseInitStructure.TIM_Prescaler = 720 - 1; //PSC
TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStructure);
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCStructInit(&TIM_OCInitStructure);//给结构体赋初始值
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//设置输出比较的模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//设置输出比较极性
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//设置输出状态
TIM_OCInitStructure.TIM_Pulse = 0; //设置CCR
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//放入Init函数中
TIM_Cmd(TIM2, ENABLE);
}
void PWM_SetCompare1(uint16_t Compare)
{
TIM_SetCompare1(TIM2, Compare);
}
PWM.h文件:
#ifndef __PWM_H
#define __PWM_H
void PWM_Init(void);
void PWM_SetCompare1(uint16_t Compare);
#endif
编译一下,可以看到没有错误也没有警告,并且成功生成了Hex文件(没有生成的点击魔法棒,选择output,勾选Create HEX File就可以了)。
3、电路连接
对于USB转TTL模块和STM32F103C8T6的连接:
GND — GND
3v3 — 3v3
TXD — A10
RXD — A9
同时将芯片上3.3V接“+”,再连一根线将小灯和PA0口连接。
实物图如下:
4、烧录和运行
将USB接入电脑,打开烧录软件,选择好串口,并找到刚刚生成的Hex文件。注意这里需要先将板子上的BOOT0按照如下配置:
然后点击开始编程,同时按下板子上的RESRT键,即可成功。
然后 将BOOT0置0,再次按下RESRT键,即可看见小灯周期性闪烁。
四、 用PWM模式运行呼吸灯
1、代码修改
在上一问的基础上对代码进行修改即添加循环,便能完成呼吸灯。
main.c文件:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "PWM.h"
uint8_t i;
int main(void)
{
OLED_Init();
PWM_Init();
while (1)
{
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(i);
Delay_ms(10);
}
for (i = 0; i <= 100; i++)
{
PWM_SetCompare1(100 - i);
Delay_ms(10);
}
}
}
编译无错,生成hex文件。
2、电路连接与烧录运行
电路的连接同上一问相同,按照上一问的步骤进行烧录,成功。
运行结果如下:
五、观察波形
点击魔术棒,更改Debug配置如下图,点击OK。
点击打开逻辑分析仪,添加引脚,更改类型为Bit,点击close。
运行结果如下:
串口显示:
总结
本次实验学习了有关定时器、PWM的相关内容,旨在探索如何用PWM模式制作一个呼吸灯,并了解其工作原理。制作呼吸灯的意义不仅在于学习PWM控制原理,更重要的是掌握板子的使用方法。经过本次实验,我提高了自己的编程能力和解决问题的能力,尽管在制作过程中遇到了一些困难,但大部分都是之前碰到过的问题,稍加思考或询问同学就成功解决,收获了宝贵的经验。