Forum: Mikrocontroller und Digitale Elektronik ATMega88 Umgebungsscan


von Orhan T. (orhan87)


Lesenswert?

Hallo Leute,

bin neu hier, nimmt es mir nicht übel falsch im falschen Thread poste, 
aber habe gerade ein Projekt am laufen und komme nicht weiter.

Und zwar sollen ich über das MiniMexle mit dem ATMega88 einen Servo über 
PWM ansteuern (bereits hier im Forum gefunden) und während dessen, einen 
Sharp IR Sender/Empfänger die Umgebung abscannen lassen und bei einem 
Hindernis, mit einem Abstand <10cm sollen die LED aufblinken. Irgendwie 
habe ich einen Wurm im meinem Quellcode und ich wäre dankbar, wenn Ihr 
mit dabei behilflich sein könntet.

Vielen Dank im Vorraus

Orhan

/*====================================================================== 
=======

Projekt:    Abstandsmessung mit Sharp-IR-Sensor-GP2Y0A21YK0F inkl. 
Umgebungsscan anhand eines schwenkenden
        Servomotors
======================================================================== 
=====*/


// Deklarationen


//===================================
// Festlegung der Quarzfrequenz

#ifndef F_CPU          // optional definieren
#define F_CPU 18432000UL    // MiniMEXLE mit 18,432 MHz Quarz
#endif


//===================================
// Include von Header-Dateien

#include <avr/io.h>        // I/O Konfiguration (intern weitere Dateien)
#include <util/delay.h>      // Definition von Delays (Wartezeiten)
#include <stdio.h>
#include <stdlib.h>
#include "lcd_lib_de.h"      // Funktionsbibliothek zum LCD-Display

//===================================
//Servo Einstellungen
#define SERVOMAX 5100                 //2,4ms => +100% => (F_CPU  8  
1000 * 2,4) -1
#define SERVOMIN 1150                 //0,5ms => -100% => (F_CPU  8  
1000 * 0,5) -1
#define SERVOCENTER 3340              //1,45ms => 0% => (F_CPU  8  
1000 * 1,45) -1
#define SERVOFRAME 46079              //20ms => (F_CPU  8  1000 * 20) 
-1

//===================================
// Konstanten

#define ON_TIME    10      // "Ein-Zeit" in Inkrementen zu 100 ms
#define OFF_TIME  10      // "Aus-Zeit" in Inkrementen zu 100 ms


float abstand_digital = 0;
float abstand_analog = 0;

char Ausgabe[5];



#define VORTEILER_WERT    90          // Faktor Vorteiler = 90
#define HUNDERTSTEL_WERT  10          // Faktor Hunderstel = 10

unsigned char vorteiler = VORTEILER_WERT;    // Zaehlvariable des 
Vorteilers
unsigned char hundertstel = HUNDERTSTEL_WERT;  // Zaehlvariable 
Hunderstel

volatile bool timertick=0;            // Bit-Botschaft alle 0,111ms (bei 
Timer-Interrupt)
volatile bool takt10ms=0;            // Bit-Botschaft alle 10ms
volatile bool takt100ms=0;            // Bit-Botschaft alle 100ms


//===================================
// Konstanten: Steigung und Y-Wert

#define M1 -0.0625     // n=1: 5 bis 7,5cm
#define C1 960.3125
#define M2 -0.0138    // n=2: 7,5 bis 10cm
#define C2 920.1035
#define M3 -0.0208     // n=3: 10 bis 12,5cm
#define C3 740.208
#define M4 -0.0294     // n=4: 12,5 bis 15cm
#define C4 620.3675
#define M5 -0.04545    // n=5: 15 bis 20cm
#define C5 535.68175
#define M6 -0.0714     // n=6: 20 bis 25cm
#define C6 426.428
#define M7 -0.1       // n=7: 25 bis 30cm
#define C7 357.5
#define M8 -0.014286  // n=8: 30 bis 35cm
#define C8 309.2858
#define M9 -0.2       // n=9: 35 bis 40cm
#define C9 277
#define M10 -0.2857   // n=10: 40 bis 50cm
#define C10 256.428
#define M11 -0.5     // n=11: 50 bis 60cm
#define C11 235
#define M12 -0.6667   // n=12: 60 bis 70cm
#define C12 230.002
#define M13 -1.0     // n=13: 70 bis 80cm
#define C13 245

unsigned int Marray [14]={100,150,200,300,400,500,600,700,800};

// Zuweisung der Y-Werte

