当前位置:   article > 正文

小兴教你做平衡小车-stm32程序开发(定时器)_stm32小车怎么设定时间

stm32小车怎么设定时间

1 前言

一说到定时器,大家应该会比较熟悉了。比如我们煮鸡蛋需要5分钟,我们就会习惯性的打开手机上的计时功能。那stm32单片机的定时器是怎么样的呢。

2 提前了解的知识

2.0 单片机通用定时器框图

在这里插入图片描述

2.1 几个重要的结构体

参考博客:stm32f103c8t6使用定时器实现1s翻转LED+cubemx生成
在这里插入图片描述
变量TIM_Prescaler是指定时器的预分频值(Prescaler value)。
变量TIM_CounterMode是指定时器的计数模式。
变量TIM_Period是指定时器的自动重装载值(Auto-reload value)。
变量TIM_ClockDivision是指定时器时钟分割。
变量TIM_RepetitionCounter是指定时器重复计数(我们一般不适用)。
在这里插入图片描述
参考博客:stm32定时器–通道pwm输出参数TIM_OCInitStructure如何配置
变量TIM_OCMode是指模式选择。
变量TIM_OutputState是指输出状态。
变量TIM_OutputNState是指互补通道的输出状态。
变量TIM_Pulse是指占空比。
变量TIM_OCPolarity是指输出极性。
变量TIM_OCNPolarity是指互补通道的输出极性。
变量TIM_OCIdleState是指空闲状态。
变量TIM_OCNIdleState是指互补通道的空闲状态。
在这里插入图片描述

变量NVIC_IRQChannel是指中断通道。
变量NVIC_IRQChannelPreemptionPriority是指抢占优先级。
变量NVIC_IRQChannelSubPriority是指子优先级。
变量NVIC_IRQChannelCmd是通道使能。
在这里插入图片描述
关于中断通道,在stm32f10x.h中有定义的。因为我们使用的是TIM3定时器,这里我们使用的是TIM3_IRQn
在这里插入图片描述
在这里插入图片描述
关于抢占优先级和子优先级的取值见下图。下图可以看出,当我们采用不同的优先组的时候,两个变量的取值也是不同的。
参考博客:STM32】NVIC 中断优先级管理,抢占优先级,响应优先级,中断寄存器
在这里插入图片描述

3 库函数解析

3.1 TIM_TimeBaseInit函数介绍

3.1.1 源码展示

在这里插入图片描述

3.1.2 TIMx_CR1寄存器内容修改

这里我们初始化的是TIM3。
首先介绍下图所示的控制寄存器TIMx_CR1
在这里插入图片描述
这里采用向上计数的模式,所以需要修改寄存器的4、5、6位。

	TIM3->CR1 &= (uint16_t)0xFF8F; //CMS[1:0]和DIR位清零
	TIM3->CR1 |= (uint16_t)0x0000;   //设置计数为向上计数
  • 1
  • 2

在这里插入图片描述
这里采用一分频,所以需要修改寄存器的8、9位。

	TIM3->CR1 &= (uint16_t)0xFFCF; //CKD[1:0]位清零
	TIM3->CR1 |= (uint16_t)0x0000;   //设置1分频
  • 1
  • 2

在这里插入图片描述
在这里插入图片描述

3.1.3 TIMx_ARR寄存器内容修改

接着需要介绍自动重装载寄存器TIMx_ARR。可以看出这个寄存器可以存放的数据为0-65535。

TIM3->ARR =  9999; //设置自动装载值
  • 1

在这里插入图片描述

3.1.4 TIMx_PSC寄存器内容修改

接着需要介绍预分频寄存器TIMx_PSC。可以看出这个寄存器可以存放的数据为0-65535。

	TIM3->PSC =  7199; //设置预分频值
  • 1

在这里插入图片描述

3.1.5 TIMx_EGR寄存器内容修改

接着需要介绍事件产生寄存器TIMx_EGR

TIM3->EGR = (uint16_t)0x0001;   
  • 1

在这里插入图片描述
在这里插入图片描述

3.2 NVIC_PriorityGroupConfig函数介绍

3.2.1 源码展示

在这里插入图片描述

3.2.2 AIRCR寄存器内容修改

其中AIRCR_VECTKEY_MASK的值如下图所示。
在这里插入图片描述
分组可以看出有5种选择,这里我们选择NVIC_PriorityGroup_2
在这里插入图片描述
那么最终传入的AIRCR寄存器的的内容为0x05FA0500

下图是AIRCR寄存器的具体图。如果想要对AIRCR寄存器做修改,高16位一定要写入0x05FA
手册查看地址:编程手册
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 NVIC_Init函数介绍

3.3.1 源码展示

