Arduino 软件定时器应用

Arduino UNO 有timer0、timer1、timer2三个定时器。delay(),millis()是用timer0实现的。timer0和timer2都是8位,timer1是16位。由于millis()函数会禁止中断,所以不能在ISR中使用。精确定时可以使用delayMicroseconds(),或者如下方法:

#define ddtick __asm__("nop\n\t");
#define dd4tick __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
//the Macro dd4tick will delay 0.25us exactly on 16MHz Arduino
#define delayOneUs() {dd4tick;dd4tick;dd4tick;dd4tick;}

 

/*
 * fifo.h
 * 
*/
struct FIFO8 {
  unsigned char *buf;
  int p, q, size, free, flags;
};

/*
 * fifo.c
 *
*/
#define FLAGS_OVERRUN    0x0001

void fifo8_init(struct FIFO8 *fifo, int size, unsigned char *buf)
{
  fifo->size = size;
  fifo->buf = buf;
  fifo->free = size;
  fifo->flags = 0;
  fifo->p = 0;
  fifo->q = 0;
  return;
}

int fifo8_put(struct FIFO8 *fifo, unsigned char data)
{
  if (fifo->free == 0) {
    fifo->flags |= FLAGS_OVERRUN;
    return -1;
  }
  fifo->buf[fifo->p] = data;
  fifo->p++;
  if (fifo->p == fifo->size) {
    fifo->p = 0;
  }
  fifo->free--;
  return 0;
}

int fifo8_get(struct FIFO8 *fifo)
{
  int data;
  if (fifo->free == fifo->size) {
    return -1;
  }
  data = fifo->buf[fifo->q];
  fifo->q++;
  if (fifo->q == fifo->size) {
    fifo->q = 0;
  }
  fifo->free++;
  return data;
}

int fifo8_status(struct FIFO8 *fifo)
{
  return fifo->size - fifo->free;
}

/*
 * timer.h
 * 
*/
int timer1_counter,i;
struct TIMERCTL {
  unsigned int count;
  unsigned int timeout;
  struct FIFO8 *fifo;
  unsigned char data;
};
struct TIMERCTL timerctl;
struct FIFO8 timerfifo;
char timerbuf[8];
int intLock=0;

/*
 * timer.c
 * 
*/

/*uint8_t oldSREG = SREG;  //狀態寄存器(包括是否允許 Interrupt),也可以使用这个寄存器解决嵌套调用问题 */
void enterCritical(void){
  noInterrupts();
  return intLock++;
}
void exitCritical(void){
  if(--intLock<1){
    interrupts();
  }
}
void settimer(unsigned int timeout, struct FIFO8 *fifo, unsigned char data)
{
  enterCritical();
  timerctl.timeout = timeout;
  timerctl.fifo = fifo;
  timerctl.data = data;
  exitCritical();
  return;
}

ISR(TIMER1_OVF_vect){
  TCNT1=timer1_counter;
  intTimer1Handler();
}

void intTimer1Handler(void)
{
  //最好加入中断完成通知
  /*
   * do sth...
  */
  timerctl.count++;
  if (timerctl.timeout > 0) { 
    timerctl.timeout--;
    if (timerctl.timeout == 0) {
      fifo8_put(timerctl.fifo, timerctl.data);
    }
  }
  return;
}

void time1Init(void){
  noInterrupts();
  TCCR1A=0;
  TCCR1B=0;
  //timer1_counter=65536-((16MHz/256)*0.5);//0.5s定时器中断
  timer1_counter=65536-60*1;//10ms   //34286;//预加载timer1 65536-16Mhz/256/2Hz
  TCNT1=timer1_counter;
  TCCR1B|=(1<<CS12);
  TIMSK1|=(1<<TOIE1);  
  interrupts();

  fifo8_init(&timerfifo, 8, timerbuf);
}

void timer1Proc(void){
  noInterrupts();
  if (fifo8_status(&timerfifo) == 0) {
    interrupts();
  } else {
    if (fifo8_status(&timerfifo) != 0) {
      i = fifo8_get(&timerfifo);
      interrupts();
      Serial.println("timer1 timeout,do something...");
      //restart timer1
      //settimer(1000, &timerfifo, 2);
    }
  }  
}
/*
 * ledButton.h
 * 
*/
// constants won't change. They're used here to set pin numbers:
const int buttonPin = 4;    // the number of the pushbutton pin
const int ledPin = 13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

/*
 * ledButton.c
 * 
*/

void ledButtonInit(void){
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);  
}

void ledButtonProc(void){
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:
    
    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;
      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
        //start timer1
        settimer(1000, &timerfifo, 1);
      }
    }
  }
  // set the LED:
  digitalWrite(ledPin, ledState);
  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;  
}

/*
 * esp.h
 * 
*/
#include "SoftwareSerial.h"
SoftwareSerial espSerial(2,3);
/*
 * esp.c
 * 
*/
void espInit(void){
  espSerial.begin(9600);
}
/*
 * espPowerOnSeq
*/
int espPwrOnStep;
int lastDelayTime4espPwrOnSeq;

void espPowerOnSeqInit(){
 espPwrOnStep=0;
 lastDelayTime4espPwrOnSeq=0;  
}

