mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Problem Drehgeber Rechnen + Senden RS232


Autor: PicNeuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
/** I N C L U D E S **********************************************************/
#include "p18f2550.h"  // PIC- Header
#include "delays.h"     // für Warteschleifen
#include "usart.h"    // für RS232- Schnittstelle

/** Configuration Fuses********************************************************/
#pragma config FOSC = HS      // CPU=20 MHz
#pragma config PWRT = ON      // PowerOnTimer AN   
#pragma config BOR = OFF      // BOR AUS
#pragma config WDT = OFF      // Watchdog Timer
#pragma config LVP = OFF      // Low Voltage ICSP AUS
#pragma config PBADEN = OFF      // PORTA Analogeingänge AUS
#pragma config VREGEN = OFF      // VREGEN AUS
#pragma config MCLRE = ON      // Master Reset AN
#pragma config PLLDIV = 1      // PLLTeiler = 1 => 20 MHz
#pragma config CPUDIV = OSC1_PLL2  // OSCTeiler = 1 => 20 MHz
#pragma config USBDIV = 1      // CPUTeiler = 1 => 20 MHz

/** Globale Variablendeklarationen**********************************************************/
signed long int counter = -18946;      // Zählvariable
signed long int ncounter = 0;        // Hilfsvariable
char gray_code = 0;              // Einlesevariable
char gray_help = 0;              // Vergleichsvariable
char ch0, ch1, ch2, ch3, ch4, ch5, ch6;    // Sendevariablen
int s1 = 0, s2 = 0, s3 = 0, s4 = 0, s5 = 0; // Counterstellenvariablen
#define Takt 200000000            // Quarz HS 20 MHZ an OSC1- OSC2
#define Baud 57600               // Baudrate über SPBRG eingestellt 1 BIT = 1,74 µs

/** Programm **************************************************/
#pragma code

void InitUsart(void)    
{
  SPBRG = 20;        // Baudrate 57600 Baud  SPBRG- Berechnung  59524 = 20000000/(16*(20+1)) = Fehlerquote unter 5%
  SPBRGH =  0;      // 8 Bit Übertragung      
  TRISCbits.TRISC6 = 1;  // Aktivierung Senden TXD
  TRISCbits.TRISC7 = 1;  // Aktivierung Empfangen RXD
  RCSTA = 0b10000100;    // Empfangsregister konfigurieren
  TXSTA = 0b00100100;    // Senderegister konfigurieren
  return 0;
}

void PICConfig(void)
{
  // PORTA => Ausgänge LEDs RA0, RA4, RA5
  TRISA = 0x00;
  PORTA = 0x00;
  LATA  = 0x00;
  
  // PORTB  => Eingänge Inkrementalgeber
  TRISB = 0xFF;
  PORTB = 0x00;
  LATB  = 0x00;

  // PORTC => alles Ausgänge  RC0, RC1, RC2
  TRISC = 0x00;   
  PORTC = 0x00;
  LATC  = 0x00;
  return 0;
}

void Senden(unsigned char byte)
{
  WriteUSART(byte);              // Byte in RS232 Sendebyte schreiben
  while(BusyUSART( ));            // Warten bis Sendebyte leer
  return 0;
}

signed long int Counter(void)
{
    gray_code = PORTBbits.RB0;        //A1      X
    gray_help = gray_code << 1;          //       X0    
    gray_code = gray_help | PORTBbits.RB1;  //B1     XY
    gray_help = gray_code << 1;         //      XY0
    Nop();                  // 0,2 µs Warten
    gray_code = gray_help | PORTBbits.RB0;  //A2    XYZ
    gray_help = gray_code << 1;         //     XYZ0
    gray_code = gray_help | PORTBbits.RB1;  //B2   XYZW
    Nop();                  // 0,2 µs Warten
    switch (gray_code)
    {
      case 0b00000001: 
        counter--;
        break;
      case 0b00000010: 
        counter++;
        break;
      case 0b00000100: 
        counter--;
        break;
      case 0b00000111: 
        counter++;
        break;
      case 0b00001101: 
        counter--;
        break;
      case 0b00001110: 
        counter++;
        break;
      case 0b00001000: 
        counter--;
        break;
      case 0b00001011: 
        counter++;
        break;
    }      // Ende Switch- Anweisung
    return counter;
}

