使用STM32实现心跳包,非阻塞延迟

背景:

项目中要使用485通信,而485通信中采用的主呼从应的方式需要一个超时时间,在呼叫指令发出时将定时器置0并开始计时,并在数据接收函数中判断是否超时。

正文:

设计思路:首先,需要一个定时产生中断的定时器(比如滴答定时器,CubeMX生成的工程滴答定时器默认为1ms中断一次),然后可以在这个定时器中断函数中做多个计数器,每次进入后计数器加1,并判断是否到达溢出条件。

代码实现:

timer.h

#ifndef __DELAY_H__
#define __DELAY_H__

#include "stdint.h"
#include "stm32f4xx.h"



typedef struct __timer
{
  uint8_t     overFlow;
  uint32_t    cnt;
  uint32_t    overFlowValue;
  void        (*timerReset)     (struct __timer* p_timer, uint32_t overFlagValue);
  void        (*timerRun)       (struct __timer* p_timer);
}timer_t;


/*
    滴答定时器进入中断的时间间隔,这个值理论上越大越好,当然这个值
    的设置还取决于你需要多长时间的溢出Flag,假如你需要一个25ms溢出
    的Flag,那么将中断时间间隔必须设置为25的约数,并且取最大值。
    另外,你可以添加新的心跳,例如下面的EnterITPer_2Ms,但记得在
    heartBeatInit()函数中添加相关的心跳计算因数设置代码。
    还有,心跳不要超过50ms,超过50ms请自测心跳是否正常
*/
typedef enum __SysTickITPeriod    
{
  EnterITPer_1Ms    = 1000,
  /*EnterITPer_2Ms  = 500,*/
  EnterITPer_5Ms    = 200,
  EnterITPer_10Ms   = 100,
  EnterITPer_50Ms   = 20,
  
}SysTickITPeriod_t;



/*------------全局变量-------------*/
extern timer_t SecondPulse;
extern timer_t RS485_Polling;
extern timer_t LEDBlinkTimer;

/*-------------全局函数-----------------*/

extern void globalTimerRun(void);

extern void heartBeatInit(SysTickITPeriod_t factor);


#endif

timer.c

/*
    @>说明:定时器的创建见下方 New_Timer 出现的位置
    
    @>说明:定时器的使用: 
                    使用 New_Timer.overFlow 判断是否溢出
                    使用 New_Timer.timerReset(&New_Timer, xxx) 来设置定时器溢出时间
                    
*/

#include "delay.h"



/*vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv心跳相关vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv*/

static uint16_t heartBeatFactor = 1;
static void timerInit(timer_t* p_timer, uint32_t overFlagValue);

timer_t SecondPulse;
timer_t LEDBlinkTimer;
timer_t RS485_Polling;
                                                                    
/*timer_t New_Timer */
/*---------------------------------------------------------------------
    @功能:更新所有的定时器计数值
-----------------------------------------------------------------------*/
void globalTimerRun(void)
{
  SecondPulse.timerRun(&SecondPulse);
  LEDBlinkTimer.timerRun(&LEDBlinkTimer);
  RS485_Polling.timerRun(&RS485_Polling);
  
  /*timer_t New_Timer.timerRun(&New_Timer) */
}


/*-----------------------------------------------------------------
    @>功能:初始化滴答定时器进入中断的时间间隔
            可选参数参见 SysTickITPeriod_t
            并且设置 heartBeatFactor 心跳计算
            因数,该数值为1ms的整数倍。
------------------------------------------------------------------*/
void heartBeatInit(SysTickITPeriod_t factor)
{
  switch(factor)
  {
    case EnterITPer_1Ms :
      heartBeatFactor = 1;
      break;
    case EnterITPer_5Ms :
      heartBeatFactor = 5;
      break;
    case EnterITPer_10Ms :
      heartBeatFactor = 10;
      break;
    case EnterITPer_50Ms :
      heartBeatFactor = 50;
      break;
  }
  HAL_SYSTICK_Config(SystemCoreClock /factor);
  
  timerInit(&SecondPulse, 1000);        /*---初始化定时器---*/
  timerInit(&RS485_Polling, 2000);
  timerInit(&LEDBlinkTimer, 100);

  
  /*timerInit(&New_Timer, 1000);*/
}











/*-----------------------------------------------------------------
    @>功能:更新定时器计数,被滴答定时器中断调用
    @>参数:p_timer          定时器指针
-------------------------------------------------------------------*/
static void timerRun(timer_t* p_timer)
{
  if(p_timer->cnt >= p_timer->overFlowValue / heartBeatFactor)
  {
    p_timer->overFlow = 1;
  }
  else 
  {
    p_timer->cnt++;
  }
}

/*-----------------------------------------------------------------
    @>功能:重新启动定时器
    @>参数:p_timer 指定定时器,overFlagValue指定溢出值单位1ms
-------------------------------------------------------------------*/
static void timerReset(timer_t* p_timer, uint32_t overFlagValue)
{
  p_timer->overFlowValue = overFlagValue;
  p_timer->cnt = 1;
  p_timer->overFlow = 0;
}


/*-----------------------------------------------------------------
    @>功能:初始化一个定时器
    @>参数:p_timer          定时器指针
            overFlagValue    设定时器溢出值
-------------------------------------------------------------------*/
static void timerInit(timer_t* p_timer, uint32_t overFlagValue)
{
  p_timer->overFlowValue = overFlagValue;
  p_timer->cnt = 1;
  p_timer->overFlow = 0;
  p_timer->timerReset = timerReset;
  p_timer->timerRun = timerRun;
}

将void globalTimerRun(void)函数置于定时器的中断中即可。

主循环进入While(1)之前调用,也可以不调用,默认的值为配置定时器后进入中断的时间间隔。

heartBeatInit(EnterITPer_1Ms );

判断定时是否到达:

if(timer.overFlow){
    ...
}

重置定时器:

timer.Reset(&timer, time);
发布了4 篇原创文章 · 获赞 1 · 访问量 101

猜你喜欢

转载自blog.csdn.net/socbis/article/details/105554404