系统定时原理是由晶振产生电流脉冲,而电流脉冲的频率F是固定的,那么通过记录脉冲节拍数N;那么:T=N/F,或者说T=1/F;
设置SysTick->CTRL的第三位(TICKINT)设置检查外部时钟还是内部时钟(我选的外部时钟),并将第十六位状态位(COUNTGLAG)置零,TICKINT一般设为0;
自动重载寄存器可以设置23位即最大值为二的23次方。我设置的是按照我修改的数据计算出21个节拍为一微秒。
计算过程:
首先得分析时钟树,PLL为CPU主频,那么PLL接收的是哪晶振呢?
根据时钟树可以看到连接HSE OSC这个,给出的频率也是一个范围,这是因为芯片型号的不同频率可能会不一样。但根据引脚编码结合原理图可以看到OSC_OUT 和OSE_IN对应的是8MHz的频率,但过程中又有那么多分频之类的。参数也是未知的。这个就是软件的事了。
通过启动程序模块的代码可以看到(不同型号的找对应信号的),一下代码,
*=============================================================================
* Supported STM32F40xxx/41xxx devices
*-----------------------------------------------------------------------------
* System Clock source | PLL (HSE)
*-----------------------------------------------------------------------------
* SYSCLK(Hz) | 168000000
*-----------------------------------------------------------------------------
* HCLK(Hz) | 168000000
*-----------------------------------------------------------------------------
* AHB Prescaler | 1
*-----------------------------------------------------------------------------
* APB1 Prescaler | 4
*-----------------------------------------------------------------------------
* APB2 Prescaler | 2
*-----------------------------------------------------------------------------
* HSE Frequency(Hz) | 25000000
*-----------------------------------------------------------------------------
* PLL_M | 25
*-----------------------------------------------------------------------------
* PLL_N | 336
*-----------------------------------------------------------------------------
* PLL_P | 2
*-----------------------------------------------------------------------------
* PLL_Q | 7
*-----------------------------------------------------------------------------
* PLLI2S_N | NA
*-----------------------------------------------------------------------------
* PLLI2S_R | NA
*-----------------------------------------------------------------------------
* I2S input clock | NA
*-----------------------------------------------------------------------------
* VDD(V) | 3.3
*-----------------------------------------------------------------------------
* Main regulator output voltage | Scale1 mode
*-----------------------------------------------------------------------------
* Flash Latency(WS) | 5
*-----------------------------------------------------------------------------
* Prefetch Buffer | ON
*-----------------------------------------------------------------------------
* Instruction cache | ON
*-----------------------------------------------------------------------------
* Data cache | ON
*-----------------------------------------------------------------------------
* Require 48MHz for USB OTG FS, | Disabled
* SDIO and RNG clock |
*-----------------------------------------------------------------------------
*=============================================================================
这里的HSE为25000 000Hz(即25MHz)那么这个参数就对不上了,HSE出来的第一个分频参数 PLL_M 也跟着最好改改 不然不好算(记得修改文件权限,因为这文件是只读的)。
改完后:
HSE(8MHz)/PLL_M(8)*PLL_N(336)/ PLL_P(2) /AHB(1) =168MHz
168MHz/8=21MHz;
所以21个节拍为1us;
SysTick->CTRL|=0x01;
定时器到达设定时间判断:标志位是否为1即可
这是一个精准延迟1微妙,通过直接操作寄存器设置完成的。
void delay_us(int x){
SysTick->CTRL=0;
SysTick->LOAD=x*21-1;
SysTick->VAL=0;
SysTick->CTRL|=0x01;
while(!(SysTick->CTRL&(0x01<<16)));
}
通用定时器跟片内滴答定时器原理基本一致,都是通过脉冲频率推算时间的;
TIM14对应的是APB1 (这里的频率为什么这么算我也不大清楚,有知道的麻烦告知)
这里采用标准库函数设置;
void timeer_init(){
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
// 设置分频 将84MH降为10000Hz
TIM_TimeBaseInitStruct.TIM_Prescaler=8400-1;
// 设置计数模式往上加,还是往下减
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
// 设置自动复位计数器为10000,恰好为1秒
TIM_TimeBaseInitStruct.TIM_Period=10000-1;
// 设置分频为1
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
// 初始化定时器
TIM_TimeBaseInit(TIM14, &TIM_TimeBaseInitStruct);
// 开启定时器
TIM_Cmd( TIM14, ENABLE);
// 打开定时器中断
TIM_ITConfig(TIM14, TIM_IT_Update,ENABLE);
// 设置仲裁优先级,并打开中断
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel= TIM8_TRG_COM_TIM14_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=5;
NVIC_InitStruct.NVIC_IRQChannelCmd= ENABLE;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStruct);
}
// 中断处理函数编写
void TIM8_TRG_COM_TIM14_IRQHandler(){
// 检查中断标准位是否为1
if(TIM_GetITStatus(TIM14,TIM_FLAG_Update)==SET){
// 开关灯
PF_ODR(9)=!PF_ODR(9);
// 降中断标志位复位
TIM_ClearITPendingBit( TIM14, TIM_FLAG_Update);
}
}