www.mikrocontroller.net

Forum: Mikrocontroller und Elektronik Unerklärter Reset


Autor: Shibby (Gast)
Datum:

Hallo,

Ich habe dies vorher in ein weniger geeignetes Forum geschrieben, tut
mir Leid, nun noch mal.
Ich habe ein kleines Problem das ich nicht ganz verstehe. Ich arbeite an
einem Programm wo man per Tasten, verschiedene Buchstaben zu einer
String hinzufügen kann. Hat man 20 Characters erreicht, so bricht der
input loop ab und es geht in den output loop. Bis hier funktioniert
alles bestens da meine Entprellroutine gut funktioniert (ich entprelle
einfach mehrere Ports gleichzeitig). Nur manchmal wenn ich richtig stark
auf die taste hämmer sodass es ganz schnell geht, springt er wieder zum
Anfang des input modes zurück und ich habe keine Ahnung warum. Danach
kann ich auch noch so langsam drücken und das was beim output mode
erscheinen soll (ein paar LEDs leuchten dann auf) flackert nur kurz auf
und man ist wieder im input mode.

Ich programmiere einen ATmega 2560.

Hier ist mein main.c file:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "Defines.h"
#include "Timer0_Function_Prototypes.h"
#include "Port_Initialization_Function_Prototypes.h"
#include "InputProc_Function_Prototypes.h"
#include "Output_Function_Prototype.h"
#include "Key_Enum.h"

#define MAX_STRING_SIZE 20

int main(void)
{
  InitPorts();
  InitTimer();
  sei();

  // No key is pressed at the beginning.
  KeyPressed keyPressed = None;
  unsigned char debouncedStateE = 0xFF;
  unsigned char debouncedStateF = 0xFF;
  
  // Mode variables.
  bool inputMode = true;
  bool outputMode = false;

  // String to store characters.
  unsigned char inputString[MAX_STRING_SIZE];
  unsigned char stringSz = 0;

  while (inputMode)
  {
    debouncedStateE = GetDebouncedStateE();
    debouncedStateF = GetDebouncedStateF();
    
    if (GetInputE(&keyPressed, debouncedStateE))
      InputProc(keyPressed, inputString, &stringSz);  
    else if (GetInputF(&keyPressed, debouncedStateF))
      InputProc(keyPressed, inputString, &stringSz);
      
    // If the max string size has been reached, switch to output mode.
    if (stringSz > MAX_STRING_SIZE - 2)
    {
      inputMode = false;
      outputMode = true;
    }          
  }

  // Append terminating null character to string.
  inputString[MAX_STRING_SIZE - 1] = '\0';

  while (outputMode)
  {
    PORTB = 0xFF;
  }

  return 0;
}

das Programm fängt wieder beim Eingabe mode an. Ich habe ein paar tests
mit LEDs gemacht und bin mir ziemlich sicher dass das Programm total
resettet, wenn ich nämlich das MSB in PORTL einfach mal auf HI setze
nachdem input mode verlassen wird, ist dieses nicht mehr Gesetzt wenn
dieser "Reset" auftritt. Manchmal habe ich das Problem garnicht, dann
zieh ich den Vcc Stecker, steck ihn wieder rein und dann taucht manchmal
das Problem auf. Ich verstehe nicht wodurch das ausgelöst werden könnte.
Ich hoffe einer von euch hat vielleicht schon mal Erfahrung mit etwas
Ähnlichem gemacht.

Gruß,
Shibby
Autor: Shibby (Gast)
Datum:

Ich habe mich mal etwas schlauer gemacht. Ich denke kaum dass es an
einer unstabilen Spannungsquelle liegen kann. Ich benutze den ATmega2560
mit einem der Fertigboards von myAVR. Das Problem tritt sowohl bei
externer Spannungsquelle, als auch USB als Spannungsquelle auf.
Den Watchdog Timer habe ich nicht eingeschaltet (wie ja im Code zu sehe
ist). Auch die Ports die ich als input benutze (E und F) lösen denk ich
mal nicht einen Interrupt aus zu dem die ISR fehlt (was ja auch zum
reset führen würde). Laut Datenblatt haben die Pins dieser Ports zwar
spezielle Eigenschaften (zB für den AD-Wandler) aber diese muss man erst
aktivieren und das habe ich nicht getan.
Komisch ist halt, dass er direkt nach Ende der Eingabe den Reset
ausführt und ich kanns mir leider nicht erklären. Wenn auch irgend
jemand nur eine Vermutung hat, würde ich diese gerne hören.
Falls es hilft kann ich auch meinen gesamten Programmcode zur Verfügung
stellen.