#define Y10    440    // Abstand = 10cm
#define Y15    310   // Abstand = 15cm
#define Y20    245   // Abstand = 20cm
#define Y30    175    // Abstand = 30cm
#define Y40    135    // Abstand = 40cm
#define Y50    110    // Abstand = 50cm
#define Y60    95    // Abstand = 60cm
#define Y70    80    // Abstand = 70cm
#define Y80    75    // Abstand = 80cm



//===================================
// Makros

#define SET_BIT(PORT, BIT)  ((PORT) |= (1<<BIT))  // Einzelbit auf Port 
SET
#define CLR_BIT(PORT, BIT)  ((PORT) &= ~(1<<BIT))  // Einzelbit auf Port 
RESET

bool LED1 = 0;
bool LED2 = 0;
bool blink=0;

//===================================
// Funktionsprototypen

void initDisplay();      // Initialisierung Display und Startanzeige
void adc_init();      // Initialisierung A-D-Wandler aufrufen
void adc_convert();      // Initialisierung Abfrage
void calc_abstand();    // Initialisierung Berechnung des Abstandes
void ausgabe_abstand();    // Initialisierung der Displayanzeige
void blinken_led();      // Initialisierung LED blinken
void Init_Timer0();      // Initialisierung Timer0

//===================================
// Funktionsprototypen
volatile int adc_conversion;
volatile int calc_tick;
volatile int timer_count=0;
volatile int fuenfhundertms_tick=0;
float y=0;
uint8_t disp_temp1 = 0;
uint8_t disp_temp2 = 0;
uint8_t disp_temp3 = 0;
uint8_t disp_temp4 = 0;
unsigned int disp_temp = 0;
int temp;
unsigned int M;

//===================================
// Hauptprogramm

int main()             // Start des Hauptprogramms
{
  lcd_init();
  initDisplay();
  Init_Timer0();
  adc_init();
  DDRC&=~(1<<DDC5);
  PORTC&=~(1<<PINC5);
  DDRD|=(1<<PIND1)|(1<<PIND0);


  TCCR2A = 0;          // Timer 2 auf "Normal Mode" schalten
  TCCR2B |= (1<<CS21);    // mit Prescaler /8 betreiben
  TIMSK2 |= (1<<TOIE2);    // Overflow-Interrupt aktivieren
  sei();


DIDR0 |= (1 << ADC5D);       // Digitalen Eingang abschalten

  while(1)
  {
    if(takt100ms)
    {
      takt100ms=0;
      adc_convert();
      calc_abstand();
      ausgabe_abstand();
    //  ausgabe();
      blinken_led();

    }
  }

}                // Ende des Hauptprogramms


void init(void) {
    DDRB |= (1<<PB1);       //OCR1x Ports auf Ausgang

                      //Timer0, Mode 14 Fast-PWM, prescaler 8
    ICR1=SERVOFRAME;                   //Impulswiederholzeit 20ms
    OCR1A=SERVOCENTER;                //Servo Mittelstellung

    TCCR1A |= (1<<COM1A1) | (1<<COM1B1) |(1<<WGM11);
    TCCR1B |= (1<<WGM13) | (1<<WGM12) | (1<<CS11);
}

int main_servo(void) {
    init();
    _delay_ms(1000);
    while(1) {
                      //Servos auf MIN
        OCR1A = SERVOMIN;

        _delay_ms(1000);

                      //Servos auf CENTER
        OCR1A = SERVOCENTER;

        _delay_ms(1000);

                      //Servos auf MAX
        OCR1A = SERVOMAX;

        _delay_ms(1000);



      while(1)
    {                //Servos auf MIN
        OCR1A = SERVOMIN;

        _delay_ms(1000);

                      //Servos auf MAX
        OCR1A = SERVOMAX;

        _delay_ms(1000);
       }
    }

}



// Funktionen 
=================================================================

//===================================
// Initialisierung A-D-Wandler


void adc_init (void)
{
  ADCSRA|=((1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2));  // Vorteiler 
128
  ADMUX|=((1<<REFS0)|(1<<REFS1)| (5<<MUX0));        // 1,1V als 
Referenzspannung

}



//===================================
// A-D-Wandlung ( 100ms )


void adc_convert (void)
{
//  if(adc_conversion)
//  {
    adc_conversion = 0;
    unsigned int convert = 0;

  //  ADCSRA |=(1<<ADEN);        // A-D-Wandler einschalten

    ADCSRA |=(1<<ADSC);        // Umwandlung beginnen

    while (ADCSRA & (1<<ADSC));    // Warten bis Wandlung beendet
    {
    }
  //  convert = ADCL;          // Lower Byte auslesen
//    convert += (ADCH<<8);      // Higher Byte auslesen
    convert=ADC;
    temp=convert;
//    ADCSRA &= ~(1<<ADEN);      // A-D-Wandler ausschalten

    abstand_digital = convert;
//  }
}



