Forum: Mikrocontroller und Digitale Elektronik PWM mit Sleepmode


von Anonym L. (helferlein)


Lesenswert?

Hallo zusammen,

Wir haben ein Problem:
Wir machen gerade einen Sonnenfolger für eine Solarzelle. Damit das 
ganze möglichst Stromsparend ist, schicken wir den uC in den Power down 
mode. Das funktioniert super. Wenn er dann wieder Aufwacht spinnt der 
PWM, d.H. Die Solarzelle wackelt herum. Das beruhigt sich nicht, bis wir 
den Stecker ziehen. Mit dem DSO haben wir ausgemessen, dass der PWM viel 
zu kleine signale sendet (1.8uS statt 1-2ms). Während dem Schlafmodus 
steht die Solarzelle still.

Wir benutzen einen aTmega 328p.

Vielen Dank

Hier noch der Code:




#include "u8g.h"

#if defined(_AVR_)
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/sleep.h>
#include <avr/power.h>

#include <util/delay.h>
#include <avr/wdt.h>

#endif

#define LINKS OCR1A-=10
#define RECHTS OCR1A+=10
#define RUNTER OCR1B+=10
#define HOCH OCR1B-=10

#define SOLARAZIMX
#define SOALRAZIMY
uint8_t adc(uint8_t Nr);
uint8_t taster(uint8_t Nr);
uint8_t akkuadc(void);
void watchdog_init(void);
void watchdog_ein (void);
void watchdog_aus (void);
void PWM_init (void);

uint8_t stateazim=9, stateelev=9, azimausgabe=3, elevausgabe=3, 
azimgrad=0, elevgrad=0, ladeflag=0, maincounter=0, flag=0;
enum stateazim {left, right};
enum stateelev {up, down};

u8g_t u8g;

void u8g_setup(void);
void sys_init(void);

volatile char ISR_zaehler = 0, ms100 = 0, sec = 0, min = 0; //ISR



void u8g_setup(void)
{
  //u8g_InitSPI(&u8g, &u8g_dev_ssd1306_128x64_hw_spi, U8G_PIN_NONE, 
U8G_PIN_NONE, PN(2, 1), PN(2, 0), U8G_PIN_NONE);
      //                      PB4      PB0    PC6

  u8g_InitSPI(&u8g, &u8g_dev_pcd8544_84x48_hw_spi, PN(1,5), PN(1,4), 
PN(1,3), PN(1,0), PN(3,6));
//uint8_t u8g_InitSPI(u8g_t *u8g, u8g_dev_t *dev,  sck,    mosi,  cs, 
a0,    reset)
  u8g_SetFont(&u8g, u8g_font_baby);          //sce,     dc,       reset
 // u8g_SetRot180(&u8g);
}

void sys_init(void)
{
#if defined(_AVR_)
  CLKPR = 0x80;
  CLKPR = 0x00;
#endif
}

void draw(void)
{
  u8g_SetFont(&u8g, u8g_font_5x7);
  u8g_DrawStr(&u8g, 0, 10, "ADC A");
  u8g_DrawStr(&u8g, 0, 20, u8g_u16toa(akkuadc(), 3));//Variabel ausgeben 
und Zeichenlänge angeben
  u8g_DrawStr(&u8g, 60, 10, "ADC E");
  u8g_DrawStr(&u8g, 65, 20, u8g_u16toa(adc(1), 3));//Variabel ausgeben 
und Zeichenlänge angeben$
  u8g_SetFont(&u8g, u8g_font_4x6);
  u8g_DrawStr(&u8g, 5, 28, "NORD");
  u8g_SetFont(&u8g, u8g_font_5x7);
  u8g_DrawStr(&u8g, 60, 45, u8g_u16toa(OCR1A, 4));//Variabel ausgeben 
und Zeichenlänge angeben
  u8g_DrawStr(&u8g, 15, 45, u8g_u16toa(OCR1B, 4));//Variabel ausgeben 
und Zeichenlänge angeben
 // u8g_DrawStr(&u8g, 60, 45, u8g_u16toa(elevgrad, 3));
  //u8g_DrawStr(&u8g, 65, 30, "°");
 // u8g_DrawStr(&u8g, 0, 45, u8g_u16toa(azimgrad, 3));
  //u8g_DrawStr(&u8g, 38, 30, "°");
 /* switch(elevausgabe)
  {
    case 1:
        u8g_DrawStr(&u8g, 70, 35, "|");
        u8g_DrawStr(&u8g, 70, 30, "|");
        break;
    case 2:
        u8g_DrawStr(&u8g, 70, 29, "/");
        u8g_DrawStr(&u8g, 67, 32, "/");
        u8g_DrawStr(&u8g, 64, 35, "/");
        break;
    case 3:

        u8g_DrawStr(&u8g, 73, 29, ".");
        u8g_DrawStr(&u8g, 71, 30, ".");
        u8g_DrawStr(&u8g, 69, 31, ".");
        u8g_DrawStr(&u8g, 67, 32, ".");
        u8g_DrawStr(&u8g, 65, 33, ".");
        u8g_DrawStr(&u8g, 63, 34, ".");
        u8g_DrawStr(&u8g, 61, 35, ".");
        u8g_DrawStr(&u8g, 59, 36, ".");
        break;
  }
  switch(azimausgabe)
  {
    case 1:
        u8g_DrawStr(&u8g, 15, 35, "|");
        u8g_DrawStr(&u8g, 15, 30, "|");
        u8g_DrawStr(&u8g, 0, 35, "-->");
        break;

    case 2:
        u8g_DrawStr(&u8g, 0, 35, "____");
        u8g_DrawStr(&u8g, 1, 35, "____");
        break;
    case 3:
        u8g_DrawStr(&u8g, 0, 35, "|");
        u8g_DrawStr(&u8g, 0, 30, "|");
        u8g_DrawStr(&u8g, 5, 35, "<--");
        break;
  }*/
}

