时基单元
- 1、什么是定时器
- 2、时基单元的基本结构
- 2.1:脉冲的来源
- 2.2:预分频器PSC
- 2.3:计数器CNT
- 2.4:update事件与预加载
- 3、标准库编程
- 3.1:通过定时器中断来设置延迟函数
1、什么是定时器
定时器是一种专门负责定时功能的片上外设,而F1系列的单片机最多由14个定时器(TIM1~TIM14)。而STM32F103C8T6一共只有4个定时器。
如上图所示:STM32F103C8T6有一个高级定时器TIM1,3个通用定时器TIM2~4。而高级定时器TIM1挂载在APB2上面。
2、时基单元的基本结构
如图为定时器的基本结构,而时基单元是定时器结构的一部分,如下图所示。
如图:时基单元的基本结构由预分频器PSC,计数器CNT,自动重装寄存器ARR,重复计数器RCR组成。而RCR只有高级定时器才有,通用定时器没有。
PSC (Prescaler): 对速时钟信号 分频
CNT (Counter) :在时钟脉冲激励下 计数
ARR (Auto Reload Register ):用于设置定时周期
RCR (Repetition Counter Register):用于设置定时的 的次
Update事件 - 当RCR溢 时产生
Update中断 - 由Update事件引发的中断
2.1:脉冲的来源
由晶振而来,具体情况可参考时钟树的相关知识。
由上图所示:如果是APB1产生的频率,那么频率 * 2,如果是APB2产生的频率,那么频率 * 1 STM32F103C8T6的定时器来源的频率max = 72MHz。
2.2:预分频器PSC
预分频器由PSC由计数器,比较器和自动重装器构成。
想要分频率的频率脉冲连接计数器,作为输入信号。当计数器从1开始计数,数值和计数周期通过比较器相较,如果计数值 > 计数周期时,比较器输出一个脉冲,计数值归0,重新开始计数。
如上图所示:计数周期为7,输入脉冲输入了8个脉冲,比较器才输出1个脉冲,实现8分频。
如上图:预分频器为16bit,就是计数器为16bit,则它能分频的最大倍数为:2^16 = 65536 。
2.3:计数器CNT
例如:如果是2bit的计数器,N也为2bit,那么最大分频倍数为2^2 = 4。
没有脉冲来时:计数器为00
第1个脉冲来:计数器为01
第2个脉冲来:计数器为10
第3个脉冲来:计数器为11
第4个脉冲来:计数器变为00,然后向外输出一个脉冲。
2.4:update事件与预加载
N值决定了 的周期,有时我们需要在 运行的过程中 态地调整N的值为了防止出错这个调整需要加一些保护措施(预加载 Preload)。
新的N值首先被写 shadow中,等到下一次Update事件时传 active ,至此才能真正发挥作用。
如图:在计数的中途改变N的值时,N的值保存在影子寄存器中,然后等待这一次的计数完成后,影子寄存器在将N的值写入shadow里面。
3、标准库编程
3.1:通过定时器中断来设置延迟函数
#include "stm32f10x.h" // Device header
void Time_Init(void);
void LED_Init(void);
void Delay_us(uint64_t us);
void Delay_ms(uint32_t ms);
static uint32_t count = 0;
int main(void)
{
Time_Init();
LED_Init();
while(1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
Delay_ms(1000);
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
Delay_us(1000000);
}
}
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStruct);
}
/*
定时器的初始化
*/
void Time_Init(void)
{
//1. 使能挂载定时器TIM3的总线时钟
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3,ENABLE);//复位
RCC_APB1PeriphResetCmd(RCC_APB1Periph_TIM3,DISABLE);//复位
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能时钟
//2. 使能ARR寄存器的预加载特性
TIM_ARRPreloadConfig(TIM3,ENABLE);//打开预加载特性
//3. 初始化时基单元,这些都是配置影子寄存器中
TIM_TimeBaseInitTypeDef TIMInitStruct;
TIMInitStruct.TIM_Prescaler = 71;//配置预分频器PSC
TIMInitStruct.TIM_Period = 999;//配置自动重装寄存器ARR
TIMInitStruct.TIM_CounterMode = TIM_CounterMode_Up;//配置计数器为向上计数模式
TIM_TimeBaseInit(TIM3,&TIMInitStruct);
//4. 收到启动Update事件,必须手动启动,因为配置好了的定时器参数在影子寄存器中
TIM_GenerateEvent(TIM3,TIM_EventSource_Update);
//5. 使能Updata中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);//打开Updata触发的中断源
//6. 配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVICInitStruct;
NVICInitStruct.NVIC_IRQChannel = TIM3_IRQn;
NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVICInitStruct.NVIC_IRQChannelSubPriority = 0;
NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVICInitStruct);
//7. 使能定时器TIM3
TIM_Cmd(TIM3,ENABLE);
}
/*
定时器的中断函数,由上面的定时器初始化得,PSC = 71,则分频72倍,72MHz/72 = 1MHz
1MHz代表1s/1000000 = 0.000001s = 1us,所以没间隔1us计数一次。
自动重装器为999,则代表每隔1000 * 1us = 1ms触发一个Update事件,然后产生一个中断。
*/
void TIM3_IRQHandler(void)
{
//判断中断标准位,是谁产生的中断源
if(TIM_GetFlagStatus(TIM3,TIM_FLAG_Update) == SET)//如果是Update产生的中断源
{
TIM_ClearFlag(TIM3,TIM_FLAG_Update);//清除中断标准位
count++;//代表每隔1ms,count加1。
}
}
/*
定义一个ms的延迟函数
*/
void Delay_ms(uint32_t ms)
{
uint64_t time = count + ms;
while(count < time);
}
/*
定义一个us的延迟函数
*/
void Delay_us(uint64_t us)
{
uint64_t time = count * 1000 + TIM_GetCounter(TIM3) + us;//TIM_GetCounter(TIM3)获取计数器计数的值
while(count * 1000 + TIM_GetCounter(TIM3) < time);
}