Forum: Mikrocontroller und Digitale Elektronik Volumenmessung mit ATmega8, einige wichtige Fragen


von Daniel L. (dannynrw)


Lesenswert?

Hallo Leute,
bin neu hier und möchte mit dem AVR-Testboard MK2 (Atmega8) ne 
Volumenmessung testweise aufbauen.
Um die Messung zu starten, müssen zwei Bedingungen erfüllt sein, sprich 
die zwei Taster müssen gedrückt sein (1-Signal).
Außerdem werden die Ergebnisse über UART ausgegeben.
Die Schleife sieht hier folgendermaßen aus.
while (abfrage1 == 0) {;}
while (abfrage2 == 0) {;}
//auszuführende Anweisungen
.
.

Hier wird doch nichts anderes gemacht als das bei einem anstehenden
0-Signal NICHTS gemacht wird oder?
Jetzt habe ich teilweise das Problem, daß die Messung auch schon mal 
gestartet wird, wenn nur EIN Taster betätigt wird. Man sieht das daran, 
daß die Ergebnisse dann auch schon auf dem Bildschirm angezeigt werden. 
Kann das damit zusammenhängen, daß die Taster einfach prellen?
Sonnige Grüße
Daniel

von Peter (Gast)


Lesenswert?

du machst den vergleich ja auch nacheinander, aber die paar µC sollte 
dabei egal sein. Ich kann mir nicht vorstellen das das Problem vom 
prellen kommt.

Wenn beide Taster an einem Port hängen kannst du es wiklich gleichzeitig 
vergleichen.

Beispiel für bit0 und bit1
while ( (port & 0b00000011) != 0b00000011 ) {};

von Martin (Gast)


Lesenswert?

In Zeile 43 hast du einen typischen Fehler, den du korrigieren solltest. 
In deinem Schaltplan scheint es auch ein Problem bei IC1 zugeben.

von R. M. (rmax)


Lesenswert?

Daniel Lo schrieb:

> Um die Messung zu starten, müssen zwei Bedingungen erfüllt sein, sprich
> die zwei Taster müssen gedrückt sein (1-Signal).

Wenn die Startbedingung ist, daß beide Taster gleichzeitig gedrückt 
sein müssen, dann mußt Du die beiden auch in einer Schleife abfragen, 
nicht hintereinander.

> while (abfrage1 == 0) {;}
> while (abfrage2 == 0) {;}

Dein Programm bleibt in der ersten Zeile so lange hängen, bis abfrage1 
erfüllt ist, dann in der zweiten Zeile, bis abfrag2 erfüllt ist, egal 
welchen Zustand zu dem Zeitpunkt abfrage1 hat. Dadurch wird die Messung 
nicht nur beim gleichzeitigen Drücken beider Taster gestartet, sondern 
auch, wenn zuerst Taster 1 gedrückt und wieder losgelassen und dann 
Taster 2 gedrückt wird.

Richtig wäre:
1
while (abfrage1 == 0 || abfrage2 == 0);

Diese Schleife wird solange wiederholt, bis beide Abfragen gleichzeitig 
einen Wert ungleich 0 liefern. Die Geschweiften Klammern kannst Du 
übrigens weglassen, wenn sie sowieso leer sind. Wie Peter schrieb, 
lassen sich die beiden Tests zusammenfassen, wenn beide Taster am 
gleichen Port hängen.

> Kann das damit zusammenhängen, daß die Taster einfach prellen?

Dein eigentliches Problem lag wie gesagt nicht am Prellen, aber eine 
Entprellung kann zusätzlich noch nötig sein, insbesondere falls die Zeit 
für eine Messung unterhalb der Prellzeit Deiner Tasten liegt.

Falls es, wie ich annehme, um Deinen ganzen Code herum eine 
Endlosschleife gibt, solltest Du außerdem nach der Messung noch warten 
bis die Tasten wieder losgelassen werden, sonst ist ja die 
Startbedingung am Ende immer noch erfüllt und es wird sofort die nächste 
Messung gestartet.

von Peter (Gast)


Lesenswert?

R. Max schrieb:
> Richtig wäre:
> while (abfrage1 == 0 || abfrage2 == 0);
> Diese Schleife wird solange wiederholt, bis beide Abfragen gleichzeitig
> einen Wert ungleich 0 liefern. Die Geschweiften Klammern kannst Du
> übrigens weglassen, wenn sie sowieso leer sind. Wie Peter schrieb,
> lassen sich die beiden Tests zusammenfassen, wenn beide Taster am
> gleichen Port hängen.

aber nur weil beide bedingungen in einer Zeile stehen werden sie immer 
noch nach einander verglichen. Das ist also nichts mit gleichzeitig. Von 
der Sache ist das auch nichts anderes als wie oben nur etwas 
üblicher/schöner geschrieben. Wird aber das Problem nicht lösen

von Daniel L. (dannynrw)


Lesenswert?