在这里插入图片描述
参考博客:NVIC_Init(&NVIC_InitStructure)学习
首先咱们先看第一句,tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;

其中有一个SCB->AIRCR很重要。下图可SCB_BASE为0xE000ED00
在这里插入图片描述
在这里插入图片描述
再看((SCB->AIRCR) & (uint32_t)0x700)这个语句首先读取AIRCR寄存器中的值,
然后对8、9、10位进行保留,其他位进行清零操作。(注意:这里只是读取AIRCR寄存器,而不是对寄存器进行操作)。这里得到的值应该是0x500

再看(0x700 - ((SCB->AIRCR) & (uint32_t)0x700)),这里得到的值为0x200

再看tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08,这里得到的值为tmppriority =2

接着我们看第二句话,tmppre = (0x4 - tmppriority),这里的tmppre = 2

接着我们看第三句话,tmpsub = tmpsub >> tmppriority;,初始的tmpsub为0x0F(0b00001111),然后右移动2位,最后得到的tmpsub=0b00000011

接着我们看第四句话,tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre,这里假设NVIC_IRQChannelPreemptionPriority 的值为1,然后向左移动2位,最后得到tmppriority=4

接着我们看第五句话,tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub,这里假设NVIC_IRQChannelSubPriority 的值为2(0b00000010),经过运算后得到tmppriority=0b00000110

接着我们看第六句话,tmppriority = tmppriority << 0x04;,经过计算后得到tmppriority = 0b01100000

接着我们看第七句话,NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;