char InttoChar(int counter)
{
   ncounter = counter;
   ch0 = 0;
   ch1 = 0;
   ch2 = 0;
   ch3 = 0;
   ch4 = 0;
   ch5 = 0;
     if(counter == 0 || counter > 0)
     {
                ch0 = '+';
     }
     if (counter < 0)
     {
                 ch0 = '-';
                 counter = (counter*(-1));
     }            
    for(;counter > 9999;counter -= 10000)
    {s1++;}
    for(;counter > 999;counter -= 1000)
    {s2++;}
    for(;counter > 99;counter -= 100)
    {s3++;}
    for(;counter > 9;counter -= 10)
    {s4++;}
    for(;counter > 0;counter -= 1)
    {s5++;}
    ch1 = s1 + 0x30;
    ch2 = s2 + 0x30;
    ch3 = s3 + 0x30;
    ch4 = s4 + 0x30;
    ch5 = s5 + 0x30;
  ch6 = '#'; 
    s1, s2, s3, s4, s5 = 0;           // Counterstellenvariablen nullen
    return ch0, ch1, ch2, ch3, ch4, ch5, ch6;  // Rückgabe von chars
}

void main(void)
{
  PICConfig();          // Konfigurieren der PORTs
  InitUsart();          // Start der USART- Schnittstelle
  PORTCbits.RC0 = 1;        // Anschalten EIN/Aus Lampe
  //InttoChar(counter);        // Zähler in chars zum Senden umwandeln
  //loop
  while(1)              //Hauptprogramm
  {
    //Counter();            // Zählen
    InttoChar(counter);          // Zähler in chars zum Senden umwandeln
    counter = ncounter;
    Nop();                // Warten
    Nop();                // Warten
    Senden(ch0);            // Senden Vorzeichen
    Senden(ch1);            // Senden Zehntausender
    Senden(ch2);            // Senden Tausender
    Senden(ch3);            // Senden Hunderter
    Senden(ch4);            // Senden Zehner
    Senden(ch5);            // Senden Einer
    Senden(ch6);            // Senden Trennzeichen
  }                // Ende Endlosschleife
  return 0;
 }                  /* Ende Mainfunktion */

Anbei mein Code!

Das Auslesen des Drehgebers funktioniert. Auch Das umrechnen von int inc 
char und auch das Senden der einzelnen Chars.


Alles funktioniert. Aber ohne die Schleife.

Sobald ich mein Inttochar() Funktion in die Schleife packe. KOmmt am PC 
nur noch Mist an. ICh weiß nicht mehr weiter. Kann sich das einer 
erklären!?

Zum Testen habe ich den Counter manuell beladen ( =-12856) for der 
Schleife umgewandelt und dann in die Schleife => Unendliches Senden. 
Funktioniert perfekt.

