原子大哥,各位大虾:
求急救!
我的情况是这样的:
1、供电是用24V->5V->3.3V(需要24V给外接的负载供电,5V要给蜂鸣器等供电),芯片是STM32F105RBT6。
2、用Systick作为基准时钟,每1ms产生一个中断更新时钟;用定时器timer6实现延时100ms后产生中断,执行关闭蜂鸣器的动作(在主函数中打开,启动timer6)。
问题描述:1、在24V上电时概率性出错——蜂鸣器一直响,没有关闭。系统按键复位的时候没有问题,屏蔽Systick和采用for循环延时的时候也没有问题,单独不频闭Systick或使用timer6时也会概率性出现。所以初步判断应与软件(主要是Systick和Timer的使用)有关。
2、在不用24V供电,而采用串口的5V供电时(即略过了24V->5V的芯片),插拔串口接头时也是该概率性问题,而且插在串口1和串口2的概率不同,所以考虑与硬件有关。
现在是用独立看门狗强制复位在,但是很想知道这个问题具体是怎么出现的,以便针对性解决。代码在下面,请大家帮忙看看,感激不尽!
int main(void)
{
// uint32_t i = 0, j = 0;
RCC_Configuration();
/*此处配置Systick每1ms产生一个中断(中断函数实现系统运行时间的递增)溢出时清零,若以后增强功能,此函数需要修改*/
/*----------------Systcik_Configuration------------------*/
SysTick_Configuration();
/*外设模块的中断配置放在各自的初始化代码段。
下面函数完成中断优先级分组和预留(未打开)的系统内部模块的中断配置,可以在需要时根据要求调整*/
/* NVIC configuration ------------------------------------------------------*/
NVIC_Configuration();
/*此处只定义了控制数字输出量和用于外部中断的部分GPIO口,其余模块的引脚在其初始化时再打开*/
/* GPIO configuration ------------------------------------------------------*/
GPIO_Configuration();
/*CAN 配置*/
CAN_Config();
/*此处完成用于热电偶温度转换的外接MAX6675和STM32片内ADC1以及DAC的配置,ADC3的配置暂时保留*/
/*外部ADC MAX6675配置,并选定温度2、3*/
ExtADC_Configuration();//这两句是配置外接的MAX6675的语句,只涉及引脚的配置问题,与定时无关
TEMP2_3_Select(TEMP2); //使温度2、3共用的MX6675接通温度2的传感器
/*---------------------USART_Init,TIM_Init------------*/
USART_Configuration();
TIM_Configuration();
/* 内部ADC1 configuration 并启动准换------------------------------------------------------*/
ADC_DMA_Configuration();
//EXTI_Configuration----
EXTIX_Configuration();
/*DAC configuration--------------*/
DAC_Configuration();
BeepON;
StartTIM6(BEEP_DELAY_100MS_OFF, 100);
/* for( i = 0 ;i < 72 ;i++)
{
for(j = 0; j < 1000; j++)
{
}
}
BeepOFF;
*/
while(1);
}
void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus; /* 定义枚举类型变量 HSEStartUpStatus */
RCC_DeInit(); /* 复位系统时钟设置*/
RCC_HSEConfig(RCC_HSE_ON); /* 开启HSE 外部高速晶振*/
HSEStartUpStatus = RCC_WaitForHSEStartUp(); /* 等待HSE起振并稳定*/
if(HSEStartUpStatus == SUCCESS) /* 判断HSE起是否振成功,是则进入if()内部 */
{
RCC_HCLKConfig(RCC_SYSCLK_Div1); /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
RCC_PCLK2Config(RCC_HCLK_Div1); /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
RCC_PCLK1Config(RCC_HCLK_Div2); /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
FLASH_SetLatency(FLASH_Latency_2); /* 设置FLASH延时周期数为2 */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 使能FLASH预取缓存 */
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9); /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
RCC_PLLCmd(ENABLE); /* 使能PLL */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); /* 等待PLL输出稳定 */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* 选择SYSCLK时钟源为PLL */
while(RCC_GetSYSCLKSource() != 0x08); /* 等待PLL成为SYSCLK时钟源 */
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); /* 打开APB2总线上的GPIOA时钟*/
}
void SysTick_Configuration()
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择系统时钟 HCLK/8
// fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
SysTick->LOAD = (SystemCoreClock/8000) - 1; //时间加载,时钟为72MHz时,该值应为9000 - 1
SysTick->VAL = 0x00; //清空计数器
SysTick->CTRL |=(1<<0 |1<<1); //开始倒数
}
//配置需要用到的定时器
void TIM_Configuration(void)
{
TIM2_Init();
TIM3_Init();
TIM5_Init();
//TIM6用于任务延时完成
TIM6_Init();
//TIM7用于定时发送刷新CAN消息
TIM7_Init();
}
//定时器6配置
//用于特定时间的定时,需要手动开启
void TIM6_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); //使能TIM6时钟,36MHz
TIM_DeInit(TIM6);
//初始化定时器6 TIM6
TIM6_TimeBaseStructure.TIM_Period = 0; //设定计数器自动重装值
TIM6_TimeBaseStructure.TIM_Prescaler = 35999; //预分频器,将72MHz降为2KHz
TIM6_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV4; //设置时钟分割:TDTS = Tck_tim,对于TIM6、7无效
TIM6_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM6, &TIM6_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
//中断分组初始化
NVIC_InitStructure.NVIC_IRQChannel = TIM6_IRQn; //TIM6中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级2级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //从优先级0级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
void StartTIM6(TIM6_TASK_FLAG TIM6taskflag, u16 ARR)
{
// printf("------->timer 6<---------");
enTIM6_TASK_FLAG = TIM6taskflag;
TIM6_TimeBaseStructure.TIM_Period = (ARR + ARR - 1); //设定计数器自动重装值
TIM_TimeBaseInit(TIM6, &TIM6_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_ARRPreloadConfig(TIM6, ENABLE);
TIM_GenerateEvent(TIM6,TIM_EventSource_Update); // 产生软件更新事件,立即更新数据
TIM_ClearFlag(TIM6,TIM_FLAG_Update); //清除标志位。定时器一打开便产生更新事件,若不清除,将会进入中断
TIM_ITConfig(TIM6,TIM_IT_Update,ENABLE);//允许更新中断、在对应的中断函数中失能该中断,以实现单次定时
TIM_Cmd(TIM6,ENABLE ); //使能定时器6
}
//定时器6中断处理函数
void TIM6_IRQHandler(void)
{
// SYSTEMTIME m_stSYSTEM_TIME;
//根据StartTIM6设定的定时目的来完成任务
switch(enTIM6_TASK_FLAG)
{
case BEEP_DELAY_100MS_OFF:
BeepOFF;
break;
case BLOWER_DELAY_5S_OFF:
StopAirBlower();
genREFORMINGROOM_HIGH_TEMP_ALARM = OFF;
break;
}
TIM_ITConfig(TIM6,TIM_IT_Update,DISABLE);//失能更新中断
enTIM6_BUSYING_FLAG = OFF;
TIM_ClearITPendingBit(TIM6, TIM_IT_Update); //清除中断标志位
}
|