因为我们使用的是TIM3定时器,这里我们使用的是TIM3_IRQnTIM3_IRQn下图可以看出为29。也就是说NVIC->IP[29] = tmppriority
在这里插入图片描述
参考博客:玩转STM32寄存器(关于NVIC的寄存器配置)
在这里插入图片描述
接着我们看第八句话,NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] = (uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
比如现在选择的通道是TIM3_IRQnTIM3_IRQn表示数字为29。 29>>5为0。
NVIC->ISER[0] = 1<< 29
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3 代码分享

main.c文件。

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "tim.h"
#include "stdio.h"

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组配置
	RCC->APB2ENR |= (uint32_t)0x00000010;//打开GPIOC时钟
	GPIOC->CRH   &= (uint32_t)0xFF0FFFFF;//使用前清零
	GPIOC->CRH   |= (uint32_t)0x00300000;//配置PC13为推挽输出,最大速度50MHz
	Delay_Init();//延时初始化
	Usart_Init(115200);//串口初始化
	Timer_Init(9999,7199); //(9999+1)*(7199+1)/72mhz = 1s
	printf("hello world!\r\n");
	while(1)
	{
		//GPIOC->BSRR  =  (uint32_t)0x00002000;//PC13引脚输出高电平
		//Delay_ms(500);                       //延时500ms
		//GPIOC->BRR  =   (uint16_t)0x2000;    //PC13引脚输出低电平
		//Delay_ms(500);   		             //延时500ms
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

tim.c文件。

#include "stm32f10x.h"
#include "tim.h"

//uint32_t my_tmppriority = 0x00,my_tmppre = 0x00,my_tmpsub = 0x0F;
void Timer_Init(uint16_t per,uint16_t psc)
{
	//库函数版本
	//----------------------------------------------------------------//
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = per;
	TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	
	NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM3,ENABLE);
	//----------------------------------------------------------------//
	
	//寄存器版本
	//----------------------------------------------------------------//
//  RCC->APB1ENR |= (uint32_t)0x00000002; //打开定时器3的时钟
//	TIM3->CR1 &= (uint16_t)0xFF8F; //CMS[1:0]和DIR位清零
//	TIM3->CR1 |= (uint16_t)0x0000;   //设置计数为向上计数
//	
//	TIM3->CR1 &= (uint16_t)0xFCFF; //CKD[1:0]位清零
//	TIM3->CR1 |= (uint16_t)0x0000;   //设置1分频
//	
//	TIM3->ARR =  9999; //设置自动装载值
//	TIM3->PSC =  7199; //设置预分频值
//	
//	TIM3->EGR = (uint16_t)0x0001;
//	
//	TIM3->DIER |= (uint16_t)0x0001;
//	
//    my_tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
//    my_tmppre = (0x4 - my_tmppriority);
//    my_tmpsub = my_tmpsub >> my_tmppriority;

//    my_tmppriority = 1 << my_tmppre; //抢占优先级为1
//    my_tmppriority |=  2 & my_tmpsub;//子优先级为2
//    my_tmppriority = my_tmppriority << 0x04;
//	
//	NVIC->IP[TIM3_IRQn] = my_tmppriority;
//	NVIC->ISER[TIM3_IRQn >> 0x05] =(uint32_t)0x01 << (TIM3_IRQn & (uint8_t)0x1F);//开启通道
//	//NVIC->ISER[0] =1<<29;
//	TIM3->CR1 |= (uint16_t)0x0001;
	//----------------------------------------------------------------//
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

tim.h文件。

#ifndef __TIM_H
#define __TIM_H

#include "stm32f10x.h"

void Timer_Init(uint16_t per,uint16_t psc);
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

stm32f10x_it.c文件

#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)
	{
		GPIOC->ODR ^= (uint16_t)0x2000;
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);   //清除TIM3上的更新中断标志位
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

4 逻辑分析仪查看定时时间

main.c文件。

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "tim.h"
#include "stdio.h"

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组配置
	RCC->APB2ENR |= (uint32_t)0x00000010;//打开GPIOC时钟
	RCC->APB2ENR |= (uint32_t)0x00000008;//打开GPIOB时钟
	GPIOC->CRH   &= (uint32_t)0xFF0FFFFF;//使用前清零
	GPIOC->CRH   |= (uint32_t)0x00300000;//配置PC13为推挽输出,最大速度50MHz
	GPIOB->CRL   &= (uint32_t)0xFFFFFFF0;//使用前清零
	GPIOB->CRL   |= (uint32_t)0x00000003;//配置PB0为推挽输出,最大速度50MHz
	Delay_Init();//延时初始化
	Usart_Init(115200);//串口初始化
	Timer_Init(9999,7199); //(9999+1)*(7199+1)/72mhz = 1s
	printf("hello world!\r\n");
	while(1)
	{
		//GPIOC->BSRR  =  (uint32_t)0x00002000;//PC13引脚输出高电平
		//Delay_ms(500);                       //延时500ms
		//GPIOC->BRR  =   (uint16_t)0x2000;    //PC13引脚输出低电平
		//Delay_ms(500);   		             //延时500ms
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

tim.c文件。

#include "stm32f10x.h"
#include "tim.h"

//uint32_t my_tmppriority = 0x00,my_tmppre = 0x00,my_tmpsub = 0x0F;
void Timer_Init(uint16_t per,uint16_t psc)
{
	//库函数版本
	//----------------------------------------------------------------//
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInitStruct.TIM_Period = per;
	TIM_TimeBaseInitStruct.TIM_Prescaler = psc;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
	
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
	
	NVIC_InitStruct.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStruct);
	
	TIM_Cmd(TIM3,ENABLE);
	//----------------------------------------------------------------//
	
	//寄存器版本
	//----------------------------------------------------------------//
//	RCC->APB1ENR |= (uint32_t)0x00000002; //打开定时器3的时钟
//	TIM3->CR1 &= (uint16_t)0xFF8F; //CMS[1:0]和DIR位清零
//	TIM3->CR1 |= (uint16_t)0x0000;   //设置计数为向上计数
//	
//	TIM3->CR1 &= (uint16_t)0xFCFF; //CKD[1:0]位清零
//	TIM3->CR1 |= (uint16_t)0x0000;   //设置1分频
//	
//	TIM3->ARR =  9999; //设置自动装载值
//	TIM3->PSC =  7199; //设置预分频值
//	
//	TIM3->EGR = (uint16_t)0x0001;
//	
//	TIM3->DIER |= (uint16_t)0x0001;
//	
//    my_tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
//    my_tmppre = (0x4 - my_tmppriority);
//    my_tmpsub = my_tmpsub >> my_tmppriority;

//    my_tmppriority = 1 << my_tmppre; //抢占优先级为1
//    my_tmppriority |=  2 & my_tmpsub;//子优先级为2
//    my_tmppriority = my_tmppriority << 0x04;
//	
//	NVIC->IP[TIM3_IRQn] = my_tmppriority;
//	NVIC->ISER[TIM3_IRQn >> 0x05] =(uint32_t)0x01 << (TIM3_IRQn & (uint8_t)0x1F);//开启通道
//	//NVIC->ISER[0] =1<<29;
//	TIM3->CR1 |= (uint16_t)0x0001;
	//----------------------------------------------------------------//
} 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

tim.h文件。

#ifndef __TIM_H
#define __TIM_H

#include "stm32f10x.h"

void Timer_Init(uint16_t per,uint16_t psc);

#endif

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

stm32f10x_it.c文件。

#include "stm32f10x.h"
#include "delay.h"
#include "stdio.h"

void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)
	{
		GPIOC->ODR ^= (uint16_t)0x2000;
		GPIOB->ODR ^= (uint16_t)0x0001;
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);   //清除TIM3上的更新中断标志位
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

通过逻辑分析仪抓取波形如下。可以看出单片机的PB0引脚高与低电平各占1s。满足我们的要求。
在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/799852
推荐阅读
相关标签
  

闽ICP备14008679号