如果不想看的可以直接使用git把我的代码下载出来,里面工程挺全的,后期会慢慢的补注释之类的
如果不会使用git快速下载可以选择直接下载压缩包或者去看看git的使用
git的使用(下载及上传_gitcode怎么下载文件_是小刘不是刘的博客-CSDN博客
本章目标:使用基本定时器制作定时,实现串口每隔1s打印一次内容,参考了野火的零死角玩转STM32
目录
2)图中的预分频器,这个东西可以将我们刚刚输入的72M进行一个分频:PSC是16位的寄存器,所以能写入进去的数据就是0-65535
3)计数器:这里最开始介绍基础定时器的时候说过,基础定时器的计数器只能向上计数,也是16位的可以填入0-65535
4)自动重载寄存器:就是你设定一个值,如果计算到达了这个值,他就将计数值帮你清零,并且会触发他的中断标志位,你如果使能了他的中断,我们就可以在中断里做一些事情了。
这一篇还是需要一点基础的,需要定时器和中断的使用基础,下面在对应的地方也给了链接,这里也给了,可以先看一看,或者看到后后面再去看。
stm32f103中断的使用_stm32f103中断程序_是小刘不是刘的博客-CSDN博客
stm32通用定时器的使用_外部时钟输入_是小刘不是刘的博客-CSDN博客
一、理论部分
1 什么是定时器
定时器在STM32中总共有8个定时器可以分为3类,基本定时器通用定时器和高级定时器
其中基本定时器:TIM6和TIM7这两个定时器是基本定时器,这两个定时器只能定时,不能外部输出任何东西
通用定时器:有基本定时器的全部功能,还可以进行输出比较产生PWM波形和输入比较,采集波形的占空比和频率
高级定时器:有通用定时器的全部功能,并且还有三相电机互补输出的功能
2 基本定时器的框图
1)单片机的外设基本上都是需要时钟源的
这里从图上可知基本定时器的时钟来源于TIMxCLK我们可以去看看时钟图到底时钟是多少,图上可以看见APB1分频后将时钟作为了定时器的输入,此时时钟为36Mhz,因为最大是36M,所以基本上我们都是对72M进行了2分频让其为36M,这里下面写了如果分频系数不为一则频率x2,这样我们就知道,TIMxCLK的时钟是72Mhz了。
2)图中的预分频器,这个东西可以将我们刚刚输入的72M进行一个分频:PSC是16位的寄存器,所以能写入进去的数据就是0-65535
3)计数器:这里最开始介绍基础定时器的时候说过,基础定时器的计数器只能向上计数,也是16位的可以填入0-65535
4)自动重载寄存器:就是你设定一个值,如果计算到达了这个值,他就将计数值帮你清零,并且会触发他的中断标志位,你如果使能了他的中断,我们就可以在中断里做一些事情了。
3定时时间的计算
这个很重要哦:因为不止是这里要用,后面的通用定时器和高级定时器你都的会算才行
有些文档把这个计算写的有点抽象其实很简单:定时器时钟=时钟/分频 假设我们分频72就还剩1M的时钟,也就是1m可以执行1M个操作,我们要算执行一次的时间,直接1/1M就好了,这时候单位是s哦(其实这种情况你直接吧K划为ms吧M化为us更舒服,因为刚好都是满1000进1所以直接上下都是除以1000 000)这时候我们直接1/1=1us就好了 = =,然后再乘以他的重载值,就是你要记多少次进入中断,你写10就是10us写1000就是1ms
二、代码部分
1 定时器初始化
首先初始化我们的基本定时器,这个我们去Tim里面找结构体就好了,写一个TimeBase_Init() 一般外设的初始化都是这个格式
定时器整体配置代码如下:
void TimeBase_Init(void)
{
TIM_TimeBaseInitTypeDef IM_TimeBaseStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);
IM_TimeBaseStruct.TIM_Prescaler=71;
IM_TimeBaseStruct.TIM_Period=999;
TIM_TimeBaseInit(TIM6,&IM_TimeBaseStruct);
TIM_Cmd(TIM6,ENABLE);
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);
}
1)开启定时器的时钟
这里有一个开启时钟,这个具体是挂在这哪个时钟总线的你需要自己去看一下参考手册的时钟图,然后我们是能他,不使能,你后面对定时器的操作都是无效的,所以你必须吧使能放在配置前面。
2)定时器结构体讲解
stm32通用定时器的使用_外部时钟输入_是小刘不是刘的博客-CSDN博客
这里有一篇通用定时器的使用,里面写的很详细。
然后解释一下这些代码的含义,首先是声明一个结构体,这样你才可以使用里面的参数
这里如果不了解的朋友可以去看一下C语言的结构体,下个月可能我会补上C语言基础和数据结构的内容。以下是这这个结构体内的成员,有分频、计数模式(向上向下这类),重载值,滤波器分频,重复计数(因为前面说过,基本定时器只有两个东西需要配置,分频和重载)所以其他的可以直接给0也能不写
然后是我的配置(我这里72分频,这里分频和重载默认会有+1,可能是因为默认就是1分频,所以你写0他是1分频,写1他就是2分频了- -不想被整出bug的设计吧可能是
然后72/72=1M 1M就是1us执行一次操作,我们这里让他执行1000次贵0并产生中断,就是1ms进一次中断了。
然后我们调用Init函数,将我们刚刚配置好的参数,写到寄存器里面去。
之后直接使能定时器6就好了
之后我没开启一下中断 TIM_ITConfig
需要配置的参数为:tim,TIM_IT,NewState
其中第二个参数可以有以下选择,1、更新中断源 2、输入比较1中断源 3差不多后面写吧、
我的配置就是上面这个了
2 NVIC的配置
之后我们去配置NVIC
整体代码如下
void BASIC_TIM_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM6_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=3;
NVIC_Init(&NVIC_InitStruct);
}
这里还是一样的配置NVIC
这里不需要开启时钟了,因为NVIC是挂在内核上的,优先级很高,这些时钟管不到他了。
1)配置中断通道
中断通道,这个大家找一下,直接复制过去千万别输错了
2)使能NVIC
使能通道的中断:NVIC_IRQChannelCmd
3)优先级配置
配置优先级和抢占优先级,这个需要大家先看看中断和优先级组的概念,前面没做详细介绍因为以前写过一篇了这里直接给个链接先去看看吧
stm32f103中断的使用_stm32f103中断程序_是小刘不是刘的博客-CSDN博客
3 中断函数的编写
中断函数,这里变量加了extern 和volatile 前者意思是我这里只是引用,定义是在其他地方定义的,后者是让编译器不要优化他。
extern volatile uint32_t time;
void TIM6_IRQHandler(void)
{
if ( TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET )
{
time++;
TIM_ClearITPendingBit(TIM6 , TIM_FLAG_Update);
}
}
中断函数名字一定不能错,去启动文件复制过来,因为错了他不会给你报警,但是函数会无效
判断标志位TIM_GetITStatus(TIM6, TIM_IT_Update) != RESET
就是判断的这个位
之后我们在函数内对time++ 因为我们定时器给的是1ms所以1ms就好++一次
4 主函数
这里要配置个中断组, NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); 这个函数,具体怎么选去看看我写的中断的章节,具体的呢在中断的章节也有讲解。
然后我们判断time是否累加到了1000如果到了1000就打印一个1并且将time归零。
volatile uint32_t time = 0; // ms ¼Æʱ±äÁ¿
int main(void)
{
Usart_Config();
TIM6_Init();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
while(1)
{
if(time==1000)
{
printf("1\r\n");
time=0;
}
}
}
测试结果,打开串口的时间显示,确认一下确实是1s打印一次,时间基本上是没有偏差的。
jvtjv't