Forum: Mikrocontroller und Digitale Elektronik duplicate case value


von Valentin S. (jonava)


Lesenswert?

Hallo ich bekomme folgenden Fehler bei diesem Code:

error: duplicate case value
für die Fälle mit PB3, PB4 und PB5.

ISR(INT0_vect) {
  uint8_t buttons = ((~PIND) & (_BV(PD0) | _BV(PD1) | _BV(PD3) | 
_BV(PD4) | _BV(PD5))) | ((~PINB) & (_BV(PB7) | _BV(PB6) |_BV(PB5) 
|_BV(PB4) |_BV(PB3))) ;
  uint8_t cmd = 0;

  switch(buttons) {
  case _BV(PD0):
    cmd = RC5_CMD_VOLUME_INC;
    break;
  case _BV(PD1):
    cmd = RC5_CMD_VOLUME_DEC;
    break;
  case _BV(PD3):
    cmd = RC5_CMD_MUTE;
    break;
  case _BV(PD4):
    cmd = RC5_CMD_INPUT_01 ;
    break;
  case _BV(PD5):
    cmd = RC5_CMD_INPUT_02;
    break;
   case _BV(PB3):
    cmd = RC5_CMD_INPUT_03;
    break;
  case _BV(PB4):
    cmd = RC5_CMD_INPUT_04;
    break;
  case _BV(PB5):
    cmd = RC5_CMD_INPUT_05;
    break;
  case _BV(PB6):
    cmd = RC5_CMD_INPUT_06;
    break;
  case _BV(PB7):
    cmd = RC5_CMD_INPUT_07;
    break;

  }

Kann mir jemand sagen warum ich da eine Fehler bekomme?

Vielen Dank im Voraus.

Viele Grüße
Jonanova

von Anja (Gast)


Lesenswert?

Dann schau dir mal die Definitionen für PB3, PB4 und PB5 an.
Du wirst mit staunen feststellen daß diese identisch mit PD3, PD4 und 
PD5 sind.

von Valentin S. (jonava)


Lesenswert?

Sorry,
aber ich kann dir nicht folgen.

Ich möchte eigentlich PD0 bis PD5 und PB3 bis PB7 als eingänge 
definieren.

was genau mache ich falsch?

Vielen Dank

jonanova

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

da musst du dir anschauen, welchen Wert _BV(PB3) und alle anderen 
enthalten, ich sehe das an deinem Programmstück nicht (Listing?). Es ist 
aber ziemlich sicher, dass der Compiler recht hat und gleiche Werte 
dabei sind. Er hat nämlich fast immer recht.

Gruss Reinhard

von Valentin S. (jonava)


Lesenswert?

DAs ist der Komplette Code:

/*
 * $Id: rc.c,v 1.2 2006-10-19 15:28:04 andreas Exp $
 */

/*
 * Copyright (c) 2006 Andreas Schroeder <andreas@a-netz.de>
 *
 * Implement functions of an infrared remote control and RC5 protocol 
with an
 * Atmel ATTiny 2313.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
USA
 *
 */

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "rc5codes.h"

/**
 * Device code to send
 */
#define RC5_DEVICE_CODE       RC5_DEV_PREAMP1

/**
 * Maximum bit count before transmission is finished. Minimum (as
 * protocol standard says) is 64. Higher values yield a lower repetition 
rate.
 */
#define MAX_BITCOUNT 64

#define RC5_TEMPLATE (0x3000 | (RC5_DEVICE_CODE << 6))

volatile uint16_t rc5data = 0;

volatile uint8_t bitcounter = MAX_BITCOUNT;
volatile uint8_t halfbitcounter;

// modulation square wave generation
// compare output mode: toggle OC0A on compare match
// if COM0Ax are all unset, the waveform generation is disabled and
// the normal PORTx value is seen on the OC0A pin.
#define ENABLE_MODULATION (TCCR0A |= _BV(COM0A0))
#define DISABLE_MODULATION (TCCR0A &= ~_BV(COM0A0))

// activate half bit timer
#define ENABLE_BIT_TIMER (TCCR1B |= _BV(CS10))
#define DISABLE_BIT_TIMER (TCCR1B &= ~_BV(CS10))

// button control
// MCUCR is setup by default to trigger INT0 on low level, so only 
external
// interrupt needs to be turned on or off
#define ENABLE_BUTTONS (GIMSK |= _BV(INT0))
#define DISABLE_BUTTONS (GIMSK &= ~_BV(INT0))


ISR(INT0_vect) {
  uint8_t buttons = ((~PIND) & (_BV(PD0) | _BV(PD1) | _BV(PD3) | 
_BV(PD4) | _BV(PD5))) | ((~PINB) & (_BV(PB7) | _BV(PB6) |_BV(PB5) 
|_BV(PB4) |_BV(PB3))) ;
  uint8_t cmd = 0;

  switch(buttons) {
  case _BV(PD0):
    cmd = RC5_CMD_VOLUME_INC;
    break;
  case _BV(PD1):
    cmd = RC5_CMD_VOLUME_DEC;
    break;
  case _BV(PD3):
    cmd = RC5_CMD_MUTE;
    break;
  case _BV(PD4):
    cmd = RC5_CMD_INPUT_01 ;
    break;
  case _BV(PD5):
    cmd = RC5_CMD_INPUT_02;
    break;
   case _BV(PB3):
    cmd = RC5_CMD_INPUT_03;
    break;
  case _BV(PB4):
    cmd = RC5_CMD_INPUT_04;
    break;
  case _BV(PB5):
    cmd = RC5_CMD_INPUT_05;
    break;
  case _BV(PB6):
    cmd = RC5_CMD_INPUT_06;
    break;
  case _BV(PB7):
    cmd = RC5_CMD_INPUT_07;
    break;

  }

  // assemble rc5 packet from TEMPLATE (2 start bits and device 
identifier)
  // and 6 command bits
  rc5data = RC5_TEMPLATE | (cmd & 0x3f);

  // activate timer 1 (half bit timer) to write out bitstream
  bitcounter = 0;
  halfbitcounter = 0;
  sleep_disable();
  DISABLE_BUTTONS;
  ENABLE_BIT_TIMER;
}

