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();
}