金牌会员
 
- 积分
- 1128
- 金钱
- 1128
- 注册时间
- 2016-3-25
- 在线时间
- 365 小时
|
有的时候,程序的实时性要求比较严格,所以会很关心某一个段程序或者某一个数据传送过程所以消耗的时间是否达标。这个时候就会想办法去获取这个时间值。
最近本人在项目上遇到了这一个问题。负责一个设备上的电源,这个电源是可调的直流电源。可调范围:0~12V,电流最大3A。PC通过USB来控制开、断。输出电压设置,
电流过载值的设定。 模块自身根据检测的电流与设定的电流过载值来开启保护(断电),把异常上报PC。
当某一种情况,电流会突然变大很大,很可能超过设定的电流过载值, 为了避免这一突发情况,判断是否是真的过流,所以这里设定了一个时间,如果电流过载时间超过
了这个设定值,那就启动保护,把电源输出切断。
我也许和大家一样,脑子里第个方案就是采用软件延时或者中断方法。采用软件延时是不可能的,我也实际测试过。PC需要不断的读取电流、电压值,查询电源的输出状态。当采用软件
延时时,PC从发送数据到接收花费几十MS,所以这个方法不可取。中断的话实时性比较高,但是这里有一个问题:当检测到电流过载时,马上开启定时器计数。到达数据时产生中断,再判断
电流是否过载,然后根据判断结果来决定是否采取保护。这逻辑是没错,但是有这样一种情况:假如我们需要检测到电流过载时间超过1秒钟就开启保护。根据中断的思路,当检测到电流过
载时,开启定时器定时,然后计数到了后判断作出是否开启保护。但是如果当检测到电流过载后,过载的时间只保持了500MS,这样还是要等1S后的中断才能作出决定。 所以领导否定了我的
中断想法。考虑到定时器的TIMX->CNT是可读的,我是否可以把定时器配置成自动重装,循环计数呢。经过测试是可以的。
思路:当检测到电流过载时,把定时器的TIMX->CNT值保存。然后不停的检测是否过过流,如果过流,获取当前 定时器TIMX->CNT的值与第一个保存的值进行求差,差值是否超延时
,根据结果来决定是否开启保护。当然这个计数值尽量大。比如计数值设置的是6000,延时时间不能超过6000,不然可能经常不会有过载保护动作。
不多说了。把代码贴上,本人也是不喜欢多说,只喜欢敲键盘验证:
1.定时器的初始化(摘自正点原子MINI-定时器中断实验)
//定时器3,时钟源为选择为APB1的2倍,而APB1为36M
void TIM3_Int_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
TIM_TimeBaseStructure.TIM_Period = 60000; //
TIM_TimeBaseStructure.TIM_Prescaler =7199; //设置用来作为TIMx时钟频率除数的预分频值 20Khz的计数频率
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
// TIM_ITConfig( //使能或者失能指定的TIM中断
// TIM3, //TIM2
// TIM_IT_Update ,
// ENABLE //使能
// );
// NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断
// NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级0级
// NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级3级
// NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
// NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
TIM_ARRPreloadConfig(TIM3, ENABLE); //自动重装使能
TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
}
把中断这一块注释了,不用中断。
2.判断延时是否到达
bool OverLoadTimeout(void)
{
uint16_t temp=0;
temp=TIM3->CNT;
if(temp<=over_current_start_time)
{
if((60000 - over_current_start_time+temp) >= Delay_Timer*10)
{
return TRUE;
}
}
else
{
if(temp - over_current_start_time >= Delay_Timer*10)
{
return TRUE;
}
}
return FALSE;
}
3.获取当前 定时器TIMX->CNT的值函数
//获取当前定时器TIMX->CNT的值。
void GetOverLoadStartTime(void)
{
over_current_start_time=TIM3->CNT;
}
好的,这是 这个帖子的核心代码。在这里声明,这个方法的时间是不精确,只是大概。
我用这个方法测试了ADS1115芯片用模拟IIC来读取AD值所以消耗的时间,是9ms。我写这个帖子目的:
1.做一个笔记,特别是在自己想知道某一段代码执行时间,可以用个来大致的测试 一下。
2.给有需要的朋友一个思路。
也不什么好思路,网友们看看就行,有什么更好的方法请不啬赐教。
有一张测试AD读取代码运行时间的结果图片,明天上传给大家看一下。
|
|