Forum: Mikrocontroller und Digitale Elektronik At90Usb interrupt


von Markus H. (mh1977)


Lesenswert?

Hallo,

ich probiere derzeit einen Messwert vom ADC über USB an den PC zu 
bringen. Es klappt auch so weit, doch irgendwie läßt sich der Interrupt 
nicht aktivieren, so dass ich nie abwarten kann, bis die Messung fertig 
ist.
Ich glaube das ist das Problem, weil ich immer zweimal auf den Knopf 
drücken muss am PC bis ich die richtige Zahl habe.
In main() mache ich eine dummy-Messung:
//für ADC
  //SREG |= (1<<I);
  sei();

  ADMUX |=(1<<REFS0)|(1<<REFS1);
  ADCSRA |= (1<<ADEN)|(0<<ADATE)|(1<<ADIE);//<<--hier ist das Problem

  ADCSRB |=(0<<ADTS0)|(0<<ADTS1)|(0<<ADTS2);
  DIDR0 |=(1<<ADC0D);
  ADMUX |=(0<<MUX0)|(0<<MUX1)|(0<<MUX2)|(0<<MUX3)|(0<<MUX4);

  ADCSRA |=(1<<ADSC);

  while (ADCSRA & (1<<ADIF)){}
  uint8_t LB;
  uint8_t HB;
  LB=ADCL;
  HB=ADCH;

ich kann meinen avr nur an usb anmelden, wenn ich (1<<ADIE) weglasse.
Ich brauch es aber für die Schleife...

Wo ist denn das Problem? SREG|=(1<<I) mag er auch nicht.

danke

Markus

von STK500-Besitzer (Gast)


Lesenswert?

Stell compilerbaren Code hier rein, oder dir kann nur Olga helfen...

von STK500-Besitzer (Gast)


Lesenswert?

>  while (ADCSRA & (1<<ADIF)){}

Entscheide dich: Entweder per Interrupt auf den ADC zugreifen (mit der 
dazugehörigen ISR) oder per Polling.

von Markus H. (mh1977)


Lesenswert?

Ok, Quellcode: Es ist die Firmware von Salewski... In Main() mache ich 
eine Dummymessung, doch wenn ich ADIE einschalte...dann geht nichts mehr 
mit USB. Den zweiten Kommentar habe ich nicht ganz verstanden... 
entscheiden? Für was?

int
main(void)
{
  //für ADC
  //SREG |= (1<<I);
  sei();

  ADMUX |=(1<<REFS0)|(1<<REFS1);
  ADCSRA |= (1<<ADEN)|(0<<ADATE)|(1<<ADIE);

  ADCSRB |=(0<<ADTS0)|(0<<ADTS1)|(0<<ADTS2);
  DIDR0 |=(1<<ADC0D);
  ADMUX |=(0<<MUX0)|(0<<MUX1)|(0<<MUX2)|(0<<MUX3)|(0<<MUX4);

  ADCSRA |=(1<<ADSC);

  //while (ADCSRA & (1<<ADIF)){}
  uint8_t LB;
  uint8_t HB;
  LB=ADCL;
  HB=ADCH;
  //ADCSRA |=(1<<ADSC);

  cli();
  CLKPR = (1<<7);
  CLKPR = 0; // clock prescaler == 0, so we have 16 MHz mpu frequency 
with our 16 MHz crystal
  USART_Init();
  USART_WriteString("\r\n------------------------------------------------- 
---------\r\n");
  UsbDevLaunchDevice(false);
  // UsbDevWaitStartupFinished(); // no reason to wait
  blinkforever();
  return 0;
}

UsbDevFillEP1FIFO(void)
{
  if UsbDevTransmitterReady()
  {
   uint8_t LB;
   uint8_t HB;
   ADCSRA |=(1<<ADSC);
   while (ADCSRA & (1<<ADIF)){}
   LB=ADCL;
   HB=ADCH;

    UsbDevClearTransmitterReady();
    UsbDevClearNAK_ResponseInBit();
    //UsbDevSelectEndpoint(1);
    UsbDevWriteByte(LB);
    UsbDevWriteByte(HB);
    UsbDevSendInData();
  }
}

von STK500-Besitzer (Gast)


Lesenswert?

Das Bit ADIE gibt den ADC-Interrupt frei. Dadurch springt der Controller 
beim Auftreten des auslösenden Ereignisses in die ISR. Eine Abfrage, ob 
das ADIF-Flag gesetzt wurde, kann nichts bringen, da zwischenzeitlich 
die ISR angesprungen wurde. Die fehlt aber scheinbar in deinem Programm.
Eine fehlende ISR bringt den Effekt, dass der Controller immer versucht, 
in die ISR zu springen, da das ADIF-Bit nicht zurückgestzt wurde.
Weiterhin sorgt das Nichtvorhandensein der ISR dazu, dass der Controller 
irgendwohin springt (Dummy-ISR?); zumindest erzeugt der GCC AFIAK solche 
Dummy-ISRs aus welchen Gründen auch immer.
Das Datenblatt deines Controllers beschreibt, wie man ADC-Interrupts 
behandelt...

von Michael U. (amiga)


Lesenswert?

Hallo,

wenn Du den Interrupt für den ADC freigibst, muß es natürlich auch die 
passenden Interruptroutine geben, in dieser wird dann der ADC ausgelesen 
und entsprechend reagiert.
Außer wird automatisch das Interruptflag des ADC gelöscht.

Wenn Du per Polling abfragst, wie hier, dann darf der ADC-Interrupt 
natürlich nicht freigegeben werden, es wird einfach gewartet, bis der 
ADC das Bit ADSC im Register ADCSRA wieder auf 0 setzt, dann ist er 
fertig.

Darauf hat STK500-Besitzer (Gast) hingewiesen.

Gruß aus Berlin
Michael

von Stefan Salewski (Gast)


Lesenswert?

>Ok, Quellcode: Es ist die Firmware von Salewski...

Wie soll das denn einer ahnen...
Mein Beispiel hat den ADC in der ISR ausgelesen, soweit ich mich 
erinnere. Wenn Du keine ISR verwendest, musst Du den ADC Code sicher 
irgendwie anpassen, wie die anderen oben schon schrieben.

von Markus H. (mh1977)


Lesenswert?

Danke...

das mit den ISR wußte ich nicht. Ich könnte dann auch eine 
while-Schleife schreiben, die wartet bis ADSC auf 0 ist...oder?

Ich denke damit komme ich weiter

Markus

von Stefan Salewski (Gast)


Lesenswert?

>Autor: Markus Haege (mh1977)
>Datum: 17.07.2009 18:51

>Danke...

>das mit den ISR wußte ich nicht. Ich könnte dann auch eine
>while-Schleife schreiben, die wartet bis ADSC auf 0 ist...oder?

Ohne ISR ist einfacher. Ich kann Dir momentan dazu nicht viel sagen, da 
ich mich in den letzten 18 Monaten nicht mit der Firmware beschäftigt 
habe. Sollte aber nicht so schwierig sein. Ich würde zunächst mal 
versuchen ohne ISR irgendwelche Datensätze über USB zu schicken. Wenn 
das geht machst Du die ADC-Abfrage ohne ISR und schickst dessen Daten 
dann Über den USB-Port. ADC und USB haben ja nicht direkt etwas 
miteinander zu tun, das war ja nur ein Beispiel. Und zum ADC findest du 
genug, auch hier im Forum.

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.