So, habe festgestellt, daß die Messung schon gestartet wird, wenn nur 
Abfrage2 (in diesem Fall mess_ok) erfüllt ist, irgendwas läuft da 
schief, am Programm selbst kann das doch nicht liegen oder? Hier mal das 
komplette Programm, ist übrigens nicht von mir geschrieben. Ich bin nur 
dabei zu versuchen, es zu verstehen.
Nochmal zum Verständnis: Es handelt sich um eine Volumenmessung, die 
folgendermaßen funktionieren soll. Es gibt ein Laufband und die 
Volumenmessung des Produktes wird durch eine Lichtschranke angestoßen, 
zusätzlich soll die Bedingung Band läuft (Variable Band_ok) erfüllt 
sein.
An der Seite sind zwei Sensoren angeschlossen und über dem Band selbst 
nochmal ein Sensor. Diese messen dann das Volumen (simuliert durch 
Potentiometer). Die Länge wird über die Bandgeschwindigkeit und die 
Lichtschranke ermittelt.


//----------------------------------------------------------------------
// Titel     : C Grundgerüst für das myAVR-Board
//----------------------------------------------------------------------
// Funktion  : ...
// Schaltung : ...
//----------------------------------------------------------------------
// Prozessor : Atmega8...
// Takt     : 3.6864 MHz
// Sprache   : C
// Datum     : 8.03.2010...
// Version   : ...
// Autor     : ...
//----------------------------------------------------------------------
#define   F_CPU 3686400  // Taktferquenz des myAVR-Boards
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
#include  <inttypes.h>  //Interrupt- Typen
#include  <avr\interrupt.h> //Defs fuer Interrupts
#define    volgrenzw  400   //Volumengrenzert
#define    speed 5        //5 mm bei 10 ms
//----------------------------------------------------------------------
//      globale Variable
//----------------------------------------------------------------------

int  adc_wert = 0;      //Variable fuer die ADC-Messung
long volume  = 0;            //Var zur Berechnung des Volumens
volatile int cnt_ms = 0;  //Zähler für Zeitmessung (10ms)
volatile int band_ok = 0;  //Band läuft
volatile int mess_ok = 0;  //Messung aktiv (Gegenstand auf Band)
int sensor_buffer = 0 ;    // Messwertspeicher
char ergebnis[7];      //5 Stellen + Kennungt + 0 für Ende

