Difference between revisions of "U23 2008-2/Gruppe1"
(→Mitglieder) |
m (Reverted edits by Oxudocopaj (talk) to last revision by Hendi) |
||
(11 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
+ | = Meta Data = | ||
== Mitglieder == | == Mitglieder == | ||
* Mark<br /> | * Mark<br /> | ||
Line 5: | Line 6: | ||
* Robert<br /> | * Robert<br /> | ||
− | == | + | = Code = |
+ | == 1. Abend == | ||
=== LED - Blinken === | === LED - Blinken === | ||
: Aufgabe: Eine LED soll zum blinken gebracht werden. | : Aufgabe: Eine LED soll zum blinken gebracht werden. | ||
Line 13: | Line 15: | ||
// * | // * | ||
// * Von Gruppe 1 | // * Von Gruppe 1 | ||
− | // * Aufgabe: | + | // * Aufgabe: Alle LEDs sollen zum blinken gebracht werden. |
− | // * | + | // * |
+ | // * Task: All LED shall blink. | ||
// * | // * | ||
//**************************************************************************** | //**************************************************************************** | ||
Line 23: | Line 26: | ||
int main(void) | int main(void) | ||
{ | { | ||
− | + | /* LED Anschluss */ | |
+ | /* LED output */ | ||
+ | /* LED1 PC4 */ | ||
+ | /* LED2 PD3 */ | ||
+ | /* LED3 PD6 */ | ||
+ | /* LED4 PD7 */ | ||
+ | |||
/* Setze Ports PC4, PD3, PD6 und PD7 als Ausgang */ | /* Setze Ports PC4, PD3, PD6 und PD7 als Ausgang */ | ||
− | + | /* Set ports PC4, PD3, PD6 and PD7 as outputs */ | |
− | + | DDRC = _BV(4); | |
− | /* | + | DDRD = _BV(7)|_BV(6)|_BV(3); |
− | |||
− | |||
while(1) | while(1) | ||
{ | { | ||
− | for (i=0;i<50;i++) | + | /* _delay_ms() verzögert um 10 Millisekunden */ |
− | + | /* 50 * 10ms = 500ms */ | |
− | + | /* _delay_ms() delays for 10 Milliseconds */ | |
+ | /* 50 * 10ms = 500ms */ | ||
+ | for (uint8_t i=0;i<50;i++) _delay_ms(10); | ||
+ | |||
+ | /* Schalte zwischen 5V und 0V an den Ausgängen hin und her */ | ||
+ | /* Toggle 5V and 0V at the outputs */ | ||
+ | PORTC ^= _BV(4); | ||
+ | PORTD ^= _BV(7)|_BV(6)|_BV(3); | ||
} | } | ||
return 0; | return 0; | ||
} | } | ||
+ | |||
</source> | </source> | ||
Line 74: | Line 89: | ||
</source> | </source> | ||
− | |||
=== LED - Lauflicht === | === LED - Lauflicht === | ||
: Code: | : Code: | ||
Line 118: | Line 132: | ||
</source> | </source> | ||
+ | === Blinksequenz aufzeichnen und später abspielen === | ||
+ | <source lang="c">#include <avr/io.h> | ||
+ | #include <util/delay.h> | ||
+ | |||
+ | #define SEQS 100 | ||
+ | |||
+ | typedef struct { | ||
+ | uint8_t bstate; | ||
+ | uint32_t dur; | ||
+ | } seq_t; | ||
+ | |||
+ | seq_t seq[SEQS]; | ||
+ | uint8_t count = 0; | ||
+ | |||
+ | void wait(uint32_t ms); | ||
+ | void record(void); | ||
+ | void play(void); | ||
+ | |||
+ | void wait(uint32_t ms) { | ||
+ | uint32_t i; | ||
+ | |||
+ | for (i = 0; i < ms; i++) { | ||
+ | _delay_ms(1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void record(void) { | ||
+ | |||
+ | uint32_t dur = 0; | ||
+ | uint8_t bstate_prev = 0x00; // prev button state | ||
+ | uint8_t bstate = 0x00; // current button state | ||
+ | |||
+ | while (1) { | ||
+ | bstate = 0x00; | ||
+ | |||
+ | // S1 | ||
+ | if (~PINC & _BV(PC0)) { | ||
+ | bstate |= 1 << 1; | ||
+ | } | ||
+ | |||
+ | // S2 | ||
+ | if (~PINC & _BV(PC1)) { | ||
+ | bstate |= 1 << 2; | ||
+ | } | ||
+ | |||
+ | // S3 | ||
+ | if (~PINC & _BV(PC2)) { | ||
+ | bstate |= 1 << 3; | ||
+ | } | ||
+ | |||
+ | // S4 | ||
+ | if (~PINC & _BV(PC3)) { | ||
+ | bstate |= 1 << 4; | ||
+ | } | ||
+ | |||
+ | // omit first state | ||
+ | if (count == 0 && bstate == 0x0) { | ||
+ | continue; | ||
+ | } | ||
+ | |||
+ | if (count >= SEQS) { | ||
+ | // overflow error => all LEDs on | ||
+ | while (1) { | ||
+ | PORTC |= _BV(PC4); | ||
+ | PORTD |= _BV(PD3) | _BV(PD6) | _BV(PD7); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if (bstate_prev == bstate) { | ||
+ | if (dur + 50 > dur) { | ||
+ | dur += 50; | ||
+ | } | ||
+ | |||
+ | if (bstate == 0x0 && count > 0 && dur >= 2000) { | ||
+ | // no button was pressed for 2s | ||
+ | return; | ||
+ | } | ||
+ | } else { | ||
+ | // save state | ||
+ | seq[count].bstate = bstate_prev; | ||
+ | seq[count].dur = dur; | ||
+ | count++; | ||
+ | |||
+ | // prepare for next state | ||
+ | dur = 0; | ||
+ | bstate_prev = bstate; | ||
+ | } | ||
+ | |||
+ | wait(50); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | void play(void) { | ||
+ | uint8_t i; | ||
+ | |||
+ | while (1) { | ||
+ | // PORTD |= _BV(PD7); | ||
+ | |||
+ | for (i = 0; i < count; i++) { | ||
+ | // LED1 | ||
+ | if (seq[i].bstate & 1 << 1) { | ||
+ | PORTC |= _BV(PC4); | ||
+ | } else { | ||
+ | PORTC &= ~_BV(PC4); | ||
+ | } | ||
+ | |||
+ | // LED2 | ||
+ | if (seq[i].bstate & 1 << 2) { | ||
+ | PORTD |= _BV(PD3); | ||
+ | } else { | ||
+ | PORTD &= ~_BV(PD3); | ||
+ | } | ||
+ | |||
+ | // LED3 | ||
+ | if (seq[i].bstate & 1 << 3) { | ||
+ | PORTD |= _BV(PD6); | ||
+ | } else { | ||
+ | PORTD &= ~_BV(PD6); | ||
+ | } | ||
+ | |||
+ | // LED4 | ||
+ | if (seq[i].bstate & 1 << 4) { | ||
+ | PORTD |= _BV(PD7); | ||
+ | } else { | ||
+ | PORTD &= ~_BV(PD7); | ||
+ | } | ||
+ | |||
+ | wait(seq[i].dur); | ||
+ | } | ||
+ | |||
+ | PORTC &= ~_BV(PC4); | ||
+ | PORTD &= ~_BV(PD3) & ~_BV(PD6) & ~_BV(PD7); | ||
+ | wait(300); | ||
+ | |||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | int main(void) { | ||
+ | DDRC |= _BV(PC4); | ||
+ | DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); // all LEDs are output | ||
+ | |||
+ | DDRC &= ~_BV(PC0) & ~_BV(PC1) & ~_BV(PC2) & ~_BV(PC3); // S[1..4] are input | ||
+ | PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3); // use pullup for S[1..4] | ||
+ | |||
+ | // wait for pullops to "settle down" | ||
+ | wait(1000); | ||
+ | |||
+ | while (1) { | ||
+ | record(); | ||
+ | play(); | ||
+ | } | ||
+ | }</source> | ||
+ | |||
+ | == 2. Abend == | ||
+ | |||
+ | Änderungen des IR-Signals werden aufgezeichnet, und auch zeitlich ausgewertet. Messung ist jedoch relativ ungenau. Implementation von Timer / Counter fehlt. | ||
+ | |||
+ | <source lang ="c"> | ||
+ | /* ################################### */ | ||
+ | /* # IR-Empfang # */ | ||
+ | /* # Von Gruppe 1 # */ | ||
+ | /* ################################### */ | ||
+ | /* # Done: IR-Signale chronologisch # */ | ||
+ | /* # aufzeichnen # */ | ||
+ | /* ################################### */ | ||
+ | /* # Todo: Counter / Timer einbauen # */ | ||
+ | /* ################################### */ | ||
+ | |||
+ | |||
+ | #include <avr/io.h> | ||
+ | #include <string.h> | ||
+ | #include <stdio.h> | ||
+ | #include <avr/pgmspace.h> | ||
+ | #include <util/delay.h> | ||
+ | #include "uart.h" | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | int status = 0; | ||
+ | int counter = 0; | ||
+ | /* initialize serial uart */ | ||
+ | uart_init(); | ||
+ | |||
+ | /* configure irrx as input */ | ||
+ | DDRC &= ~_BV(PC3); | ||
+ | |||
+ | /* init led pin as output */ | ||
+ | DDRD |= _BV(PD3); | ||
+ | |||
+ | while(1) { | ||
+ | counter++; | ||
+ | for (int i = 0; i<10; i++) | ||
+ | { | ||
+ | _delay_us(10); | ||
+ | } | ||
+ | /* if ir rx is high, turn off led */ | ||
+ | if (PINC & _BV(PC3)) { | ||
+ | // Kein IR | ||
+ | PORTD &= ~_BV(PD3); | ||
+ | if (status == 1) | ||
+ | { | ||
+ | uart_printf("Ir jetzt aus %u\n",counter); | ||
+ | counter = 0; | ||
+ | } | ||
+ | status = 0; | ||
+ | |||
+ | } else { | ||
+ | PORTD |= _BV(PD3); | ||
+ | if (status == 0) | ||
+ | { | ||
+ | uart_printf("Ir jetzt an %u\n",counter); | ||
+ | counter = 0; | ||
+ | } | ||
+ | status = 1; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | |||
+ | == 3. Abend == | ||
+ | === IR-Jammer === | ||
+ | Sendet, sobald er IR empfängt, für 1000ms und wartet dann 5ms, damit er das ausgesandte Signal nicht wieder empfängt. | ||
+ | |||
+ | <source lang="c"> | ||
+ | #include <avr/io.h> | ||
+ | #include <avr/interrupt.h> | ||
+ | #include <util/delay.h> | ||
+ | #include "uart.h" | ||
+ | |||
+ | /* constants */ | ||
+ | #define MAX 160 | ||
+ | /* 38khz: freq = F_CPU/(2*prescaler*frequency) | ||
+ | * 20mhz/(2*8*38khz) = ~33 | ||
+ | * real frequency: 20mhz/(2*8*33) = ~37878Hz */ | ||
+ | #define PWM_FREQ 33 | ||
+ | |||
+ | /* global variables */ | ||
+ | /* allocate 160*2 = 320 byte memory for storing a code, | ||
+ | * this means we can store 80 on/off sequence timings */ | ||
+ | volatile uint16_t code[MAX]; | ||
+ | /* current index in code[] (default: 0) */ | ||
+ | volatile uint8_t pos = 0; | ||
+ | /* current pin state (default: high == idle) */ | ||
+ | volatile uint8_t state = 1; | ||
+ | /* signal for the main application that a code has been received | ||
+ | * (default: 0) */ | ||
+ | volatile uint8_t done = 0; | ||
+ | /* signal button presses from interrupt to main */ | ||
+ | volatile uint8_t button_press; | ||
+ | /* current system mode */ | ||
+ | enum { | ||
+ | MODE_OFF = 0, | ||
+ | MODE_DISPLAY = 1, | ||
+ | MODE_JAM = 2, | ||
+ | MODE_RECORD = 3, | ||
+ | } mode = MODE_DISPLAY; | ||
+ | /* current viewmode */ | ||
+ | enum { | ||
+ | VIEW_VALUE_AND_TIME = 0, | ||
+ | VIEW_VALUE = 1, | ||
+ | VIEW_TIME = 2, | ||
+ | } view = VIEW_VALUE_AND_TIME; | ||
+ | |||
+ | /* call every 10 ms, for buttons at pins PC0-PC3 */ | ||
+ | static uint8_t button_sample(void) | ||
+ | { | ||
+ | /* initialize state, buttons are active low! */ | ||
+ | static uint8_t btn_state = 15; //0b1111; | ||
+ | /* initialize old sample */ | ||
+ | static uint8_t last_sample = 15; //0b1111; | ||
+ | /* read inputs */ | ||
+ | uint8_t new_sample = PINC & 15; //0b1111; | ||
+ | |||
+ | /* mark bits which are sampled with the same value */ | ||
+ | uint8_t same_sample = (last_sample ^ ~new_sample); | ||
+ | /* all bits set in same_sample now have been sampled with the same value | ||
+ | * at least two times, which means the button has settled */ | ||
+ | |||
+ | /* compare the current button state with the most recent sampled value, | ||
+ | * but only for those bits which have stayed the same */ | ||
+ | uint8_t state_different = btn_state ^ (new_sample & same_sample); | ||
+ | /* all bits set in state_different have been sampled at least two times | ||
+ | * with the same value, and this value is different from the current | ||
+ | * button state */ | ||
+ | |||
+ | /* if a bit is set in state (means: button is not pressed) AND bit is set | ||
+ | * in state_different (means: input has settled and value is different | ||
+ | * from state) together means: button has been pressed recently */ | ||
+ | uint8_t btn_press = btn_state & state_different; | ||
+ | |||
+ | /* toggle all bits for inputs which switched state */ | ||
+ | btn_state ^= state_different; | ||
+ | |||
+ | /* store current sample for next time */ | ||
+ | last_sample = new_sample; | ||
+ | |||
+ | /* if bit is set in btn_press, a button has been pressed | ||
+ | * (not released yet) */ | ||
+ | return btn_press; | ||
+ | } | ||
+ | |||
+ | void wait(uint32_t s) { | ||
+ | uint32_t i; | ||
+ | for (i = 0; i < s; i++) { | ||
+ | _delay_ms(1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* set up timer 0 to generate a carrier using pwm at freq on pin OC0B (PD5) */ | ||
+ | static void ir_enable(uint8_t freq) { | ||
+ | /* timer 0: fast pwm mode, clear OC0B on match, prescaler 8 */ | ||
+ | TCCR0A = _BV(WGM00) | _BV(COM0B1); | ||
+ | TCCR0B = _BV(CS01) | _BV(WGM02); | ||
+ | |||
+ | /* set frequency */ | ||
+ | OCR0A = freq; | ||
+ | |||
+ | /* set duty-cycle to 50% */ | ||
+ | OCR0B = freq/2; | ||
+ | } | ||
+ | |||
+ | /* disable timer 0 and pwm generation */ | ||
+ | static void ir_disable(void) { | ||
+ | TCCR0A = 0; | ||
+ | TCCR0B = 0; | ||
+ | } | ||
+ | |||
+ | |||
+ | /* pin change interrupt 1 service function */ | ||
+ | ISR(PCINT1_vect) | ||
+ | { | ||
+ | /* do nothing if we are just processing a code in the main loop, | ||
+ | * or no more space is available for a timer value */ | ||
+ | if (done || pos == MAX) | ||
+ | return; | ||
+ | |||
+ | /* if this would be the first timing value ever recorded, and the | ||
+ | * state before was high (=idle), do not record the timing value | ||
+ | * and just reset the timer */ | ||
+ | if (state && pos == 0) { | ||
+ | TCNT1 = 0; | ||
+ | /* else record the timing value */ | ||
+ | } else { | ||
+ | /* store current timer value in code[] | ||
+ | * and reset the timer */ | ||
+ | code[pos++] = TCNT1; | ||
+ | TCNT1 = 0; | ||
+ | } | ||
+ | |||
+ | /* toggle second led */ | ||
+ | PORTD ^= _BV(PD3); | ||
+ | |||
+ | /* toggle state */ | ||
+ | state = !state; | ||
+ | } | ||
+ | |||
+ | /* timer 1 compare A interrupt service function */ | ||
+ | ISR(TIMER1_COMPA_vect) | ||
+ | { | ||
+ | /* do nothing if we are just processing a code in the main loop */ | ||
+ | if (done) | ||
+ | return; | ||
+ | |||
+ | /* if some code has been received */ | ||
+ | if (pos > 0) { | ||
+ | /* if pos is odd, one last 'off'-timing is missing, fill with zero */ | ||
+ | if (pos % 2 == 1) | ||
+ | code[pos++] = 0; | ||
+ | |||
+ | /* signal main */ | ||
+ | done = 1; | ||
+ | |||
+ | /* turn on third led */ | ||
+ | PORTD |= _BV(PD6); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* timer 2 compare A interrupt service function */ | ||
+ | ISR(TIMER2_COMPA_vect) | ||
+ | { | ||
+ | /* sample buttons every 10ms */ | ||
+ | button_press |= button_sample(); | ||
+ | } | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | /* initialize uart */ | ||
+ | uart_init(); | ||
+ | uart_printf("rumpus ir analyzer\n"); | ||
+ | |||
+ | /* configure led pins as outputs and turn leds off */ | ||
+ | DDRC |= _BV(PC4); | ||
+ | DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); | ||
+ | PORTC &= ~_BV(PC4); | ||
+ | PORTD &= ~(_BV(PD3) | _BV(PD6) | _BV(PD7)); | ||
+ | |||
+ | /* configure ir input pin, with pullup */ | ||
+ | DDRC &= ~_BV(PC3); | ||
+ | PORTC |= _BV(PC3); | ||
+ | |||
+ | /* configure button input pins, with pullup */ | ||
+ | DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3)); | ||
+ | PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3); | ||
+ | |||
+ | /* configure ir send pin as output, set low */ | ||
+ | DDRD |= _BV(PD5); | ||
+ | PORTD &= ~_BV(PD5); | ||
+ | |||
+ | /* wait until pin is high (no ir carrier is detected) */ | ||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | /* enable pin change interrupt 1 for ir input pin (PC3/PCINT11) */ | ||
+ | PCMSK1 |= _BV(PCINT11); | ||
+ | PCICR |= _BV(PCIE1); | ||
+ | |||
+ | /* configure timer1 with prescaler 64 and CTC for measuring ir timings */ | ||
+ | TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12); | ||
+ | /* configure timer action after 200ms: 20mhz/64/5 */ | ||
+ | OCR1A = F_CPU/5/64; | ||
+ | /* enable OCR1A interrupt */ | ||
+ | TIMSK1 = _BV(OCIE1A); | ||
+ | |||
+ | /* configure timer 2 with prescaler 1024 and CTC | ||
+ | * for button sampling */ | ||
+ | TCCR2A = _BV(WGM21); | ||
+ | TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); | ||
+ | /* configure compare event a to occur after 10ms and enable interrupt */ | ||
+ | OCR2A = F_CPU/1024/100; | ||
+ | TIMSK2 = _BV(OCIE2A); | ||
+ | |||
+ | /* signal user availability by turning on led 1 */ | ||
+ | PORTC |= _BV(PC4); | ||
+ | |||
+ | /* enable interrupts */ | ||
+ | sei(); | ||
+ | |||
+ | /* signal the user that the analyzer part has started by turning led 1 on */ | ||
+ | PORTC |= _BV(PC3); | ||
+ | |||
+ | while(1) { | ||
+ | /* if a code has been received */ | ||
+ | if (mode == MODE_DISPLAY && done) { | ||
+ | |||
+ | /* print code to serial uart */ | ||
+ | uart_printf("complete code received, %u on-off-timings:\n", pos/2); | ||
+ | for (uint8_t i = 0; i < pos; i += 2) { | ||
+ | |||
+ | if (view == VIEW_VALUE_AND_TIME) { | ||
+ | uint32_t on, off; | ||
+ | |||
+ | /* compute timing in microseconds */ | ||
+ | on = ((uint32_t)code[i]) * 64 / 20; | ||
+ | off = ((uint32_t)code[i+1]) * 64 / 20; | ||
+ | |||
+ | uart_printf(" %5lu us (%5u) on, %5lu us (%5u) off\n", | ||
+ | on, code[i], | ||
+ | off, code[i+1]); | ||
+ | } else if (view == VIEW_VALUE) { | ||
+ | uart_printf(" %5u on, %5u off\n", | ||
+ | code[i], code[i+1]); | ||
+ | } else if (view == VIEW_TIME) { | ||
+ | uint32_t on, off; | ||
+ | |||
+ | /* compute timing in microseconds */ | ||
+ | on = ((uint32_t)code[i]) * 64 / 20; | ||
+ | off = ((uint32_t)code[i+1]) * 64 / 20; | ||
+ | |||
+ | uart_printf(" %5lu us on, %5lu us off\n", | ||
+ | on, off); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | /* turn off second and third led */ | ||
+ | PORTD &= ~(_BV(PD3) | _BV(PD6)); | ||
+ | |||
+ | /* wait until pin is high (no ir carrier is detected) */ | ||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | /* reset all global variables */ | ||
+ | pos = 0; | ||
+ | state = 1; | ||
+ | done = 0; | ||
+ | } | ||
+ | |||
+ | if (mode == MODE_JAM) { | ||
+ | // hier wird gejammt! | ||
+ | |||
+ | if (!state) { | ||
+ | DDRC |= _BV(PC3); // ir empfang aus | ||
+ | |||
+ | ir_enable(PWM_FREQ); | ||
+ | wait(1000); | ||
+ | ir_disable(); | ||
+ | |||
+ | wait(5); // damit wir unser eben gesendetes signal nicht empfangen | ||
+ | DDRC &= ~_BV(PC3); // ir empfang an | ||
+ | |||
+ | done = 0; | ||
+ | pos = 0; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | if (button_press) { | ||
+ | /* first button toggles system mode */ | ||
+ | if (button_press & 1) { | ||
+ | mode++; | ||
+ | if (mode > MODE_RECORD) | ||
+ | mode = MODE_OFF; | ||
+ | |||
+ | if (mode == MODE_OFF) { | ||
+ | uart_printf("ir analyzer switched off\n"); | ||
+ | |||
+ | /* disable timer1 and pin change interrupts */ | ||
+ | TIMSK1 &= ~_BV(OCIE1A); | ||
+ | PCMSK1 &= ~_BV(PCINT11); | ||
+ | |||
+ | /* turn off led1 */ | ||
+ | PORTC &= ~_BV(PC4); | ||
+ | |||
+ | } else if (mode == MODE_DISPLAY) { | ||
+ | uart_printf("scan and display codes\n"); | ||
+ | |||
+ | /* clear interrupt flags, enable timer1 and pin change interrupts */ | ||
+ | TIFR1 = _BV(OCIE1A); | ||
+ | TIMSK1 |= _BV(OCIE1A); | ||
+ | PCMSK1 |= _BV(PCINT11); | ||
+ | |||
+ | /* turn on led1 */ | ||
+ | PORTC |= _BV(PC4); | ||
+ | } else if (mode == MODE_JAM) { | ||
+ | /* clear interrupt flags, enable timer1 and pin change interrupts */ | ||
+ | TIFR1 = _BV(OCIE1A); | ||
+ | TIMSK1 |= _BV(OCIE1A); | ||
+ | PCMSK1 |= _BV(PCINT11); | ||
+ | |||
+ | uart_printf("jamming mode active\n"); | ||
+ | } else if (mode == MODE_RECORD) { | ||
+ | uart_printf("record and replay a code\n"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | /* second button toggles view mode */ | ||
+ | if (button_press & 2) { | ||
+ | view++; | ||
+ | if (view > VIEW_TIME) | ||
+ | view = VIEW_VALUE_AND_TIME; | ||
+ | |||
+ | if (view == VIEW_VALUE_AND_TIME) | ||
+ | uart_printf("display timer value and time (in us)\n"); | ||
+ | else if (view == VIEW_VALUE) | ||
+ | uart_printf("display timer value\n"); | ||
+ | else if (view == VIEW_TIME) | ||
+ | uart_printf("display time (in us)\n"); | ||
+ | } | ||
+ | |||
+ | if (button_press & 4) { | ||
+ | static uint8_t pwm = 0; | ||
+ | |||
+ | if (!pwm) { | ||
+ | ir_enable(PWM_FREQ); | ||
+ | uart_printf("pwm on\n"); | ||
+ | } else { | ||
+ | ir_disable(); | ||
+ | uart_printf("pwm off\n"); | ||
+ | } | ||
+ | pwm = !pwm; | ||
+ | } | ||
+ | |||
+ | button_press = 0; | ||
+ | } | ||
+ | } | ||
+ | }</source> | ||
+ | |||
+ | == 4. Abend == | ||
+ | === IR-Jammer in schlau === | ||
+ | Misst die kürzeste Impulsdauer und sendet mit dieser (plus einer kleinen, sich ändernden Verzögerung) in die Pausen. | ||
+ | |||
+ | <source lang="c">#include <avr/io.h> | ||
+ | #include <avr/interrupt.h> | ||
+ | #include <util/delay.h> | ||
+ | #include "uart.h" | ||
+ | |||
+ | /* constants */ | ||
+ | #define MAX 160 | ||
+ | /* 38khz: freq = F_CPU/(2*prescaler*frequency) | ||
+ | * 20mhz/(2*8*38khz) = ~33 | ||
+ | * real frequency: 20mhz/(2*8*33) = ~37878Hz */ | ||
+ | #define PWM_FREQ 33 | ||
+ | |||
+ | /* global variables */ | ||
+ | |||
+ | /* allocate 160*2 = 320 byte memory for storing a code, | ||
+ | * this means we can store 80 on/off sequence timings */ | ||
+ | volatile uint16_t code[MAX]; | ||
+ | /* current index in code[] (default: 0) */ | ||
+ | volatile uint8_t pos = 0; | ||
+ | /* current pin state (default: high == idle) */ | ||
+ | volatile uint8_t state = 1; | ||
+ | /* signal for the main application that a code has been received | ||
+ | * (default: 0) */ | ||
+ | volatile uint8_t done = 0; | ||
+ | /* signal button presses from interrupt to main */ | ||
+ | volatile uint8_t button_press; | ||
+ | /* current system mode */ | ||
+ | enum { | ||
+ | MODE_OFF = 0, | ||
+ | MODE_DISPLAY = 1, | ||
+ | MODE_JAM = 2, | ||
+ | MODE_RECORD = 3, | ||
+ | } mode = MODE_DISPLAY; | ||
+ | /* current viewmode */ | ||
+ | enum { | ||
+ | VIEW_VALUE_AND_TIME = 0, | ||
+ | VIEW_VALUE = 1, | ||
+ | VIEW_TIME = 2, | ||
+ | } view = VIEW_VALUE_AND_TIME; | ||
+ | |||
+ | /* call every 10 ms, for buttons at pins PC0-PC3 */ | ||
+ | static uint8_t button_sample(void) | ||
+ | { | ||
+ | /* initialize state, buttons are active low! */ | ||
+ | static uint8_t btn_state = 15; //0b1111; | ||
+ | /* initialize old sample */ | ||
+ | static uint8_t last_sample = 15; //0b1111; | ||
+ | /* read inputs */ | ||
+ | uint8_t new_sample = PINC & 15; //0b1111; | ||
+ | |||
+ | /* mark bits which are sampled with the same value */ | ||
+ | uint8_t same_sample = (last_sample ^ ~new_sample); | ||
+ | /* all bits set in same_sample now have been sampled with the same value | ||
+ | * at least two times, which means the button has settled */ | ||
+ | |||
+ | /* compare the current button state with the most recent sampled value, | ||
+ | * but only for those bits which have stayed the same */ | ||
+ | uint8_t state_different = btn_state ^ (new_sample & same_sample); | ||
+ | /* all bits set in state_different have been sampled at least two times | ||
+ | * with the same value, and this value is different from the current | ||
+ | * button state */ | ||
+ | |||
+ | /* if a bit is set in state (means: button is not pressed) AND bit is set | ||
+ | * in state_different (means: input has settled and value is different | ||
+ | * from state) together means: button has been pressed recently */ | ||
+ | uint8_t btn_press = btn_state & state_different; | ||
+ | |||
+ | /* toggle all bits for inputs which switched state */ | ||
+ | btn_state ^= state_different; | ||
+ | |||
+ | /* store current sample for next time */ | ||
+ | last_sample = new_sample; | ||
+ | |||
+ | /* if bit is set in btn_press, a button has been pressed | ||
+ | * (not released yet) */ | ||
+ | return btn_press; | ||
+ | } | ||
+ | |||
+ | static void wait(uint32_t s) { | ||
+ | uint32_t i; | ||
+ | for (i = 0; i < s; i++) { | ||
+ | _delay_us(1); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* set up timer 0 to generate a carrier using pwm at freq on pin OC0B (PD5) */ | ||
+ | static void ir_enable(uint8_t freq) { | ||
+ | /* timer 0: fast pwm mode, clear OC0B on match, prescaler 8 */ | ||
+ | TCCR0A = _BV(WGM00) | _BV(COM0B1); | ||
+ | TCCR0B = _BV(CS01) | _BV(WGM02); | ||
+ | |||
+ | /* set frequency */ | ||
+ | OCR0A = freq; | ||
+ | |||
+ | /* set duty-cycle to 50% */ | ||
+ | OCR0B = freq/2; | ||
+ | } | ||
+ | |||
+ | /* disable timer 0 and pwm generation */ | ||
+ | static void ir_disable(void) { | ||
+ | TCCR0A = 0; | ||
+ | TCCR0B = 0; | ||
+ | } | ||
+ | |||
+ | static void jam(void) { | ||
+ | static uint32_t dur; | ||
+ | static uint16_t i; | ||
+ | uint8_t j = 0; | ||
+ | uint32_t dur_tmp; | ||
+ | |||
+ | if (pos == 0 || done) { | ||
+ | dur = 0xFFFFFFFF; | ||
+ | } | ||
+ | |||
+ | if (i % 500 == 0) { | ||
+ | i=0; | ||
+ | if (!state) { | ||
+ | uart_printf("-"); | ||
+ | } else { | ||
+ | uart_printf("."); | ||
+ | } | ||
+ | } | ||
+ | i++; | ||
+ | |||
+ | |||
+ | if (pos < 1) { | ||
+ | return; | ||
+ | } | ||
+ | |||
+ | // shortest measured duration | ||
+ | dur_tmp = ((uint32_t)code[pos-1]) * 64 / 20; | ||
+ | dur = dur_tmp < dur ? dur_tmp : dur; | ||
+ | |||
+ | while (!state && j < 10) { | ||
+ | j++; | ||
+ | DDRC |= _BV(PC3); // ir reciever off | ||
+ | |||
+ | ir_enable(PWM_FREQ); | ||
+ | uart_printf("*"); | ||
+ | wait(dur+i); | ||
+ | ir_disable(); | ||
+ | |||
+ | wait(250); // we don't want to recieve our own signal (due to lags in the ir receiver) | ||
+ | DDRC &= ~_BV(PC3); // ir reciever on | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* pin change interrupt 1 service function */ | ||
+ | ISR(PCINT1_vect) | ||
+ | { | ||
+ | /* do nothing if we are just processing a code in the main loop, | ||
+ | * or no more space is available for a timer value */ | ||
+ | if (done || pos == MAX) | ||
+ | return; | ||
+ | |||
+ | /* if this would be the first timing value ever recorded, and the | ||
+ | * state before was high (=idle), do not record the timing value | ||
+ | * and just reset the timer */ | ||
+ | if (state && pos == 0) { | ||
+ | TCNT1 = 0; | ||
+ | /* else record the timing value */ | ||
+ | } else { | ||
+ | /* store current timer value in code[] | ||
+ | * and reset the timer */ | ||
+ | code[pos++] = TCNT1; | ||
+ | TCNT1 = 0; | ||
+ | } | ||
+ | |||
+ | /* toggle second led */ | ||
+ | PORTD ^= _BV(PD3); | ||
+ | |||
+ | /* toggle state */ | ||
+ | state = !state; | ||
+ | } | ||
+ | |||
+ | /* timer 1 compare A interrupt service function */ | ||
+ | ISR(TIMER1_COMPA_vect) | ||
+ | { | ||
+ | /* do nothing if we are just processing a code in the main loop */ | ||
+ | if (done) | ||
+ | return; | ||
+ | |||
+ | /* if some code has been received */ | ||
+ | if (pos > 0) { | ||
+ | /* if pos is odd, one last 'off'-timing is missing, fill with zero */ | ||
+ | if (pos % 2 == 1) | ||
+ | code[pos++] = 0; | ||
+ | |||
+ | /* signal main */ | ||
+ | done = 1; | ||
+ | |||
+ | /* turn on third led */ | ||
+ | PORTD |= _BV(PD6); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* timer 2 compare A interrupt service function */ | ||
+ | ISR(TIMER2_COMPA_vect) | ||
+ | { | ||
+ | /* sample buttons every 10ms */ | ||
+ | button_press |= button_sample(); | ||
+ | } | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | /* initialize uart */ | ||
+ | uart_init(); | ||
+ | uart_printf("rumpus ir analyzer\n"); | ||
+ | |||
+ | /* configure led pins as outputs and turn leds off */ | ||
+ | DDRC |= _BV(PC4); | ||
+ | DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); | ||
+ | PORTC &= ~_BV(PC4); | ||
+ | PORTD &= ~(_BV(PD3) | _BV(PD6) | _BV(PD7)); | ||
+ | |||
+ | /* configure ir input pin, with pullup */ | ||
+ | DDRC &= ~_BV(PC3); | ||
+ | PORTC |= _BV(PC3); | ||
+ | |||
+ | /* configure button input pins, with pullup */ | ||
+ | DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3)); | ||
+ | PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3); | ||
+ | |||
+ | /* configure ir send pin as output, set low */ | ||
+ | DDRD |= _BV(PD5); | ||
+ | PORTD &= ~_BV(PD5); | ||
+ | |||
+ | /* wait until pin is high (no ir carrier is detected) */ | ||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | /* enable pin change interrupt 1 for ir input pin (PC3/PCINT11) */ | ||
+ | PCMSK1 |= _BV(PCINT11); | ||
+ | PCICR |= _BV(PCIE1); | ||
+ | |||
+ | /* configure timer1 with prescaler 64 and CTC for measuring ir timings */ | ||
+ | TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12); | ||
+ | /* configure timer action after 200ms: 20mhz/64/5 */ | ||
+ | OCR1A = F_CPU/5/64; | ||
+ | /* enable OCR1A interrupt */ | ||
+ | TIMSK1 = _BV(OCIE1A); | ||
+ | |||
+ | /* configure timer 2 with prescaler 1024 and CTC | ||
+ | * for button sampling */ | ||
+ | TCCR2A = _BV(WGM21); | ||
+ | TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); | ||
+ | /* configure compare event a to occur after 10ms and enable interrupt */ | ||
+ | OCR2A = F_CPU/1024/100; | ||
+ | TIMSK2 = _BV(OCIE2A); | ||
+ | |||
+ | /* signal user availability by turning on led 1 */ | ||
+ | PORTC |= _BV(PC4); | ||
+ | |||
+ | /* enable interrupts */ | ||
+ | sei(); | ||
+ | |||
+ | /* signal the user that the analyzer part has started by turning led 1 on */ | ||
+ | PORTC |= _BV(PC3); | ||
+ | |||
+ | while(1) { | ||
+ | /* if a code has been received */ | ||
+ | if (mode == MODE_DISPLAY && done) { | ||
+ | |||
+ | /* print code to serial uart */ | ||
+ | uart_printf("complete code received, %u on-off-timings:\n", pos/2); | ||
+ | for (uint8_t i = 0; i < pos; i += 2) { | ||
+ | |||
+ | if (view == VIEW_VALUE_AND_TIME) { | ||
+ | uint32_t on, off; | ||
+ | |||
+ | /* compute timing in microseconds */ | ||
+ | on = ((uint32_t)code[i]) * 64 / 20; | ||
+ | off = ((uint32_t)code[i+1]) * 64 / 20; | ||
+ | |||
+ | uart_printf(" %5lu us (%5u) on, %5lu us (%5u) off\n", | ||
+ | on, code[i], | ||
+ | off, code[i+1]); | ||
+ | } else if (view == VIEW_VALUE) { | ||
+ | uart_printf(" %5u on, %5u off\n", | ||
+ | code[i], code[i+1]); | ||
+ | } else if (view == VIEW_TIME) { | ||
+ | uint32_t on, off; | ||
+ | |||
+ | /* compute timing in microseconds */ | ||
+ | on = ((uint32_t)code[i]) * 64 / 20; | ||
+ | off = ((uint32_t)code[i+1]) * 64 / 20; | ||
+ | |||
+ | uart_printf(" %5lu us on, %5lu us off\n", | ||
+ | on, off); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | /* turn off second and third led */ | ||
+ | PORTD &= ~(_BV(PD3) | _BV(PD6)); | ||
+ | |||
+ | /* wait until pin is high (no ir carrier is detected) */ | ||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | /* reset all global variables */ | ||
+ | pos = 0; | ||
+ | state = 1; | ||
+ | done = 0; | ||
+ | } | ||
+ | |||
+ | if (mode == MODE_JAM) { | ||
+ | jam(); | ||
+ | } | ||
+ | |||
+ | if (done) { | ||
+ | // code completely detected | ||
+ | |||
+ | /* reset all global variables */ | ||
+ | pos = 0; | ||
+ | state = 1; | ||
+ | done = 0; | ||
+ | } | ||
+ | |||
+ | if (button_press) { | ||
+ | /* first button toggles system mode */ | ||
+ | if (button_press & 1) { | ||
+ | mode++; | ||
+ | if (mode > MODE_RECORD) | ||
+ | mode = MODE_OFF; | ||
+ | |||
+ | if (mode == MODE_OFF) { | ||
+ | uart_printf("ir analyzer switched off\n"); | ||
+ | |||
+ | /* disable timer1 and pin change interrupts */ | ||
+ | TIMSK1 &= ~_BV(OCIE1A); | ||
+ | PCMSK1 &= ~_BV(PCINT11); | ||
+ | |||
+ | /* turn off led1 */ | ||
+ | PORTC &= ~_BV(PC4); | ||
+ | |||
+ | } else if (mode == MODE_DISPLAY) { | ||
+ | uart_printf("scan and display codes\n"); | ||
+ | |||
+ | /* clear interrupt flags, enable timer1 and pin change interrupts */ | ||
+ | TIFR1 = _BV(OCIE1A); | ||
+ | TIMSK1 |= _BV(OCIE1A); | ||
+ | PCMSK1 |= _BV(PCINT11); | ||
+ | |||
+ | /* turn on led1 */ | ||
+ | PORTC |= _BV(PC4); | ||
+ | } else if (mode == MODE_JAM) { | ||
+ | /* clear interrupt flags, enable timer1 and pin change interrupts */ | ||
+ | TIFR1 = _BV(OCIE1A); | ||
+ | TIMSK1 |= _BV(OCIE1A); | ||
+ | PCMSK1 |= _BV(PCINT11); | ||
+ | |||
+ | uart_printf("jamming mode active\n"); | ||
+ | } else if (mode == MODE_RECORD) { | ||
+ | uart_printf("record and replay a code\n"); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | /* second button toggles view mode */ | ||
+ | if (button_press & 2) { | ||
+ | view++; | ||
+ | if (view > VIEW_TIME) | ||
+ | view = VIEW_VALUE_AND_TIME; | ||
+ | |||
+ | if (view == VIEW_VALUE_AND_TIME) | ||
+ | uart_printf("display timer value and time (in us)\n"); | ||
+ | else if (view == VIEW_VALUE) | ||
+ | uart_printf("display timer value\n"); | ||
+ | else if (view == VIEW_TIME) | ||
+ | uart_printf("display time (in us)\n"); | ||
+ | } | ||
+ | |||
+ | if (button_press & 4) { | ||
+ | static uint8_t pwm = 0; | ||
+ | |||
+ | if (!pwm) { | ||
+ | ir_enable(PWM_FREQ); | ||
+ | uart_printf("pwm on\n"); | ||
+ | } else { | ||
+ | ir_disable(); | ||
+ | uart_printf("pwm off\n"); | ||
+ | } | ||
+ | pwm = !pwm; | ||
+ | } | ||
+ | |||
+ | button_press = 0; | ||
+ | } | ||
+ | } | ||
+ | }</source> | ||
+ | |||
+ | === Eigener Chat === | ||
+ | Hier wird die neue uart.c benutzt (die mit Senden und Empfangen). Leider funktioniert der Chat dann nicht mehr, vermutlich kommt der neue uart-Interrupt der wait-Funktion in die Query. Wenn man die alte uart.c benutzt kann man sich wunderbar über die 4 Taster unterhalten :) [[User:Hendi|Hendi]] | ||
+ | |||
+ | <source lang="c">#include <avr/io.h> | ||
+ | #include <avr/interrupt.h> | ||
+ | #include <util/delay.h> | ||
+ | #include "uart.h" | ||
+ | |||
+ | /* constants */ | ||
+ | #define MAX 160 | ||
+ | /* 38khz: freq = F_CPU/(2*prescaler*frequency) | ||
+ | * 20mhz/(2*8*38khz) = ~33 | ||
+ | * real frequency: 20mhz/(2*8*33) = ~37878Hz */ | ||
+ | #define PWM_FREQ 33 | ||
+ | |||
+ | /* global variables */ | ||
+ | |||
+ | /* allocate 160*2 = 320 byte memory for storing a code, | ||
+ | * this means we can store 80 on/off sequence timings */ | ||
+ | volatile uint16_t code[MAX]; | ||
+ | /* current index in code[] (default: 0) */ | ||
+ | volatile uint8_t pos = 0; | ||
+ | /* current pin state (default: high == idle) */ | ||
+ | volatile uint8_t state = 1; | ||
+ | /* signal for the main application that a code has been received | ||
+ | * (default: 0) */ | ||
+ | volatile uint8_t done = 0; | ||
+ | /* signal button presses from interrupt to main */ | ||
+ | volatile uint8_t button_press; | ||
+ | /* current system mode */ | ||
+ | enum { | ||
+ | MODE_OFF = 0, | ||
+ | MODE_DISPLAY = 1, | ||
+ | MODE_JAM = 2, | ||
+ | MODE_RECORD = 3, | ||
+ | } mode = MODE_DISPLAY; | ||
+ | /* current viewmode */ | ||
+ | enum { | ||
+ | VIEW_VALUE_AND_TIME = 0, | ||
+ | VIEW_VALUE = 1, | ||
+ | VIEW_TIME = 2, | ||
+ | } view = VIEW_VALUE_AND_TIME; | ||
+ | |||
+ | /* call every 10 ms, for buttons at pins PC0-PC3 */ | ||
+ | static uint8_t button_sample(void) | ||
+ | { | ||
+ | /* initialize state, buttons are active low! */ | ||
+ | static uint8_t btn_state = 15; //0b1111; | ||
+ | /* initialize old sample */ | ||
+ | static uint8_t last_sample = 15; //0b1111; | ||
+ | /* read inputs */ | ||
+ | uint8_t new_sample = PINC & 15; //0b1111; | ||
+ | |||
+ | /* mark bits which are sampled with the same value */ | ||
+ | uint8_t same_sample = (last_sample ^ ~new_sample); | ||
+ | /* all bits set in same_sample now have been sampled with the same value | ||
+ | * at least two times, which means the button has settled */ | ||
+ | |||
+ | /* compare the current button state with the most recent sampled value, | ||
+ | * but only for those bits which have stayed the same */ | ||
+ | uint8_t state_different = btn_state ^ (new_sample & same_sample); | ||
+ | /* all bits set in state_different have been sampled at least two times | ||
+ | * with the same value, and this value is different from the current | ||
+ | * button state */ | ||
+ | |||
+ | /* if a bit is set in state (means: button is not pressed) AND bit is set | ||
+ | * in state_different (means: input has settled and value is different | ||
+ | * from state) together means: button has been pressed recently */ | ||
+ | uint8_t btn_press = btn_state & state_different; | ||
+ | |||
+ | /* toggle all bits for inputs which switched state */ | ||
+ | btn_state ^= state_different; | ||
+ | |||
+ | /* store current sample for next time */ | ||
+ | last_sample = new_sample; | ||
+ | |||
+ | /* if bit is set in btn_press, a button has been pressed | ||
+ | * (not released yet) */ | ||
+ | return btn_press; | ||
+ | } | ||
+ | |||
+ | static void wait(uint32_t s) { | ||
+ | uint32_t i; | ||
+ | s /= 100; | ||
+ | s *= 2.75; | ||
+ | for (i = 0; i < s; i++) { | ||
+ | _delay_us(100); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* set up timer 0 to generate a carrier using pwm at freq on pin OC0B (PD5) */ | ||
+ | static void ir_enable(uint8_t freq) { | ||
+ | /* timer 0: fast pwm mode, clear OC0B on match, prescaler 8 */ | ||
+ | TCCR0A = _BV(WGM00) | _BV(COM0B1); | ||
+ | TCCR0B = _BV(CS01) | _BV(WGM02); | ||
+ | |||
+ | /* set frequency */ | ||
+ | OCR0A = freq; | ||
+ | |||
+ | /* set duty-cycle to 1/4 */ | ||
+ | OCR0B = freq/4; | ||
+ | } | ||
+ | |||
+ | /* disable timer 0 and pwm generation */ | ||
+ | static void ir_disable(void) { | ||
+ | TCCR0A = 0; | ||
+ | TCCR0B = 0; | ||
+ | } | ||
+ | |||
+ | |||
+ | /* pin change interrupt 1 service function */ | ||
+ | ISR(PCINT1_vect) | ||
+ | { | ||
+ | /* do nothing if we are just processing a code in the main loop, | ||
+ | * or no more space is available for a timer value */ | ||
+ | if (done || pos == MAX) | ||
+ | return; | ||
+ | |||
+ | /* if this would be the first timing value ever recorded, and the | ||
+ | * state before was high (=idle), do not record the timing value | ||
+ | * and just reset the timer */ | ||
+ | if (state && pos == 0) { | ||
+ | TCNT1 = 0; | ||
+ | /* else record the timing value */ | ||
+ | } else { | ||
+ | /* store current timer value in code[] | ||
+ | * and reset the timer */ | ||
+ | code[pos++] = TCNT1; | ||
+ | TCNT1 = 0; | ||
+ | } | ||
+ | |||
+ | /* toggle second led */ | ||
+ | PORTD ^= _BV(PD3); | ||
+ | |||
+ | /* toggle state */ | ||
+ | state = !state; | ||
+ | } | ||
+ | |||
+ | /* timer 1 compare A interrupt service function */ | ||
+ | ISR(TIMER1_COMPA_vect) | ||
+ | { | ||
+ | /* do nothing if we are just processing a code in the main loop */ | ||
+ | if (done) | ||
+ | return; | ||
+ | |||
+ | /* if some code has been received */ | ||
+ | if (pos > 0) { | ||
+ | /* if pos is odd, one last 'off'-timing is missing, fill with zero */ | ||
+ | if (pos % 2 == 1) | ||
+ | code[pos++] = 0; | ||
+ | |||
+ | /* signal main */ | ||
+ | done = 1; | ||
+ | |||
+ | /* turn on third led */ | ||
+ | PORTD |= _BV(PD6); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | /* timer 2 compare A interrupt service function */ | ||
+ | ISR(TIMER2_COMPA_vect) | ||
+ | { | ||
+ | /* sample buttons every 10ms */ | ||
+ | button_press |= button_sample(); | ||
+ | } | ||
+ | |||
+ | // NEC protocol, see http://www.sbprojects.com/knowledge/ir/nec.htm | ||
+ | static void send1(void) { | ||
+ | // uart_printf("1"); | ||
+ | ir_enable(PWM_FREQ); | ||
+ | wait(560); | ||
+ | ir_disable(); | ||
+ | wait(560); | ||
+ | wait(560); | ||
+ | } | ||
+ | |||
+ | static void send0(void) { | ||
+ | // uart_printf("0"); | ||
+ | ir_enable(PWM_FREQ); | ||
+ | wait(560); | ||
+ | ir_disable(); | ||
+ | wait(560); | ||
+ | } | ||
+ | |||
+ | static void send(uint8_t msg[]) { | ||
+ | uint8_t sendcode; | ||
+ | |||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | // say hello | ||
+ | ir_enable(PWM_FREQ); | ||
+ | wait(9000); | ||
+ | ir_disable(); | ||
+ | wait(4500); | ||
+ | |||
+ | for (uint8_t z=0; z<100; z++) { | ||
+ | if (msg[z] == '\r') { | ||
+ | z=100; | ||
+ | } | ||
+ | |||
+ | sendcode = msg[z]; | ||
+ | |||
+ | // send data | ||
+ | for (uint8_t i=0; i<8; i++) { | ||
+ | if (sendcode & (1 << i)) { | ||
+ | send1(); | ||
+ | } else { | ||
+ | send0(); | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | // enable IR, so we know how long it was off | ||
+ | ir_enable(PWM_FREQ); | ||
+ | wait(560); | ||
+ | ir_disable(); | ||
+ | wait(560); | ||
+ | } | ||
+ | |||
+ | static void receive(void) { | ||
+ | uint8_t rcv; | ||
+ | |||
+ | //uart_printf("-- %d --\n", pos); | ||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | // transform time to ms | ||
+ | for (uint8_t i = 0; i < pos; i++) { | ||
+ | code[i] *= 64 / 20; | ||
+ | } | ||
+ | |||
+ | // receive hello | ||
+ | if (code[0] < 8500 || code[0] > 9500 | ||
+ | || code[1] < 4000 || code[1] > 5000 | ||
+ | || pos < 10 | ||
+ | ) { | ||
+ | // no nec hello found | ||
+ | uart_printf("no nec\n"); | ||
+ | // return; | ||
+ | } | ||
+ | |||
+ | // receive msg | ||
+ | for (uint8_t j=0; j<pos/8; j++) { | ||
+ | for (uint8_t i=0; i<8; i++) { | ||
+ | uart_printf("%d - ", code[16*j + 2*i + 2]); | ||
+ | uart_printf("%d", code[16*j + 2*i + 3]); | ||
+ | //uart_printf(" ----- "); | ||
+ | |||
+ | if (!(code[16*j + 2*i + 2] > 400 && code[16*j + 2*i + 2] < 800)) { | ||
+ | // bit doesn't start with ON | ||
+ | rcv = ' '; //uart_printf(" off FAIL (%d)\n", code[16*j + 2*i +2]); | ||
+ | |||
+ | i=8; continue; // go to next byte | ||
+ | } | ||
+ | |||
+ | if (code[16*j + 2*i + 3] > 400 && code[16*j + 2*i + 3] < 800) { | ||
+ | // bit is 0 | ||
+ | rcv &= ~(1 << i); | ||
+ | } else if (code[16*j + 2*i + 3] > 900 && code[16*j + 2*i + 3] < 1300) { | ||
+ | // bit is 1 | ||
+ | rcv |= 1 << i; | ||
+ | } else { | ||
+ | // not sure which value we have | ||
+ | rcv = ' '; //uart_printf(" FAIL (%d)\n", code[16*j + 2*i + 3]); | ||
+ | |||
+ | i=8; continue; // go to next byte | ||
+ | } | ||
+ | } | ||
+ | uart_printf("%c", rcv); | ||
+ | if (rcv == '\r') { | ||
+ | j=pos/8; | ||
+ | } | ||
+ | uart_printf("\n"); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | int main(void) | ||
+ | { | ||
+ | /* initialize uart */ | ||
+ | uart_init(); | ||
+ | uart_printf("rumpus ir chat\n"); | ||
+ | |||
+ | /* configure led pins as outputs and turn leds off */ | ||
+ | DDRC |= _BV(PC4); | ||
+ | DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); | ||
+ | PORTC &= ~_BV(PC4); | ||
+ | PORTD &= ~(_BV(PD3) | _BV(PD6) | _BV(PD7)); | ||
+ | |||
+ | /* configure ir input pin, with pullup */ | ||
+ | DDRC &= ~_BV(PC3); | ||
+ | PORTC |= _BV(PC3); | ||
+ | |||
+ | /* configure button input pins, with pullup */ | ||
+ | DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3)); | ||
+ | PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3); | ||
+ | |||
+ | /* configure ir send pin as output, set low */ | ||
+ | DDRD |= _BV(PD5); | ||
+ | PORTD &= ~_BV(PD5); | ||
+ | |||
+ | /* wait until pin is high (no ir carrier is detected) */ | ||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | /* enable pin change interrupt 1 for ir input pin (PC3/PCINT11) */ | ||
+ | PCMSK1 |= _BV(PCINT11); | ||
+ | PCICR |= _BV(PCIE1); | ||
+ | |||
+ | /* configure timer1 with prescaler 64 and CTC for measuring ir timings */ | ||
+ | TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12); | ||
+ | /* configure timer action after 200ms: 20mhz/64/5 */ | ||
+ | OCR1A = F_CPU/5/64; | ||
+ | /* enable OCR1A interrupt */ | ||
+ | TIMSK1 = _BV(OCIE1A); | ||
+ | |||
+ | /* configure timer 2 with prescaler 1024 and CTC | ||
+ | * for button sampling */ | ||
+ | TCCR2A = _BV(WGM21); | ||
+ | TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); | ||
+ | /* configure compare event a to occur after 10ms and enable interrupt */ | ||
+ | OCR2A = F_CPU/1024/100; | ||
+ | TIMSK2 = _BV(OCIE2A); | ||
+ | |||
+ | /* signal user availability by turning on led 1 */ | ||
+ | PORTC |= _BV(PC4); | ||
+ | |||
+ | /* enable interrupts */ | ||
+ | sei(); | ||
+ | |||
+ | /* signal the user that the analyzer part has started by turning led 1 on */ | ||
+ | PORTC |= _BV(PC3); | ||
+ | |||
+ | while(1) { | ||
+ | |||
+ | /* if a code has been received */ | ||
+ | if (done) { | ||
+ | receive(); | ||
+ | uart_printf("\n"); | ||
+ | |||
+ | /* turn off second and third led */ | ||
+ | PORTD &= ~(_BV(PD3) | _BV(PD6)); | ||
+ | |||
+ | /* wait until pin is high (no ir carrier is detected) */ | ||
+ | while(!(PINC & _BV(PC3))); | ||
+ | |||
+ | /* reset all global variables */ | ||
+ | pos = 0; | ||
+ | state = 1; | ||
+ | done = 0; | ||
+ | } | ||
+ | |||
+ | if (uart_done == 1) { | ||
+ | send(uart_input); | ||
+ | uart_len = 0; | ||
+ | uart_done = 0; | ||
+ | } | ||
+ | |||
+ | if (button_press) { | ||
+ | /* first button toggles system mode */ | ||
+ | uint8_t msg[7] = "Hallo!\r"; | ||
+ | // SENDE | ||
+ | if (button_press & (1 << 0)) { | ||
+ | send(msg); | ||
+ | } else if (button_press & (1 << 1)) { | ||
+ | send(("Gruppe 1\r")); // 0b101 | ||
+ | } else if (button_press & (1 << 2)) { | ||
+ | send("1234567890\r"); // 0b10001 | ||
+ | } else if (button_press & (1 << 3)) { | ||
+ | send("XY\r"); | ||
+ | } | ||
+ | |||
+ | |||
+ | button_press = 0; | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
[[Category:U23 2008]] | [[Category:U23 2008]] |
Latest revision as of 17:36, 24 November 2010
Contents
Meta Data
Mitglieder
- Mark
- Christoph
- Hendrik
- Robert
Code
1. Abend
LED - Blinken
- Aufgabe: Eine LED soll zum blinken gebracht werden.
- Code:
<source lang ="c"> //**************************************************************************** // * // * Von Gruppe 1 // * Aufgabe: Alle LEDs sollen zum blinken gebracht werden. // * // * Task: All LED shall blink. // * //****************************************************************************
- include <avr/io.h>
- include <util/delay.h>
int main(void) { /* LED Anschluss */ /* LED output */ /* LED1 PC4 */ /* LED2 PD3 */ /* LED3 PD6 */ /* LED4 PD7 */
/* Setze Ports PC4, PD3, PD6 und PD7 als Ausgang */
/* Set ports PC4, PD3, PD6 and PD7 as outputs */
DDRC = _BV(4);
DDRD = _BV(7)|_BV(6)|_BV(3);
while(1) {
/* _delay_ms() verzögert um 10 Millisekunden */ /* 50 * 10ms = 500ms */ /* _delay_ms() delays for 10 Milliseconds */ /* 50 * 10ms = 500ms */ for (uint8_t i=0;i<50;i++) _delay_ms(10);
/* Schalte zwischen 5V und 0V an den Ausgängen hin und her */ /* Toggle 5V and 0V at the outputs */ PORTC ^= _BV(4); PORTD ^= _BV(7)|_BV(6)|_BV(3);
} return 0; }
</source>
LED - Einschalten
- Aufgabe: Eine LED soll zum leuchten gebracht werden.
- Code:
<source lang ="c"> //**************************************************************************** // * // * Von Gruppe 1 // * Aufgabe: Eine LED soll zum leuchten gebracht werden. // * //****************************************************************************
- include <avr/io.h>
int main(void) {
/* PC4 auf Ausgang */ DDRC = &b10000; /* Alternativ Hex: 0xF oder Dezimal: 16 */ /* 7 6 5 4 3 2 1 0 */ /* 0 0 0 1 0 0 0 0 */
/* PC4 einschalten */ PORTD = &b10000;
/* Endlosschleife */ while(1) { }
}
</source>
LED - Lauflicht
- Code:
<source lang ="c"> //**************************************************************************** // * // * Von Gruppe 1 // * //****************************************************************************
- include <avr/io.h>
- include <util/delay.h>
int main(void) { unsigned int i;
/* Setze Ports PC4, PD3, PD6 und PD7 als Ausgang */ DDRC = (1<<DDC4); DDRD = (1<<DDD7)|(1<<DDD6)|(1<<DDD3); /* Setze Ports PC4, PD3, PD6 und PD7 auf low */ PORTC = (0<<PC4); PORTD = (0<<PD7)|(0<<PD6)|(0<<PD3);
while(1) {
PORTC ^= _BV(PC4); for (i=0;i<50;i++) _delay_loop_2(0); PORTC ^= _BV(PC4); PORTD ^= _BV(PD3); for (i=0;i<50;i++) _delay_loop_2(0); PORTD ^= _BV(PD3); PORTD ^= _BV(PD6); for (i=0;i<50;i++) _delay_loop_2(0); PORTD ^= _BV(PD6); PORTD ^= _BV(PD7); for (i=0;i<50;i++) _delay_loop_2(0); PORTD ^= _BV(PD7);
} return 0; } </source>
Blinksequenz aufzeichnen und später abspielen
<source lang="c">#include <avr/io.h>
- include <util/delay.h>
- define SEQS 100
typedef struct { uint8_t bstate; uint32_t dur; } seq_t;
seq_t seq[SEQS]; uint8_t count = 0;
void wait(uint32_t ms); void record(void); void play(void);
void wait(uint32_t ms) {
uint32_t i;
for (i = 0; i < ms; i++) { _delay_ms(1); } }
void record(void) {
uint32_t dur = 0; uint8_t bstate_prev = 0x00; // prev button state uint8_t bstate = 0x00; // current button state
while (1) { bstate = 0x00;
// S1 if (~PINC & _BV(PC0)) { bstate |= 1 << 1; }
// S2 if (~PINC & _BV(PC1)) { bstate |= 1 << 2; }
// S3 if (~PINC & _BV(PC2)) { bstate |= 1 << 3; }
// S4 if (~PINC & _BV(PC3)) { bstate |= 1 << 4; }
// omit first state if (count == 0 && bstate == 0x0) { continue; }
if (count >= SEQS) { // overflow error => all LEDs on while (1) { PORTC |= _BV(PC4); PORTD |= _BV(PD3) | _BV(PD6) | _BV(PD7); } }
if (bstate_prev == bstate) { if (dur + 50 > dur) { dur += 50; }
if (bstate == 0x0 && count > 0 && dur >= 2000) { // no button was pressed for 2s return; } } else { // save state seq[count].bstate = bstate_prev; seq[count].dur = dur; count++;
// prepare for next state dur = 0; bstate_prev = bstate; }
wait(50); } }
void play(void) { uint8_t i;
while (1) { // PORTD |= _BV(PD7);
for (i = 0; i < count; i++) { // LED1 if (seq[i].bstate & 1 << 1) { PORTC |= _BV(PC4); } else { PORTC &= ~_BV(PC4); }
// LED2 if (seq[i].bstate & 1 << 2) { PORTD |= _BV(PD3); } else { PORTD &= ~_BV(PD3); }
// LED3 if (seq[i].bstate & 1 << 3) { PORTD |= _BV(PD6); } else { PORTD &= ~_BV(PD6); }
// LED4 if (seq[i].bstate & 1 << 4) { PORTD |= _BV(PD7); } else { PORTD &= ~_BV(PD7); }
wait(seq[i].dur); }
PORTC &= ~_BV(PC4); PORTD &= ~_BV(PD3) & ~_BV(PD6) & ~_BV(PD7); wait(300);
} }
int main(void) {
DDRC |= _BV(PC4);
DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); // all LEDs are output
DDRC &= ~_BV(PC0) & ~_BV(PC1) & ~_BV(PC2) & ~_BV(PC3); // S[1..4] are input PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3); // use pullup for S[1..4]
// wait for pullops to "settle down" wait(1000);
while (1) { record(); play(); } }</source>
2. Abend
Änderungen des IR-Signals werden aufgezeichnet, und auch zeitlich ausgewertet. Messung ist jedoch relativ ungenau. Implementation von Timer / Counter fehlt.
<source lang ="c"> /* ################################### */ /* # IR-Empfang # */ /* # Von Gruppe 1 # */ /* ################################### */ /* # Done: IR-Signale chronologisch # */ /* # aufzeichnen # */ /* ################################### */ /* # Todo: Counter / Timer einbauen # */ /* ################################### */
- include <avr/io.h>
- include <string.h>
- include <stdio.h>
- include <avr/pgmspace.h>
- include <util/delay.h>
- include "uart.h"
int main(void) { int status = 0; int counter = 0;
/* initialize serial uart */ uart_init();
/* configure irrx as input */ DDRC &= ~_BV(PC3);
/* init led pin as output */ DDRD |= _BV(PD3);
while(1) { counter++; for (int i = 0; i<10; i++) { _delay_us(10);
}
/* if ir rx is high, turn off led */ if (PINC & _BV(PC3)) { // Kein IR PORTD &= ~_BV(PD3); if (status == 1) { uart_printf("Ir jetzt aus %u\n",counter); counter = 0; } status = 0; } else { PORTD |= _BV(PD3); if (status == 0) { uart_printf("Ir jetzt an %u\n",counter); counter = 0; } status = 1; } }
} </source>
3. Abend
IR-Jammer
Sendet, sobald er IR empfängt, für 1000ms und wartet dann 5ms, damit er das ausgesandte Signal nicht wieder empfängt.
<source lang="c">
- include <avr/io.h>
- include <avr/interrupt.h>
- include <util/delay.h>
- include "uart.h"
/* constants */
- define MAX 160
/* 38khz: freq = F_CPU/(2*prescaler*frequency)
* 20mhz/(2*8*38khz) = ~33 * real frequency: 20mhz/(2*8*33) = ~37878Hz */
- define PWM_FREQ 33
/* global variables */
/* allocate 160*2 = 320 byte memory for storing a code,
* this means we can store 80 on/off sequence timings */
volatile uint16_t code[MAX]; /* current index in code[] (default: 0) */ volatile uint8_t pos = 0; /* current pin state (default: high == idle) */ volatile uint8_t state = 1; /* signal for the main application that a code has been received
* (default: 0) */
volatile uint8_t done = 0; /* signal button presses from interrupt to main */ volatile uint8_t button_press; /* current system mode */ enum {
MODE_OFF = 0, MODE_DISPLAY = 1, MODE_JAM = 2, MODE_RECORD = 3,
} mode = MODE_DISPLAY; /* current viewmode */ enum {
VIEW_VALUE_AND_TIME = 0, VIEW_VALUE = 1, VIEW_TIME = 2,
} view = VIEW_VALUE_AND_TIME;
/* call every 10 ms, for buttons at pins PC0-PC3 */ static uint8_t button_sample(void) {
/* initialize state, buttons are active low! */ static uint8_t btn_state = 15; //0b1111; /* initialize old sample */ static uint8_t last_sample = 15; //0b1111; /* read inputs */ uint8_t new_sample = PINC & 15; //0b1111;
/* mark bits which are sampled with the same value */ uint8_t same_sample = (last_sample ^ ~new_sample); /* all bits set in same_sample now have been sampled with the same value * at least two times, which means the button has settled */
/* compare the current button state with the most recent sampled value, * but only for those bits which have stayed the same */ uint8_t state_different = btn_state ^ (new_sample & same_sample); /* all bits set in state_different have been sampled at least two times * with the same value, and this value is different from the current * button state */
/* if a bit is set in state (means: button is not pressed) AND bit is set * in state_different (means: input has settled and value is different * from state) together means: button has been pressed recently */ uint8_t btn_press = btn_state & state_different;
/* toggle all bits for inputs which switched state */ btn_state ^= state_different;
/* store current sample for next time */ last_sample = new_sample;
/* if bit is set in btn_press, a button has been pressed * (not released yet) */ return btn_press;
}
void wait(uint32_t s) { uint32_t i; for (i = 0; i < s; i++) { _delay_ms(1); } }
/* set up timer 0 to generate a carrier using pwm at freq on pin OC0B (PD5) */ static void ir_enable(uint8_t freq) {
/* timer 0: fast pwm mode, clear OC0B on match, prescaler 8 */ TCCR0A = _BV(WGM00) | _BV(COM0B1); TCCR0B = _BV(CS01) | _BV(WGM02);
/* set frequency */ OCR0A = freq;
/* set duty-cycle to 50% */ OCR0B = freq/2;
}
/* disable timer 0 and pwm generation */ static void ir_disable(void) {
TCCR0A = 0; TCCR0B = 0;
}
/* pin change interrupt 1 service function */
ISR(PCINT1_vect)
{
/* do nothing if we are just processing a code in the main loop, * or no more space is available for a timer value */ if (done || pos == MAX) return;
/* if this would be the first timing value ever recorded, and the * state before was high (=idle), do not record the timing value * and just reset the timer */ if (state && pos == 0) { TCNT1 = 0; /* else record the timing value */ } else { /* store current timer value in code[] * and reset the timer */ code[pos++] = TCNT1; TCNT1 = 0; }
/* toggle second led */ PORTD ^= _BV(PD3);
/* toggle state */ state = !state;
}
/* timer 1 compare A interrupt service function */ ISR(TIMER1_COMPA_vect) {
/* do nothing if we are just processing a code in the main loop */ if (done) return;
/* if some code has been received */ if (pos > 0) { /* if pos is odd, one last 'off'-timing is missing, fill with zero */ if (pos % 2 == 1) code[pos++] = 0;
/* signal main */ done = 1;
/* turn on third led */ PORTD |= _BV(PD6); }
}
/* timer 2 compare A interrupt service function */ ISR(TIMER2_COMPA_vect) {
/* sample buttons every 10ms */ button_press |= button_sample();
}
int main(void) {
/* initialize uart */ uart_init(); uart_printf("rumpus ir analyzer\n");
/* configure led pins as outputs and turn leds off */ DDRC |= _BV(PC4); DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); PORTC &= ~_BV(PC4); PORTD &= ~(_BV(PD3) | _BV(PD6) | _BV(PD7));
/* configure ir input pin, with pullup */ DDRC &= ~_BV(PC3); PORTC |= _BV(PC3);
/* configure button input pins, with pullup */ DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3)); PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3);
/* configure ir send pin as output, set low */ DDRD |= _BV(PD5); PORTD &= ~_BV(PD5);
/* wait until pin is high (no ir carrier is detected) */ while(!(PINC & _BV(PC3)));
/* enable pin change interrupt 1 for ir input pin (PC3/PCINT11) */ PCMSK1 |= _BV(PCINT11); PCICR |= _BV(PCIE1);
/* configure timer1 with prescaler 64 and CTC for measuring ir timings */ TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12); /* configure timer action after 200ms: 20mhz/64/5 */ OCR1A = F_CPU/5/64; /* enable OCR1A interrupt */ TIMSK1 = _BV(OCIE1A);
/* configure timer 2 with prescaler 1024 and CTC * for button sampling */ TCCR2A = _BV(WGM21); TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); /* configure compare event a to occur after 10ms and enable interrupt */ OCR2A = F_CPU/1024/100; TIMSK2 = _BV(OCIE2A);
/* signal user availability by turning on led 1 */ PORTC |= _BV(PC4);
/* enable interrupts */ sei();
/* signal the user that the analyzer part has started by turning led 1 on */ PORTC |= _BV(PC3);
while(1) { /* if a code has been received */ if (mode == MODE_DISPLAY && done) {
/* print code to serial uart */ uart_printf("complete code received, %u on-off-timings:\n", pos/2); for (uint8_t i = 0; i < pos; i += 2) {
if (view == VIEW_VALUE_AND_TIME) { uint32_t on, off;
/* compute timing in microseconds */ on = ((uint32_t)code[i]) * 64 / 20; off = ((uint32_t)code[i+1]) * 64 / 20;
uart_printf(" %5lu us (%5u) on, %5lu us (%5u) off\n", on, code[i], off, code[i+1]); } else if (view == VIEW_VALUE) { uart_printf(" %5u on, %5u off\n", code[i], code[i+1]); } else if (view == VIEW_TIME) { uint32_t on, off;
/* compute timing in microseconds */ on = ((uint32_t)code[i]) * 64 / 20; off = ((uint32_t)code[i+1]) * 64 / 20;
uart_printf(" %5lu us on, %5lu us off\n", on, off); } }
/* turn off second and third led */ PORTD &= ~(_BV(PD3) | _BV(PD6));
/* wait until pin is high (no ir carrier is detected) */ while(!(PINC & _BV(PC3)));
/* reset all global variables */ pos = 0; state = 1; done = 0; }
if (mode == MODE_JAM) { // hier wird gejammt!
if (!state) { DDRC |= _BV(PC3); // ir empfang aus
ir_enable(PWM_FREQ); wait(1000); ir_disable();
wait(5); // damit wir unser eben gesendetes signal nicht empfangen DDRC &= ~_BV(PC3); // ir empfang an
done = 0; pos = 0; } }
if (button_press) { /* first button toggles system mode */ if (button_press & 1) { mode++; if (mode > MODE_RECORD) mode = MODE_OFF;
if (mode == MODE_OFF) { uart_printf("ir analyzer switched off\n");
/* disable timer1 and pin change interrupts */ TIMSK1 &= ~_BV(OCIE1A); PCMSK1 &= ~_BV(PCINT11);
/* turn off led1 */ PORTC &= ~_BV(PC4);
} else if (mode == MODE_DISPLAY) { uart_printf("scan and display codes\n");
/* clear interrupt flags, enable timer1 and pin change interrupts */ TIFR1 = _BV(OCIE1A); TIMSK1 |= _BV(OCIE1A); PCMSK1 |= _BV(PCINT11);
/* turn on led1 */ PORTC |= _BV(PC4); } else if (mode == MODE_JAM) { /* clear interrupt flags, enable timer1 and pin change interrupts */ TIFR1 = _BV(OCIE1A); TIMSK1 |= _BV(OCIE1A); PCMSK1 |= _BV(PCINT11);
uart_printf("jamming mode active\n"); } else if (mode == MODE_RECORD) { uart_printf("record and replay a code\n"); } }
/* second button toggles view mode */ if (button_press & 2) { view++; if (view > VIEW_TIME) view = VIEW_VALUE_AND_TIME;
if (view == VIEW_VALUE_AND_TIME) uart_printf("display timer value and time (in us)\n"); else if (view == VIEW_VALUE) uart_printf("display timer value\n"); else if (view == VIEW_TIME) uart_printf("display time (in us)\n"); }
if (button_press & 4) { static uint8_t pwm = 0;
if (!pwm) { ir_enable(PWM_FREQ); uart_printf("pwm on\n"); } else { ir_disable(); uart_printf("pwm off\n"); } pwm = !pwm; }
button_press = 0; } }
}</source>
4. Abend
IR-Jammer in schlau
Misst die kürzeste Impulsdauer und sendet mit dieser (plus einer kleinen, sich ändernden Verzögerung) in die Pausen.
<source lang="c">#include <avr/io.h>
- include <avr/interrupt.h>
- include <util/delay.h>
- include "uart.h"
/* constants */
- define MAX 160
/* 38khz: freq = F_CPU/(2*prescaler*frequency)
* 20mhz/(2*8*38khz) = ~33 * real frequency: 20mhz/(2*8*33) = ~37878Hz */
- define PWM_FREQ 33
/* global variables */
/* allocate 160*2 = 320 byte memory for storing a code,
* this means we can store 80 on/off sequence timings */
volatile uint16_t code[MAX]; /* current index in code[] (default: 0) */ volatile uint8_t pos = 0; /* current pin state (default: high == idle) */ volatile uint8_t state = 1; /* signal for the main application that a code has been received
* (default: 0) */
volatile uint8_t done = 0; /* signal button presses from interrupt to main */ volatile uint8_t button_press; /* current system mode */ enum {
MODE_OFF = 0, MODE_DISPLAY = 1, MODE_JAM = 2, MODE_RECORD = 3,
} mode = MODE_DISPLAY; /* current viewmode */ enum {
VIEW_VALUE_AND_TIME = 0, VIEW_VALUE = 1, VIEW_TIME = 2,
} view = VIEW_VALUE_AND_TIME;
/* call every 10 ms, for buttons at pins PC0-PC3 */ static uint8_t button_sample(void) {
/* initialize state, buttons are active low! */ static uint8_t btn_state = 15; //0b1111; /* initialize old sample */ static uint8_t last_sample = 15; //0b1111; /* read inputs */ uint8_t new_sample = PINC & 15; //0b1111;
/* mark bits which are sampled with the same value */ uint8_t same_sample = (last_sample ^ ~new_sample); /* all bits set in same_sample now have been sampled with the same value * at least two times, which means the button has settled */
/* compare the current button state with the most recent sampled value, * but only for those bits which have stayed the same */ uint8_t state_different = btn_state ^ (new_sample & same_sample); /* all bits set in state_different have been sampled at least two times * with the same value, and this value is different from the current * button state */
/* if a bit is set in state (means: button is not pressed) AND bit is set * in state_different (means: input has settled and value is different * from state) together means: button has been pressed recently */ uint8_t btn_press = btn_state & state_different;
/* toggle all bits for inputs which switched state */ btn_state ^= state_different;
/* store current sample for next time */ last_sample = new_sample;
/* if bit is set in btn_press, a button has been pressed * (not released yet) */ return btn_press;
}
static void wait(uint32_t s) { uint32_t i; for (i = 0; i < s; i++) { _delay_us(1); } }
/* set up timer 0 to generate a carrier using pwm at freq on pin OC0B (PD5) */ static void ir_enable(uint8_t freq) {
/* timer 0: fast pwm mode, clear OC0B on match, prescaler 8 */ TCCR0A = _BV(WGM00) | _BV(COM0B1); TCCR0B = _BV(CS01) | _BV(WGM02);
/* set frequency */ OCR0A = freq;
/* set duty-cycle to 50% */ OCR0B = freq/2;
}
/* disable timer 0 and pwm generation */ static void ir_disable(void) {
TCCR0A = 0; TCCR0B = 0;
}
static void jam(void) { static uint32_t dur; static uint16_t i; uint8_t j = 0; uint32_t dur_tmp;
if (pos == 0 || done) { dur = 0xFFFFFFFF; }
if (i % 500 == 0) { i=0; if (!state) { uart_printf("-"); } else { uart_printf("."); } } i++;
if (pos < 1) {
return;
}
// shortest measured duration dur_tmp = ((uint32_t)code[pos-1]) * 64 / 20; dur = dur_tmp < dur ? dur_tmp : dur;
while (!state && j < 10) { j++; DDRC |= _BV(PC3); // ir reciever off
ir_enable(PWM_FREQ); uart_printf("*"); wait(dur+i); ir_disable();
wait(250); // we don't want to recieve our own signal (due to lags in the ir receiver) DDRC &= ~_BV(PC3); // ir reciever on } }
/* pin change interrupt 1 service function */ ISR(PCINT1_vect) {
/* do nothing if we are just processing a code in the main loop, * or no more space is available for a timer value */ if (done || pos == MAX) return;
/* if this would be the first timing value ever recorded, and the * state before was high (=idle), do not record the timing value * and just reset the timer */ if (state && pos == 0) { TCNT1 = 0; /* else record the timing value */ } else { /* store current timer value in code[] * and reset the timer */ code[pos++] = TCNT1; TCNT1 = 0; }
/* toggle second led */ PORTD ^= _BV(PD3);
/* toggle state */ state = !state;
}
/* timer 1 compare A interrupt service function */ ISR(TIMER1_COMPA_vect) {
/* do nothing if we are just processing a code in the main loop */ if (done) return;
/* if some code has been received */ if (pos > 0) { /* if pos is odd, one last 'off'-timing is missing, fill with zero */ if (pos % 2 == 1) code[pos++] = 0;
/* signal main */ done = 1;
/* turn on third led */ PORTD |= _BV(PD6); }
}
/* timer 2 compare A interrupt service function */ ISR(TIMER2_COMPA_vect) {
/* sample buttons every 10ms */ button_press |= button_sample();
}
int main(void) {
/* initialize uart */ uart_init(); uart_printf("rumpus ir analyzer\n");
/* configure led pins as outputs and turn leds off */ DDRC |= _BV(PC4); DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); PORTC &= ~_BV(PC4); PORTD &= ~(_BV(PD3) | _BV(PD6) | _BV(PD7));
/* configure ir input pin, with pullup */ DDRC &= ~_BV(PC3); PORTC |= _BV(PC3);
/* configure button input pins, with pullup */ DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3)); PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3);
/* configure ir send pin as output, set low */ DDRD |= _BV(PD5); PORTD &= ~_BV(PD5);
/* wait until pin is high (no ir carrier is detected) */ while(!(PINC & _BV(PC3)));
/* enable pin change interrupt 1 for ir input pin (PC3/PCINT11) */ PCMSK1 |= _BV(PCINT11); PCICR |= _BV(PCIE1);
/* configure timer1 with prescaler 64 and CTC for measuring ir timings */ TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12); /* configure timer action after 200ms: 20mhz/64/5 */ OCR1A = F_CPU/5/64; /* enable OCR1A interrupt */ TIMSK1 = _BV(OCIE1A);
/* configure timer 2 with prescaler 1024 and CTC * for button sampling */ TCCR2A = _BV(WGM21); TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); /* configure compare event a to occur after 10ms and enable interrupt */ OCR2A = F_CPU/1024/100; TIMSK2 = _BV(OCIE2A);
/* signal user availability by turning on led 1 */ PORTC |= _BV(PC4);
/* enable interrupts */ sei();
/* signal the user that the analyzer part has started by turning led 1 on */ PORTC |= _BV(PC3);
while(1) { /* if a code has been received */ if (mode == MODE_DISPLAY && done) {
/* print code to serial uart */ uart_printf("complete code received, %u on-off-timings:\n", pos/2); for (uint8_t i = 0; i < pos; i += 2) {
if (view == VIEW_VALUE_AND_TIME) { uint32_t on, off;
/* compute timing in microseconds */ on = ((uint32_t)code[i]) * 64 / 20; off = ((uint32_t)code[i+1]) * 64 / 20;
uart_printf(" %5lu us (%5u) on, %5lu us (%5u) off\n", on, code[i], off, code[i+1]); } else if (view == VIEW_VALUE) { uart_printf(" %5u on, %5u off\n", code[i], code[i+1]); } else if (view == VIEW_TIME) { uint32_t on, off;
/* compute timing in microseconds */ on = ((uint32_t)code[i]) * 64 / 20; off = ((uint32_t)code[i+1]) * 64 / 20;
uart_printf(" %5lu us on, %5lu us off\n", on, off); } }
/* turn off second and third led */ PORTD &= ~(_BV(PD3) | _BV(PD6));
/* wait until pin is high (no ir carrier is detected) */ while(!(PINC & _BV(PC3)));
/* reset all global variables */ pos = 0; state = 1; done = 0; }
if (mode == MODE_JAM) { jam(); }
if (done) { // code completely detected
/* reset all global variables */ pos = 0; state = 1; done = 0;
}
if (button_press) { /* first button toggles system mode */ if (button_press & 1) { mode++; if (mode > MODE_RECORD) mode = MODE_OFF;
if (mode == MODE_OFF) { uart_printf("ir analyzer switched off\n");
/* disable timer1 and pin change interrupts */ TIMSK1 &= ~_BV(OCIE1A); PCMSK1 &= ~_BV(PCINT11);
/* turn off led1 */ PORTC &= ~_BV(PC4);
} else if (mode == MODE_DISPLAY) { uart_printf("scan and display codes\n");
/* clear interrupt flags, enable timer1 and pin change interrupts */ TIFR1 = _BV(OCIE1A); TIMSK1 |= _BV(OCIE1A); PCMSK1 |= _BV(PCINT11);
/* turn on led1 */ PORTC |= _BV(PC4); } else if (mode == MODE_JAM) { /* clear interrupt flags, enable timer1 and pin change interrupts */ TIFR1 = _BV(OCIE1A); TIMSK1 |= _BV(OCIE1A); PCMSK1 |= _BV(PCINT11);
uart_printf("jamming mode active\n"); } else if (mode == MODE_RECORD) { uart_printf("record and replay a code\n"); } }
/* second button toggles view mode */
if (button_press & 2) {
view++;
if (view > VIEW_TIME)
view = VIEW_VALUE_AND_TIME;
if (view == VIEW_VALUE_AND_TIME) uart_printf("display timer value and time (in us)\n"); else if (view == VIEW_VALUE) uart_printf("display timer value\n"); else if (view == VIEW_TIME) uart_printf("display time (in us)\n"); }
if (button_press & 4) { static uint8_t pwm = 0;
if (!pwm) { ir_enable(PWM_FREQ); uart_printf("pwm on\n"); } else { ir_disable(); uart_printf("pwm off\n"); } pwm = !pwm; }
button_press = 0; } } }</source>
Eigener Chat
Hier wird die neue uart.c benutzt (die mit Senden und Empfangen). Leider funktioniert der Chat dann nicht mehr, vermutlich kommt der neue uart-Interrupt der wait-Funktion in die Query. Wenn man die alte uart.c benutzt kann man sich wunderbar über die 4 Taster unterhalten :) Hendi
<source lang="c">#include <avr/io.h>
- include <avr/interrupt.h>
- include <util/delay.h>
- include "uart.h"
/* constants */
- define MAX 160
/* 38khz: freq = F_CPU/(2*prescaler*frequency)
* 20mhz/(2*8*38khz) = ~33 * real frequency: 20mhz/(2*8*33) = ~37878Hz */
- define PWM_FREQ 33
/* global variables */
/* allocate 160*2 = 320 byte memory for storing a code,
* this means we can store 80 on/off sequence timings */
volatile uint16_t code[MAX]; /* current index in code[] (default: 0) */ volatile uint8_t pos = 0; /* current pin state (default: high == idle) */ volatile uint8_t state = 1; /* signal for the main application that a code has been received
* (default: 0) */
volatile uint8_t done = 0; /* signal button presses from interrupt to main */ volatile uint8_t button_press; /* current system mode */ enum {
MODE_OFF = 0, MODE_DISPLAY = 1, MODE_JAM = 2, MODE_RECORD = 3,
} mode = MODE_DISPLAY; /* current viewmode */ enum {
VIEW_VALUE_AND_TIME = 0, VIEW_VALUE = 1, VIEW_TIME = 2,
} view = VIEW_VALUE_AND_TIME;
/* call every 10 ms, for buttons at pins PC0-PC3 */ static uint8_t button_sample(void) {
/* initialize state, buttons are active low! */ static uint8_t btn_state = 15; //0b1111; /* initialize old sample */ static uint8_t last_sample = 15; //0b1111; /* read inputs */ uint8_t new_sample = PINC & 15; //0b1111; /* mark bits which are sampled with the same value */ uint8_t same_sample = (last_sample ^ ~new_sample); /* all bits set in same_sample now have been sampled with the same value * at least two times, which means the button has settled */ /* compare the current button state with the most recent sampled value, * but only for those bits which have stayed the same */ uint8_t state_different = btn_state ^ (new_sample & same_sample); /* all bits set in state_different have been sampled at least two times * with the same value, and this value is different from the current * button state */ /* if a bit is set in state (means: button is not pressed) AND bit is set * in state_different (means: input has settled and value is different * from state) together means: button has been pressed recently */ uint8_t btn_press = btn_state & state_different; /* toggle all bits for inputs which switched state */ btn_state ^= state_different; /* store current sample for next time */ last_sample = new_sample; /* if bit is set in btn_press, a button has been pressed * (not released yet) */ return btn_press;
}
static void wait(uint32_t s) { uint32_t i; s /= 100; s *= 2.75; for (i = 0; i < s; i++) { _delay_us(100); } }
/* set up timer 0 to generate a carrier using pwm at freq on pin OC0B (PD5) */ static void ir_enable(uint8_t freq) {
/* timer 0: fast pwm mode, clear OC0B on match, prescaler 8 */ TCCR0A = _BV(WGM00) | _BV(COM0B1); TCCR0B = _BV(CS01) | _BV(WGM02); /* set frequency */ OCR0A = freq; /* set duty-cycle to 1/4 */ OCR0B = freq/4;
}
/* disable timer 0 and pwm generation */ static void ir_disable(void) {
TCCR0A = 0; TCCR0B = 0;
}
/* pin change interrupt 1 service function */
ISR(PCINT1_vect)
{
/* do nothing if we are just processing a code in the main loop, * or no more space is available for a timer value */ if (done || pos == MAX) return; /* if this would be the first timing value ever recorded, and the * state before was high (=idle), do not record the timing value * and just reset the timer */ if (state && pos == 0) { TCNT1 = 0; /* else record the timing value */ } else { /* store current timer value in code[] * and reset the timer */ code[pos++] = TCNT1; TCNT1 = 0; } /* toggle second led */ PORTD ^= _BV(PD3); /* toggle state */ state = !state;
}
/* timer 1 compare A interrupt service function */ ISR(TIMER1_COMPA_vect) {
/* do nothing if we are just processing a code in the main loop */ if (done) return; /* if some code has been received */ if (pos > 0) { /* if pos is odd, one last 'off'-timing is missing, fill with zero */ if (pos % 2 == 1) code[pos++] = 0; /* signal main */ done = 1; /* turn on third led */ PORTD |= _BV(PD6); }
}
/* timer 2 compare A interrupt service function */ ISR(TIMER2_COMPA_vect) {
/* sample buttons every 10ms */ button_press |= button_sample();
}
// NEC protocol, see http://www.sbprojects.com/knowledge/ir/nec.htm static void send1(void) { // uart_printf("1"); ir_enable(PWM_FREQ); wait(560); ir_disable(); wait(560); wait(560); }
static void send0(void) { // uart_printf("0"); ir_enable(PWM_FREQ); wait(560); ir_disable(); wait(560); }
static void send(uint8_t msg[]) { uint8_t sendcode;
while(!(PINC & _BV(PC3)));
// say hello ir_enable(PWM_FREQ); wait(9000); ir_disable(); wait(4500);
for (uint8_t z=0; z<100; z++) { if (msg[z] == '\r') { z=100; }
sendcode = msg[z];
// send data
for (uint8_t i=0; i<8; i++) { if (sendcode & (1 << i)) { send1(); } else { send0(); } }
}
// enable IR, so we know how long it was off ir_enable(PWM_FREQ); wait(560); ir_disable(); wait(560); }
static void receive(void) {
uint8_t rcv;
//uart_printf("-- %d --\n", pos); while(!(PINC & _BV(PC3)));
// transform time to ms for (uint8_t i = 0; i < pos; i++) { code[i] *= 64 / 20; } // receive hello if (code[0] < 8500 || code[0] > 9500 || code[1] < 4000 || code[1] > 5000 || pos < 10 ) { // no nec hello found
uart_printf("no nec\n"); // return; }
// receive msg
for (uint8_t j=0; j<pos/8; j++) {
for (uint8_t i=0; i<8; i++) {
uart_printf("%d - ", code[16*j + 2*i + 2]); uart_printf("%d", code[16*j + 2*i + 3]); //uart_printf(" ----- ");
if (!(code[16*j + 2*i + 2] > 400 && code[16*j + 2*i + 2] < 800)) { // bit doesn't start with ON
rcv = ' '; //uart_printf(" off FAIL (%d)\n", code[16*j + 2*i +2]);
i=8; continue; // go to next byte
} if (code[16*j + 2*i + 3] > 400 && code[16*j + 2*i + 3] < 800) { // bit is 0 rcv &= ~(1 << i); } else if (code[16*j + 2*i + 3] > 900 && code[16*j + 2*i + 3] < 1300) { // bit is 1 rcv |= 1 << i; } else { // not sure which value we have
rcv = ' '; //uart_printf(" FAIL (%d)\n", code[16*j + 2*i + 3]);
i=8; continue; // go to next byte
} }
uart_printf("%c", rcv); if (rcv == '\r') { j=pos/8; } uart_printf("\n");
}
}
int main(void) {
/* initialize uart */ uart_init(); uart_printf("rumpus ir chat\n"); /* configure led pins as outputs and turn leds off */ DDRC |= _BV(PC4); DDRD |= _BV(PD3) | _BV(PD6) | _BV(PD7); PORTC &= ~_BV(PC4); PORTD &= ~(_BV(PD3) | _BV(PD6) | _BV(PD7)); /* configure ir input pin, with pullup */ DDRC &= ~_BV(PC3); PORTC |= _BV(PC3); /* configure button input pins, with pullup */ DDRC &= ~(_BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3)); PORTC |= _BV(PC0) | _BV(PC1) | _BV(PC2) | _BV(PC3); /* configure ir send pin as output, set low */ DDRD |= _BV(PD5); PORTD &= ~_BV(PD5); /* wait until pin is high (no ir carrier is detected) */ while(!(PINC & _BV(PC3))); /* enable pin change interrupt 1 for ir input pin (PC3/PCINT11) */ PCMSK1 |= _BV(PCINT11); PCICR |= _BV(PCIE1); /* configure timer1 with prescaler 64 and CTC for measuring ir timings */ TCCR1B = _BV(CS11) | _BV(CS10) | _BV(WGM12); /* configure timer action after 200ms: 20mhz/64/5 */ OCR1A = F_CPU/5/64; /* enable OCR1A interrupt */ TIMSK1 = _BV(OCIE1A); /* configure timer 2 with prescaler 1024 and CTC * for button sampling */ TCCR2A = _BV(WGM21); TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20); /* configure compare event a to occur after 10ms and enable interrupt */ OCR2A = F_CPU/1024/100; TIMSK2 = _BV(OCIE2A); /* signal user availability by turning on led 1 */ PORTC |= _BV(PC4); /* enable interrupts */ sei(); /* signal the user that the analyzer part has started by turning led 1 on */ PORTC |= _BV(PC3); while(1) { /* if a code has been received */ if (done) { receive();
uart_printf("\n");
/* turn off second and third led */ PORTD &= ~(_BV(PD3) | _BV(PD6)); /* wait until pin is high (no ir carrier is detected) */ while(!(PINC & _BV(PC3))); /* reset all global variables */ pos = 0; state = 1; done = 0; } if (uart_done == 1) {
send(uart_input); uart_len = 0; uart_done = 0; }
if (button_press) { /* first button toggles system mode */ uint8_t msg[7] = "Hallo!\r"; // SENDE if (button_press & (1 << 0)) { send(msg); } else if (button_press & (1 << 1)) { send(("Gruppe 1\r")); // 0b101 } else if (button_press & (1 << 2)) { send("1234567890\r"); // 0b10001 } else if (button_press & (1 << 3)) { send("XY\r"); }
button_press = 0;
}
}
}
</source>