I have created a small program which receives an IR command and sends back an IR command based on the status of two input pins. The program needed to be small enough to fit into a Attiny85 with room to spare. Hence the reason for using the code from the following sources;
The IR transmitter section is taken from David Johnson’s “IR Remote Wand v2” (see Technoblogy - IR Remote Wand.
And the receiver section was taken from his other project “IR Remote Control Detective v4” (see Technoblogy - IR Remote Control Detective [Updated]).
Both sections use Timer/Counter1 to execute their functions.
The problem that I am experiencing is once either function is activated (or triggered), the other function will not execute. The Attint85 basically halts and a reset is required.
The sequence of events is as follows;
- Wait for a specific IR code to be received.
- If Code is received, read the status of the two input pins and send back a corresponding IR code.
Loop
I have tried many things such as disabling interrupts right after the IR code is received, then re-enabling interrupts after sending the IR code, but that did not seem to work.
I even went as far as using an I/O pin to externally trigger a reset condition, which works, but is not a fix I willing to live with.
So, I am hoping that someone can explain to me why these two functions do not want to play well together.
The settings are; Clock = 1MHz, BOD disabled.
My code is below.
Any help with this is greatly appreciated.
// IR transmitter **********************************************
const int LED = 1; // IR LED output
int rx_flag = 0;
int addr = 0;
int cmnd = 0;
const int top = 23; // 1000000/26 = 38.5kHz
const int match = 18; // approx. 25% mark/space ratio
// Set up Timer/Counter1 to output PCM on OC1A (PB1)
void SetupPCM () {
TCCR1 = 1<<PWM1A | 3<<COM1A0 | 1<<CS10; // Inverted PWM output on OC1A divide by 1
OCR1C = top; // 38.5kHz
OCR1A = top; // Keep output low
}
// Generate count cycles of carrier followed by gap cycles of gap
void Pulse (int count, int gap) {
OCR1A = match; // Generate pulses
for (int i=0; i<2; i++) {
for (int c=0; c<count; c++) {
while ((TIFR & 1<<TOV1) == 0);
TIFR = 1<<TOV1;
}
count = gap; // Generate gap
OCR1A = top;
}
}
void Send (char IRtype, unsigned int Address, unsigned int Command) {
// NEC or Samsung codes
if ((IRtype == 'N') || (IRtype == 'M')) {
unsigned long code = ((unsigned long) Command<<16 | Address);
TCNT1 = 0; // Start counting from 0
// Send Start pulse
if (IRtype == 'N') Pulse(342, 171); else Pulse(190, 190);
// Send 32 bits
for (int Bit=0; Bit<32; Bit++)
if (code & ((unsigned long) 1<<Bit)) Pulse(21, 64); else Pulse(21, 21);
Pulse(21, 0);
}
}
// NEC IR Receiver **********************************************
#define IR_OUT PB3 // IR receiver pin
// Globals
volatile unsigned long RecdData;
volatile int Bit, Edge;
volatile char IRtype;
// Protocol timings
const int Micros = 64; // Number of microseconds per TCNT1 count
const int SonyIntro = 2400/Micros;
const int SonyMean = 900/Micros;
const int NECIntro = 9000/Micros;
const int NECGap = 4500/Micros;
const int NECPulse = 562/Micros;
const int NECMean = 1125/Micros;
const int SamsungIntro = 5000/Micros;
const int SamsungGap = 5000/Micros;
const int RC5Half = 889/Micros; // 0.889ms
const int RC5Full = 1778/Micros;
const int RC5Mean = 1334/Micros;
// IR types
const uint8_t NECtype = 1;
const uint8_t SAMtype = 2;
const uint8_t RC5type = 3;
const uint8_t SONtype = 4;
void ReceivedCode(char IRtype, unsigned int Address, unsigned int Command) {
addr = Address;
cmnd = Command;
rx_flag = 1;
}
// Calculate difference
uint16_t diff(uint16_t a, uint16_t b) {
if (a > b) return (a - b);
return (b - a);
}
// Interrupt service routine - called on Timer/Counter1 overflow
ISR(TIMER1_OVF_vect) {
ReceivedCode(Bit, RecdData>>7, RecdData & 0x7F);
TIMSK = TIMSK & ~(1<<TOIE1); // Disable overflow interrupt
TCNT1 = 250; // clear counter
}
// Interrupt service routine - called on each edge of IR pin
ISR(PCINT0_vect) {
static uint8_t Mid; // edge: 0 = falling, 1 = rising
uint16_t Time = TCNT1;
if(TIFR & 1<<TOV1) { IRtype = 0; Edge = 1; } // overflow
else if(Edge != (PINB>>PINB3 & 1)); // ignore if wrong edge
else if(IRtype == 0) {
// End of intro pulse
if(diff(Time, RC5Half) < 5) {
IRtype = RC5type; RecdData = 0x2000; Bit = 12; Edge = 0; Mid = 0;
} else if(diff(Time, RC5Full) < 5) {
IRtype = RC5type; RecdData = 0x2000; Bit = 11; Edge = 0; Mid = 1;
} else if((diff(Time, SonyIntro) < 5) && (Edge == 1)) {
IRtype = SONtype; RecdData = 0; Bit = 0;
TIMSK = TIMSK | 1<<TOIE1; // enable overflow interrupt
} else if(diff(Time, SamsungIntro) < 18) {
IRtype = SAMtype; RecdData = 0; Bit = -1; Edge = 0; // ignore first falling edge
} else if(diff(Time, NECIntro) < 18) {
IRtype = NECtype; RecdData = 0; Bit = -1; Edge = 0; // ignore first falling edge
}
// Data bit
} else if(IRtype == RC5type) {
Edge = !Edge;
if((Time < RC5Mean) && Mid) {
Mid = 0;
} else {
Mid = 1;
RecdData = RecdData | ((uint32_t) Edge<<Bit);
if(Bit == 0) ReceivedCode(RC5type, RecdData>>6 & 0x1F, (~(RecdData>>6) & 0x40) | (RecdData & 0x3F));
Bit--;
}
} else if((IRtype == NECtype) || (IRtype == SAMtype)) {
if(Time > NECMean && Bit >= 0) RecdData = RecdData | ((uint32_t) 1<<Bit);
Bit++;
if(Bit == 32) ReceivedCode(IRtype, RecdData & 0xFFFF, RecdData>>16);
}
TCNT1 = 0; // clear counter
TIFR = TIFR | 1<<TOV1; // clear overflow
}
// Setup demo **********************************************
void setup() {
pinMode(PB4, OUTPUT);
digitalWrite(PB4,LOW);
pinMode(LED, OUTPUT);
pinMode(PB5, INPUT_PULLUP);
pinMode(PB2, INPUT_PULLUP);
pinMode(PB0, INPUT_PULLUP);
TCCR1 = 0x07; // 7<<CS10; // no compare matches ; /64
PCMSK = 1<<IR_OUT; // interrupt on IR pin (PB3)
GIMSK = 1<<PCIE; // enable pin change interrupts
sei(); // enable global interrupts
}
void loop() {
if (rx_flag == 1){
if ((addr == 0x0909) && (cmnd == 0x0D55)){
SetupPCM();
delay(500);
if((digitalRead(PB0)==1) && (digitalRead(PB2)==1)){
Send('M', 0x2525, 0x0B55);
}
else if (digitalRead(PB0)==1){
Send('M', 0x2525, 0x0C55);
}
else if (digitalRead(PB2)==1){
Send('M', 0x2525, 0x0C66);
}
else
{
Send('M', 0x2525, 0x0B66);
}
rx_flag = 0;
}
}
}