//---------------------------------------------------------------------- 
----
//      Initialisiere Uart- Schnittstelle
//---------------------------------------------------------------------- 
----
void usartinit (void)
{
    /* Das Frameformat Start, 8Datenbits u. 1 Stoppbit ist nach Reset
       bereits im USART eingestellt */
  UBRRL = 23;        //9600  Baud
  UCSRB =0x08;       //Sender enable
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//      Gebe Zeichen über Uart aus
//---------------------------------------------------------------------- 
----
void usartputc(char data )
{
  while (!(UCSRA&32));     //warte bis usart leer
  UDR=data;        //sende zeichen
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//      Ausgabe Buffer über Usart
//---------------------------------------------------------------------- 
----
void print(char buffer[])  //Ausgabe Zeichenpuffer
{
  for (int i=0;buffer[i] != 0 ;i++ )
    usartputc(buffer[i]);
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//      Umwandlung Int nach ASCII String
//---------------------------------------------------------------------- 
----
void int_to_string(int x,char s[],char ken)
{
  int i      ;        //Index,lokale Variable
  for (i=0;i<6;i++ )        //Vorbesetzung mit Leerzeichen
    s[i]= ' ';
  s[i] = 0;            //kennzeichne Ende String
  s[0] = ken;                     //Ausgabe Kennung
  i=5;              //Umsetzung von bin nach dez
  do
  {
    s[i--] = x % 10 + '0';    //Modulus 10 der Rest nach ASCII
  }
  while (( x /= 10) > 0);      //Wert ist Wert durch 10
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//           Ausgabe CR und LF an das Terminal
//---------------------------------------------------------------------- 
----
void cr_lf()    // Ausgabe CR und LF an das Terminal
{
  usartputc(0x0d);  //Ausgabe Wagenrücklaufzeichen
  usartputc(0x0a);  //Ausgabe Zeilenwechselzeichen
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
--
//      Längenmessung über eine Laufzeitmessung (v=s/t)
//----------------------------------------------------------------------
ISR (TIMER0_OVF_vect)
{
  TCNT0 = (255-144) ;   // Wert für 10 ms bei Vorteiler 256
  if (band_ok && mess_ok)   //Messung aktiv und gültig
  ++cnt_ms;
}

//----------------------------------------------------------------------
//      ISR INT0: Band läuft; von externer Steuerung
//----------------------------------------------------------------------
ISR (INT0_vect)
{
  if (PIND & 0b00000100)  //Abfrage PD2 (Pin 4)auf ein
    band_ok = 1;      //Band läuft
  else
    band_ok = 0;            //Band ist aus
}

//----------------------------------------------------------------------
//      ISR INT1: In Messung; von Reflexionslichtschranke
//----------------------------------------------------------------------
ISR (INT1_vect)
{
  if (PIND & 0b00001000)  //Abfrage PD3 (Pin 5)auf ein
    mess_ok = 1;      //Objekt in Lichtschranke
  else
    mess_ok = 0;            //Objekt ist nicht in Lichtschrank
}

//----------------------------------------------------------------------
//      ADC Messung mit 10 Bit
//----------------------------------------------------------------------

void adc_mess(void)
{
 sbi(ADCSRA,6);          //starte Messung
 while (ADCSRA & 0b01000000)//Messung fertig ?
 {
  ;
 }
 sbi (ADCSRA,4);      //lösche ADIF Bit
 adc_wert = ADC;      //lese Messwert
 adc_wert &= 0x3ff;      //auf 10 Bit begrenzen
}

//----------------------------------------------------------------------
//      Init- Funktion
//----------------------------------------------------------------------
void init (void)
{
usartinit();
TCNT0 =(255-144);      //Wert für 10ms bei Vort. 256
TCCR0 = 0x04  ;      //Vorteiler 256 für Timer 0
TIMSK = 0x01  ;      //Freigabe Interrupt Timer 0
              //DDRC u. Dsind nach Reset
              //Eingänge
PORTD |=  0b00001100;    //Pul up auf Bit 2 u. 3
DDRB  |=  0b00000011;    //Bit 0 u. 1von Port B sind Ausgänge
PORTB  &=   0b11111100;     //Port B Bit 0 u. 1 auf 0
GICR   =    0b11000000;    //Freigabe ext.INT0 u. 1
MCUCR  =  0b00000101;    //Interrupt auf jeder Flanke
ADMUX  =    0;        //externe Ref., Mux auf Kanal 0
ADCSRA =  0b10010101;      //ADC Einzelmessung,Vorteiler ./.32
}



main ()            // Hauptprogramm, startet bei Power ON und Reset
{
  int b=0,b1=0,b2=0,h=0,l=0;  //interne Variable
  init ()  ;          //Initialisierung
  sei  ()  ;          //Hauptfreigabe Interrupt
  for (;;)
  {
   while (band_ok == 0){;}  //warte auf Band läuft
   while (mess_ok == 0){;}  //warte auf Reflexionslichtschranke
   ADMUX = 0;          //starte mit Sensor Breite 1 (ADMUX=0 --> PC0, 
siehe Pinbelegung ATmega8)
   adc_mess();        //Messung Breite 1
   b1 = adc_wert;        //Breite 1
   sensor_buffer = b1;
   int_to_string(sensor_buffer,ergebnis,'L'); //Umwandlung Ergebnis von 
int nach ASCII string
   print(ergebnis); //Ausgabe Ergebnis
   cr_lf()       ; //Ausgabe CR und LF an das Terminal
   ADMUX = 1;          //starte mit Sensor Breite 2 (ADMUX=1 --> PC1, 
siehe Pinbelegung ATmega8)
   adc_mess();        //Messung Breite 2
   b2 = adc_wert;        //Breite 2
   sensor_buffer = b2;
   int_to_string(sensor_buffer,ergebnis,'R'); //Umwandlung Ergebnis von 
int nach ASCII string
   print(ergebnis); //Ausgabe Ergebnis
   cr_lf()       ; //Ausgabe CR und LF an das Terminal
   ADMUX = 2;          //starte mit Sensor Höhe (ADMUX=2 --> PC2, siehe 
Pinbelegung ATmega8)
   adc_mess();        //Messung Höhe
   h = adc_wert;        //Höhe
   sensor_buffer = h;
   int_to_string(sensor_buffer,ergebnis,'H'); //Umwandlung Ergebnis von 
int nach ASCII string
   print(ergebnis); //Ausgabe Ergebnis
   cr_lf()       ; //Ausgabe CR und LF an das Terminal
   while (mess_ok == 1){;}  //warte auf Ende Längenmessung
   l = cnt_ms ;               //Zeit in 10 ms TICS
   l *= speed ;               //Länge in mm
   if (l<=0){l=1;}      //Mindestlänge 1mm
   cnt_ms = 0;        //neu stellen
   b = 1200 -  (b1 + b2);    //Näherungswert für Breite in mm
   h = 2500 -(h*244/100);    //Berechne Höhe in mm
   if (h < 0){h = 1;}      //nicht negativ
   if (h>2000) {h=2000;}    //nicht höher als 2000mm
   b = 200;          //Test
   h = 1000;          //Test
   l = 1999;          //Test vol < 400
//   l = 2000;                  //Test für vol >=400
   volume = (long)b;       //Breite
   volume = volume *(long)h;  //Breite * Höhe
   volume = volume * (long)l; //Volumen
   volume = volume /1000000;  //Umrechnung in dm³
   if (volume < volgrenzw)
   {
    PORTB &= 0b11111101;     // Volumen groß aus
    PORTB |= 0b00000001;     // Volumen klein ein (PB0)
   }
   else
    {
    PORTB &= 0b11111110;     // Volumen klein aus
    PORTB |= 0b00000010;     // Volumen groß ein (PB1)
   }
  }
}
//----------------------------------------------------------------------

von R. M. (rmax)


Lesenswert?

Peter schrieb:

> aber nur weil beide bedingungen in einer Zeile stehen werden sie immer
> noch nach einander verglichen.

Der Punkt ist nicht, daß die Bedingungen in einer Zeile stehen, sondern 
daß sie in einer Schleife stehen. Meine Variante "merkt" sich nicht, daß 
Taste 1 schonmal gedrückt wurde und läßt sich dann alleine mit Taste 2 
starten. Die paar Taktzyklen, die zwischen den beiden Vergleichen 
vergehen, sind für manuell betätigte Taster vernachlässigbar.

von R. M. (rmax)


Lesenswert?

Daniel Lo schrieb:

> Es gibt ein Laufband und die Volumenmessung des Produktes wird durch eine
> Lichtschranke angestoßen, zusätzlich soll die Bedingung Band läuft (Variable
> Band_ok) erfüllt sein.

Dann mach es so, wie ich geschrieben habe. Dein Code stellt derzeit nur 
sicher, daß das Band zu Beginn des Hauptschleifendurchlaufs läuft, aber 
er merkt nicht, wenn es vor dem Ansprechen der Lichtschranke wieder 
abgeschaltet wird.

von Rolf Magnus (Gast)


Lesenswert?

Daniel Lo schrieb:
> Hallo Leute,
> bin neu hier und möchte mit dem AVR-Testboard MK2 (Atmega8) ne
> Volumenmessung testweise aufbauen.
> Um die Messung zu starten, müssen zwei Bedingungen erfüllt sein, sprich
> die zwei Taster müssen gedrückt sein (1-Signal).
> Außerdem werden die Ergebnisse über UART ausgegeben.
> Die Schleife sieht hier folgendermaßen aus.
> while (abfrage1 == 0) {;}
> while (abfrage2 == 0) {;}
> //auszuführende Anweisungen
> .
> .
>
> Hier wird doch nichts anderes gemacht als das bei einem anstehenden
> 0-Signal NICHTS gemacht wird oder?

Ja.

> Jetzt habe ich teilweise das Problem, daß die Messung auch schon mal
> gestartet wird, wenn nur EIN Taster betätigt wird.

Nachdem du vorher den anderen einzeln betätigt hast? Du wartest nämlich 
zuerst, bis abfrage1 ungleich 0 ist, ohne dich dabei für abfrage2 zu 
interessieren. Sobald das eingetreten ist, springst du zur zweiten 
Warteschleife und wartest dort nun, bis abfrage2 ungleich 0 ist, 
unabhängig davon, wie inzwischen der Wert von abfrage1 ist.

von Daniel L. (dannynrw)


Lesenswert?

Danke, das war ein wichtiger Hinweis. Wenn ich das ganze zum ersten Mal 
ablaufen lasse, dann muß ich tatsächlich zuerst Taste 1 drücken.
Werde das mit der vorgeschlagenen Schleife direkt mal ausprobieren.
Mal was anderes. Als Messergebnisse werden ja momentan die Werte von 
Sensor Links ('L'), Sensor Rechts ('R') und Sensor oben ('H') 
ausgegeben.
Jetzt habe ich zusätzlich mal die Länge anzeigen wollen, was auch 
scheinbar klappt. Nur egal wie lange ich die Taste gedrückt halte, es 
kommen immer andere (sprich unplausible) Ergebnisse heraus, woran kann 
das liegen? Könnte es in diesem Fall an evtl. prellenden Tastern liegen?
Hier nochmal das geänderte Programm, habe die neu eingefügten Zeilen
vorne mit einem Pfeil (-->) gekennzeichnet, damit man die Änderungen 
leichter sieht.

//----------------------------------------------------------------------
// Titel     : C Grundgerüst für das myAVR-Board
//----------------------------------------------------------------------
// Funktion  : ...
// Schaltung : ...
//----------------------------------------------------------------------
// Prozessor : Atmega8...
// Takt     : 3.6864 MHz
// Sprache   : C
// Datum     : 8.03.2010...
// Version   : ...
// Autor     : ...
//----------------------------------------------------------------------
#define   F_CPU 3686400  // Taktferquenz des myAVR-Boards
#include  <avr\io.h>    // AVR Register und Konstantendefinitionen
#include  <inttypes.h>  //Interrupt- Typen
#include  <avr\interrupt.h> //Defs fuer Interrupts
// #include    <stdio.h>
#define    volgrenzw  400   //Volumengrenzert
#define    speed 5        //5 mm bei 10 ms
//----------------------------------------------------------------------
//      globale Variable
//----------------------------------------------------------------------

int  adc_wert = 0;      //Variable fuer die ADC-Messung
long volume  = 0;            //Var zur Berechnung des Volumens
volatile int cnt_ms = 0;  //Zähler für Zeitmessung (10ms)
volatile int band_ok = 0;  //Band läuft
volatile int mess_ok = 0;  //Messung aktiv (Gegenstand auf Band)
int sensor_buffer = 0 ;    // Messwertspeicher
char ergebnis[7];      //5 Stellen + Kennungt + 0 für Ende

//---------------------------------------------------------------------- 
----
//      Initialisiere Uart- Schnittstelle
//---------------------------------------------------------------------- 
----
void usartinit (void)
{
    /* Das Frameformat Start, 8Datenbits u. 1 Stoppbit ist nach Reset
       bereits im USART eingestellt */
  UBRRL = 23;        //9600  Baud
  UCSRB =0x08;       //Sender enable
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//      Gebe Zeichen über Uart aus
//---------------------------------------------------------------------- 
----
void usartputc(char data )
{
  while (!(UCSRA&32));     //warte bis usart leer
  UDR=data;        //sende zeichen
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//      Ausgabe Buffer über Usart
//---------------------------------------------------------------------- 
----
void print(char buffer[])  //Ausgabe Zeichenpuffer
{
  for (int i=0;buffer[i] != 0 ;i++ )
    usartputc(buffer[i]);
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//      Umwandlung Int nach ASCII String
//---------------------------------------------------------------------- 
----
void int_to_string(int x,char s[],char ken)
{
  int i      ;        //Index,lokale Variable
  for (i=0;i<6;i++ )        //Vorbesetzung mit Leerzeichen
    s[i]= ' ';
  s[i] = 0;            //kennzeichne Ende String
  s[0] = ken;                     //Ausgabe Kennung
  i=5;              //Umsetzung von bin nach dez
  do
  {
    s[i--] = x % 10 + '0';    //Modulus 10 der Rest nach ASCII
  }
  while (( x /= 10) > 0);      //Wert ist Wert durch 10
}

//---------------------------------------------------------------------- 
-----

void laenge()            //Ausgabe Wort Länge
{
  usartputc(0x4c);        //L
  usartputc(0x61);        //a
  usartputc(0x65);        //e
  usartputc(0x6e);        //n
  usartputc(0x67);        //g
  usartputc(0x65);        //e
  usartputc(0x0d);        //Wagenrücklauf
  usartputc(0x0a);        //Zeilenwechsel
}



//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
----
//           Ausgabe CR und LF an das Terminal
//---------------------------------------------------------------------- 
----
void cr_lf()    // Ausgabe CR und LF an das Terminal
{
  usartputc(0x0d);  //Ausgabe Wagenrücklaufzeichen
  usartputc(0x0a);  //Ausgabe Zeilenwechselzeichen
}
//---------------------------------------------------------------------- 
----

//---------------------------------------------------------------------- 
--
//      Längenmessung über eine Laufzeitmessung (v=s/t)
//----------------------------------------------------------------------
ISR (TIMER0_OVF_vect)
{
  TCNT0 = (255-144) ;   // Wert für 10 ms bei Vorteiler 256
  if (band_ok && mess_ok)   //Messung aktiv und gültig
  ++cnt_ms;
}

//----------------------------------------------------------------------
//      ISR INT0: Band läuft; von externer Steuerung
//----------------------------------------------------------------------
ISR (INT0_vect)
{
  if (PIND & 0b00000100)  //Abfrage PD2 (Pin 4)auf ein
    band_ok = 1;      //Band läuft
  else
    band_ok = 0;            //Band ist aus
}

//----------------------------------------------------------------------
//      ISR INT1: In Messung; von Reflexionslichtschranke
//----------------------------------------------------------------------
ISR (INT1_vect)
{
  if (PIND & 0b00001000)  //Abfrage PD3 (Pin 5)auf ein
    mess_ok = 1;      //Objekt in Lichtschranke
  else
    mess_ok = 0;            //Objekt ist nicht in Lichtschrank
}

//----------------------------------------------------------------------
//      ADC Messung mit 10 Bit
//----------------------------------------------------------------------

void adc_mess(void)
{
 sbi(ADCSRA,6);          //starte Messung
 while (ADCSRA & 0b01000000)//Messung fertig ?
 {
  ;
 }
 sbi (ADCSRA,4);      //lösche ADIF Bit
 adc_wert = ADC;      //lese Messwert
 adc_wert &= 0x3ff;      //auf 10 Bit begrenzen
}

//----------------------------------------------------------------------
//      Init- Funktion
//----------------------------------------------------------------------
void init (void)
{
usartinit();
TCNT0 =(255-144);      //Wert für 10ms bei Vort. 256
TCCR0 = 0x04  ;    //Vorteiler 256 für Timer 0
TIMSK = 0x01  ;    //Freigabe Interrupt Timer 0
        //DDRC u. Dsind nach Reset
        //Eingänge
PORTD |=  0b00001100;    //Pul up auf Bit 2 u. 3
DDRB  |=  0b00000011;    //Bit 0 u. 1von Port B sind Ausgänge
PORTB  &=   0b11111100;              //Port B Bit 0 u. 1 auf 0
GICR   =    0b11000000;    //Freigabe ext.INT0 u. 1
MCUCR  =  0b00000101;    //Interrupt auf jeder Flanke
ADMUX  =    0;      //externe Ref., Mux auf Kanal 0
ADCSRA =  0b10010101;      //ADC Einzelmessung,Vorteiler ./.32
}



main ()            // Hauptprogramm, startet bei Power ON und Reset
{
  int b=0,b1=0,b2=0,h=0,l=0,lae=0;  //interne Variable
  init ()  ;          //Initialisierung
  sei  ()  ;          //Hauptfreigabe Interrupt
  for (;;)
  {
   while (band_ok == 0){;}  //warte auf Band läuft
   while (mess_ok == 0){;}  //warte auf Reflexionslichtschranke
   cr_lf();
   ADMUX = 0; //starte mit Sensor Breite 1 (ADMUX=0 --> PC0, siehe 
Pinbelegung ATmega8)
   adc_mess();        //Messung Breite 1
   b1 = adc_wert;        //Breite 1
   sensor_buffer = b1;
   int_to_string(sensor_buffer,ergebnis,'L'); //Umwandlung Ergebnis von 
int nach ASCII string
   print(ergebnis); //Ausgabe Ergebnis
   cr_lf()       ; //Ausgabe CR und LF an das Terminal
   ADMUX = 1;          //starte mit Sensor Breite 2 (ADMUX=1 --> PC1, 
siehe Pinbelegung ATmega8)
   adc_mess();        //Messung Breite 2
   b2 = adc_wert;        //Breite 2
   sensor_buffer = b2;
   int_to_string(sensor_buffer,ergebnis,'R'); //Umwandlung Ergebnis von 
int nach ASCII string
   print(ergebnis); //Ausgabe Ergebnis
   cr_lf()       ; //Ausgabe CR und LF an das Terminal
   ADMUX = 2;          //starte mit Sensor Höhe (ADMUX=2 --> PC2, siehe 
Pinbelegung ATmega8)
   adc_mess();        //Messung Höhe
   h = adc_wert;        //Höhe
   sensor_buffer = h;
   int_to_string(sensor_buffer,ergebnis,'H'); //Umwandlung Ergebnis von 
int nach ASCII string
   print(ergebnis); //Ausgabe Ergebnis
   cr_lf()       ; //Ausgabe CR und LF an das Terminal
   while (mess_ok == 1){;}  //warte auf Ende Längenmessung
   l = cnt_ms ;               //Zeit in 10 ms TICS
   l *= speed ;               //Länge in mm
   if (l<=0){l=1;}    //Mindestlänge 1mm

//   lae = l;    //Länge (l) wird der Variable lae zugeordnet
//   lae = 2000;
-->   int_to_string(l,ergebnis,'Z'); //Umwandlung Ergebnis von int
                                         //nach ASCII string
-->   laenge();
-->   print(ergebnis);           //Ausgabe Ergebnis
-->   cr_lf();             //neue Zeile

   cnt_ms = 0;    //neu stellen
   b = 1200 -(b1 + b2);  //Näherungswert für Breite in mm
   h = 2500 -(h*244/100);  //Berechne Höhe in mm
   if (h < 0){h = 1;}  //nicht negativ
   if (h>2000) {h=2000;}  //nicht höher als 2000mm
//   b = 200;      //Test
//   h = 1000;    //Test
//   l = 1999;    //Test vol <400
//   l = 2000;                       //Test für vol >=400
   volume = (long)b;     //Breite
   volume = volume *(long)h;  //Breite * Höhe
   volume = volume * (long)l; //Volumen
   volume = volume /1000000;  //Umrechnung in dm³
   if (volume < volgrenzw)
   {
    PORTB &= 0b11111101;     // Volumen groß aus
    PORTB |= 0b00000001;     // Volumen klein ein (PB0)
   }
   else
    {
    PORTB &= 0b11111110;     // Volumen klein aus
    PORTB |= 0b00000010;     // Volumen groß ein (PB1)
   }
  }
}
//----------------------------------------------------------------------

von Daniel L. (dannynrw)


Lesenswert?

Kann mir vielleicht auch nochmal jemand die Funktion int_to_string 
erklären?
Hänge da ein wenig, was das Verständnis angeht.
Versuche das mal mit meinen eigenen Worten zu beschreiben soweit 
möglich.
Also:
Zuerst wird eine Integer-Variable i erzeugt, danach in einer 
for-Schleife auf 0 gesetzt. Ist nun i kleiner 6, so wird i mit jedem 
Durchlauf um 1 erhöht.
Danach hört's bei mir leider schon auf.

von Lutz (Gast)


Lesenswert?

R. Max schrieb:
> Richtig wäre:
> while (abfrage1 == 0 || abfrage2 == 0);

Nö. Versuch statt || (ODER) mal && (UND) ...

von Lutz (Gast)


Lesenswert?

Ist doch eigentlich gut kommentiert.
i wird als Arrayindex genommen. Mit i = 5 wird auf das letzte "echte" 
Zeichen im Array zugegriffen und der Wert mit dem Trick (+ '0') in ASCII 
umgewandelt. Im ASCII-Code liegen alle Zeichen schön sortiert 
hintereinander; schau dir mal die Tabelle irgendwo an. Mit + '0' wird 
daher ein konstanter Abstand vom Start der Tabelle hergestellt. Steht in 
so jedem C-Buch drin.

von R. M. (rmax)


Lesenswert?

Lutz schrieb:
> R. Max schrieb:
>> Richtig wäre:
>> while (abfrage1 == 0 || abfrage2 == 0);
>
> Nö. Versuch statt || (ODER) mal && (UND) ...

Das ODER stimmt schon, denn die beiden Terme liefern 1, solange die 
jweilige Taste nicht gedrückt ist und die Schleife soll erst verlassen 
werden, wenn beide Tasten gedrückt sind, nicht schon bei einer.

von Karl H. (kbuchegg)


Lesenswert?

Daniel Lo schrieb:

> Versuche das mal mit meinen eigenen Worten zu beschreiben soweit
> möglich.
> Also:
> Zuerst wird eine Integer-Variable i erzeugt, danach in einer
> for-Schleife auf 0 gesetzt. Ist nun i kleiner 6, so wird i mit jedem
> Durchlauf um 1 erhöht.
> Danach hört's bei mir leider schon auf.


Du erklärst das nicht mit eigenen Worten. Du liest nur vor. Das hat mit 
erklären nichts zu tun.

Punkt 1
*******
Du brauchst Wissen, wie Stringverarbeitung in C funktioniert

http://www.mikrocontroller.net/articles/FAQ#Wie_funktioniert_String-Verarbeitung_in_C.3F


Punkt 2
*******
Was ergibt 38 dividiert durch 10

    38 / 10   ->   3

Und was ist der Rest bei dieser Division?  (% ist die Modulo-Opertion 
und sie liefert den Rest einer Division)

    38 % 10   ->    8

Hmm, 38 .... 3 und 8,  38 .... 3 und 8

Wie ist das mit 594

      594 / 10   ->  59
      594 % 10   ->  4

  und  59 / 10   ->  5
       59 % 10   ->  9

Hmm   594   ...  5, 9 und 4,  594 ...  5, 9 und 4


Punt 3
******
Du brauchst eine ASCII Tabelle. Dann siehst du das die ASCII Zeichen für 
die Zíffern '0', '1', '2' etc alle hintereinander kommen.
habe ich also zb die Zahl 5 in eine Variablen stehen, dann ergibt mir 
'0' + Variable  genau den ASCII Code für das Zeichen '5'


So und jetzt versuch noch einmal, die Funktion zu 'erklären'. Aber 
diesmal wirklich erklären, nicht vorlesen! Dazu ist es auch hilfreich, 
wenn du einmal Computer spielst, dir eine Wert für x und für kenn 
ausdenkst und ganz einfach auf dem Papier mal die Funktion durchspielst.
Fang damit an, dir am Papier die Variablen aufzumalen


    x              kenn         i
   +-------+      +-------+    +------+
   |  836  |      |  '#'  |    |      |
   +-------+      +-------+    +------+

   s
   +---+---+---+---+---+---+---+---+---+
   |   |   |   |   |   |   |   |   |   |
   +---+---+---+---+---+---+---+---+---+

Jetzt übernimmst du, und führst die Funktion aus. Aber mach nur das, was 
auch tatsächlich in den Anweisungen steht.
Wenn an eine Variable etwas zugewiesen wird, dann radierst du den alten 
Wert der Variablen aus und schreibst den neuen Wert hinein (den du 
erhältst indem du die rechte Seite der Zuweisung ausrechnest, sofern da 
nicht eine konstante Zahl dasteht). Wenn eine Variable auf der rechten 
Seite in einer Formel verwendet wird, dann siehst du auf dem papier 
nach, welches der aktuelle Wert der Variablen ist.

Wenn du am Ende der Funktion angelangt bist, lehnst du dirch zurück und 
denkst über das was du während der Abarbeitung gemacht hast nach. Wenn 
du dir bei einzelnen Schritten nicht sicher bist, warum sie genau so und 
nicht anders aussehen müssen, dann formulierst du erst mal eine 
Hypothese: Warum denkst du müsste das so sein. Im Idealfall kommst du 
dann mit einem Beispiel hoch, dass deine Hypothese stützt oder widerlegt 
und probierst dieses Beispiel durch. Solange, bis aus der Annahme 
Gewissheit geworden ist.

So analysiert man fremden Code. Mit der Zeit kriegst du Übung darin und 
dann brauchst du zumindest für kurze Funktionen Papier und Bleistift 
nicht mehr. Das Prinzip ist aber dasselbe: Man geht den Code durch 
(entweder mit Papier oder im Kopf), vollzieht alle Operationen die im 
Code stehen, lehnt sich zurück und fasst das mas man gemacht hat in 
eigenen Worten zusammen, wobei man sich vom Code löst und auf größere 
Bausteine zurückgreift. Mit noch mehr Erfahrung erkennt man dann auch 
typische Programmstrukturen auf Anhieb und das Analysieren fällt immer 
leichter, weil man nicht mehr für jeden Furz den Code durchspielen muss, 
sondern aus der Erfahrung heraus durch Hinschauen sagen kann, was im 
nächsten Code Abschnitt passiert.

Aber am Anfang steht: DU bist µC und DU arbeitest den Code ab.

von Christian D. (chris83)


Lesenswert?

@ R. Max
Wiedersprichst du dir nicht gerade selbst?

R. Max schrieb:
> Daniel Lo schrieb:

>
> Richtig wäre:
>
>
1
> while (abfrage1 == 0 || abfrage2 == 0);
2
>
>
> Diese Schleife wird solange wiederholt, bis beide Abfragen gleichzeitig
> einen Wert ungleich 0 liefern.

So und unten hast du geschrieben

R. Max schrieb:
> Das ODER stimmt schon, denn die beiden Terme liefern 1, solange die
> jweilige Taste nicht gedrückt ist

Das würde doch bedeuten dass die Schleife garnicht ausgeführt wird, da 
abfrage1 und 2 den Wert 1 haben, wenn die Schalter nicht gedrückt sind.
Und somit wäre die Bedingung für die Schleife schon nicht mehr erfüllt.

Und eine ODER verknüpfung habe ich immer so verstanden, dass einer der 
Beiden nicht mehr die Bedingung erfüllen muss, um die Schleife zu 
verlassen.
Oder irre ich mich da?

von Karl H. (kbuchegg)


Lesenswert?

Christian D. schrieb:

> So und unten hast du geschrieben
>
> R. Max schrieb:
>> Das ODER stimmt schon, denn die beiden Terme liefern 1, solange die
>> jweilige Taste nicht gedrückt ist
>
> Das würde doch bedeuten dass die Schleife garnicht ausgeführt wird, da
> abfrage1 und 2 den Wert 1 haben, wenn die Schalter nicht gedrückt sind.
> Und somit wäre die Bedingung für die Schleife schon nicht mehr erfüllt.

Vorsicht.
R.Max spricht von 'Termen' nicht von Eingängen.
Der Term
    abfrage == 0
liefert eine 1, wenn die Abfrage den Wert 0 ergab

von R. M. (rmax)


Lesenswert?

Malen wir uns doch einfach mal eine Wahrheitstabelle hin, wobei die 
abfrage-Variablen 1 werden, sobald die Taste gedrückt ist und termN die 
Vergleiche links und rechts des ODER sind:
1
 abfrage1 | abfrage2 || term1 | term2 || ergebnis | Bemerkung
2
----------+----------++-------+-------++----------+------------
3
    0     |    0     ||   1   |   1   ||    1     | Keine Taste gedrückt
4
    1     |    0     ||   0   |   1   ||    1     | Taste 1 gedrückt
5
    0     |    1     ||   1   |   0   ||    1     | Taste 2 gedrückt
6
    1     |    1     ||   0   |   0   ||    0     | Beide Tasten gedrückt

Bei einer UND-Verknüpfung würde die Ergebinis-Spalte von oben nach unten 
1 0 0 0 lauten, was nicht dem gewünschten Verhalten entspricht, daß die 
Schleife erst dann verlassen werden soll, wenn beide Tasten gedrückt 
sind.

Weil das Ganze aber eigentlich eine NAND-Verknüpfung der beiden 
abfrage-Variablen ist, kann man die Bedingung auch so schreiben:
1
while (!(abfrage1 && abfrage2));
Daraus läßt sich die Logik "solange nicht beide Tasten gleichzeitig 
gedrückt sind" vielleicht etwas leichter herleiten als aus der 
Schreibweise mit ODER und negierten Eingängen.

von Christian D. (chris83)


Lesenswert?

Ok danke,
nun hab ich es verstanden, hatte das mit den Termen nicht 
berücksichtigt.
Aber nun ist es klar.

nobody is perfect :)

von Lutz (Gast)


Lesenswert?

War ich auch drauf reingefallen. Ist ein sehr gutes Beispiel, wie man es 
auch nicht machen sollte, da es eben kein intuitiver Ausdruck ist.

Intuitiv wäre (zumindest nach meiner Intuition):
1
while ((abfrage1 && abfrage2) == 0)
2
   ;

von R. M. (rmax)


Lesenswert?

Das ist sicher Geschackssache, aber was findest Du an dem Vergleich mit 
0, angewandt auf einen logischen Wert, intuitiver als die logische 
Negation (!), die ich zuletzt vorgeschlagen hatte und die sich ja auch 
in dem Satz wiederfindet, wenn man die Bedingung umgangssprachlich 
formuliert?

von Lutz (Gast)


Lesenswert?

R. Max schrieb:
> was findest Du an dem Vergleich mit
> 0, angewandt auf einen logischen Wert, intuitiver als die logische
> Negation (!), die ich zuletzt vorgeschlagen hatte

Lutz schrieb:
> Intuitiv wäre (zumindest nach meiner Intuition):

Intuition läßt sich nun mal nicht erklären. Meine Denke ist da halt so. 
Logisch korrekt ist ja beides, aber ich würde es für mich eben so 
machen. Ich mag z.B. auch sehr gerne Spinat ... Na in der Richtung muß 
man das halt sehen.

von R. M. (rmax)


Lesenswert?

Lutz schrieb:

> Ich mag z.B. auch sehr gerne Spinat ...

OK, das erklärt alles! ;)

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.