From 919208c65f3519ae4df984e5f9c10a1740318722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=9F=83=E5=8D=9A=E6=8B=89=E9=85=B1?= Date: Sun, 4 Jul 2021 16:49:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=A4=BA=E4=BE=8B=E3=80=81?= =?UTF-8?q?=E6=96=87=E6=A1=A3=EF=BC=8C=E4=BF=AE=E5=A4=8Dbug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 6 +- examples/LedAndBuzzerShow.ino | 12 - .../LedAndBuzzerShow/LedAndBuzzerShow.ino | 29 ++ examples/SerialTimer/SerialTimer.ino | 17 + src/.vscode/c_cpp_properties.json | 5 +- src/TimersOneForAll.h | 466 ++++-------------- 6 files changed, 150 insertions(+), 385 deletions(-) delete mode 100644 examples/LedAndBuzzerShow.ino create mode 100644 examples/LedAndBuzzerShow/LedAndBuzzerShow.ino create mode 100644 examples/SerialTimer/SerialTimer.ino diff --git a/README.md b/README.md index 8b6c087..183d049 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Currently all APIs are function templates, which means all arguments must be kno # Timers All public APIs are under namespace TimersOneForAll, and require TimerCode as the first template argument. TimerCode indicates which hardware timer you want to use. Hardware timers vary by CPUs. For ATMega2560, there're 6 timers: ## Timer 0 -This timer is 8-bit, which means it has 2^8=256 states. It can generate COMPA and COMPB interrupts, but not OVF, because it's occupied by Arduino builtin function `millis()`. This means this timer is the last one you want to use among all the timers. Only use it if you really have strong reasons. +This timer is 8-bit, which means it has 2^8=256 states. It can generate COMPA and COMPB interrupts, but not OVF, because it's occupied by Arduino builtin function `millis();delay();micros();`. This means this timer is the last one you want to use among all the timers. Only use it if you really have strong reasons. ## Timer 1, 3, 4, 5 These timers are all 16-bit, with 65536 states, which means that they're more accurate than 8-bit timers. COMPA, COMPB and OVF interrupts are all available. You may want to use these timers for most scenarios. ## Timer 2 @@ -76,6 +76,10 @@ void SquareWave() //Generate the square wave for only RepeatTimes cycles. template void SquareWave() +//阻塞当前代码执行指定毫秒数 +//Block current code from running for DelayMilliseconds +template +void Delay() //取消指定给特定计时器的所有任务。其它计时器不受影响。 //Abort all tasks assigned to TimerCode. Other timers won't be affected. template diff --git a/examples/LedAndBuzzerShow.ino b/examples/LedAndBuzzerShow.ino deleted file mode 100644 index 5595254..0000000 --- a/examples/LedAndBuzzerShow.ino +++ /dev/null @@ -1,12 +0,0 @@ -/* - -*/ -#include -void setup() -{ -tone() -} -void loop() -{ - -} \ No newline at end of file diff --git a/examples/LedAndBuzzerShow/LedAndBuzzerShow.ino b/examples/LedAndBuzzerShow/LedAndBuzzerShow.ino new file mode 100644 index 0000000..9e40805 --- /dev/null +++ b/examples/LedAndBuzzerShow/LedAndBuzzerShow.ino @@ -0,0 +1,29 @@ +//上传该示例之前,请在7号口连接一个LED灯,8号口连接一个无源蜂鸣器的IO端口 +#include +using namespace TimersOneForAll; +constexpr uint8_t LED = 7; +constexpr uint8_t Buzzer = 8; +void setup() +{ + pinMode(7, OUTPUT); + pinMode(8, OUTPUT); + digitalWrite(LED,HIGH); + //设置计时器3在5秒后熄灭LED灯,但不阻断程序 + DoAfter<3,5000,LightDown>(); + //设置4号计时器,每隔2秒,就用5号计时器生成2000㎐脉冲1秒,重复3次 + RepeatAfter<4,2000,PlayTone<5,Buzzer,2000,1000>,3>(); + //设置计时器1,将程序阻断7秒 + Delay<1,7000>(); + //设置计时器1,将LED灯先亮2秒,再熄灭1秒,无限循环 + SquareWave<1,LED,2000,1000>(); + //设置计时器3在8秒后停止计时器1 + DoAfter<3,8000,ShutDown<1>>(); + //观察到,LED灯明暗循环两次后,最终停在了亮状态,因为1号计时器尚未触发暗事件就被停止了 +} +void LightDown() +{ + digitalWrite(LED,LOW); +} +void loop() +{ +} \ No newline at end of file diff --git a/examples/SerialTimer/SerialTimer.ino b/examples/SerialTimer/SerialTimer.ino new file mode 100644 index 0000000..a813cfc --- /dev/null +++ b/examples/SerialTimer/SerialTimer.ino @@ -0,0 +1,17 @@ +#include +using namespace TimersOneForAll; +//上传该示例之前,请确保你的PC准备好收发串口信号 +void setup() +{ + Serial.begin(9600); + //使用1号计时器开始计时 + StartTiming<1>(); + Serial.setTimeout(-1); +} +void loop() +{ + static uint8_t Instruction = 0; + Serial.readBytes(&Instruction, 1); + Serial.write((uint8_t*)&MillisecondsElapsed<1>, 2); +} +//上传后,可以从PC上向串口发送任意单字节,每次发送都会受到一个16位整数,指示经过的毫秒数。达到65535毫秒后会归零。 \ No newline at end of file diff --git a/src/.vscode/c_cpp_properties.json b/src/.vscode/c_cpp_properties.json index f3d8f5c..ae18843 100644 --- a/src/.vscode/c_cpp_properties.json +++ b/src/.vscode/c_cpp_properties.json @@ -12,10 +12,7 @@ "F_CPU=16000000", "ARDUINO_ARCH_AVR" ], - //支持__attribute__,不能用msvc - "intelliSenseMode": "gcc-x64", - "cStandard": "c17", - "cppStandard": "c++17" + "compilerPath": "C:\\Users\\vhtmf\\AppData\\Local\\Arduino15\\packages\\arduino\\tools\\avr-gcc\\7.3.0-atmel3.6.1-arduino7\\bin\\avr-gcc.exe" } ], "version": 4 diff --git a/src/TimersOneForAll.h b/src/TimersOneForAll.h index 39fcb99..71878ab 100644 --- a/src/TimersOneForAll.h +++ b/src/TimersOneForAll.h @@ -3,10 +3,10 @@ #error 仅支持AVR架构 #endif #include -//Give the timer you want to use as the first template argument. One timer can undertake one task only at the same time. If you assign a new task on a timer, it will abort the task assigned before. +//一个计时器只能同时执行一个任务。如果先布置的任务尚未完成,将会被后布置的任务覆盖掉。 namespace TimersOneForAll { - //Get milliseconds elapsed after the last call of StartTiming. + //取得上次调用StartTiming以来经过的毫秒数 template static volatile uint16_t MillisecondsElapsed; template @@ -153,140 +153,9 @@ namespace TimersOneForAll template volatile static uint32_t SR; template - volatile static uint32_t LR; + volatile static int32_t LR; #pragma endregion #pragma region 内部功能实现核心 - template - void CompaDLarge() - { - if (!--LR) - { - TIMSK = 0; - DoTask(); - } - }; - template - void CompaDSmall() - { - if (!--SR) - { - SetOCRA(TCNTLarge); - COMPA = CompaDLarge; - } - }; - template - void CompaRLarge(); - template - void CompaRSmall() - { - if (!--SR) - { - SR = LargeRepeats; - if (TCNTLarge < TimerMax[TimerCode]) - { - SetOCRA(TCNTLarge); - COMPA = CompaRLarge; - } - else - TIMSK = 1; - } - }; - template - void CompaRLarge() - { - if (!--SR) - { - SR = SmallRepeats; - if (TCNTLarge < TimerMax[TimerCode]) - { - SetOCRA(TCNTSmall); - COMPA = CompaRSmall; - } - else - TIMSK = 2; - DoTask(); - } - }; - template - void CompaRSelf() - { - if (!--SR) - { - SR = SelfRepeats; - DoTask(); - } - } - template - void CompaRLargeT(); - template - void CompaRSmallT() - { - if (!--SR) - { - SR = LargeRepeats; - if (TCNTLarge < TimerMax[TimerCode]) - { - SetOCRA(TCNTLarge); - COMPA = CompaRLargeT; - } - else - TIMSK = 1; - } - }; - template - void CompaRLargeT() - { - if (!--SR) - { - if (--LR) - { - SR = SmallRepeats; - if (TCNTLarge < TimerMax[TimerCode]) - { - SetOCRA(TCNTSmall); - COMPA = CompaRSmallT; - } - else - TIMSK = 2; - } - else - TIMSK = 0; - DoTask(); - } - }; - template - void CompaRSelfRepeat() - { - if (!--SR) - { - if (--LR) - SR = SelfRepeats; - else - TIMSK = 0; - DoTask(); - } - }; - template - void OvfR() - { - if (!--SR) - { - SR = IdealRepeats; - DoTask(); - } - }; - template - void OvfRT() - { - if (!--SR) - { - if (--LR) - SR = IdealRepeats; - else - TIMSK = 0; - DoTask(); - } - }; template void EfficientDigitalToggle() { @@ -318,166 +187,102 @@ namespace TimersOneForAll if (!--LR) TIMSK = 0; } - template - void InternalDA() + //Compa0表示自我重复,不切换 + template + void Compa0() { - constexpr bool Timer02 = TimerCode == 0 || TimerCode == 2; - if (TCNT) + if (!--SR) { - constexpr uint32_t TM = TimerMax[TimerCode]; - TIMSK = 0; - if (Timer02) - TCCRB = PrescalerBits; + if (InfiniteLr || --LR) + SR = SmallRepeats; else - TCCRA = 0; - //拒绝外部振荡源 - bitWrite(ASSR, AS2, false); - if (TCNT < TM) + TIMSK = 0; + DoTask(); + } + } + template + void Compa2(); + //Compa1是小重复,结束后要切换到大重复,但是大重复有可能是COMPA也可能是OVF + template + void Compa1() + { + if (!--SR) + { + if (Tcnt2 < TimerMax[TimerCode]) { - if (Timer02) - TCCRA = 0; - else - TCCRB = PrescalerBits; - SetOCRA(TCNT); - COMPA = [] - { - TIMSK = 0; - DoTask(); - }; - SetTCNT(0); - TIMSK = 2; + SetOCRA(Tcnt2); + COMPA = Compa2; } else + TIMSK = 1; + SR = SR2; + } + } + //Compa2是大重复,结束后要执行动作,如果有重复次数还要切换到小重复 + template + void Compa2() + { + if (!--SR) + { + if (InfiniteLr || --LR) { - constexpr uint16_t IdealRepeats = TCNT / (TM - (TimerCode == 0)); - if (IdealRepeats * TM < TCNT || TimerCode == 0) //Timer0的OVF不可用 + if (Tcnt2 < TimerMax[TimerCode]) { - constexpr uint16_t ActualRepeats = IdealRepeats + 1; - constexpr uint16_t TCNTSmall = TCNT / ActualRepeats; - constexpr uint16_t TCNTLarge = TCNTSmall + 1; - constexpr uint16_t SmallRepeats = ActualRepeats * TCNTLarge - TCNT; - constexpr uint16_t LargeRepeats = TCNT - ActualRepeats * TCNTSmall; - if (Timer02) - TCCRA = 2; - else - TCCRB = PrescalerBits + 8; - if (SmallRepeats) - { - SetOCRA(TCNTSmall); - if (LargeRepeats) - { - SR = SmallRepeats; - LR = LargeRepeats; - COMPA = CompaDSmall; - } - else - { - //大重复为0,小重复晋级为大重复 - LR = SmallRepeats; - COMPA = CompaDLarge; - } - } - else - { - //小重复为0,大重复必不为0,直接开始 - SetOCRA(TCNTLarge); - LR = LargeRepeats; - COMPA = CompaDLarge; - } - SetTCNT(0); - TIMSK = 2; + SetOCRA(Tcnt1); + COMPA = Compa1; } else - { - SR = IdealRepeats; - OVF = [] - { - if (!--SR) - { - TIMSK = 0; - DoTask(); - } - }; - if (Timer02) - TCCRA = 0; - else - TCCRB = PrescalerBits; - SetTCNT(0); - TIMSK = 1; - } + TIMSK = 2; + SR = SR1; } - } - else + else + TIMSK = 0; DoTask(); + } } - template - void InternalRA() + template + void SLRepeaterSet() { - constexpr uint32_t TM = TimerMax[TimerCode]; TIMSK = 0; - constexpr bool Timer02 = TimerCode == 0 || TimerCode == 2; - if (Timer02) - TCCRB = PrescalerBits; - else - TCCRA = 0; - //拒绝外部振荡源 - bitWrite(ASSR, AS2, false); - if (TCNT < TM) + if (RepeatTimes != 0) { + constexpr uint32_t TM = TimerMax[TimerCode]; + constexpr uint16_t IdealRepeats = TCNT / (TM - (TimerCode == 0)); + constexpr bool Timer02 = TimerCode == 0 || TimerCode == 2; if (Timer02) - TCCRA = 2; + TCCRB = PrescalerBits; else - TCCRB = PrescalerBits + 8; - SetOCRA(TCNT); - COMPA = DoTask; - SetTCNT(0); - TIMSK = 2; - } - else - { - constexpr uint16_t IdealRepeats = TCNT / (TM - (TimerCode == 0)); //Timer0的OVF不可用,因此只能用COMPA,最大255 - if (IdealRepeats * TM < TCNT || TimerCode == 0) //Timer0的OVF不可用 + TCCRA = 0; + if (RepeatTimes > 0) + LR = RepeatTimes; + if (IdealRepeats * TM < TCNT || TimerCode == 0) //Timer0的OVF不可用 { if (Timer02) TCCRA = 2; else TCCRB = PrescalerBits + 8; constexpr uint16_t ActualRepeats = IdealRepeats + 1; - constexpr uint16_t TCNTSmall = TCNT / ActualRepeats; - constexpr uint16_t TCNTLarge = TCNTSmall + 1; - constexpr uint16_t SmallRepeats = ActualRepeats * TCNTLarge - TCNT; - constexpr uint16_t LargeRepeats = TCNT - ActualRepeats * TCNTSmall; - if (SmallRepeats) + constexpr uint16_t Tcnt1 = TCNT / ActualRepeats; + constexpr uint16_t Tcnt2 = Tcnt1 + 1; + constexpr uint16_t SR1 = ActualRepeats * Tcnt2 - TCNT; //必大于0 + constexpr uint16_t SR2 = TCNT - ActualRepeats * Tcnt1; + SetOCRA(Tcnt1); + SR = SR1; + if (SR2) { - SR = SmallRepeats; - SetOCRA(TCNTSmall); - if (LargeRepeats) - { - COMPA = CompaRSmall; - if (TCNTLarge == TM) - OVF = CompaRLarge; - } - else - COMPA = CompaRSelf; + COMPA = Compa1; + if (Tcnt2 == TM) + OVF = Compa2; } else - { - SR = LargeRepeats; - if (TCNTLarge < TM) - { - SetOCRA(TCNTLarge); - COMPA = CompaRSelf; - } - else - OVF = CompaRSelf; - } + COMPA = Compa0; SetTCNT(0); TIMSK = 2; } else { SR = IdealRepeats; - OVF = OvfR; + OVF = Compa0; if (Timer02) TCCRA = 0; else @@ -487,90 +292,6 @@ namespace TimersOneForAll } } } - template - void InternalRA() - { - switch (RepeatTimes) - { - case 0: - TIMSK = 0; - break; - case 1: - InternalDA(); - break; - default: - constexpr uint32_t TM = TimerMax[TimerCode]; - TIMSK = 0; - constexpr bool Timer02 = TimerCode == 0 || TimerCode == 2; - if (Timer02) - TCCRB = PrescalerBits; - else - TCCRA = 0; - //拒绝外部振荡源 - bitWrite(ASSR, AS2, false); - LR = RepeatTimes; - if (TCNT < TM) - { - if (Timer02) - TCCRA = 2; - else - TCCRB = PrescalerBits + 8; - SetOCRA(TCNT); - COMPA = [] - { - if (!--LR) - TIMSK = 0; - DoTask(); - }; - SetTCNT(0); - TIMSK = 2; - } - else - { - constexpr uint16_t IdealRepeats = TCNT / (TM - (TimerCode == 0)); - if (IdealRepeats * TM < TCNT || TimerCode == 0) //Timer0的OVF不可用 - { - constexpr uint16_t ActualRepeats = IdealRepeats + 1; - constexpr uint16_t TCNTSmall = TCNT / ActualRepeats; - constexpr uint16_t TCNTLarge = TCNTSmall + 1; - constexpr uint16_t SmallRepeats = ActualRepeats * TCNTLarge - TCNT; - constexpr uint16_t LargeRepeats = TCNT - ActualRepeats * TCNTSmall; - if (Timer02) - TCCRA = 2; - else - TCCRB = PrescalerBits + 8; - if (SmallRepeats) - { - SR = SmallRepeats; - SetOCRA(TCNTSmall); - if (LargeRepeats) - { - COMPA = CompaRSmallT; - if (TCNTLarge == TM) - OVF = CompaRLargeT; - } - else - COMPA = CompaRSelfRepeat; - } - else - { - SR = LargeRepeats; - SetOCRA(TCNTLarge); - COMPA = CompaRSelfRepeat; - } - SetTCNT(0); - TIMSK = 2; - } - else - { - SR = IdealRepeats; - OVF = OvfRT; - SetTCNT(0); - TIMSK = 1; - } - } - } - } template void MEAdd() { @@ -597,7 +318,7 @@ namespace TimersOneForAll { constexpr TimerSetting TS = GetTimerSetting(TimerCode, HighMilliseconds); EfficientDigitalWrite(); - InternalRA>(); + SLRepeaterSet>(); } else { @@ -622,9 +343,9 @@ namespace TimersOneForAll SetOCRB(TryTS.TCNT * HighMilliseconds / FullCycle); COMPA = EfficientDigitalWrite; COMPB = EfficientDigitalWrite; - EfficientDigitalWrite(); SetTCNT(0); TIMSK = 6; + EfficientDigitalWrite(); } else { @@ -677,7 +398,7 @@ namespace TimersOneForAll { constexpr TimerSetting TS = GetTimerSetting(TimerCode, HighMilliseconds); EfficientDigitalWrite(); - InternalRA, RepeatTimes * 2 - 1>(); + SLRepeaterSet, RepeatTimes * 2 - 1>(); } else { @@ -747,66 +468,75 @@ namespace TimersOneForAll } } } + template + static volatile bool Delaying; + template + void Undelay() + { + Delaying = false; + } } #pragma endregion #pragma region 公开API - //Call your function with a timer interrupt after given milliseconds + //在指定毫秒数后执行任务 template void DoAfter() { constexpr Internal::TimerSetting TS = Internal::GetTimerSetting(TimerCode, AfterMilliseconds); - Internal::InternalDA(); + Internal::SLRepeaterSet(); } - //Repetitively and infinitely call your function with a timer interrupt for each given milliseconds. The first interrupt happens after your milliseconds, too. - template + //每隔指定毫秒数重复执行任务。重复次数若为负数,或不指定重复次数,则默认无限重复 + template void RepeatAfter() { constexpr Internal::TimerSetting TS = Internal::GetTimerSetting(TimerCode, IntervalMilliseconds); - Internal::InternalRA(); + Internal::SLRepeaterSet(); } - //Repeat for only given times - template - void RepeatAfter() - { - constexpr Internal::TimerSetting TS = Internal::GetTimerSetting(TimerCode, IntervalMilliseconds); - Internal::InternalRA(); - } - //Set the time now as 0 and start to record time elapsed. Read MillisecondsElapsed variable to get the time elapsed. + //设置当前为零时刻进行计时。从MillisecondsElapsed变量读取经过的时间 template void StartTiming() { MillisecondsElapsed = 0; RepeatAfter>(); } - //Play a tone of given frequency on given pin endlessly. + //无限播放音调 template void PlayTone() { constexpr Internal::TimerSetting TS = Internal::GetTimerSetting(TimerCode, 500.f / FrequencyHz); Internal::EfficientDigitalToggle(); - Internal::InternalRA>(); + Internal::SLRepeaterSet>(); } - //Play for only given milliseconds + //播放有限的毫秒数 template void PlayTone() { constexpr Internal::TimerSetting TS = Internal::GetTimerSetting(TimerCode, 500.f / FrequencyHz); Internal::EfficientDigitalToggle(); - Internal::InternalRA, uint32_t(FrequencyHz) * Milliseconds / 500>(); + Internal::SLRepeaterSet, uint32_t(FrequencyHz) * Milliseconds / 500>(); } - //Generate an infinite sequence of square wave. The high level and low level can have different time length. + //生成高低电平时长不一的方波,无限循环 template void SquareWave() { Internal::InternalSW(); } - //Generate the square wave for only given cycles. + //生成循环数有限的方波 template void SquareWave() { Internal::InternalSW(); } - //Abort all tasks assigned above. + //阻塞当前代码执行指定毫秒数 + template + void Delay() + { + Internal::Delaying = true; + DoAfter>(); + while (Internal::Delaying) + ; + } + //取消上述任何任务。只影响特定的计时器。 template void ShutDown() {