void espPowerOnSeqExit(){
 espPwrOnStep=-1;
 lastDelayTime4espPwrOnSeq=0;  
}

void espPowerOnSeq(void){
  if(espPwrOnStep==0){
    if((millis()-lastDelayTime4espPwrOnSeq)>10){
      Serial.println("delay 10ms");
      lastDelayTime4espPwrOnSeq=millis();
      espPwrOnStep=1;
    }
  }
  if(espPwrOnStep==1){
    if((millis()-lastDelayTime4espPwrOnSeq)>20){
      Serial.println("delay 20ms");
      lastDelayTime4espPwrOnSeq=millis();
      espPowerOnSeqExit();
    }
  }  
}
/*
 * doCMD
*/
String str;
int doCmdStep;
int doCmdSubStep1;
int lastDelayTime4doCMD;
int delayCount4doCMD; //timeout

void doCMDInit(){
  str="";
  doCmdStep=0;
  doCmdSubStep1=0;
  lastDelayTime4doCMD=0;
  delayCount4doCMD=0; //timeout 
}

void doCMDExit(){
  str="";
  doCmdStep=-1;
  doCmdSubStep1=0;
  lastDelayTime4doCMD=0;
  delayCount4doCMD=0; //timeout 
}

bool doCMD(String cmd,String flag,long timeout){
  if(doCmdStep==0){
    str="";  
    delayCount4doCMD=timeout/100;
    flag.toLowerCase();//小写
    espSerial.println(cmd);//发送命令
    //delay 10ms
    if((millis()-lastDelayTime4doCMD)>10){
      Serial.println("delay 10ms");
      lastDelayTime4doCMD=millis();
      doCmdStep=1;
    }
  }
  if(doCmdStep==1){
    if(espSerial.available()){
      if(doCmdSubStep1==0){
        str+=espSerial.read();
        doCmdSubStep1=1;      
      }
      if(doCmdSubStep1==1){
        //delay 2ms
        if((millis()-lastDelayTime4doCMD)>2){
          Serial.println("delay 2ms");
          lastDelayTime4doCMD=millis();
          doCmdSubStep1=0;
        }        
      }
    }else{
      doCmdStep=2;  
    }
  }
  if(doCmdStep==2){
    if(str!=""){
      Serial.println(str);
      str.toLowerCase();
      String flag1="",flag2="";
      int indexPosition=flag.indexOf('|');
      //有"|",多个关键字符串
      if(indexPosition>-1){
        flag1=flag.substring(0,indexPosition);
        flag2=flag.substring(indexPosition+1,flag.length());

        if(flag1!=""&&flag2!=""){
          if(str.indexOf(flag1)>-1||str.indexOf(flag2)){
            doCMDExit();
            return true;
          }
        }
      }
      //没有"|",单个关键字符串
      if(str.indexOf(flag)>-1){
        doCMDExit();
        return true;
      }
    }
    //delay 100ms
    if((millis()-lastDelayTime4doCMD)>100){
      Serial.println("delay 100ms");
      lastDelayTime4doCMD=millis();
      doCmdStep=1;
      delayCount4doCMD>0 ? delayCount4doCMD--:doCmdStep=3;
    }              
  }
  if(doCmdStep==3){
    doCMDExit();
    return false;
  }
}

void commaSplit(String message){
  int commaPosition;
  do{
    commaPosition=message.indexOf(',');
    if(commaPosition!=-1){
      Serial.println(message.substring(0,commaPosition));
      message=message.substring(commaPosition+1,message.length());
    }
    else{
      if(message.length()>0){
        Serial.println(message);
      }
    }
  }while(commaPosition!=-1);
}
//arduino UNO confige
void setup() {
  Serial.begin(9600);
  espInit();
  ledButtonInit(); 
  time1Init();
  commaSplit("1,2,3,4");
}
//round-robin scheduling
void loop() {
  timer1Proc();
  ledButtonProc();
}
 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Arduino ESP8266有多个定时器可用,其中最常用的是硬件定时器软件定时器。 硬件定时器: ESP8266有两个硬件定时器,分别是timer0和timer1。这些定时器的频率是固定的,在ESP8266上分别为80MHz和160MHz。这些定时器可以用来实现精确的定时操作,例如延迟、PWM等。 软件定时器软件定时器是通过编写代码来模拟一个定时器的方式实现的。这种定时器的精度比硬件定时器低,但是可以在任何GPIO引脚上使用。软件定时器通常使用定时中断来实现,当计时器达到设定的时间时,会触发一个中断。在中断处理程序中,可以执行所需的操作。 以下是一个使用软件定时器的例子: //定义一个计时器 unsigned long timer = 0; //定义定时器时间 unsigned long interval = 1000; void setup() { //初始化串口 Serial.begin(9600); } void loop() { if (millis() - timer > interval) { //如果计时器达到了定时器时间 timer = millis(); //重置计时器 Serial.println("Hello World!"); //输出Hello World! } } 在这个例子中,我们使用了Arduino的内置函数millis()来获取当前时间。当计时器达到设定的时间时,我们重置计时器并执行所需的操作。这个例子每隔1秒输出一次“Hello World!”。 总结: 硬件定时器软件定时器都有各自的优缺点,具体使用哪种定时器取决于应用的要求。使用定时器可以让我们在Arduino ESP8266上实现精确的定时操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值