Gruß,
Shibby
Autor: Karl Heinz Buchegger (kbuchegg) (Moderator)
Datum:

Du zeigst viel zu viel Code nicht, als das man da irgendetwas
verlässliches sagen könnte.
Autor: Lothar Miller (lkmiller) (Moderator) Benutzerseite
Datum:

> da meine Entprellroutine gut funktioniert
Da würde ich nochmal mit einem Fragezeichen ansetzen...

Und warum nimmst du nicht einfach nur 1 Zustandsvariable mode.
Wenn z.B. mode == 0 dann Input, wenn mode == 1 dann Output.
Autor: Shibby (Gast)
Datum:
Angehängte Dateien:

Danke für eure Antworten,

Ich habe den kompletten Code hinzugefügt und die ein oder andere
vorgeschlagene Änderung vorgenommen.

Falls ihr den Code nicht runterladen wollt, fasse ich hier die
wichtigsten .c Files mal zusammen:

main.c (Das Hauptprogramm)
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Defines.h"
#include "Timer0_Function_Prototypes.h"
#include "Port_Initialization_Function_Prototypes.h"
#include "InputProc_Function_Prototypes.h"
#include "Output_Function_Prototype.h"
#include "Key_Enum.h"

#define MAX_STRING_SIZE 20

int main(void)
{
  InitPorts();
  InitTimer();
  sei();

  // No key is pressed at the beginning.
  KeyPressed keyPressed = None;
  unsigned char debouncedStateE = 0xFF;
  unsigned char debouncedStateF = 0xFF;
  
  // Mode variable.
  unsigned char mode = 0;

  // String to store characters.
  unsigned char inputString[MAX_STRING_SIZE];
  unsigned char stringSz = 0;

  PORTL = 0x01;

  while (true)
  {
    while (mode == 0)
    {
      debouncedStateE = GetDebouncedStateE();
      debouncedStateF = GetDebouncedStateF();
    
      if (GetInputE(&keyPressed, debouncedStateE))
        InputProc(keyPressed, inputString, &stringSz);  
      else if (GetInputF(&keyPressed, debouncedStateF))
        InputProc(keyPressed, inputString, &stringSz);
      
      // If the max string size has been reached, switch to output mode.
      if (stringSz > MAX_STRING_SIZE - 2)
      {
        mode = 1;
      }          
    }

    // Append terminating null character to string.
    inputString[MAX_STRING_SIZE - 1] = '\0';

    PORTL = 0x80;

    while (mode == 1)
    {
      OutputString(inputString, stringSz);
    }
  }

  return 0;
}

Port_Initialization_Function.c (Ports konfigurieren)
#include <avr/io.h>
#include "Port_Initialization_Function_Prototypes.h"

void InitPorts(void)
{
  DDRB = 0xFF;
  PORTB = 0x00;

  DDRL = 0xFF;
  PORTL = 0x00;

  DDRE = 0x00;
  PORTE = 0xFF;

  DDRF = 0x00;
  PORTF = 0xFF;
}

Timer0_Functions.c (Alles was mit entprellen und dem Timer zu tun hat)
#include <avr/io.h>
#include <avr/interrupt.h>
#include "Defines.h"
#include "Timer0_Function_Prototypes.h"

#define MAXCHECKS 10

// state is used to compare the last MAXCHECKS states of the input port.
// index is used to index the array in the ISR.
volatile unsigned char statePORTE[MAXCHECKS];
volatile unsigned char statePORTF[MAXCHECKS];
volatile unsigned char stateIndex;

void InitTimer(void)
{
  // Fill arrays with 1's.
  for (int i = 0; i < MAXCHECKS; i++)
    statePORTE[i] = 0xFF;

  for (int i = 0; i < MAXCHECKS; i++)
    statePORTF[i] = 0xFF;

  stateIndex = 0;

  // Set register bits.
  TCCR0A = 0x02;
  TCCR0B = 0x04;
  OCR0A = 62;
  TIMSK0 = 0x02;
}

// This function is used when you want to know which switches are debounced or not (PORTE).
char GetDebouncedStateE(void)
{
  char debouncedState = 0x00;

  for (int i = 0; i < MAXCHECKS; i++)
    debouncedState |= statePORTE[i];

  return debouncedState;
}

