历史上的今天
今天是:2024年10月08日(星期二)
2018年10月08日 | STM32定时器不准确启动时钟的问题
2018-10-08 来源:eefocus
用STM32 F407IG 开发一硬件控制器,需要精准的定时器。我使用了IIM2,可上电启动。有时候准确,有时候开机
定时器,很慢,比如定时500MS 闪烁一次,可能3秒才闪烁一次。源代码如下。
int main(void)
{
GPIO_Configuration();
TIM_Config();
NVIC_TIM_Config();
while(1)
{
}
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(LED1_RCC_AHBPeriph|LED2_RCC_AHBPeriph|LED3_RCC_AHBPeriph|LE D4_RCC_AHBPeriph , ENABLE);
GPIO_InitStructure.GPIO_Pin = LED1_Pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(LED1_Port, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LED2_Pin;
GPIO_Init(LED2_Port, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LED3_Pin;
GPIO_Init(LED3_Port, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LED4_Pin;
GPIO_Init(LED4_Port, &GPIO_InitStructure);
}
void TIM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_DeInit(TIM2);//初始化TIM1寄存器 407IG 主频为 168MHZ
TIM_TimeBaseStructure.TIM_Period = 10000-1;
TIM_TimeBaseStructure.TIM_Prescaler =4100-1;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ARRPreloadConfig(TIM2, ENABLE); //ARR自动装载默认是打开的,可以不设置
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_Cmd(TIM2, ENABLE); //使能TIM1定时器
}
void NVIC_TIM_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组为1
NVIC_InitStructure.NVIC_IRQChannel =TIM2_IRQn; //嵌套中断通道为TIM2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //响应优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能中断
NVIC_Init(&NVIC_InitStructure);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)
{
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
DispLed(3);
}
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
}
void DispLed(uint8_t ln)
{
if(ln==2)
{
Led2++;
if(Led2==0x2ffff)
{
GPIO_SetBits(LED2_Port , LED2_Pin);
}
else if(Led2==0x4ffff)
{
GPIO_ResetBits(LED2_Port , LED2_Pin);
}
else if(Led2>0x4ffff)
Led2=0;
}
else if(ln==1)
{
Led1++;
if(Led1==10)
{
GPIO_SetBits(LED1_Port , LED1_Pin);
}
else if(Led1==20)
{
GPIO_ResetBits(LED1_Port , LED1_Pin);
}
else if(Led1>20)
Led1=0;
}
else if(ln==4)
{
if(Led4==0)
{
Led4=1;
GPIO_SetBits(LED4_Port , LED4_Pin);
}
else
{
Led4=0;
GPIO_ResetBits(LED4_Port , LED4_Pin);
}
}
else if(ln==3)
{
if(Led3==0)
{
Led3=1;
GPIO_SetBits(LED3_Port , LED3_Pin);
}
else
{
Led3=0;
GPIO_ResetBits(LED3_Port , LED3_Pin);
}
}
}
折腾几天,定时就是,有时候准确,有时候特别慢,检查代码,反复比对。没有错误。后考虑,可能启动的系统采用的时钟不对。但,所有的例子程序,F407,都是默认的系统时钟。进一步分析系统启动过程
startup_stm32f4xx.s(系统启动文件)
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
在主程序启动之前,调用
//system_stm32f4xx.c
void SystemInit(void)
{
//设定FPU
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));
#endif
RCC->CR |= (uint32_t)0x00000001; //使能内部时钟
RCC->CFGR = 0x00000000; // Reset CFGR register 选择HSI振荡器做系统时钟 16MHZ
//关闭HSE,关闭时钟安全系统,关闭PLL和PLLI2S
RCC->CR &= (uint32_t)0xFEF6FFFF; // Reset HSEON, CSSON and PLLON bits
//配置PLLQ=4,选择HSI为PLL和PLLI2S时钟源,PLLP=2,PLLP=192,PLLM=16
RCC->PLLCFGR = 0x24003010;
//HSEBYPASS=0,即外部提供晶体非晶振
RCC->CR &= (uint32_t)0xFFFBFFFF;
//禁止所有中断
RCC->CIR = 0x00000000;
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif
SetSysClock();
//设定中断向量表
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
#endif
}
void SetSysClock(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
// Enable HSE :使能HSE外部时钟
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
//等待HSERDY位准备好(含超时次数检查)
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01; //准备好,则HSEStatus 为1
}
else
{
HSEStatus = (uint32_t)0x00; //否则,HSEStatus 为0
}
if (HSEStatus == (uint32_t)0x01) //如果HSEStatus 为1,则表示外部时钟准备好
{
//使能APB1供电,并使VOS=1支持高频
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
PWR->CR |= PWR_CR_VOS;
// HCLK = SYSCLK / 1:HCLK=System Clock(=168MHz)
RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
// PCLK2 = HCLK / 2 (:=84MHz)
RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
// PCLK1 = HCLK / 4(:=42MHz)
RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
// Configure the main PLL 配置锁相环
RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
(RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
// Enable the main PLL 使能PLL和PLLI2S
RCC->CR |= RCC_CR_PLLON;
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
// Configure Flash prefetch, Instruction cache, Data cache and wait state
//配置FLASH读写时序参数
FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
// Select the main PLL as system clock source
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= RCC_CFGR_SW_PLL;
// Wait till the main PLL is used as system clock source
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
{
}
}
else
{ //如果HSEStatus 为0,则表示外部时钟有问题
//用户可以添加代码处理
}
}
通过这两个函数分析,可能是系统启动时,当外部时钟准备失败。本来168M的时钟,采用了默认的16M时钟,所以定时变慢了。
尝试在主程序中,重新加载一次,系统时钟设定。
SetSysClock();
把这个函数重新定义到#include "system_stm32f4xx.h"
然后在主程序中添加 #include "system_stm32f4xx.h"
搞定。
史海拾趣
|
微波产业尽管在持续创新,许多产品仍根植于相同技术。例如,砷化镓(GaAs)就是目前许多先进功放及其它有源器件的核心技术。但在这些现象中,孕育着可能变革许多产品制造方式方法的创新。这些“颠覆性技术”会以闻所未闻、见所未见的完全新奇的面目兴 ...… 查看全部问答> |
|
今天一个家伙对我说 他同事 裁剪带有网络功能的uclinux 到 300多KB. 不带网络功能的 170多KB. 来自EEWORLD合作群:arm linux fpga 嵌入0(49900581) 群主:wangkj… 查看全部问答> |
|
我写了一个小程序,在c51中编译结果总是0,我知道是变量覆盖问题,但我不知道如何去写,请教大虾!!! #include int factorial( int n); int factorial( int n) { int result; if(n == 0) result=1; else &n ...… 查看全部问答> |