ISR(TIMER1_COMPA_vect) {
  uint8_t bit = ((rc5data & 0x2000) >> 13);
  uint8_t half = (bit ^ ((halfbitcounter == 0) ? 1 : 0));

  // transmit 14 bit rc5 packet
  if(half && bitcounter < 14) {
    ENABLE_MODULATION;
  } else {
    DISABLE_MODULATION;
  }

  if(bitcounter >= MAX_BITCOUNT) {
    // we can now prepare for the next key press
    ENABLE_BUTTONS;
    DISABLE_BIT_TIMER;
    sleep_enable();
  } else if(bitcounter == 14) {
    // rc5 packet has been transmitted
    DISABLE_MODULATION;
  }

  if(halfbitcounter == 0) {
    halfbitcounter++;
  } else {
    halfbitcounter = 0;
    bitcounter++;
    rc5data <<= 1; // shift left rc5 data
  }
}

int main(void) {
  // setup rc oscillator clock divider to div 1
  // (=> 8MHz with internal RC oscollator)
  CLKPR = _BV(CLKPCE); // enable clock prescale change
  CLKPR = 0; // div1 => 8 MHz

  // setup waveform generation to 36kHz on timer 0
  TCCR0A |= _BV(WGM01); // Clear timer on compare match
  TCCR0B |= _BV(CS00); // timer source is system clock
  //OCR0A = 107; // 36kHz @ 8 (7,77) MHz
  // verify correct frequency! The internal oscillator is not really 
accurate
  OCR0A = 113;

  //OCR0A = 27; // 36kHz @ 1 MHz

  DDRB |= _BV(PB2); // port b.2 as output
  PORTB &= ~_BV(PB2); // pb2 is lo

  // setup half-bit clock (555Hz) on timer1
  TCCR1A = 0;
  TCCR1B = _BV(WGM12); // Clear timer on compare match
  // verify correct frequency! The internal oscillator is not really 
accurate
  OCR1A = 7350; // ~ 889us @ 8MHz

  TIMSK |= _BV(OCIE1A); // output compare interrupt enable 1a

  // button port is input, pullup enabled
  // buttons on PD0,1,3,4,5, int0 on pd2
  PORTD = _BV(PD0) | _BV(PD1) | _BV(PD2) | _BV(PD3) | _BV(PD4) | 
_BV(PD5);
  PORTB = _BV(PB3) | _BV(PB4) | _BV(PB5) | _BV(PB6) | _BV(PB7);

  // save energy, disable analog comaprator
  ACSR |= _BV(ACD);

  // setup external interrupt
  ENABLE_BUTTONS;

  sei();
  // set sleep mode to power down mode (i.e. all functions except 
external
  // level (!) interrupts are disabled. Tiny2313 needs ~ 0.5uA then.
  set_sleep_mode( _BV(SM0) | _BV(SM1) );

//   enable sleep mode
  sleep_enable();

  for(;;) {
    // sleep and wait for external interrupt (from button press)
    sleep_cpu();
  }

}

