Your whole question is not very clear, so I will mainly give you explanations, of how the Timer code works (since you don't seem to understand that) and give hints.
Let's look at ir_start()
, where you configure Timer1 for the IR operation:
void ir_start()
{
DDRB |= 10;
ICR1 = 416;
OCR1A = 104;
TCCR1A = 2;
TCCR1B = 24;
TIMSK1 = 1;
ir_on();
TCCR1B |= 1;
}
First you should better not use the decimal representation of numbers here. Most of them consist of single or few bits, that a bound to a specific configuration option. You can better see, what is going on, when you use hex or better binary. So instead of DDRB |= 10;
you would write DDRB |= 0b1010;
(0b
marking the binary representation, and 1010
being the binary representation of 10). That makes it easier to read by others or by you, when you leave that code for a time and come back to it. Using decimal is good in the cases, where you write registers, that represent a single value (like ICR1
).
Now let's go through each line. Here I will only state, what the line does, not if that makes sense or if it is correct.
DDRB |= 10;
is equal to DDRB |= 0b1010
and will set will configure PB1 and PB3 (pin 9 and 11 on the Uno) as output pins.
ICR1 = 416;
sets the input capture register 1, which - when not in input capture mode - sets the TOP value of the Timer, meaning the max value, to which it will count until overflow.
OCR1A = 104;
sets the timer value, where the Timer will toggle the output compare pin A of Timer1 (PB1, aka pin 9) (of course only, if the output compare mode is activated).
TCCR1A = 2;
is equivalent to TCCR1A = 0b00000010
. It disables the output compare mode, thus normal port operation. Also bit WGM11
is set to 1 and WGM10
is set to 0 (explanation with the next line).
TCCR1B = 24;
is equal to TCCR1B = 0b00011000
. It sets WGM12
and WGM13
to one. Together with the other bits of the last line, this sets the Timer mode to FastPWM, counting to the value in ICR1
, resetting there. Also the clock source bits are all set to zero, so disabling the Timer.
TIMSK1 = 1;
This enables the Timer1 overflow interrupt, and is of course equal to TIMSK1 = 0b1
.
In ir_on()
you use
TCCR1A |= 192;
which is equal to TCCR1A |= 0b11000000
. It enables the output compare for OC1A, configured for setting it at the compare match and clearing it on resetting (also called inverted mode).
TCCR1B |= 1;
will set the clock source of the Timer to the main clock without any prescaler. A prescaler would scale the counter values. For example with a prescaler of 8 (setting the clock source bits to 0b010
) would mean, that the Timer value would increment by one every 8 clock transitions, instead of on every transition. Here you have no prescaler, so the Timer runs with full speed. You can make it slower by changing the prescaler. The fine tuning can then be done by changing the ICR1
value, which is used as TOP. Setting the clock source will also turn the Timer on.
Then in ir_off()
you use
TCCR1A &= -193;
Decimal -193
is a value, that needs 2 bytes as a signed integer (twos-complement). It's binary value is 0b11111111 00111111
. You assign to a 1 byte register, so the high byte will be cut off. So you actually use the decimal value 63
. It will disable the output compare for OC1A, so disabling the PWM output on the OC1A pin.
So, to sum up the actual function of that code: The Timer is configured to run from 0 to 416 without any prescaler. At the value 104 the OC1A pin is set, on timer reset/overflow it is reset. The frequency of the signal will be 16MHz / 416 = 38,5 kHz
, with a duty cycle of (416 - 104) / 416 = 75%
.
By changing ICR1 and OCR1A, you can go down to 16MHz / 65535 = 244Hz
. So for a frequency of 500Hz, you could use the ICR1 value 32000
. For the same duty cycle you then need the OCR1A value of 8000.
If you need an even lower frequency, you could use the prescaler by setting the clock source bits correspondingly.
Note: You use the timer overflow as your smallest time measure (since you are incrementing sent_array_numbers
in the ISR). So by changing the Timer frequency, you also change the amount of time, that one increment of sent_array_numbers
represents. While this time is 1 / 38.5kHz = 26.3us
with 38.5kHz, it will be 1 / 500Hz = 2ms
for 500Hz. Just keep that fact in mind, when writing the IR pulse values into the array.
You can read about all this in the datasheet of the Atmega328p, which is used in the Arduino Uno.
Notes besides the Timer configuration:
Make sure, that all variables, that get changed inside of an ISR, are declared as volatile
, so that the compiler knows, that the variable can change at any time and that it cannot optimize the access to it.
Make sure, that the index, that you use with the array, is not exceeding the size of the array. Otherwise you will read from whatever was placed behind that array in the memory.
Every variable should have a fitting speaking name, which tells exactly, what it is. Its function might not be that obvious, when you look at your code after a few years.
The first 4 values in the array with the IR codes are not used. From your code I cannot understand, why. (Though you suggested, that this is not the complete code).
I hope, that helps. If not, then you need to be more precise with your question. And provide a complete compilable minimal example code.
ir_seq_index
, so once you got through the array, it will still increment. Then you will get garbage, since you are reading from outside the array.