RCStrobo
RCStrobo basiert auf der gleichen Platine wie das RCLight. Statt eines Fernsteuerempfängerausgangs wird hier ein HAL Sensor TLE4905g verwendet, um die an den Schaltausgängen angeschlossenen Leistungs LEDs mit dem Hauptrotor eines Helikopters zu synchronisieren. Dadurch entsteht ein farbiges stehendes Bild beim Nachtflug.
Die Idee dazu habe ich bei Aleksey Zaitsevsky gesehen, aber vollständig selber entwickelt. Wobei das Berechnen der richtigen Werte für den Prescaler des Controller Timers das Aufwendigste war, da der RCtiny wenig Reserven für diese zeitkritische Anwendung hat.
Der Schaltplan als PDF liegt hier.
Die Firmware ist Atmels AVR-Studio entwickelt und dann mit USBasp geflasht. Als Programmierstecker dient ein halbierter Floppydisk Platinenstecker, der nur einige Sekunden auf die Platinenpads gehalten werden muss.
Der C-Source Code ist hier als Download. Die nicht kommerzielle Nutzung der Daten ist gestattet.
/* * RcStrobo I/O * Author: Heinz Bruederlin * 01.04.10 First implemented * * CPU: ATtiny 13 * * Clock: 9.6MHz * Prescaler: 64 * Timer0 Freq: 150kHz * Timer0 Period: 0,00000667sec * Timer0 Overflow: 0,00170667sec * * Timing * Speed 1500RPM 3000RPM * Rotation / second 25 50 * Time / Rotation 0,040000sec = 6000(1770)tic 0,020000sec = 3000(0BB8)tic * Time / Segment 2 0,020000sec = 3000(0BB8)tic 0,010000sec = 1500(05DC)tic * 4 0,010000sec = 1500(05DC)tic 0,005000sec = 750(02EE)tic * 8 0,005000sec = 750(02EE)tic 0,002500sec = 375(0177)tic * 16 0,002500sec = 375(0177)tic 0,001250sec = 188(00BB)tic * 32 0,001250sec = 188(00BB)tic 0,000625sec = 94(005D)tic * * OUT1 : red * OUT2 : green * OUT3 : yellow * OUT4 : blue */ #ifndef F_CPU #define F_CPU 9600000 /* Clock in Hz */ #endif #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> FUSES = { .low = 0xff & (FUSE_CKSEL0 & /* internal RC 9.6MHz */ FUSE_SUT0 & /* max startup time */ FUSE_SPIEN), /* SPI enabled */ .high = 0xff & (FUSE_BODLEVEL1) /* Brown-out 2.7V */ }; /* PORTB defines */ #define OUT4 _BV(PB0) /* connected to FET */ #define HAL _BV(PB1) /* connected to HAL Sensor*/ #define OUT1 _BV(PB2) /* connected to FET */ #define OUT2 _BV(PB3) /* connected to FET */ #define OUT3 _BV(PB4) /* connected to FET */ /* * globals */ typedef struct { uint8_t l,h; } bytelh_t; typedef union { bytelh_t _; uint16_t __; } uint8_16_t; volatile uint8_t TcntH; // high byte (timer overflow) volatile uint8_16_t SegDuration; // 16 bit duration for one segment volatile uint8_16_t SegTime; // 16 bit time of next segment switch volatile uint8_t SegCnt; // number of segments volatile uint8_t SegIdx; // current segment index modulo 4 /* * io_init - * init io ports */ void io_init(void) { /* switch off outputs and set pullup at input */ PORTB = HAL; /* Set PORT B outputs */ DDRB = OUT1 | OUT2 | OUT3 | OUT4; } /* * timer_init - * init timer 0 */ void timer_init(void) { TCCR0B |= _BV(CS01) | _BV(CS00); // set timer0 prescaler to 64 TCNT0 = 0; // clear timer0 TcntH = 0; // clear high byte TIFR0 |= _BV(TOV0); // clear pending overflow } /* * global_init - * init globals */ void global_init(void) { SegCnt = 8; } /* * intr_init - * enable timer0 overflow and int0 interrupts */ void intr_init(void) { TIMSK0 |= _BV(OCIE0A) | // enable timer0 compare match A interrupt _BV(TOIE0); // enable timer0 overflow interrupt MCUCR |= _BV(ISC01)|_BV(ISC00); // rising edge generates an interrupt GIMSK |= _BV(INT0); // enable external interrupt for HAL sei(); // enable interupts } /* * setLeds - * sets LED depending on SegIdx */ void setLeds() { uint8_t o = PORTB & ~(OUT1 | OUT2 | OUT3 | OUT4); switch(SegIdx) { case 0: o |= OUT1; break; case 1: o |= OUT2; break; case 2: o |= OUT3; break; case 3: o |= OUT4; break; } PORTB = o; } /* * TIM0_OVF_vect - * timer 0 overflow interrupt handler */ ISR(TIM0_OVF_vect) { TcntH++; } /* * INT0_vect - * external interrupt 0 * called on each rising edge of HAL */ ISR(INT0_vect) { SegDuration._.l = TCNT0; SegDuration._.h = TcntH; TCNT0 = 0; // clear timer0 TcntH = 0; // clear high byte SegDuration.__ /= SegCnt; SegTime.__ = SegDuration.__; SegIdx = 0; OCR0A = SegTime._.l; setLeds(); } /* * TIM0_COMPA_vect - * Timer0 Compare Match A interrupt * called on when timer 0 reached compare value */ ISR(TIM0_COMPA_vect) { if (TcntH == SegTime._.h) { SegTime.__ += SegDuration.__; OCR0A = SegTime._.l; SegIdx++; if (SegIdx > 3) SegIdx = 0; setLeds(); } } /* * main - * init everything and go to endlees loop */ int main(void) { io_init(); timer_init(); global_init(); intr_init(); for(;;) { } }