ISR(WDT_vect)
{
    watchdog_aus();
}

int main(void)
{

  DDRD &= ~((1<<PD2)|(1<<PD3)|(1<<PD4));//Taster zu eingang machen
  PORTD |= ((1<<PD2)|(1<<PD3)|(1<<PD4));//Pullup
  DDRD |= ((1<<PD6) | (1<<PD7));
  DDRB|=((1<<PB2)|(1<<PB1)|(1<<PB0) | (1<<PB3) | (1<<PB4) | 
(1<<PB5));//PB1/2
  PORTB|=((1<<PB2)|(1<<PB1));
  DDRC|=(1<<PC5);
  PORTC|=(1<<PC5);
  /******************PWM*******************/
  ICR1=0x9C40; // -> 20ms Periodendauer (Topwert, ab da wieder auf 0) 
vorher 7fff
  TCCR1A  |= ((1<<COM1A1) | (1<<COM1B1));  //Bei Wert ICR1 auf 1 und bei 
wert OCR1a/-B auf 0  -> PINS im DDR definieren!!

  TCCR1A |= (1<<WGM11);          //----------------------------
  TCCR1B  |=((1<<WGM12) | (1<<WGM13));  //--------PWM als fast-Mode PWM 
konfg

  TCCR1B |= (1<<CS11);        //Taktvorteiler 8
  TCNT0=0;
  /****************************************/

  ////////////////////ADC////////////////////
  ADMUX|= (1<<MUX1);
  ADMUX|=(1<<REFS0);//interne referenz 2.56V
  ADMUX|=(1<<ADLAR);//ergebnis in ADCH
  ADCSRA|=(1<<ADEN);
  ADCSRA|=(1<<ADPS1);
  ADCSRA|=(1<<ADPS0);
  ////////////////DISPLAY///////////////
  u8g_setup();//Display initialisieren
  sys_init();//Display setup


  /********************initialisierung*********************/
  OCR1A=1600;//Servo_X Mitte(linker stecker)
  OCR1B=1500;//Servo_Y Mitte (rechter stecker)
  watchdog_init();
    while (1)
    {

    if(taster(1))//(((adc(1)<130)||(adc(1)>124))&&((adc(2)<130)||(adc(2)>124 
)))||maincounter==60)
    {
      watchdog_ein();
      maincounter=0;
    }
    else{
      maincounter++;
    }
    ////////////LADE-STEUERUNG//////////////
    if(akkuadc()<50)//wenn akku <3V ladung(PC5) aus
    {
      PORTC&=~(1<<PC5);
      ladeflag=1;
    }
    else if(ladeflag==0)PORTC|=(1<<PC5);
    if(akkuadc()>75) ladeflag=0;
    ///////////////SONNENSENSOR AUSWERTEN//////////////
    if(adc(2)<124)//azimut
    {
      stateazim=left;
    }
    else if(adc(2)>130)
    {
      stateazim=right;
    }
    else
    {
      stateazim=100;//default
    }


    if(adc(1)<124)//elevation
    {
      stateelev=up;
    }
    else if(adc(1)>130)
    {
      stateelev=down;
    }
    else
    {
      stateelev=100;//default
    }
    //////////MANUELLE STEUERUNG///////////////
    /*if(taster(1)||taster(2)||taster(3))
    {
      if((taster(2)&&taster(3))||(taster(2)&&taster(1)))
      {
        if(taster(2)&&taster(1))
        {
          stateelev=up;
        }
        else if(taster(2)&&taster(3))
        {
          stateelev=down;
        }
      }
      else
      {
        stateelev=100;
      }

      if((taster(3)||taster(1))&&(!taster(2)))
      {
        if(taster(1))
        {
          stateazim=left;
        }
        else if(taster(3))
        {
          stateazim=right;
        }
      }
      else
      {
        stateazim=100;
      }
    }*/
    ///////////////////////SOLARPANEL DREHEN///////////////
    switch(stateazim)
    {
      case left:   if(OCR1A>760) LINKS;//--

            break;
      case right: if(OCR1A<2250)RECHTS;//++
            break;
      default:
            break;
    }
    ////////////SOLARPANEL HEBEN//////////////////
    switch(stateelev)
    {
      case up:   if(OCR1B>760)HOCH;//--
            break;
      case down:   if(OCR1B<2260)RUNTER;//++
            break;
      default:
            break;
    }

    /////////////////////DISPLAY AUSGABE///////////////
     u8g_FirstPage(&u8g);//auf Display schreiben
    do
    {
      draw();
    } while (u8g_NextPage(&u8g));
    }//end of while
}//end of main

