Difference between revisions of "U23 2008-2/Gruppe1"

From C4 Wiki
Jump to: navigation, search
(LED - Blinken)
m (Reverted edits by Oxudocopaj (talk) to last revision by Hendi)
 
(13 intermediate revisions by 7 users not shown)
Line 1: Line 1:
 +
= Meta Data =
 
== Mitglieder ==
 
== Mitglieder ==
 
* Mark<br />
 
* Mark<br />
 
* Christoph<br />
 
* Christoph<br />
 
* Hendrik<br />
 
* Hendrik<br />
* ?<br />
+
* Robert<br />
  
== Aufgaben ==
+
= 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: Eine LED soll zum blinken gebracht werden.
+
// * Aufgabe: Alle LEDs sollen zum blinken gebracht werden.
// * Lösung: Alle LEDs werden zum blinken gebracht
+
// *  
 +
// * Task: All LED shall blink.
 
// *  
 
// *  
 
//****************************************************************************
 
//****************************************************************************
Line 23: Line 26:
 
int main(void)
 
int main(void)
 
{
 
{
unsigned int i;
+
/* 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 */
DDRC = (1<<DDC4);
+
/* Set ports PC4, PD3, PD6 and PD7 as outputs */
DDRD = (1<<DDD7)|(1<<DDD6)|(1<<DDD3);
+
DDRC = _BV(4);
/* Setze Ports PC4, PD3, PD6 und PD7 auf high */
+
DDRD = _BV(7)|_BV(6)|_BV(3);
PORTC = (1<<PC4);
 
PORTD = (1<<PD7)|(1<<PD6)|(1<<PD3);
 
  
 
while(1)
 
while(1)
 
{
 
{
for (i=0;i<50;i++) _delay_loop_2(0);
+
    /* _delay_ms() verzögert um 10 Millisekunden */
PORTC ^= _BV(PC4);
+
    /* 50 * 10ms = 500ms */
PORTD ^= _BV(PD7)|_BV(PD6)|_BV(PD3);
+
    /* _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 ===
 +
: 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 :) [[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

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. // * //****************************************************************************

  1. include <avr/io.h>
  2. 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. // * //****************************************************************************

  1. 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 // * //****************************************************************************

  1. include <avr/io.h>
  2. 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>

  1. include <util/delay.h>
  1. 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 # */ /* ################################### */


  1. include <avr/io.h>
  2. include <string.h>
  3. include <stdio.h>
  4. include <avr/pgmspace.h>
  5. include <util/delay.h>
  6. 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">

  1. include <avr/io.h>
  2. include <avr/interrupt.h>
  3. include <util/delay.h>
  4. include "uart.h"

/* constants */

  1. define MAX 160

/* 38khz: freq = F_CPU/(2*prescaler*frequency)

* 20mhz/(2*8*38khz) = ~33
* real frequency: 20mhz/(2*8*33) = ~37878Hz */
  1. 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>

  1. include <avr/interrupt.h>
  2. include <util/delay.h>
  3. include "uart.h"

/* constants */

  1. define MAX 160

/* 38khz: freq = F_CPU/(2*prescaler*frequency)

* 20mhz/(2*8*38khz) = ~33
* real frequency: 20mhz/(2*8*33) = ~37878Hz */
  1. 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>

  1. include <avr/interrupt.h>
  2. include <util/delay.h>
  3. include "uart.h"

/* constants */

  1. define MAX 160

/* 38khz: freq = F_CPU/(2*prescaler*frequency)

* 20mhz/(2*8*38khz) = ~33
* real frequency: 20mhz/(2*8*33) = ~37878Hz */
  1. 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>