/*
Blink with Scope https://github.com/Dlloydev/Wokwi-Chip-Scope
and https://github.com/Dlloydev/Wokwi-Chip-PWM
Wokwi Uno https://wokwi.com/projects/390819301187622913
Wokwi Mega: https://wokwi.com/projects/390819455604080641
*/
// MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START * MACRO-START *
// a detailed explanation how these macros work is given in this tutorial
// https://forum.arduino.cc/t/comfortable-serial-debug-output-short-to-write-fixed-text-name-and-content-of-any-variable-code-example/888298
#define dbg(myFixedText, variableName) \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName);
#define dbgi(myFixedText, variableName,timeInterval) \
{ \
static unsigned long intervalStartTime; \
if ( millis() - intervalStartTime >= timeInterval ){ \
intervalStartTime = millis(); \
Serial.print( F(#myFixedText " " #variableName"=") ); \
Serial.println(variableName); \
} \
}
#define dbgc(myFixedText, variableName) \
{ \
static long lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
#define dbgcf(myFixedText, variableName) \
{ \
static float lastState; \
if ( lastState != variableName ){ \
Serial.print( F(#myFixedText " " #variableName" changed from ") ); \
Serial.print(lastState); \
Serial.print( F(" to ") ); \
Serial.println(variableName); \
lastState = variableName; \
} \
}
// MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END * MACRO-END *
unsigned long MyTestTimer = 0; // Timer-variables MUST be of type unsigned long
const byte OnBoard_LED = 13; // onboard-LED uno, mega
constexpr float PWM_bitIsOne = 8620.69;//17241.379; // 15e3; // 15 kHz
constexpr float PWM_bitIsZero = 5000.00; // 15e3; // 15 kHz
constexpr uint16_t PERIOD_bitIsOne = round(F_CPU / PWM_bitIsOne);
constexpr uint16_t PERIOD_bitIsZero = round(F_CPU / PWM_bitIsZero);
constexpr uint16_t PERIOD_Diff = PERIOD_bitIsZero - PERIOD_bitIsOne;
volatile boolean bitIs1 = true;
volatile byte ISRCnt = 0;
void setupTimer1() {
// Configure Timer 1 for X kHz PWM on pin 9 = PB1 = OC1A.
DDRB |= _BV(PB5); // set pin as output
//pinMode(11,OUTPUT);
TCCR1B = 0; // stop timer
TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
| _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
TCCR1B = _BV(WGM12) // ditto
| _BV(WGM13) // ditto
| _BV(CS10) ;
// | 0b100<<CS10; // clock @ F_CPU
ICR1 = PERIOD_bitIsOne - 1; // period
OCR1A = PERIOD_bitIsOne / 2; // duty cycle 1/2 = 50%
TIMSK1 |= (1 << TOIE1) | (1<<OCIE1A); // enable timer compare interrupt
dbg("TS", PERIOD_bitIsOne);
dbg("TS", PERIOD_bitIsZero);
}
void setup() {
Serial.begin(115200);
Serial.println("Setup-Start");
PrintFileNameDateTime();
setupTimer1();
}
// enable with TIMSK1 |= (1<<OCIE1A);
ISR(TIMER1_COMPA_vect){
// set the on-time cor the next bit
OCR1A = bitIs1 ? PERIOD_bitIsZero / 2 : PERIOD_bitIsOne / 2;
}
ISR(TIMER1_OVF_vect) {
if (bitIs1) {
bitIs1 = false;
ICR1 = PERIOD_bitIsZero - 1; // period
OCR1A = PERIOD_bitIsZero / 2; // duty cycle 1/2 = 50%
}
else {
bitIs1 = true;
ICR1 = PERIOD_bitIsOne - 1; // period
//OCR1A = PERIOD_bitIsOne / 2; // duty cycle 1/2 = 50%
}
}
void loop() {
BlinkHeartBeatLED(OnBoard_LED, 250);
}
// helper-functions
void PrintFileNameDateTime() {
Serial.println( F("Code running comes from file ") );
Serial.println( F(__FILE__) );
Serial.print( F(" compiled ") );
Serial.print( F(__DATE__) );
Serial.print( F(" ") );
Serial.println( F(__TIME__) );
}
// easy to use helper-function for non-blocking timing
// explanation see here
// https://forum.arduino.cc/t/example-code-for-timing-based-on-millis-easier-to-understand-through-the-use-of-example-numbers-avoiding-delay/974017
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
unsigned long currentMillis = millis();
if ( currentMillis - startOfPeriod >= TimePeriod ) {
// more time than TimePeriod has elapsed since last time if-condition was true
startOfPeriod = currentMillis; // a new period starts right here so set new starttime
return true;
}
else return false; // actual TimePeriod is NOT yet over
}
void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
static unsigned long MyBlinkTimer;
pinMode(IO_Pin, OUTPUT);
if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
}
}
Wokwi MegaScope
https://wokwi.com/projects/390819455604080641