//===================================
// Berechnung des Abstandswertes alle 100ms


void calc_abstand (void)
{
  if(calc_tick)
  {
    calc_tick = 0;

    y = (abstand_digital*1100)/1024;  // y-Wert bestimmen

  lcd_gotoxy(1,8);          // Ausgabe des aktuell berechneten Wertes
  //lcd_putstr("M1");

    if ((y<=Y10)&&(y>Y15))       //Abstand zwischen 10 und 15cm
    {
  //  lcd_putstr("M1 ");
    M=1;
    abstand_analog = (y-C1)/(M1);   //Geradengleichung
    }
    if ((y<=Y15)&&(y>Y20))       //Abstand zwischen 15 und 20cm
    {
    //lcd_putstr("M2 ");
    M=2;
    abstand_analog = (y-C2)/(M2);
    }
    if ((y<=Y20)&&(y>Y30))     //Abstand zwischen 20 und 30cm
    {
  //  lcd_putstr("M3 ");
    M=3;
    abstand_analog = (y-C3)/(M3);
    }
    if ((y<=Y30)&&(y>Y40))     //Abstand zwischen 30 und 40cm
    {
    //lcd_putstr("M4 ");
    M=4;
    abstand_analog = (y-C4)/(M4);
    }
    if ((y<=Y40)&&(y>Y50))       //Abstand zwischen 40 und 50cm
    {
    //lcd_putstr("M5 ");
    M=5;
    abstand_analog = (y-C5)/(M5);
    }
    if ((y<=Y50)&&(y>Y60))       //Abstand zwischen 50 und 60cm
    {
    //lcd_putstr("M6 ");
    M=6;
    abstand_analog = (y-C6)/(M6);
    }
    if ((y<=Y60)&&(y>Y70))       //Abstand zwischen 60 und 70cm
    {
    //lcd_putstr("M7 ");
    M=7;
    abstand_analog = (y-C7)/(M7);
    }
    if ((y<=Y70)&&(y>Y80))       //Abstand zwischen 70 und 80cm
    {
    //lcd_putstr("M8 ");
    M=8;
    abstand_analog = (y-C8)/(M8);
    }


    if (M<1)  //if (y=10)
    {
    blink=1;
    }
    else
    {
    blink=0;
    }
    disp_temp = abstand_analog;
    disp_temp1 = disp_temp / 1000;       //Zehnerstelle
    disp_temp2 = (disp_temp % 1000) / 100;   //Einerstelle
    disp_temp3 = (disp_temp % 100) / 10;   //Zehntelstelle
    disp_temp4 = (disp_temp % 10) / 1;     //Hundertstelstelle

  }
}

//===================================
// Initialisierung Display-Anzeige

void initDisplay()            // Start der Funktion
{
  lcd_init();              // Initialisierungsroutine aus der lcd_lib

  lcd_gotoxy(0,0);               // Cursor auf 1. Zeile, 1. Zeichen
  lcd_putstr(" Abstandsmessung");     // Ausgabe Festtext: 16 Zeichen

//  lcd_gotoxy(1,13);               // Cursor auf 2. Zeile, 1. Zeichen
//  lcd_putstr("cm ");          // Ausgabe Festtext: 16 Zeichen

}                    // Ende der Funktion


//===================================
// Ausgabe Abstand

void ausgabe_abstand()
{
  lcd_gotoxy(1,7);             // Cursor auf 2. Zeile, 1. Zeichen

  lcd_putstr("s=");        // s= Abstand
  unsigned int Mtemp=Marray[M];



  lcd_putc(48 + (Mtemp/100)%10);  // Ausgabe Festtext: 16 Zeichen
  lcd_putc(48 + (Mtemp/10)%10);  // Ausgabe Festtext: 16 Zeichen
  lcd_putstr(",");
  lcd_putc(48 + Mtemp%10);
  lcd_putstr("cm");




}            // Ende der Funktion

//===================================
//LED1 + LED2 blinken


void blinken_led()
{
  if (blink==1)  //if (y=10cm)
  {
  PORTD^=((1<<PIND1)|(1<<PIND0));
  }
  if (blink==0)
  {
  PORTD&=~((1<<PIND0)|(1<<PIND1));
  }
}                // Ende des Programms



//===================================
// Timer 1 - verschiedene Taktzeiten
/*
       Takt1 - 100ms - Teiler 7  (~7,25)
       Takt2 - 250ms - Teiler 18  (~18,12)
       Takt3 - 500ms - Teiler 36  (~36,23)   berechnet durch 
t/0.0138=Teiler

die nicht benötigten Taktzeiten sollen als Text hinterlegt werden  */