// This function is used when you want to know which switches are debounced or not (PORTF).
char GetDebouncedStateF(void)
{
  char debouncedState = 0x00;

  for (int i = 0; i < MAXCHECKS; i++)
    debouncedState |= statePORTF[i];

  return debouncedState;
}

// Interrupt Service Routine.
ISR(TIMER0_COMPA_vect)
{
  // The ISR only updates the state array. Use GetDebouncedState to get current debounced status on port.
  // Very important: Only increment stateIndex after the LAST array has had it's value set!
  statePORTE[stateIndex] = PINE;
  statePORTF[stateIndex++] = PINF;

  if (stateIndex >= MAXCHECKS)
    stateIndex = 0;
}


In der ISR werden nur die beiden arrays aktualisiert. Wenn ich den
entprellten Status eines Ports haben möchte, dann verwende ich die
entsprechende Funktion (GetDebouncedStateE() oder GetDebouncedStateF()).
Ich weiß nicht mehr genau wie lange entprellt wird, da muss ich nochmal
meine Settings im Datenblatt überprüfen, aber ich glaube es sind 20ms
was meiner Ansicht nach völlig ausreichend ist.

InputProc_Functions.c (Die Funktionen die für die Verarbeitung des
Inputs verantwortlich sind)
#include <avr/io.h>
#include "Defines.h"
#include "Key_Enum.h"
#include "InputProc_Function_Prototypes.h"

bool GetInputE(KeyPressed* pKeyPressed, unsigned char debouncedStateE)
{
  // i represents the pin to be checked.
  for (int i = 0; i < 8; i++)
  {
    if (!(debouncedStateE & (1 << i)) && *pKeyPressed == None)
    {
      switch (i)
      {
        case 0:
          *pKeyPressed = Num0;
          return true;

        case 1:
          *pKeyPressed = Num1;
          return true;

        case 2:
          *pKeyPressed = Num2;
          return true;

        case 3:
          *pKeyPressed = Num3;
          return true;

         case 4:
          *pKeyPressed = Num4;
          return true;

         case 5:
          *pKeyPressed = Num5;
          return true;

         case 6:
          *pKeyPressed = Num6;
          return true;

         case 7:
          *pKeyPressed = Num7;
          return true;
      }
    }
    else if (debouncedStateE & (1 << i) && *pKeyPressed - 1 == i)
    {
      // If we arrive here, it means that the bit being checked is NOT set,
      // i.e. the button is not pressed or debounced BUT *pKeyPressed says that it is.
      // This means the key was previously pressed and was released.
      *pKeyPressed = None;
    }
  }

  // No changes in keys being pressed (on this port). Some might have been released.
  return false;
}

bool GetInputF(KeyPressed* pKeyPressed, unsigned char debouncedStateF)
{
  // i represents the pin to be checked.
  for (int i = 0; i < 8; i++)
  {
    if (!(debouncedStateF & (1 << i)) && *pKeyPressed == None)
    {
      switch (i)
      {
        case 0:
          *pKeyPressed = Num8;
          return true;

        case 1:
          *pKeyPressed = Num9;
          return true;

        case 2:
          *pKeyPressed = Plus;
          return true;

        case 3:
          *pKeyPressed = Minus;
          return true;

         case 4:
          *pKeyPressed = Multiply;
          return true;

         case 5:
          *pKeyPressed = Divide;
          return true;

         case 6:
          *pKeyPressed = LeftParenthesis;
          return true;

         case 7:
          *pKeyPressed = RightParenthesis;
          return true;
      }
    }
    else if (debouncedStateF & (1 << i) && *pKeyPressed - Num8 == i)
    {
      // Notice + Num8 here. Num8 and up are the integer values 9 and up in the enum KeyPressed.
      // If we arrive here, it means that the bit being checked is NOT set,
      // i.e. the button is not pressed or debounced BUT *pKeyPressed says that it is.
      // This means the key was previously pressed and was released.
      *pKeyPressed = None;
    }
  }

  // No changes in keys being pressed (on this port). Some might have been released.
  return false;
}  

