Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[AVR] Arduino Led blinking at 0.125 Hz with Timer1 using ISR

Status
Not open for further replies.

shomikc

Member level 4
Member level 4
Joined
Apr 19, 2013
Messages
71
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
1,953
Hi.

I am new to Arduino. I am not able to understand how to get 0.125 Hz with Timer1. I know it has something to do with Prescaling

but I could not find any documentation on the internet. The problem is to blink built-in LED at 1 Hz if a button is not pressed and

to blink the LED at 0.125 Hz if the button is pressed. Please help. If you can point me to any good document on Timer1 calculations

that would be very helpful. Thankyou.

Code:
const int button_pin_number = 2;

const int led_pin_number =  13;

int button_unpressed_pressed = 0;



void setup() {

pinMode(led_pin_number, OUTPUT);

pinMode(button_pin_number, INPUT);

noInterrupts();

TCCR1A = 0;  

TCCR1B = 0;  

TCNT1 = 0;

TCCR1B |= (1 << CS12);

TIMSK1 |= (1 << TOIE1);

interrupts();
}



ISR(TIMER1_COMPA_vect)

{

button_unpressed_pressed  = digitalRead(button_pin_number);



if (button_unpressed_pressed == LOW)

{   OCR1A = 15624;

digitalWrite(led_pin_number, digitalRead(led_pin_number) ^ 1);  

}



if (button_unpressed_pressed == HIGH)

{  OCR1A = 124992;

digitalWrite(led_pin_number, digitalRead(led_pin_number) ^ 1);

}



}



void loop()

{

}
 

Hi,

It's one of the most often asked question, million explanations here in this forum in the internet.
There are even (thousands of) videos, and online calculators.
You surely need to improve your search skills.
******

I did not read datasheet .... but you have to!

Most important: timer has an input clock. Without giving information about input clock frequency no one can give detailed support.

Independent of manufacturer and exact microcontroller type most timer periferals (including sw) work the same:

Input_clock --> eventual_fixed_prescaler --> configurable_prescaler --> adjustable_count_number --> eventual_software_count_number --> output

Let's say your input clock is 4MHz.
And you want a blink frequency of 0.125Hz with 50%duty cycle => 4s ON , 4s OFF

So you need to count 4MHz x 4s = 16 clock cycles = 16,000,000.
I do it the mathematical way: prime factorisation: (there are online prime factorisation tools)
But it's simple: 16 = 4 × 4 = 2 × 2 × 2 × 2 = 2^4
1,000,000 = 10^6 = (2 × 5)^6 = 2^6 × 5^6
In total: 2^10 × 5^6

AVRs usually have no fixed_prescaler, and configurable prescalers of 256 and 16 bit counter registers.
So with a prescaler of 256 = 2^8 ... the remaining count number is: 2^10 × 5^6 / 2^8 = 2^2 × 5^6 = 62500
Luckily 62500 is within the 16bit range, so you don't need a software counter.

*****
To your software: (issues)
* it misses input frequency information (at least as comment)
* it misses prescaler information (at least as comment)
* it says: OCR1A = 124992 --> this value is beyond 16 bit limit of 65535.

Klaus
 

    shomikc

    Points: 2
    Helpful Answer Positive Rating
Another thread just inspired to make a sketch using ATMEGA328 timers. I assume it's Arduino UNO and clock frequency is 16 Mhz. The highest clock divider is 1024 which makes it easy to make 1 Hz without sw variables so I made an example of that. This code was tested with Arduino Duemilanove and I think UNO is pretty close to the same. It blinks the led using the timer. I see these differences to your code, but might be more:
-I set wave generation mode
-I have CS12 and CS10 on prescaler
-I activate different interrupt in TIMSK1, OCIE1A instead of TOIE1


Code:
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
 
  noInterrupts();
  TCCR1A = 0;
  TCCR1B = 0;
  //Waveform Generation Mode 4, CTC
  //WGM13 WGM12 WGM11 WGM10
  //  0     1     0     0
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (1 << CS12) | (1 << CS10) ;//prescaler clk/1024 -> 15625 Hz
  OCR1A=15624;//1 Hz
  TIMSK1 = (1 << OCIE1A);//output compare interrupt
  interrupts();
}

void loop() {
  // put your main code here, to run repeatedly:
}

//toggle led
ISR(TIMER1_COMPA_vect) {
  digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
}
 
Last edited by a moderator:

    shomikc

    Points: 2
    Helpful Answer Positive Rating
This is a quick and dirty way to do your function. Using block language, kids in school
use it to program robots.

1628330283286.png



You drag and drop blocks onto design canvas, config, then hit upload. mBlock then
generates the C code, shown on right, from your block config. I think this would fit in
an ATTINY85 8 pin, you would use an Arduino Nano or Uno board to program the
ATTINY85.

Its not optimal, or engineering at its finest, just simple. There are other block languages,
like Snap4Arduino, Ardublock, flowcode.....that offer other/more capabilities in the
blocks. Like a tethered situation where you easily create a talking voltmeter using windows
OS calls (you dont get into weeds on this, just use a block to speak the A/D value).....


Lots of fun, dont have to get into the weeds on a part when you are in a hurray
or dont feel like breaking out your C programming card and chip manual.

Here is example doing timed events -




Regards, Dana.
 

Attachments

  • 1628329486468.png
    1628329486468.png
    201 KB · Views: 189
Last edited:

    shomikc

    Points: 2
    Helpful Answer Positive Rating
Hi,

one little issue I sse regarding the solution of post#3:
You toggle every 1.00 second. So the LED is ON for 1s and OFF for 1s making a total of 2s. = 0.5Hz

My recommendation (modifications to code of post#3):
Code:
* set prescaler to 256
* set OCR1A to 31249  (to run the ISR every 0.5s)

// (pseudo code)
static uint8 sw_blink;
volatile uint8 LED_mode; (0 = OFF, 1=ON, 2=1Hz, 3=0.125Hz);
volatile boolean LED8;

ISR(TIMER1_COMPA_vect) {
boolean LED = false:
sw_blink++; (counts up every 0.5s, so bit 0 "blinks" with 1Hz, bit1 with 0.5Hz, bit2 with 0.25Hz, bit3 with 0.125Hz...)
if LED_mode == 1 then LED = true;
if LED_mode == 2 then LED = sw_blink & 0x01;
if LED_mode == 3 then LED = sw_blink & 0x08;
digitalWrite(LED_BUILTIN, LED));
}
 

    shomikc

    Points: 2
    Helpful Answer Positive Rating
You toggle every 1.00 second. So the LED is ON for 1s and OFF for 1s making a total of 2s. = 0.5Hz
I saw OP used 15624 so I used that, but yes frequency is not 1 Hz. I also completely omitted 0.125 Hz and button presses. My idea was to give a working example regarding timer settings.
 

    shomikc

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top