void Init_Timer0(void)          // Initialisierung Timer 0

  {
   TCCR0A |= (1<<WGM01);          // Clear Timer on Compare (CTC)
   TCCR0B |= ((1<<CS02)|(1<<CS00));   // Prescaler auf Teilung durch 
1024 setzen
   OCR0A = 249;              // Output Compare Register A belegen
   TIMSK0 |= (1<<OCIE0A);         // Interrupt Timer/C0 Output Compare 
Match A
   sei();
  }



//===================================
// Interrupt-Routine


ISR (TIMER0_COMPA_vect)    // Takteinstellung für A-D-Wandlung

/*
// Takt1 - 100ms
{
  timer_count++;
  if (timer_count == 7)
   {
   timer_count = 0;
   hundertms_tick = 1;
   adc_conversion = 1;
   calc_tick = 1;
   }

}
*/

/*
// Takt2 - 250ms
{
  timer_count ++;
  if (timer_count == 18)
   {
   timer_count = 0;
   zweifuenfzigms_tick = 1;
   adc_conversion = 1;
   calc_tick = 1;
   }
}
*/


//Takt3 - 500ms
{
  timer_count ++;
  if (timer_count == 36)
   {
   timer_count = 0;
   fuenfhundertms_tick = 1;
   adc_conversion = 1;
   calc_tick = 1;
   }
}



ISR (TIMER2_OVF_vect)
/*   In der Interrupt-Routine sind die Softwareteiler realisiert, die 
die Takt-
  botschaften (10ms, 100ms, 1s) fuer die gesamte Uhr erzeugen. Die 
Interrupts
  werden von Timer 2 ausgeloest (Interrupt Nr. 1)

  Ausgangsvariable:    takt10ms
              takt100ms
              takt1s
*/


{
  timertick = 1;          // Botschaft 0,111ms senden
  --vorteiler;          // Vorteiler dekrementieren
  if (vorteiler==0)        // wenn 0 erreicht: 10ms abgelaufen
  {
    vorteiler = VORTEILER_WERT;  //    Vorteiler auf Startwert
    takt10ms = 1;        //    Botschaft 10ms senden
    --hundertstel;        //    Hunderstelzaehler dekrementieren

    if (hundertstel==0)      // wenn 0 erreicht: 100ms abgelaufen
    {
      hundertstel = HUNDERTSTEL_WERT; // Teiler auf Startwert
      takt100ms = 1;      //    Botschaft 100ms senden

    }
  }
}

von Orhan T. (orhan87)


Lesenswert?

folgende Meldung wird ausgewertet nachdem der Code aufgebaut wird:

Build started 7.1.2013 at 13:49:29
avr-gcc  -mmcu=atmega88p -Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char 
-funsigned-bitfields -fpack-struct -fshort-enums -MD -MP -MT 
AbstandsmessungSharp.o -MF dep/AbstandsmessungSharp.o.d  -c 
../AbstandsmessungSharp.c
../AbstandsmessungSharp.c: In function 'main_servo':
../AbstandsmessungSharp.c:258: warning: no return statement in function 
returning non-void
avr-gcc -mmcu=atmega88p -Wl,-Map=AbstandsmessungSharp.map 
AbstandsmessungSharp.o     -o AbstandsmessungSharp.elf
avr-objcopy -O ihex -R .eeprom -R .fuse -R .lock -R .signature 
AbstandsmessungSharp.elf AbstandsmessungSharp.hex
avr-objcopy -j .eeprom --set-section-flags=.eeprom="alloc,load" 
--change-section-lma .eeprom=0 --no-change-warnings -O ihex 
AbstandsmessungSharp.elf AbstandsmessungSharp.eep || exit 0
avr-objdump -h -S AbstandsmessungSharp.elf > AbstandsmessungSharp.lss

AVR Memory Usage
----------------
Device: atmega88p

Program:    6026 bytes (73.6% Full)
(.text + .data + .bootloader)

Data:        377 bytes (36.8% Full)
(.data + .bss + .noinit)


Build succeeded with 1 Warnings...

von Helmut L. (helmi1)


Lesenswert?

Orhan T. schrieb:
> ../AbstandsmessungSharp.c:258: warning: no return statement in function
> returning non-void

Dann gibt doch deiner Main Funktion einen Returnwert und wenn es 0 ist.

von Oliver (Gast)


Lesenswert?

Orhan T. schrieb:
> Irgendwie
> habe ich einen Wurm im meinem Quellcode und ich wäre dankbar, wenn Ihr
> mit dabei behilflich sein könntet.

