How to make the built-in LED(pin 13) blink with a frequency of 5 Hz using interrupts
Do you have to use interrupts or are other methods allowed ?
How strict is the requirement to use interrupts ? I ask because delay() uses interrupts, so you could meet the requirements to use interrupts if you used delay()
#include <TimerOne.h>
const byte PinLed = LED_BUILTIN;
const int Period = 25;
int cnt;
void isr (void) {
if (Period <= ++cnt) {
cnt = 0;
digitalWrite (PinLed, ! digitalRead (PinLed));
}
}
void
loop (void)
{
}
void
setup (void)
{
Serial.begin (9600);
pinMode (PinLed, OUTPUT);
Timer1.initialize (100000);
Timer1.attachInterrupt (isr);
}
I used time interrupt 2, I don't know if I implemented it well, the task is: after five clicks on OK, the built-in LED starts flashing with a frequency of 5Hz using an interrupt. After the eighth click on OK, the flashing (and glowing) should stop:
bool ledState = false;
volatile bool ledOn = true;
void setup(){
TCCR2A = 0;
TCCR2B = 0;
TIMSK2 = 0;
TCNT2 = 0;
OCR2A = 77;
TCCR2B |= (1 << CS22) | (1 << CS21) | (1 << CS20);
TIMSK2 |= (1 << OCIE2A);
pinMode(13, OUTPUT);
}
void loop(){
if(button5.buttonPressedCount >= 5 && button5.buttonPressedCount < 8){
ledState = true;
}
if(button5.buttonPressedCount > 7){
ledState = false;
}
}
ISR(TIMER2_COMPA_vect){
if(ledState){
digitalWrite(13, ledOn);
ledOn = !ledOn;
}
}
This is the first mention of a button as far as I remember. Are there any other details of the project that you have not shared yet ?
Where is the button input defined ?
the buttons from the remote control and the receiver
So now there is a remote control and a receiver in your project. As I said previously
In any case, the sketch that you posted does not compile
With a clock frequency of 16MHz and a max prescaler value of 1024, the lowest frequency TIMER2 is capable of is 16 000 000 / 1024 / 256 = 61.03515625 Hz. You then need to divide that 12 to get about 5Hz.
Here is what I coded (using Nick Gammon's tutorial) to blink an LED using interrupts :
TIMER2 generates an interrupt every 1ms.
/*****************************************/
/* V2 : Serial Dialog added */
/*****************************************/
const int ON_DURATION = 100;
const int OFF_DURATION = 200-ON_DURATION;
const int SAFETY_MARGIN = 10;
volatile unsigned int offInterval = OFF_DURATION;
volatile unsigned int pulseWidth = ON_DURATION;
// internal to counting routine
unsigned int timerTicks = 0;
unsigned int timerPeriod;
byte LedState = 0;
void startCounting()
{
// reset Timer 2
TCCR2A = 0;
TCCR2B = 0;
// Timer 2 - gives us our 1 ms counting interval
// 16 MHz clock (62.5 ns per tick) - prescaled by 128
TCCR2B = bit(CS20) | bit(CS22) ;
// counter increments every 8 µs.
// So we count 125 of them, giving exactly 1000 µs (1 ms)
TCCR2A = bit(WGM21) ; // CTC mode
OCR2A = 125 - 1; // count up to 125 (zero relative !!!!)
// Timer 2 - interrupt on match (ie. every 1 ms)
TIMSK2 = bit(OCIE2A); // enable Timer2 Interrupt
TCNT2 = 0; // Counter to zero
// Reset prescalers
GTCCR = bit(PSRASY); // reset prescaler now
// start Timer 2
} // Ready to roll !!!
//******************************************************************
// Timer2 Interrupt Service is invoked by hardware Timer 2 every 1 ms = 1000 Hz
// 16Mhz / 128 / 125 = 1000 Hz
ISR(TIMER2_COMPA_vect)
{
// see if we have reached timing period
if(++timerTicks >= timerPeriod)
{
timerTicks = 0; // reset interrupt counter
LedState = !LedState; // inverser l'état (virtuel) de la LED
digitalWrite(LED_BUILTIN, LedState); // commuter la LED
if(LedState == HIGH)
{
timerPeriod = pulseWidth;
}
else
{
timerPeriod = offInterval;
}
}
} // end of TIMER2_COMPA_vect
void setup()
{
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT); // configurer la broche de la LED comme sortie
LedState = 0;
digitalWrite(LED_BUILTIN, LedState);
while(!Serial)
{
; // wait for serial port to connect. Needed for native USB port only
}
Serial.println("Timer Interrupt LED Blink V2");
Serial.println("Type 'Pxxx' to set Period (ms) & 'Wxxx' to set Width (ms)");
Serial.println("Enjoy !!!");
startCounting();
} // end of setup
void loop()
{
unsigned int MessageVal, localPulseWidth, LocalOffInterval;
if(Serial.available()) //if data available
{
String Message = Serial.readStringUntil('\n');
Message.trim(); // remove any \r \n whitespace at the end of the String
switch(Message[0])
{
case 'P':
case 'p':
Message = Message.substring(1);
MessageVal = Message.toInt();
if(MessageVal > pulseWidth + SAFETY_MARGIN)
{
LocalOffInterval = MessageVal - pulseWidth;
noInterrupts();
offInterval = LocalOffInterval;
interrupts();
Serial.print("Period changed to ");
Serial.println(MessageVal);
}
else
{
Serial.print("Command Discarded. Pulse Width is ");
Serial.println(pulseWidth);
Serial.print("Minimum Period : ");
Serial.println(pulseWidth + SAFETY_MARGIN);
}
break;
case 'W':
case 'w':
Message = Message.substring(1);
localPulseWidth = Message.toInt();
noInterrupts();
pulseWidth = localPulseWidth;
interrupts();
Serial.print("Pulse Width changed to ");
Serial.println(localPulseWidth);
break;
default:
Serial.print("Unknown Command : '");
Serial.print(Message);
Serial.println("'");
Serial.println("Type 'Pxxx' to set Period (ms) & 'Wxxx' to set Width (ms)");
break;
}
}
}
It is very stable as long as timerPeriod
is less than 256, probably because 16 bit comparison takes less time when high bytes are different : no need to compare low bytes. Little bit of jitter above 255.
I should tinker with union
or highByte()
lowByte()
and exclusive or to solve this.
Not true, a previous version was spot on... Investigation required...
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.