void watchdog_ein (void)
{
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
  power_adc_disable();
  sleep_cpu();
  sei();
}

void watchdog_aus (void)
{
  sleep_disable();
  power_adc_enable();
  power_all_disable();
  cli();
}

void watchdog_init(void)
{
  cli();  //Interrups sperren
  wdt_reset();
  MCUSR=0x00;
  WDTCSR=0x00;
  WDTCSR |= ((1<<WDCE) |(1<<WDE));
  //Prescalereinstellungen muessen als HEX wert egschrieben werden eine 
"veroderte" schreibweise duaert laenger
  //als vier Takte und damit wird die prescalereinstellung nicht 
uebernommen.
  //siehe Datenblatt
  wdt_enable(WDTO_8S);//WDTCSR = 0x61;  //8 sekunden
  sei();      //Interrupt freigeben
}

void PWM_init(void)
{
  ICR1=0x9C40; // -> 20ms Periodendauer (Topwert, ab da wieder auf 0) 
vorher 7fff
  TCCR1A  |= ((1<<COM1A1) | (1<<COM1B1));  //Bei Wert ICR1 auf 1 und bei 
wert OCR1a/-B auf 0  -> PINS im DDR definieren!!

  TCCR1A |= (1<<WGM11);          //----------------------------
  TCCR1B  |=((1<<WGM12) | (1<<WGM13));  //--------PWM als fast-Mode PWM 
konfg

  TCCR1B |= (1<<CS11);        //Taktvorteiler 8
  TCNT0=0;
}
uint8_t taster(uint8_t Nr)
{
  switch(Nr)
  {
    case 1://taster1
        if(!(PIND & (1<<PD2)))//an
        {
          return 1;
        }
        else return 0;
        break;//herausspringen aus Schlaufe

    default: return 0;//Wert, der bei keiner übereinstimmung 
zurückgegeben wird

    case 2://taster2
        if(!(PIND & (1<<PD3)))//an
        {
          return 1;
        }
        else return 0;
        break;

    case 3://taster3
        if(!(PIND & (1<<PD4)))//an
        {
          return 1;
        }
        else return 0;
        break;
  }//end of switch
}//ende void taster


uint8_t adc(uint8_t Nr)
{
  ADMUX&=~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3));//adc kanal 
zurücksetzen
  switch(Nr)
    {
      case 1:
      {
          ADMUX|= (1<<MUX2);

      }
      break;//herausspringen aus Schlaufe
      case 2:
      {
          ADMUX|= ((1<<MUX0)|(1<<MUX1));
      }
      break;

    }//end of switch
    ADCSRA|=(1<<ADSC);//startet messung
    while((ADCSRA & (1<<ADSC)));
    return ADCH;
}

uint8_t akkuadc(void)
{
  ADMUX&=~((1<<MUX0)|(1<<MUX1)|(1<<MUX2)|(1<<MUX3));//adc kanal 
zurücksetzen
  ADMUX|=(1<<MUX1);
  ADCSRA|=(1<<ADSC);//startet messung
  while((ADCSRA & (1<<ADSC)));
  return ADCH;
}

von Peter D. (peda)


Lesenswert?

Antwort schreiben
Wichtige Regeln - erst lesen, dann posten!

    Groß- und Kleinschreibung verwenden
    Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

1
C-Code

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.