// This function processes input.
void InputProc(KeyPressed keyPressed, unsigned char* pInputString, unsigned char* pStringSz)
{
  // "None" case cannont be handles as the function is never called under such a circumstance.
  switch (keyPressed)
  {
    case Num0:
      PORTB = 0x3F;
      pInputString[*pStringSz] = '0';
      break;
    
    case Num1:
      PORTB = 0x06;
      pInputString[*pStringSz] = '1';
      break;

    case Num2:
      PORTB = 0x5B;
      pInputString[*pStringSz] = '2';
      break;
    
    case Num3:
      PORTB = 0x4F;
      pInputString[*pStringSz] = '3';
      break;

    case Num4:
      PORTB = 0x66;
      pInputString[*pStringSz] = '4';
      break;
    
    case Num5:
      PORTB = 0x6D;
      pInputString[*pStringSz] = '5';
      break;

    case Num6:
      PORTB = 0x7D;
      pInputString[*pStringSz] = '6';
      break;
    
    case Num7:
      PORTB = 0x07;
      pInputString[*pStringSz] = '7';
      break;

    case Num8:
      PORTB = 0x7F;
      pInputString[*pStringSz] = '8';
      break;
    
    case Num9:
      PORTB = 0x6F;
      pInputString[*pStringSz] = '9';
      break;

    case Plus:
      PORTB = 0x73;
      pInputString[*pStringSz] = '+';
      break;

    case Minus:
      PORTB = 0x40;
      pInputString[*pStringSz] = '-';
      break;

    case Multiply:
      PORTB = 0x80;
      pInputString[*pStringSz] = '*';
      break;

    case Divide:
      PORTB = 0x52;
      pInputString[*pStringSz] = '/';
      break;

    case LeftParenthesis:
      PORTB = 0x39;
      pInputString[*pStringSz] = '(';
      break;

    case RightParenthesis:
      PORTB = 0x0F;
      pInputString[*pStringSz] = ')';
      break;
  }

  // Increment size by 1.
  (*pStringSz)++;
}

Die Prototypen der Funktionen in den einzelnen source files befinden
sich in den entsprechenden Header Dateien. Tut mir Leid dass die
Comments auf Englisch sind, aber Englisch kann ich nunmal leider etwas
besser als Deutsch :).

Ich hoffe mit Hilfe dieser Infos könnt ihr mir helfen, ich bin noch ein
Anfänger und befinde mich schnell in einem Loch wenn ich auf solche
Probleme stoße, aber ich versuche jeden Tag dazu zu lernen weil ichs
einfach sehr interessant finde.

Gruß,
Shibby
Autor: special swine flu (Gast)
Datum:

Du hast oben von ''hammer'' gesprochen...du erzeugst dabei einen
Wackelkontakt ....und ein Reset !
Autor: Shibby (Gast)
Datum:

Auch wenn ich mittelschnell auf die Taste drücke kommt es vor dass
dieser Reset ausgelöst wird. Ich habe grade den dritten Taster probiert
den ich vorher noch nicht verwendet habe und da ist der Reset auch
aufgetreten. Abgesehen von der Ineffizienz meines Codes muss sich da
irgendwo ein Fehler verbergen.

Gruß,
Shibby
Autor: STK500-Besitzer (Gast)
Datum:

>Abgesehen von der Ineffizienz meines Codes muss sich da
>irgendwo ein Fehler verbergen.

Dann solltest du ihn am bsten komplett überarbeiten/neu schreiben...
Autor: Shibby (Gast)
Datum:

Sehr lustig. Wenn ich das vorhaben würde interessiere ich mich trotzdem
für den Auslöser für den Reset. Wenn dein Auto total abkackt willste
doch bestimmt auch wissen was passiert ist damit du weißt worauf du beim
neuen besser achten muss.

Die InputProc_Functions.c Funktionen werde ich eh noch überarbeiten und
etwas schneller gestalten, aber ich bin meist etwas besessen von Fehlern
wenn sie auftreten.
Autor: Shibby (Gast)
Datum:

Also kleiner Update, die Spannungsquelle ist stabil. Der Reset wird nur
vom Input in den Pins: E4, F5, F6, F7 ausgelöst. Ich habe ins Datenblatt
geschaut aber da stand nichts was ich noch nicht über diese Pins wusste.
Ich habe auch beide Ports gewechselt und es sind immer noch diese Pins
als Übertäter aufgetreten. Deswegen bin ich von einem Softwarefehler
ausgegangen, kann aber bei den Input-Verarbeitenden Funktionen nichts
erkennen und bin daher ratlos, ich glaube ich schreibe das ganze Ding
wirklich nochmal neu, aber obs was bringt, keine Ahnung.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

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

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel




Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder GIF-Format hochladen.
Siehe Bildformate
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken erkennst du die Nutzungsbedingungen an.

webmaster@mikrocontroller.netImpressumNutzungsbedingungenWerbung auf Mikrocontroller.net