Doch sobal ich das Umrechnen in die Schleife schiebe, funktioniert gar 
nix mehr;-(

Hat vielleicht jemand ne Idee?

Grüße Pascal

Autor: Josef Schneider (chnaideur)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
InttoChar() enthaelt eindeuting fehler:
In C kann man Variablen nicht zur gleichen zeit aendern (normaler 
weise).

s1, s2, s3, s4, s5 = 0;

wird

s1 = 0;
s2 = 0;
etc.

Man kann auch nicht mehrere Variablen von einer function zurueck 
schicken - brauchst du hier sowieso nicht da ch1 - ch6 global deklariert 
sind; du kannst sie ueberall im Programm benutzen.
InttoChar() schaut sonst aus als ob es funktionieren sollte, koennte 
aber viel eleganter sein (mit for loop und einem array)

Ich hoffe das hilft!
Josef

Autor: olaf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht sollte man auch mal den Compiler
wechseln. Ich finde es bemerkenswert das
bei soetwas:

>  return ch0, ch1, ch2, ch3, ch4, ch5, ch6;  // Rückgabe von chars

nicht sofort beim Compiler die Alarmglocken angehen.
Oder handelt es sich um das typische
Nachwuchsproblem? (aka: Kann posten aber nicht lesen,
z.b Fehlermeldungen)

Olaf

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
olaf schrieb:
>>  return ch0, ch1, ch2, ch3, ch4, ch5, ch6;  // Rückgabe von chars
>
> nicht sofort beim Compiler die Alarmglocken angehen.
> Oder handelt es sich um das typische
> Nachwuchsproblem? (aka: Kann posten aber nicht lesen,
> z.b Fehlermeldungen)

Da gibt es keine Fehlermeldung.
Es ist in C erlaubt, Anweisungen durch Komma zu trennen. Der 
Rückgabewert ist dann die letzte Anweisung ch6.


Peter

Autor: PicNeuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke für die schnelle Hilfe.

Hab eureTipps befolgt und jetzt funktioniert, das immerwährende Senden.

Es lag daran, dass meine Stellenvariablen s1 - s5 global definiert waren 
und somit immer irreale zufällige Werte annahmen. Hab sie nur lokal in 
der Funktion deklariert und jetzt gehts.

Jetzt muss ich mich nur noch ans Zählen machen.
Da hätt ich auch das gleiche Problem:
Hier nochmla die FUnktion
void Counter(void)
{
        gray_code = PORTBbits.RB0;                //A1      X
        gray_help = gray_code << 1;                  //       X0       
        gray_code = gray_help | PORTBbits.RB1;    //B1     XY
        gray_help = gray_code << 1;                 //      XY0
        Nop();                                    // 0,2 µs Warten
        gray_code = gray_help | PORTBbits.RB0;    //A2    XYZ
        gray_help = gray_code << 1;                 //     XYZ0
        gray_code = gray_help | PORTBbits.RB1;    //B2   XYZW
        Nop();                                    // 0,2 µs Warten
        switch (gray_code)
        {
            case 0b00000001:
                counter--;
                break;
            case 0b00000010:
                counter++;
                break;
            case 0b00000100:
                counter--;
                break;
            case 0b00000111:
                counter++;
                break;
            case 0b00001101:
                counter--;
                break;
            case 0b00001110:
                counter++;
                break;
            case 0b00001000:
                counter--;
                break;
            case 0b00001011:
                counter++;
                break;
        }            // Ende Switch- Anweisung
        return counter;
}
Meine Codelogik funktioniert irgendwie nicht.

Was passiert, wenn ich die Eingänge in ein char speichere?

Speichert der PIC für ein High eine 1 bzw. 0b0000001 / 0x01 ? oder eine 
ASCI CODE EINS?

Daran hängts bei mir gerade noch.

Weil er bei mir willkürlich und langsam vor und zurück zählt.

Grüße

Pascal

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PicNeuling schrieb:

> Was passiert, wenn ich die Eingänge in ein char speichere?
>
> Speichert der PIC für ein High eine 1 bzw. 0b0000001 / 0x01 ? oder eine
> ASCI CODE EINS?

Ein char ist auch nichts anderes als eine Variable, die einen kleinen 
Integer speichern kann, lediglich bei I/O (also printf, scanf und 
Konsorten) wird ein char anders behandelt.

Du solltest dir aber angewöhnen, für alles was in Wirklichkeit Bytes 
sind, immer 'unsigned char' zu benutzen. Bei char alleine ist nicht 
festgelegt, ob da jetzt ein Vorzeichen berücksichtigt wird oder nicht. 
Je nachdem können Schiebeoperationen mächtig in die Hose gehen.

Wenn du in einen char die Zahl 1 speicherst, dann steht da auch das 
Bitmuster für die Zahl 1 drinnen.

>
> Daran hängts bei mir gerade noch.

Es hängt bei dir daran, dass du kein C-Buch hast, welches dir die 
Grundlagen von C beigebracht hat.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PicNeuling schrieb:

> Weil er bei mir willkürlich und langsam vor und zurück zählt.

Sieh dir mal diese Sequenz an
        gray_code = PORTBbits.RB0;                //A1      X
        gray_help = gray_code << 1;                  //       X0       
        gray_code = gray_help | PORTBbits.RB1;    //B1     XY
        gray_help = gray_code << 1;                 //      XY0
        Nop();                                    // 0,2 µs Warten
        gray_code = gray_help | PORTBbits.RB0;    //A2    XYZ
        gray_help = gray_code << 1;                 //     XYZ0
        gray_code = gray_help | PORTBbits.RB1;    //B2   XYZW
        Nop();                                    // 0,2 µs Warten

        switch (gray_code)

Aha. Du denkst tatsächlich, dass dein Benutzer den Drehgeber exakt in 
den 0.2µs drehen wird, die du ihm dafür Zeit gibst, während er in den 
restlichen Millisekunden, die du fürs UART senden brauchst, drehen kann 
wie ein Verrückter und nichts passiert.

Dein Code kann nur Veränderungen feststellen, die sich zeitlich nach dem 
erstmaligen Abfragen hier
        gray_code = PORTBbits.RB0;                //A1      X
        gray_help = gray_code << 1;                  //       X0       
        gray_code = gray_help | PORTBbits.RB1;    //B1     XY
        gray_help = gray_code << 1;                 //      XY0
        Nop();                                    // 0,2 µs Warten

und dem nächsten Abfragen hier
        gray_code = gray_help | PORTBbits.RB0;    //A2    XYZ
        gray_help = gray_code << 1;                 //     XYZ0
        gray_code = gray_help | PORTBbits.RB1;    //B2   XYZW
        Nop();                                    // 0,2 µs Warten

        switch (gray_code)

ereignet haben.
Alles andere kriegt er nicht mit.

Autor: PicNeuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab ein C- Buch.


Mir gehts es um das Problem:



char c1 = PORTBbits.RB0;
char c2 = PORTBBIts.RB1;

Wenn ein Lowpegel anliegt (0V) => Was ist in c1 und c2 gespeichert.
Wenn ein Highpegel anliegt (2,5V => Schmitttrigger erkennt es ls High) 
=> Was ist in c1 und c2 gespeichert?
Für Highpegel:
c1 = 1;
oder
c1 = '1' bzw. c1 = 0x31 bzw. c1 = 61;

Für Lowpegel:
c1 = 0;
oder
c1 = '0' oder c1 = 0x30 bzw. c1 = 60;

Welche Zeile speichert der PIC?

Ich weiß einfach nicht wie der PIC den Highpegel interpretiert und ich 
keinem Buch finde ich etwas.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PicNeuling schrieb:
> Ich hab ein C- Buch.
>
>
> Mir gehts es um das Problem:
>
>
>
> char c1 = PORTBbits.RB0;
> char c2 = PORTBBIts.RB1;
>
> Wenn ein Lowpegel anliegt (0V) => Was ist in c1 und c2 gespeichert.

0

> Wenn ein Highpegel anliegt (2,5V => Schmitttrigger erkennt es ls High)
> => Was ist in c1 und c2 gespeichert?

1

> Für Highpegel:
> c1 = 1;
> oder
> c1 = '1' bzw. c1 = 0x31 bzw. c1 = 61;

Wo sollen die her komme?

Nochmal. Ein char ist ein (kleiner) Integer. Wenn du dort ein Bit setzt, 
dann setzt du ein Bit. Nur weil das Teil char heisst, tauchen da nicht 
magisch irgendwelche ASCII Zeichen auf.

Autor: PicNeuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@kbuchegg

Danke für die Char Antwort. Das wollte ich wissen.

Ok das mit dem Abfragen erscheint mir logisch.

Das muss per Timerinterrupt geschehen, oder?

Doch was muss genau in die Interruptroutine und wie aktiviere ich sie!? 
Nur bei A?


grüße
PAscal

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
PicNeuling schrieb:
> @kbuchegg
>
> Danke für die Char Antwort. Das wollte ich wissen.
>
> Ok das mit dem Abfragen erscheint mir logisch.
>
> Das muss per Timerinterrupt geschehen, oder?

Kann, muss nicht (fürs erste).
Ein erster Erfolg wäre es, wenn in der Funktion der aktuelle Zustand des 
Drehgebers mit dem Zustand des Drehgebers im vorhergehenden 
Funktionsaufruf verglichen werden würde.
Vorausgesetzt die Funktion wird häufig genug aufgerufen, kann dir somit 
keine Veränderung am Drehgeber mehr durch die Lappen gehen.

Autor: PicNeuling (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier ist meine überarbeitete Funktion

char codenew=0;              // Neuer Zustand
char gray_help = 0;      // Hilfvariable
char codeold = 0;            // Alter Zustand
char code = 0;              // Graycode
void Counter(void)
{
    codenew = PORTBbits.RB0;        //A1      X
    gray_help = codenew << 1;        //       X0
    codenew = gray_help | PORTBbits.RB1;  //B1     XY
    codeold = codenew << 2;          //     XY00
    code = codeold | codenew;
    switch (code)
    {
      case 0b00000001:
        counter--;
        break;
      case 0b00000010:
        counter++;
        break;
      case 0b00000100:
        counter--;
        break;
      case 0b00000111:
        counter++;
        break;
      case 0b00001101:
        counter--;
        break;
      case 0b00001110:
        counter++;
        break;
      case 0b00001000:
        counter--;
        break;
      case 0b00001011:
        counter++;
        break;
    }      // Ende Switch- Anweisung

    return 0;
}

Ist der Code logisch korrekt?

Countr wird in einer while(1) schleife Augerufen?

grüße

PAscal

Autor: PicNeuling (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hi @all

Danke erstmal für die Hilfe.
Mein Programm funktioniet jetzt. Doch leider ist das Auslesen des 
Drehgebers viel zu langsam. (Er hat 5000 Schritte pro Umdrehung).

Also muss ich doch auf den Interrupt umzwischen.

Ich denke mal, das logischte wäre ein PORTB-ON-CHANGE Interrupt der bei 
einem Highsignal von A (also RB0) in diese InterruptServiceroutine geht, 
oder?

zum Aktivieren der Interrupts, reicht
    // PORTB-ON-CHANGE-INTERRUPT konfigurieren
    INTCON  = 0x11001000;
    INTCON2 = 0x10000001;
oder?

nun nehme ich einfach meine Counter funktion und packe sie in die ISR, 
oder?

void Interrupt(void)
{
  new = (PORTBbits.RB0<<1) | (PORTBbits.RB1);

code = (old<<2) | (new);
  switch (code)
  {
  case 0b00000001: counter++;  break;
  case 0b00000111: counter++;  break;
  case 0b00001110: counter++;  break;
  case 0b00001000: counter++;  break;

case 0b00000010: counter--;  break;
  case 0b00000100: counter--;  break;
  case 0b00001101: counter--;  break;
  case 0b00001011: counter--;  break;
  }  // Ende Switch- Anweisung
  old = new;
 flag=1;

INTCON.RBIF = 0;
 return 0;
}

Doch wenn der PIC die Routine abgearbeitet hat, wo steht er dann 
innerhalb der main- funktion!?

Denn wenn er an die letzte Stelle vom Programm springt, an der er gerade 
war.

Brauche ich ja meine Endlosschleife noch, die immer int in char 
umrechnet und sendet,oder!?

Reicht das schon?


Echt nochmal und schonmal vielen vielen Dank für eureHilfe

Grüße

Also hat vielleicht jemand so eine allgemeine Interruptroutine und 
Konfiguration

Pascal

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
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
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 bestätigst du, die Nutzungsbedingungen anzuerkennen.