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
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
Datum:
Du zeigst viel zu viel Code nicht, als das man da irgendetwas verlässliches sagen könnte.
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.
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
Datum:
Du hast oben von ''hammer'' gesprochen...du erzeugst dabei einen Wackelkontakt ....und ein Reset !
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
Datum:
>Abgesehen von der Ineffizienz meines Codes muss sich da >irgendwo ein Fehler verbergen. Dann solltest du ihn am bsten komplett überarbeiten/neu schreiben...
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.
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.