12.10.2019, 01:37 | #1 (permalink) |
Новичок
Регистрация: 27.09.2019
Сообщений: 3
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Репутация: 10
|
Attiny13a и ИК пульт
Имеется сигнал с кнопки, снятый через RCExplorer: Код:
addr=0xFF00 cmd=0x67 Код:
/** * Copyright (c) 2016, Łukasz Marcin Podkalicki * ATtiny13/011 * Control LEDs with IR remote control. Example of monblocking * IR signal reader (38kHz, TSOPxxx) and NEC protocol decoder. * MCU Settings: * FUSE_L=0x7A * FUSE_H=0xFF * F_CPU=9600000 */ #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #define LED1_PIN PB0 #define LED2_PIN PB2 #define LED3_PIN PB3 #define LED4_PIN PB4 #define IR_IN_PIN PB1 #define IR_IN_PORT PORTB #define IR_OCR0A (122) #define LOW (0) #define HIGH (1) #define IR_SUCCESS (0) #define IR_ERROR (1) #define IR_EVENT_IDLE (0) #define IR_EVENT_INIT (1) #define IR_EVENT_FINI (2) #define IR_EVENT_PROC (3) #define IR_PROTO_EVENT_INIT (0) #define IR_PROTO_EVENT_DATA (1) #define IR_PROTO_EVENT_FINI (2) #define IR_PROTO_EVENT_HOOK (3) volatile uint16_t IR_timeout = 0; volatile uint16_t IR_counter = 0; volatile uint32_t IR_rawdata = 0; uint8_t IR_event = 0; uint8_t IR_proto_event = 0; uint8_t IR_index = 0; uint32_t IR_data = 0; static void IR_init() { DDRB &= ~_BV(IR_IN_PIN); // set IR IN pin as INPUT PORTB &= ~_BV(IR_IN_PIN); // set LOW level to IR IN pin TCCR0A |= _BV(WGM01); // set timer counter mode to CTC TCCR0B |= _BV(CS00); // set prescaler to 1 TIMSK0 |= _BV(OCIE0A); // enable Timer COMPA interrupt OCR0A = IR_OCR0A; // set OCR0n to get ~38.222kHz timer frequency GIMSK |= _BV(INT0); // enable INT0 interrupt handler MCUCR &= ~_BV(ISC01); // trigger INTO interrupt on raising MCUCR |= _BV(ISC00); // and falling edge sei(); // enable global interrupts } static int8_t IR_NEC_process(uint16_t counter, uint8_t value) { int8_t retval = IR_ERROR; switch(IR_proto_event) { case IR_PROTO_EVENT_INIT: /* expecting a space */ if (value == HIGH) { if (counter > 330 && counter < 360) { /* a 4.5ms space for regular transmition of NEC Code; counter => 0.0045/(1.0/38222.0) * 2 = 344 (+/- 15) */ IR_proto_event = IR_PROTO_EVENT_DATA; IR_data = IR_index = 0; retval = IR_SUCCESS; } else if (counter > 155 && counter < 185) { /* a 2.25ms space for NEC Code repeat; counter => 0.00225/(1.0/38222.0) * 2 = 172 (+/- 15) */ IR_proto_event = IR_PROTO_EVENT_FINI; retval = IR_SUCCESS; } } break; case IR_PROTO_EVENT_DATA: /* Reading 4 octets (32bits) of data: 1) the 8-bit address for the receiving device 2) the 8-bit logical inverse of the address 3) the 8-bit command 4) the 8-bit logical inverse of the command Logical '0' – a 562.5µs pulse burst followed by a 562.5µs (<90 IR counter cycles) space, with a total transmit time of 1.125ms Logical '1' – a 562.5µs pulse burst followed by a 1.6875ms (>=90 IR counter cycles) space, with a total transmit time of 2.25ms */ if (IR_index < 32) { if (value == HIGH) { IR_data |= ((uint32_t)((counter < 90) ? 0 : 1) << IR_index++); if (IR_index == 32) { IR_proto_event = IR_PROTO_EVENT_HOOK; } } retval = IR_SUCCESS; } break; case IR_PROTO_EVENT_HOOK: /* expecting a final 562.5µs pulse burst to signify the end of message transmission */ if (value == LOW) { IR_proto_event = IR_PROTO_EVENT_FINI; retval = IR_SUCCESS; } break; case IR_PROTO_EVENT_FINI: /* copying data to volatile variable; raw data is ready */ IR_rawdata = IR_data; break; default: break; } return retval; } static void IR_process() { uint8_t value; uint16_t counter; /* load IR counter value to local variable, then reset counter */ counter = IR_counter; IR_counter = 0; /* read IR_IN_PIN digital value (NOTE: logical inverse value = value ^ 1 due to sensor used) */ value = (PINB & (1 << IR_IN_PIN)) > 0 ? LOW : HIGH; switch(IR_event) { case IR_EVENT_IDLE: /* awaiting for an initial signal */ if (value == HIGH) { IR_event = IR_EVENT_INIT; } break; case IR_EVENT_INIT: /* consume leading pulse burst */ if (value == LOW) { if (counter > 655 && counter < 815) { /* a 9ms leading pulse burst, NEC Infrared Transmission Protocol detected, counter = 0.009/(1.0/38222.) * 2 = 343.998 * 2 = 686 (+/- 30) */ IR_event = IR_EVENT_PROC; IR_proto_event = IR_PROTO_EVENT_INIT; IR_timeout = 7400; } else { IR_event = IR_EVENT_FINI; } } else { IR_event = IR_EVENT_FINI; } break; case IR_EVENT_PROC: /* read and decode NEC Protocol data */ if (IR_NEC_process(counter, value)) IR_event = IR_EVENT_FINI; break; case IR_EVENT_FINI: /* clear timeout and set idle mode */ IR_event = IR_EVENT_IDLE; IR_timeout = 0; break; default: break; } } static int8_t IR_read(uint8_t *address, uint8_t *command) { if (!IR_rawdata) return IR_ERROR; *address = IR_rawdata; *command = IR_rawdata >> 16; IR_rawdata = 0; return IR_SUCCESS; } ISR(INT0_vect) { IR_process(); } ISR(TIM0_COMPA_vect) { /* When transmitting or receiving remote control codes using the NEC IR transmission protocol, the communications performs optimally when the carrier frequency (used for modulation/demodulation) is set to 38.222kHz. */ if (IR_counter++ > 10000) IR_event = IR_EVENT_IDLE; if (IR_timeout && --IR_timeout == 0) IR_event = IR_EVENT_IDLE; } int main(void) { uint8_t addr, cmd; /* setup */ DDRB |= _BV(LED1_PIN)|_BV(LED2_PIN)|_BV(LED3_PIN)|_BV(LED4_PIN); IR_init(); /* loop */ while (1) { if (IR_read(&addr, &cmd) == IR_SUCCESS) { if (addr != 0x01) continue; switch(cmd) { case 0x01: /* turn all LEDs off */ PORTB &= ~(_BV(LED1_PIN)|_BV(LED2_PIN)|_BV(LED3_PIN)|_BV(LED4_PIN)); break; case 0x00: PORTB ^= _BV(LED1_PIN); // toggle LED1 break; case 0x07: PORTB ^= _BV(LED2_PIN); // toggle LED2 break; case 0x06: PORTB ^= _BV(LED3_PIN); // toggle LED3 break; case 0x04: PORTB ^= _BV(LED4_PIN); // toggle LED4 break; default: break; }; } } } Код:
/* * IR Receiver.cpp * * Created: 12/1/2017 11:10:41 AM * Author : Dz Inventors */ #define F_CPU 9600000 // Must stay at this speed #include <avr/io.h> #include <util/delay.h> #include <avr/interrupt.h> #define IR_Input_Pin PORTB1 bool IR_Code(uint32_t data); // Check the IR Code void IR_Scan(); // Scan IR data void IR_Setup(); // Setup mode uint32_t IR_data_out = 0; // IR data store int main(void) { IR_Setup(); DDRB |= 1 << PORTB4; DDRB &= ~(1 << IR_Input_Pin); PORTB = 0x00; while (1) { if (IR_Code(0x00FFA857)) { // Put the code you want to check it in the IR_Code function PORTB |= 1 << PORTB4; // Do some actions } if (IR_Code(0x00FF6897)) { PORTB &= ~(1 << PORTB4); } if (IR_Code(0x10EFF906)) { PORTB |= 1 << PORTB4; } if (IR_Code(0x10EFE916)) { PORTB &= ~(1 << PORTB4); } } } void IR_Setup() { GIMSK |= 1 << INT0; // Enable the interrupt pin ( at PB1) MCUCR = (1 << ISC00); // Set interrupt configuration in PB1 (see page 46 for any change mode) sei(); TCCR0B |= 1 << CS00 | 1 << CS02; //set timer 0 with max scaler (F_CPU/1024) } bool IR_Code(uint32_t data) { // Prettified IR data output code uint8_t IR_data_byte[4]; IR_data_byte[0] = (IR_data_out >> 24); IR_data_byte[1] = (IR_data_out >> 16); IR_data_byte[2] = (IR_data_out >> 8); IR_data_byte[3] = (IR_data_out); // Prettified IR data input code uint8_t data_byte[4]; data_byte[0] = (data >> 24); data_byte[1] = (data >> 16); data_byte[2] = (data >> 8); data_byte[3] = (data); if (IR_data_byte[0] == data_byte[0] || IR_data_byte[1] == data_byte[1]) { // If address data is = if (IR_data_byte[2] == data_byte[2] || IR_data_byte[3] == data_byte[3]) { // If command data is = IR_data_out = 0; // Clear IR data Output return true; } } return false; } ISR(INT0_vect) { IR_Scan(); } uint8_t time_high = 0; uint8_t time_low = 0; bool interrupter1 = false; bool interrupter2 = false; bool one_time = false; int conter = -1; uint8_t TCNT0_buffer = 0; uint8_t time_span = 0; void IR_Scan() { // Timer unit = 106.666 µs if (TCNT0 >= TCNT0_buffer) // If timer doesn't overflow time_span = TCNT0 - TCNT0_buffer; // Get span time else //if timer overflow time_span = (256 - TCNT0_buffer) + TCNT0; // Get span time if (time_span <= 2) // Delete any noise < or = then 213 µs return void(); if ((PINB & (1 << IR_Input_Pin)) == 0) time_high = time_span; // Get the time low else time_low = time_span; // Get the time high if ((time_low >= 78) && (time_low <= 91)) // Low for 9ms interrupter1 = true; // Enable the first interrupter if ((time_high >= 36 && time_high <= 49) && (interrupter1 == true)) { // High time 4.5ms IR_data_out = 0; // Clear data conter = -1; // Restart counter variable interrupter2 = true; // Enable the second interrupter (start condition is true) } if (conter == 32) { // Check if data send is over interrupter1 = interrupter2 = false; // Restart interrupters conter = -1; // Restart conter variable } if (interrupter2 == true) { // See if start condition is true if (one_time == true) { // Enter one time in two loops if (conter != -1) { // Over enter in the first time if (time_high > time_low * 2) // Means we read logic 1 IR_data_out |= 0x80000000 >> conter; // Put the logic 1 in high significant bit and shift it to the right every loop } // else // IR_data_out=0; // Clear data conter++; // Up counter } one_time = !one_time; // Reverse state } TCNT0_buffer = TCNT0; // Scan timer } Во втором примере как-то странно реагирует на любую кнопку: подставлял IR_Code(0xFF0067) и первое нажатие подает 2.4 вольта, второе нажатие подается 5 вольт, третье нажатие на любую кнопку выключает питание с ножки, и так далее по кругу. |
12.10.2019, 01:37 | |
Helpmaster
Member
Регистрация: 08.03.2016
Сообщений: 0
|
Прочтение аналогичных тем очень эффективно в решении проблемы ATtiny13A: не мигает светодиод после отключения прогамматора Пульт ДУ для ПК Пульт от ТВ |
Ads | |
Member
Регистрация: 31.10.2006
Сообщений: 40200
Записей в дневнике: 0
Сказал(а) спасибо: 0
Поблагодарили 0 раз(а) в 0 сообщениях
Репутация: 55070
|
|
|