Ср май 23, 2018 03:16:26
// RC5 Infrared Transmitter for Arduino Diecimila
//
// Two timers are used, TIMER2 and TIMER1. TIMER1 is used as the RC5 state machine clock,
// with tick length of irparams.t (e.g., 889 microseconds), the basic RC5 time unit.
// The on/off state of the IR LED carrier (pulse clock) may change on any given tick of
// this clock.
//
// TIMER2 is used to generate a square wave on OC2A (pin 11) at the frequency of the RC5
// pulse clock (e.g., 36 kHz). The pulse clock is modulated (turned on and off) by setting
// or clearing the COM2A0 bit of register TCCR2A. Therefore, an IR LED connected between
// pin 11 and ground is the only external circuitry needed to implement the basic IR
// transmitter.
//
// Using a high power IR LED (Vishay TSAL6100) connected this way (without a current-
// limiting resistor) results in an "on" current of about 80ma. This is within spec of
// that device (100ma max). The Arduino output pins are specced at 40ma max, so the
// current of 80ma exceeds the Arduino spec, but the duty cycle is low (50% max),
// so it's probably OK.
//
// RC5 encoding:
//
// START + TOGGLEBIT + UNITCODE + BUTTONCODE
//
// where:
// START is a two-bit code, always 11
// TOGGLEBIT is a one-bit code which toggles on each successive button
// UNITCODE is a five-bit code specifying the unit being commanded (TV, VCR, etc.)
// BUTTONCODE is a six-bit code for the button command
//
// Each bit, 0 or 1, is transmitted according to "Manchester" encoding:
//
// 0: MARK followed by SPACE, each of duration irparams.t
// 1: SPACE followed by MARK
//
// To adapt this code to use another RC5-compatible device, minimally
// the unit code needs to be set according to the device, and any
// specific button encodings need to be defined in irparams.h. Note
// the function brand() where the buttons and other parameters are
// actually loaded into the state machine structure.
//
// The demo program below simply sets the brand to PHILIPSTV,
// turns power on, waits 15 seconds, sets channel to 03, mutes the TV,
// waits 15 seconds, and turns the TV off.
//
// Note that the call to button(buttonid,retransmitcount) returns
// before the code is finished transmitting, so successive calls should
// be separted by at least some delay, e.g., 100 msec. The retransmission
// count is 2 here because that seems to be common.
//
// For more info on RC5, see: http://www.sbprojects.com/knowledge/ir/rc5.htm
//
// Joe Knapp jmknapp AT gmail DOT com 30APR08
#include "c:\2\irparams.h"
#define IROUT 11 // pin 11 is OC2A output from TIMER2
#define BLINKLED 13 // mirrors the state of IROUT
#define TICKSPERUSEC ((SYSCLOCK/1000000.)/PRESCALE)
#define mark() (irparams.irledstate = 1)
#define space() (irparams.irledstate = 0)
// xmitter states
#define START 1
#define STOP 2
#define IDLE 3
#define REXMIT 4
#define CODE 5
#define MANCHONE 6
#define MANCHZERO 7
#define TOGGLE 8
// Pulse clock interrupt uses 16-bit TIMER1
#define INIT_TIMER_COUNT1 (65536 - (int)(TICKSPERUSEC*irparams.t))
#define RESET_TIMER1 TCNT1 = INIT_TIMER_COUNT1
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// function prototypes
void button(byte buttonid, int n) ;
void brand(byte brandcode) ;
uint8_t timer2top(unsigned int freq) ;
unsigned long buttoncode(byte buttonid) ;
int tmp1=0;
// state machine variables
struct rbutton {
byte id ;
unsigned long code ; // button codes can be up to 32 bits
} ;
struct {
byte xmitstate ;
byte returnstate ;
byte timer ;
byte unitlength ;
byte buttonlength ;
byte sendflag ;
byte retransmit ;
byte codelen ;
byte bitcounter ;
byte togbit ;
byte nbuttons ;
byte blinkstate ;
byte irledstate ;
unsigned long unit ;
unsigned long button ;
unsigned long code1 ;
unsigned int mask16 ;
unsigned int t ;
unsigned int retransgap ;
struct rbutton buttons[MAXBUTTONS] ;
} irparams ;
void setup() {
Serial.begin(9600) ;
Serial.println("XMITIR 0.0.0.1a") ;
cbi(TCCR2A,COM2A1) ; // disconnect OC2A for now (COM2A0 = 0)
cbi(TCCR2A,COM2A0) ;
cbi(TCCR2B,WGM22) ; // CTC mode for TIMER2
sbi(TCCR2A,WGM21) ;
cbi(TCCR2A,WGM20) ;
TCNT2 = 0 ;
cbi(ASSR,AS2) ; // use system clock for timer 2
OCR2A = 255 ; // set TOP to 255 for now
cbi(TCCR2B,CS22) ; // TIMER2 prescale = 1
cbi(TCCR2B,CS21) ;
sbi(TCCR2B,CS20) ;
cbi(TCCR2B,FOC2A) ; // clear forced output compare bits
cbi(TCCR2B,FOC2B) ;
pinMode(IROUT, OUTPUT) ; // set OC2A to OUPUT
pinMode(BLINKLED, OUTPUT) ;
digitalWrite(BLINKLED, LOW) ;
// setup pulse clock timer interrupt
TCCR1A = 0; // normal mode
//Prescale /8 (16M/8 = 0.5 microseconds per tick)
// Therefore, the timer interval can range from 0.5 to 128 microseconds
// depending on the reset value (255 to 0)
cbi(TCCR1B,CS12) ;
sbi(TCCR1B,CS11) ;
cbi(TCCR1B,CS10) ;
//Timer1 Overflow Interrupt Enable
sbi(TIMSK1,TOIE1) ;
RESET_TIMER1;
sei(); // enable interrupts
// initialize some state machine variables
irparams.sendflag = 0 ;
irparams.togbit = 0 ;
irparams.blinkstate = HIGH ;
irparams.xmitstate = IDLE ;
}
// main loop
// Just for a demo, the code here the first time through just sets
// the brand to PHILIPSTV, turns the TV on, sets the channel to THREE,
// mutes the TV and finally turns the TV off.
void loop() {
static byte first = 1 ;
if (first) {
brand(PHILIPSTV) ;
button(ONE,3) ; // hello world settings
delay(600) ;
Serial.println("1") ;
// while (1) {}
for (tmp1=0; tmp1>=100; tmp1++) {
if (tmp1 != 1) {
Serial.println(tmp1) ;
button(tmp1,3) ;
delay(1000) ;
}
}
button(SEVEN,2) ; // 1
delay(400) ;
button(SEVEN,2) ; //1
delay(400) ;
button(EIGHT,2) ;
delay(400) ;
button(EIGHT,2) ;
delay(400) ;
button(STORE ,2) ;
// delay(1000) ;
// button(POWER,2) ; // over and out
first = 0 ;
}
}
// xmit state machine
// RC5 protocol
ISR(TIMER1_OVF_vect) {
RESET_TIMER1;
switch(irparams.xmitstate) {
case START:
if (irparams.timer == 4) {
irparams.code1 = ((unsigned long)irparams.unit << irparams.buttonlength) | irparams.button ;
irparams.codelen = irparams.unitlength + irparams.buttonlength ;
irparams.mask16 = (unsigned int)0x1 << (irparams.codelen - 1) ;
}
irparams.timer-- ;
switch(irparams.timer) {
case 3:
mark() ;
break ;
case 2:
space() ;
break ;
case 1:
mark() ;
irparams.xmitstate = TOGGLE ;
break ;
}
break ;
case TOGGLE:
irparams.returnstate = CODE ; // go to CODE after toggle bit
irparams.bitcounter = 0 ;
if (irparams.togbit) {
space() ;
irparams.xmitstate = MANCHONE ;
}
else {
mark() ;
irparams.xmitstate = MANCHZERO ;
}
break ;
case CODE:
irparams.returnstate = CODE ;
if (irparams.bitcounter == irparams.codelen) {
space() ;
irparams.xmitstate = STOP ;
}
else {
if (irparams.code1 & irparams.mask16) { // send ONE
space() ;
irparams.xmitstate = MANCHONE ;
}
else {
mark() ;
irparams.xmitstate = MANCHZERO ;
}
irparams.bitcounter++ ;
irparams.mask16 >>= 1 ;
}
break ;
case STOP:
if (irparams.retransmit) {
irparams.xmitstate = REXMIT ;
irparams.timer = irparams.retransgap ;
irparams.sendflag = 0 ;
}
else {
irparams.xmitstate = IDLE ;
irparams.sendflag = 0 ;
space() ;
irparams.togbit ^= 0x1 ;
}
break ;
case IDLE:
if (irparams.sendflag) {
irparams.xmitstate = START ;
space() ;
irparams.timer = 4 ; // RC5 start is SPACE/MARK/SPACE/MARK
}
break ;
case MANCHONE:
mark() ;
irparams.xmitstate = irparams.returnstate ;
break ;
case MANCHZERO:
space() ;
irparams.xmitstate = irparams.returnstate ;
break ;
case REXMIT:
irparams.timer-- ;
if (irparams.timer == 0) {
irparams.sendflag = 1 ;
irparams.xmitstate = IDLE ;
irparams.retransmit-- ;
}
break ;
}
// update LEDs
if (irparams.irledstate) {
digitalWrite(BLINKLED, HIGH) ;
sbi(TCCR2A,COM2A0) ; // connect pulse clock
}
else {
digitalWrite(BLINKLED, LOW) ;
cbi(TCCR2A,COM2A0) ; // disconnect pulse clock
}
}
// end RC5 state machine
// send code for given buttonid, repeat n times
void button(byte buttonid, int n)
{
irparams.button = buttoncode(buttonid) ; // get code
irparams.retransmit = n - 1;
irparams.sendflag = 1; // flag for the ISR to send irparams.button
}
// return ir code for given buttonid
unsigned long buttoncode(byte buttonid)
{
int i ;
byte found ;
i = 0 ;
found = 0 ;
while (!found && (i < irparams.nbuttons)) {
if (buttonid == irparams.buttons[i].id) {
found = 1 ;
}
else
i++ ;
}
if (found)
return(irparams.buttons[i].code) ;
else
return(0) ; // ERROR
}
// set parameters for given brand
void brand(byte brandcode)
{
int i ;
switch(brandcode) {
case PHILIPSTV:
OCR2A = timer2top(PHILIPSTV_PULSECLOCK) ; // sets TOP value for TIMER2
irparams.unit = PHILIPSTV_UNIT ;
irparams.unitlength = PHILIPSTV_UNITLENGTH ;
irparams.buttonlength = PHILIPSTV_BUTTONLENGTH ;
irparams.t = PHILIPSTV_T ;
irparams.retransgap = PHILIPSTV_RETRANSGAP ;
// buttons
irparams.nbuttons = 0 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B01 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C01 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B02 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C02 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B03 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C03 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B04 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C04 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B05 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C05 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B06 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C06 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B07 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C07 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B08 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C08 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B09 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C09 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B10 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C10 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B11 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C11 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B12 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C12 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B13 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C13 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B14 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C14 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B15 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C15 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B16 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C16 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B17 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C17 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B18 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C18 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B19 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C19 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B20 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C20 ;
irparams.buttons[irparams.nbuttons].id = PHILIPSTV_B21 ;
irparams.buttons[irparams.nbuttons++].code = PHILIPSTV_C21 ;
break ;
default:
Serial.println("ERROR: brand not found") ;
break ;
}
}
// return TIMER2 TOP value per given desired frequency (Hz)
uint8_t timer2top(unsigned int freq)
{
return((byte)((unsigned long)SYSCLOCK/2/freq) - 1) ;
}
Ср май 23, 2018 05:18:33
#define mark() (irparams.irledstate = 1)
#define space() (irparams.irledstate = 0)
Ср май 23, 2018 09:42:20
Ср май 23, 2018 14:20:09
Ср май 23, 2018 14:45:03
ну да: теперь кое-кто вместо того, чтобы прочитать про RC5 и сделать самому, пользуется этой библиотекой и задаёт вопросы на форумах.AonMaster писал(а):наверное, не зря люди старались.
Ср май 23, 2018 16:15:13
А для чего это нужно? И выложите полностью проект, а то тот zip не скачивается.AonMaster писал(а):Как можно добавить туда функцию передачи просто прямоугольных импульсов, не модулированных несущей 36 кГц?
Ср май 23, 2018 18:19:30
Чт май 24, 2018 18:02:00
Это понятно, но зачем вам понадобилсяAonMaster писал(а):Для того, чтоб управлять часами, у которых есть пульт, но нет кнопок - без пульта, подключившись к выходу ИК приемника.
МЕААААНДР.AonMaster писал(а):Как можно добавить туда функцию передачи просто прямоугольных импульсов, не модулированных несущей 36 кГц?
Чт май 24, 2018 18:41:48
Пт май 25, 2018 08:09:56
Пт май 25, 2018 08:35:58
/** Передача кода.
* Передает коды в стандарте RC5
* @param data передаваемый код
*/
static void send_code(uint16_t data){
for(uint8_t i=0; i < RC5_CODELEN; i++){
// передача старшего бита
if(data & 0x2000){
// send 1
out_Lo();
_delay_us(HALF_BIT_TIME);
// программная генерация сигнала 1
#if MODULATED_OUTPUT == 1
// модулированная единица
modulate();
#else
// немодулированная единица
out_Hi();
_delay_us(HALF_BIT_TIME);
#endif
} else {
// send 0
// программная генерация сигнала 0
#if MODULATED_OUTPUT == 1
// модулированная единица
modulate();
#else
// немодулированная единица
out_Hi();
_delay_us(HALF_BIT_TIME);
#endif
// ноль
out_Lo();
_delay_us(HALF_BIT_TIME);
}
// сдвиг кода для передачи следующего бита
data <<= 1;
}
// в конце передачи устанавливаем на выходе 0
out_Lo();
}
Пт май 25, 2018 11:58:41
Пт май 25, 2018 13:20:28
за других не скажу, а я всегда реализую самое простое решение из возможных. потому что так проще и легче. простая задача - простое решение.AonMaster писал(а):Как-то всё просто получается, а другие зачем целые страницы кода и с таймерами в том числе пишут...
Сб май 26, 2018 10:06:45
Чт июн 07, 2018 11:09:33
Вс июн 10, 2018 14:13:54
Вс июн 10, 2018 19:08:59
Пн июн 11, 2018 06:04:55
Ср июн 13, 2018 06:49:24