Vielen Dank.

Gruß
jonanova

von Karl H. (kbuchegg)


Lesenswert?

PD3 ist ein Makro
#define PD3   3

PB3 ist ein Makro
#define PB3   3


und damit haben PD3 und PB3 denselben Wert.
Du kannst anhand PD3 bzw. PB3 nicht mehr unterscheiden, von welchem Port
der Wert gekommen ist.
Besser wäre es gewesen, da nicht PD3 bzw. PB3 einzuführen, sondern sowas
wie BIT_3. Dann wäre das klarer.

von Karl H. (kbuchegg)


Lesenswert?

1
  uint8_t buttons = ((~PIND) & (_BV(PD0) | _BV(PD1) | _BV(PD3) | _BV(PD4) | _BV(PD5))) |
2
                    ((~PINB) & (_BV(PB7) | _BV(PB6) |_BV(PB5) |_BV(PB4) |_BV(PB3))) ;

Du musst Zauberkünstler sein:
10 Bits in nur 8 Bit Speicherfläche unterbringen. Das macht dir so 
schnell keiner nach. Tatsächlich ist in buttons aber das Bit 3, Bit 4 
und Bit 5 gesetzt, wenn das jeweilige Bit in mindetsens entweder PIND 
oder PINB gelöscht ist.

von Peter D. (peda)


Lesenswert?

Das Switch ist hier eh der falsche Ansatz.
Jede Taste ist doch ein Pin, also mußt Du nur jeweils einen Pin prüfen.
Dadurch wird dann auch der Code schneller, da der AVR Pintestbefehle 
hat.
1
if( PINu & 1<<Puv ) ...
2
if( PINx & 1<<Pxy ) ...
3
...


Peter

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

_BV ist ein Bit-Value, aber für verschiedene Ports kommt das gleiche 
raus, also ist _BV(PD3) = _BV(PB3). Das ist was anderes als bei 
8051-Prozessoren, wo jedes Bit in den SFRs einen eigenen Wert hat, der 
geht dann aber von 0..255 und ist nur mit Bit-Befehlen benutzbar. _BV 
bildet eine Bitmaske: 1,2,4,8,16 usw.

Könnte mich auch täuschen, aber am schnellsten siehst du was läuft, wenn 
du prüfst, welchen Wert PB3 und PD3 haben. Das müsste in io.h stehen.

Gruss Reinhard

von Reinhard Kern (Gast)


Lesenswert?

Hallo,

es sollte inzwischen klar sein, warum der Fehler kommt, aber dein Ansatz 
hat noch ein anderes Problem (ausser dem, dass du einen grösseren Vektor 
als nur 8 bit definieren müsstest): was passiert, wenn jemand 2 Buttons 
drückt? Ist das so beabsichtigt?

Gruss Reinhard

von Valentin S. (jonava)


Lesenswert?

Hallo,

vielen Dank erstmal an alle.
Ich wusste leider nicht wofür _BV stand, aber Dank eurer Hilfe bin ich 
jetzt klüger.
Ich habe es jetzt über die If Schleife nach dem Vorschlag von Peter 
gelöst.

@Reinhard: Der Code ist für eine Ir Fernbedienung. Wenn dort jemand auch 
zwei Tasten gleichzeitig drücken würde, dann könnte der Attiny eh nur 
einen Code generieren. Das heißt es wäre aber auch nicht so schlimm, 
wenn er gar nichts machen würde.

Vielen Dank für eure Hilfe.

Viele Grüße
jonanova

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.