AVR based RC5 decoder (subwoofer-switch)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

207 lines
6.2 KiB

  1. /***************************************************************************
  2. * Copyright (C) 04/2011 by Olaf Rempel *
  3. * razzor@kopf-tisch.de *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; version 2 of the License, *
  8. * *
  9. * This program is distributed in the hope that it will be useful, *
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  12. * GNU General Public License for more details. *
  13. * *
  14. * You should have received a copy of the GNU General Public License *
  15. * along with this program; if not, write to the *
  16. * Free Software Foundation, Inc., *
  17. * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
  18. ***************************************************************************/
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #include <avr/eeprom.h>
  22. #include <avr/sleep.h>
  23. /*
  24. * attiny24: (no self programming, 2.7V BOD, 8MHz internal RC Osz)
  25. * LFUSE = 0xC2
  26. * HFUSE = 0xDD
  27. * EFUSE = 0xFF
  28. *
  29. * RC5 Input on PB2 (INT0)
  30. * PROGMODE Jumper (active low) on PB1
  31. * OUTPUT (active low) on PB0
  32. */
  33. /* RC5 bitlength is 1778us +/-10% convert to timer0 ticks (8us) */
  34. #define BITWIDTH (1778 / 8)
  35. #define BITWIDTH_MIN (BITWIDTH - (BITWIDTH / 10))
  36. #define BITWIDTH_MAX (BITWIDTH + (BITWIDTH / 10))
  37. #define RC5_BITCNT 14
  38. #define RC5_CMD_MASK 0x37FF
  39. #define RC5_COMPLETE 0x8000
  40. #define OUTPUT_ON() { PORTB &= ~(1<<PORTB0); }
  41. #define OUTPUT_OFF() { PORTB |= (1<<PORTB0); }
  42. struct ee_param {
  43. uint16_t rc5cmd;
  44. uint8_t state;
  45. };
  46. struct ee_param params;
  47. struct ee_param params_in_eeprom EEMEM = {
  48. .rc5cmd = 0x350C,
  49. .state = 0x00,
  50. };
  51. static uint8_t bitcnt;
  52. static volatile uint16_t value;
  53. static volatile uint8_t button_debounce;
  54. static volatile uint8_t button;
  55. ISR(PCINT1_vect)
  56. {
  57. /* get button state */
  58. button = !(PINB & (1<<PINB1));
  59. /* 20 * 2ms = 40ms */
  60. button_debounce = 20;
  61. /* clear and enable overflow interrupt */
  62. TIFR0 = (1<<TOV0);
  63. TIMSK0 |= (1<<TOIE0);
  64. /* disable Pinchange interrupt */
  65. GIMSK &= ~(1<<PCIE1);
  66. }
  67. ISR(TIM0_OVF_vect)
  68. {
  69. button_debounce--;
  70. if (button_debounce == 0x00)
  71. {
  72. /* disable overflow interrupt */
  73. TIMSK0 &= ~(1<<TOIE0);
  74. /* clear & enable Pinchange interrupt */
  75. GIFR = (1<<PCIF1);
  76. GIMSK |= (1<<PCIE1);
  77. }
  78. }
  79. ISR(EXT_INT0_vect)
  80. {
  81. if (bitcnt == 0)
  82. value = 0;
  83. bitcnt++;
  84. value = (value << 1);
  85. if (!(PINB & (1<<PINB2)))
  86. value |= 0x0001;
  87. /* setup sample window for next edge */
  88. OCR0A = TCNT0 + BITWIDTH_MIN;
  89. OCR0B = TCNT0 + BITWIDTH_MAX;
  90. /* clear and enable COMPA / COMPB */
  91. TIFR0 = (1<<OCF0A) | (1<<OCF0B);
  92. TIMSK0 |= (1<<OCIE0A) | (1<<OCIE0B);
  93. /* disable INT0 until COMPA hits */
  94. GIMSK &= ~(1<<INT0);
  95. }
  96. ISR(TIM0_COMPA_vect)
  97. {
  98. /* clear and enable INT0 */
  99. GIFR = (1<<INTF0);
  100. GIMSK |= (1<<INT0);
  101. }
  102. ISR(TIM0_COMPB_vect)
  103. {
  104. /* disable sample window */
  105. TIMSK0 &= ~((1<<OCIE0A) | (1<<OCIE0B));
  106. /* final bit received? */
  107. if (bitcnt >= RC5_BITCNT)
  108. value |= RC5_COMPLETE;
  109. bitcnt = 0;
  110. }
  111. int main(int argc, char *argv[])
  112. {
  113. DDRB = (1<<PORTB0);
  114. /* pullup on RC5IN and PROGMEM, OUTPUT is low active */
  115. PORTB = (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);
  116. /* INT0: both edges generate interrupt */
  117. /* PB1: enable pin change interrupt */
  118. MCUCR = (1<<ISC00);
  119. GIMSK = (1<<INT0) | (1<<PCIE1);
  120. PCMSK1 = (1<<PCINT9);
  121. /* Timer0: 8Mhz/64 */
  122. TCCR0B = (1<<CS01) | (1<<CS00);
  123. /* load configuration, restore state */
  124. eeprom_read_block(&params, &params_in_eeprom, sizeof(struct ee_param));
  125. if (params.state) {
  126. OUTPUT_ON();
  127. } else {
  128. OUTPUT_OFF();
  129. }
  130. /* all interrupts can wake up */
  131. set_sleep_mode(SLEEP_MODE_IDLE);
  132. sei();
  133. uint16_t old_value = 0x0000;
  134. uint8_t toggle = 0x00;
  135. while (1) {
  136. /* wait for next interrupt */
  137. sleep_mode();
  138. if (value & RC5_COMPLETE) {
  139. /* PROGMODE jumper set? */
  140. if (!(PINB & (1<<PINB1))) {
  141. params.rc5cmd = (value & RC5_CMD_MASK);
  142. eeprom_write_block(&params, &params_in_eeprom, sizeof(struct ee_param));
  143. /* current command matches stored one */
  144. } else if (params.rc5cmd == (value & RC5_CMD_MASK) && value != old_value) {
  145. toggle = 1;
  146. old_value = value;
  147. }
  148. value = 0x0000;
  149. }
  150. else if (button)
  151. {
  152. toggle = 1;
  153. button = 0;
  154. }
  155. if (toggle)
  156. {
  157. if (params.state) {
  158. params.state = 0;
  159. OUTPUT_OFF();
  160. } else {
  161. params.state = 1;
  162. OUTPUT_ON();
  163. }
  164. eeprom_write_block(&params, &params_in_eeprom, sizeof(struct ee_param));
  165. toggle = 0;
  166. }
  167. }
  168. return 0;
  169. }