Schwertlilien
As a recoder: notes and ideas.

嵌入式上机实验2

实验二 定时器

对于定时器的实现:

软件实现的for循环不太精确,采用内部系统时钟,可实现精确的定时,其工作模式为:普通模式、比较输出/PWM输出模式、捕获输入模式

PWM:输出指定波形

捕获输入:测量输入信号频率和占空比,测量外部时间

示波器:可以以准确的时间看捏

一、实验目的

  • 掌握Proteus和Keil联调的方法。

  • 掌握STM32上利用定时器的技术模式进行延时的方法。

  • 掌握STM32上定时器的PWM模式的运用方法。

二、实验环境

OS:Windows11

软件:Keil uVision5,Proteus

三、实验内容

根据实验原理图配置对应的GPIO口和定时器,实现下述功能:

① 配置三个LED和串口相关的IO功能;

② 配置TIM1,根据系统8MHz时钟,配置定时周期为1秒,向上计数模式;然后在while循环中使能定时器,查询等待定时器时间到,点亮3个LED灯,再次使能定时器,等待定时时间到,熄灭3个LED灯,循环往复。

③ 配置TIM1,根据系统8MHz时钟,配置定时周期为1秒,向上计数模式;配置TIM1的CH1、CH2、CH3为PWM模式,生成占空比为50%的波形;使能定时器和PWM输出;在while循环中空循环即可。

④ 上述两种模式可以单独实现,也可通过宏定义控制的形式实现在一个main.c中。

四、实验原理

①首先配置三个LED灯和串口相关的IO功能,此处使用的是实验一中介绍的片内外设GPIO来配置。使能APB1总线上的引脚PA8,9,10所属端口GPIOA的时钟,设置需要使用的GPIOA端口,将PA8,9,10配置为普通推挽输出。

1
2
3
4
5
//now need config the IO-PA8,9,10
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10|GPIO_Pin_9|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOA,&GPIO_InitStructure);

再来配置TIM1:根据系统内8MHZ的时钟,配置器定时周期为1s。对于定时周期为1s的设置,需要根据公式:
$$
T=\frac{(TIM_{Prescaler}+1)(TIM_{Period}+1)}{TIMxCLK}
$$
TIMxCLK在软件仿真中取值8MHZ,因此为使T=1s,则$(TIM_{Prescaler}+1)(TIM_{Period}+1)$要取值为8M。此处取Prescaler预分频为8k,那么Period持续时间选择1k。

然后,将TIM1设置为向上计数模式。对于计数模式共有两种:中心对齐和边沿对齐。此处选择的是边沿对齐的向上计数。因此就将TIM1的要求配置完毕。

1
2
3
4
5
6
7
8
9
//then finish TIM1's requirements
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
TIM_TimeBaseStructure.TIM_Prescaler=8000-1;//1khz=1ms
TIM_TimeBaseStructure.TIM_Period=1000-1;//1ms*1k=1s
TIM_TimeBaseStructure.TIM_ClockDivision=0;
TIM_TimeBaseStructure.TIM_RepetitionCounter=0;
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1,&TIM_TimeBaseStructure);

②对于完成第二项功能,使用的是普通输出模式。要求将自行在while(1)无限循环中写于有关的测试代码以实现:在while循环中使能定时器,查询等待定时时间到,点亮3个LED灯,再此使能定时器,等待定时时间到,熄灭3个LED灯。

因此先将PA8,9,10引脚设置为低电平,这样三个LED灯的初始状态即为亮;在开启TIM1计时后,会通过循环轮询TIM1标志位的状态。当TIM1计时结束后,清除TIM1的标志位的状态。此时将PA8,9,10引脚设置为高电平,这样三个LED灯就会熄灭;再次进行TIM1计时,以达到循环亮灭的目的。

1
2
3
4
5
6
7
8
9
10
11
12
/* Infinite loop */
while (1) {
GPIO_ResetBits(GPIOA,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10);//light on
TIM_Cmd(TIM1,ENABLE);
while(TIM_GetFlagStatus(TIM1,TIM_FLAG_Update)==RESET);
TIM_ClearFlag(TIM1,TIM_FLAG_Update);

GPIO_SetBits(GPIOA,GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10);//light off
TIM_Cmd(TIM1,ENABLE);
while(TIM_GetFlagStatus(TIM1,TIM_FLAG_Update)==RESET);
TIM_ClearFlag(TIM1,TIM_FLAG_Update);
}

③功能三需要使用PWM模式,要求其占空比为50%。对于使用PWM模式的输出,需要先复用端口,即将上文中的GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP改为GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP,设置为复用推挽输出模式。

在PWM模式下电平的高低有PWM模块进行控制,而不是芯片来控制,因此需要复用PA8,9,10三个引脚即可,而while循环中空循环即可。

TIM_OCInitTypeDef结构体来储存配置信息。我们设置TIM_OCModeTIM_OCMode_PWM1TIM_OCPolarityTIM_OCPolarity_Low。我们需要设置占空比为50%,根据公式,占空比等于$\frac{(TIM_{Pulse})}{(TIM_{Period} + 1)}$,上面我们设置了TIM_Period为1000 – 1,这里为了达到占空比为50%,需要设置TIM_Period为500,然后开启输出比较状态。

配置TIM1的CH1,2,3为PWM模式:根据复用关系表我们可以知道,三个端口PA8,9,10分别复用了TIM1的通道1,通道2和通道3,因此我们需要分别初始化三个通道和使能三个通道的CCR预装载器。最后使能ARR的预装载器;最后,我们只需要开启TIM1,使能TIM1的主输出即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//set OCL/OCH=1:1 and start state
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OCInitStructure.TIM_Pulse=500;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;
//AF_OC1,2,3
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_ARRPreloadConfig(TIM1,ENABLE);
//start TIM1
TIM_Cmd(TIM1,ENABLE);
TIM_CtrlPWMOutputs(TIM1,ENABLE);

五、实验结果及其分析

先不用PWM,常用推挽输出模式,所得的结果为:三个LED灯周期性闪烁,当PA8,9,10为高电平时,LED灯熄灭。反之,则LED灯亮起。其亮起的时间(即示波为低电平的时间)为5*0.2ms=1ms

使用PWM模式下,所得的周期是推挽输出模式的一半。

定时器时间没变的情况下,为什么跑出来的周期不一样呢?

对于普通的推挽模式下选择的是每次经过一次完整计时后设置小灯的状态;但是对于PWM模式下就是将一个周期通过设置占空比将其分为两部分,其中一半的时间小灯熄灭,一半的时间小灯亮起。

对于上述的两功能,选择#ifdef:判断某个宏是否被定义,若已定义,执行随后的语句。来选择执行的代码部分。

具体结果见视频。

六、心得体会与建议

通过本次实验,深入学习掌握了TIM定时器系统和PWM定时输出模式。

搜索
匹配结果数:
未搜索到匹配的文章。