Es wäre sehr viel einfacher, wenn du das Problem näher beschreiben 
könntest.

Bitte hänge den Code als Anhang an. So ist der schlecht lesbar.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

> int main_servo(void) {
>    init();
>    _delay_ms(1000);
>    while(1) {
>                      //Servos auf MIN
>        OCR1A = SERVOMIN;
>
>        _delay_ms(1000);
>        ...

Ähm.
Du hast da etwas missverstanden.

Bestehenden Komplett-Beispiele weiterverwenden bedeutet nicht, den Code 
einfach so wie er ist, in das bereits vorhandenen Code einkopieren und 
der Compiler soll sich dann selbst zusammensuchen, wie das alles 
zusammengehört.


Wenn du Servo-Code gefunden hast, dann übernimmst du die Programm-IDEE 
und baust diese in deinem Programm ein. Indem du NEUEN Code schreibst 
und nicht einfach nur auf Biegen und Brechen stumpfsinnig kopierst. Dass 
man beim Schreiben des neuen Codes, den einen oder anderen Codeabschnitt 
mehr oder weniger 1:1 kopieren kann, liegt in der Natur der Sache. Aber 
komplette main() einfach so einzukopieren, das geht mit 100% Sicherheit 
schief.

Bei der Übernahme und Weiterbenutzung von fremden Code, steht an erster 
Stelle, dass man die in diesem Code ausgedrückte Idee versteht und dann 
sich ansieht, wie diese Code-Idee ins eigene Programm hineinpasst.
Der Code in main_servo, den du zukopiert hast, der zeigt dir, wie du die 
Servo-Funktionalität benutzen kannst, welche Initialisierungen zb nötig 
sind. D.h. du musst dir in DEINEM main() überlegen, wie und wo du dort 
genau dieselbe Initialisierung gebacken kriegst. Und der Rest von 
main_servo() ist einfach nur ein Beispiel, das zeigt was man tun muss, 
wenn man das Servo an eine bestimmte Position schicken will. D.h. da 
überlegst du dir in DEINEM Programm, wie und wo du in DEINEM Programm 
die Position herbekommst an die das Servo fahren soll und übernimmst aus 
dem Beispiel die Technik (ist ja nur eine Zuweisung), wie du diese 
Position dem 'Servo-Treiber' kommunizierst.

Solche Codebeispiele sind im Grunde fast immer gleich zu sehen:
Da gibt es Funktionalität, die in Form von Funktionen zur Verfügung 
gestellt wird, die mehr oder weniger 1:1 übernommen werden kann. Und das 
main() im Beispiel zeigt einem, wie man diese Funktionalität 
beispielhaft verwendet bzw. einsetzt.

von Vlad T. (vlad_tepesch)


Lesenswert?

das Forum stimmt.
Was nicht stimmt ist deine Frage.

1. Aufbau: MiniMexle? was ist das? sollen wir uns jetzt selber dusslig 
suchen?
2. Code in [c ] [/ c] tags (ohne leerzeichen) posten
3. Problembeschreibung: was genau geht denn nicht?

von iregendein besserwisser (Gast)


Lesenswert?

Ich fürchte, main_servo() wird niemals aufgerufen.
Das ist auch gut so, weil die Funktion niemals zurückkehren würde.
Mehrere Sachen "gleichzeitig" machen ist nicht soo einfach.
Mit geschickter Nutzung von Interrupts lässt sich da evtl. was machen.

von Orhan T. (orhan87)


Lesenswert?

Hallo nochmal vielen herzlichen Dank für die superschnellen Antworten :) 
ja beim Reinkopieren habe ich leider vergessen, die int_... zu 
deklarieren jetzt klappt alles wunderbar :) trotzdem Vielen Dank

von Oliver (Gast)


Lesenswert?

Orhan T. schrieb:
> jetzt klappt alles wunderbar :)

Ja nee, is klar ...

Oliver

von Orhan T. (orhan87)


Lesenswert?

Sobald das Projekt fertig ist udn zu 100% alles richtig funktioniert 
werde ich den Quellcode hier rein setzen, damit diejenigen die in dieser 
Richtung was aufbauen möchten sich gerne bedienen können.

von Karl H. (kbuchegg)


Lesenswert?

Orhan T. schrieb:
> Sobald das Projekt fertig ist udn zu 100% alles richtig funktioniert
> werde ich den Quellcode hier rein setzen, damit diejenigen die in dieser
> Richtung was aufbauen möchten sich gerne bedienen können.


Hmmm. (Ohne dich beleidigen zu wollen)
Wenn ich mir den jetzigen Code so ansehe ....

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.