0

I have some basic code that I will soon expand for my project which is a universal remote for air conditioners. I have all of the codes but the problem is 3 of the codes are below 1khz. (500hz). My sketch doesn't allow for anything to go lower and the frequency in the actual code doesn't seem to go that low. 108 is 38khz.

uint16_t fuck[] = {0,108,0,0,347,173,22,22,22,22,22,22,22,65,22,65,22,65,22,22,22,22,22,65,22,65,22,65,22,22,22,22,22,22,22,65,22,65,22,22,22,65,22,22,22,22,22,65,22,22,22,22,22,22,22,65,22,22,22,65,22,65,22,22,22,65,22,65,22,65,22,1527,347,87,22,3692};
static uint16_t sent_array_numbers;
static uint8_t ir_seq_index = 4;
static uint8_t pin_state;

void ir_on()
{
  TCCR1A |= 192;
  pin_state = 1;
}

void ir_off()
{
  TCCR1A &= -193;
  pin_state = 0;
}

void ir_toggle()
{
  if (pin_state)
    ir_off();
  else
    ir_on();
}

void ir_start()
{
  DDRB |= 10;
  ICR1 = 416;
  OCR1A = 104;
  TCCR1A = 2;
  TCCR1B = 24;
  TIMSK1 = 1;
  ir_on();
  TCCR1B |= 1;
}


ISR(TIMER1_OVF_vect) {

  sent_array_numbers++;

  if (sent_array_numbers == fuck[ir_seq_index]) {
    ir_toggle();
    sent_array_numbers = 0;
    ir_seq_index++;



       }
}

void setup() {
  ir_start();
}

void loop() {
  
}
8
  • 2
    what is your question? – jsotola Oct 30 '20 at 21:31
  • 1
    what is running at the frequency of 500 Hz, and how did you determine it? – jsotola Oct 30 '20 at 21:32
  • 1
    You have nothing to reset 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. – chrisl Oct 30 '20 at 22:00
  • If you want the timer to run slower, you could change its settings, for example raising the prescaler – chrisl Oct 30 '20 at 22:01
  • Where did you get this code from? Also the array for the IR code looks very odd. There shouldn't be any zeros in it. Also, most IR codes start with a long pulse, while yours kind of ends with two. – Gerben Oct 31 '20 at 15:27
2

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.

1
  • I can't yet test it (Arduino broke) but from the looks of it this looks to be correct. Thanks alot <3. I'll post code when I can get my arduino to work again :) – Macaroni Nov 1 '20 at 11:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.