Forum: Mikrocontroller und Digitale Elektronik Datenübertragung über Centronics-Schnittstelle


von Carsten (Gast)


Lesenswert?

Hallo,

ich habe mir ein kleines Assembler und C++ - Programm geschrieben, mit 
dem ich Zahlen in der Größe eines Bytes vom PC über die parallele 
Schnittstelle in den Mikrocontroller übertragen kann. Das C++ - Programm 
ist eine Konsolenanwendung, bestehend aus „DataExchange.h“ 
und „DataExchange.cpp“, die ich mit Visual C++ compiliert 
habe.
Die Assembler Datei heißt PCtoMC.asm

Die über eingelesene Zahl wird auf LEDs über PORT B ausgegeben. Über 
PORT D wird die bisher eingegebene Zahl ausgegeben.
Im Prinzip funktioniert das Zusammenspiel recht gut. Allerdings wenn vom 
PC eine Zahl größer 224 gesendet wurde und danach eine Zahl unter 32 
(z.B. 8) ausgegeben werden soll wird vom MC Null ausgegeben. Beim 2. 
Versuch ist alles OK.
Mein Eindruck ist, daß mit der Speicherverwaltung des MC etwas nicht 
stimmt, kann aber keinen Fehler finden. Die Verzweigungen sind 
vielleicht etwas unelegant programmiert, aber ich habe versucht mit 
möglichst wenig RJMP-Befehlen auszukommen.

Vielleicht findet einer von Euch den Fehler

Carsten



C++ Dateien :

Header-Datei „DataExchange.h“

/*Programm zur Eingabe bzw. Übernahme von 8Bit-Zahlen vom 
Mikrocontroller (MC) zum PC und umgekehrt.
 Das MSB-Bit (Bit 7) wird zuerst übertragen

-> Belegung der Leitungen beim Senden der Daten vom PC zum MC
Eingabeleitungen vom PC:
X0: Datenleitung (Data0)
X1: Taktsignal, das erste Bit wird mit HIGH-Pegel gesendet (Data1)
X2: Byte korrekt gesendet (Data3)
X3: Empfangsbereitschaft auslösen durch HIGH-Pegel (Data2)

Empfangsleitung zum PC:
X4: Datenleitung (ERROR)
X5: Taktsignal (SELECT)
X6: Byte erfolgreich empfangen (PAPER EMPTY)
X7: Mikrocontroller ist empfangsbereit (ACKNOWLEDGE)
*/

#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <windows.h>  //Für Sleep-Funktion



//*******************************************************************
class DataExchange
//*******************************************************************
{
  public:

    //Schnittstellenfunktionen
    //Verbindung zum Mikrocontroller herstellen
    int ConnectToMC(void);
    //Übernahme der an den MC zu sendenden Daten
    int DataToSend(int DataToMC);
    //Ausgabe der vom MC eingelesenen Daten
    int DataReadFromMC(void);
    //Verbindung zum Mikrocontroller beenden
    void DisconnectMC(void);

    DataExchange();
    ~DataExchange();

  private:

    //Sende- und Empfangsfunktionen
    int SendDataToMC(void);  //Sendevorgang einleiten
    //Kontrollfunktionen
    //Prüfen Antworten MC beim Senden Daten PC an MC
    int ControlSendToMC(unsigned int Flag);
    //Prüfen Antworten MC beim Einlesen Daten vom MC an PC
    int ControlReadFromMC(unsigned int Flag);
    //allgemeine "Konstanten"
    int PORT;    //LPT1
    int HIGH, LOW;  //Spannungspegel

    //Konstanten für Meldungen PC an MC
    int CONNECT;  //Sendenbereitschaft auf DATA2

    //Konstanten für Meldung MC an PC
    int MCREADY;    //Bereitschaft MC auf Acknowledge
    int MCBYTEOK;    //MC hat Byte korrekt empfangen/gesendet 
(PaperEmpty)
    int PCBYTEOK;    //PC hat Byte korrekt empfangen/gesendet
    int MCTAKT;      //Taktsignal auf Select
    int MCDATA;      //Datensignal auf Error

    //Fehlermeldungen
    int NO;        //Kein Fehler aufgetreten
    int YES;

    //Variablen
    int ByteIO, BitIO;      //Übertragenes Bit bzw. Byte
    int Fehler;          //Fehler bei Übertragung?
    int MsgToMC, MsgFromMC;    //Übertragung zum und vom 
Mikrocontroller
    int TaktMC, TaktPC;      //Taktsignal und übertragenes Bit
    time_t t_start, t_aktuell;
};
//-------------------------------------------------------------------

//*******************************************************************
DataExchange::DataExchange()
//Konstruktor
//*******************************************************************
{
  //Initialisierung der Konstanten
  PORT = 0x378;
  HIGH = 1;
  LOW = 0;
  NO = 0;
  YES = 1;

  CONNECT = 8;  //Data3
  PCBYTEOK = 4;  //Data2


  MCREADY = 64;  //ACKNOWLEDGE
  MCBYTEOK = 32;  //PAPER EMPTY
  MCTAKT = 16;  //SELECT
  MCDATA = 8;    //ERROR nicht benutzt
  return;
}
//-------------------------------------------------------------------

//*******************************************************************
DataExchange::~DataExchange()
//Destruktor
//*******************************************************************
{
  _outp(PORT, 0);
  return;
}
//-------------------------------------------------------------------


//*******************************************************************
int DataExchange::DataToSend(int DataToMC)
//*******************************************************************
{
  ByteIO = DataToMC;
  //Bitweises Senden der Daten
  Fehler = SendDataToMC();
  return Fehler;
}
//-------------------------------------------------------------------


//*******************************************************************
int DataExchange::ConnectToMC(void)
//*******************************************************************
{
  MsgToMC = CONNECT;
  _outp(PORT, MsgToMC);
  time(&t_start);
  for(;;)
  {
    MsgFromMC = _inp(PORT+1);
    //MsgFromMC so umformen, daß an gesetzen Eingängen
    //eine "1" steht
    MsgFromMC = MsgFromMC ^ 128;
    MsgFromMC = MsgFromMC & 248;
    MsgFromMC = ~MsgFromMC;
    MsgFromMC = MsgFromMC - 7;

    if((MsgFromMC & MCREADY) == MCREADY)
    {
      Fehler = NO;
      break;
    }
    //Bei Zeitüberschreitung Fehlermeldung
    time(&t_aktuell);
    if((t_aktuell - t_start) > 3)
    {
      Fehler = YES;
      break;
    }
  }
  return Fehler;
}
//-------------------------------------------------------------------

//*******************************************************************
void DataExchange::DisconnectMC(void)
//*******************************************************************
{
  _outp(PORT, 0);
  return;
}
//-------------------------------------------------------------------



//*******************************************************************
int DataExchange::SendDataToMC(void)
//*******************************************************************
{

  //ByteOut wird Bitweise ausgegeben
  //Maske zum Bitweisen senden von ByteOut
  unsigned int Mask, Flag;
  Mask = 128; //Zur Prüfung auf MSB-Bit Bit7

  for(Flag = 1; Flag < 9; Flag++)
  {
    if(Flag % 2)
      TaktPC = HIGH;
    else
      TaktPC = LOW;

    if((ByteIO & Mask) == 128)
      BitIO = HIGH;
    else
      BitIO = LOW;

    //Ausgabe des Bits, DATA0 = Bit, DATA1 = Takt, DATA2 = Sendebereit
    MsgToMC = BitIO + 2 * TaktPC + CONNECT;
    _outp(PORT, MsgToMC);
    //Sleep(500);
    //Prüfen, ob Bit oder Byte angekommen ist
    Fehler = ControlSendToMC(Flag);
    if(Fehler != NO)
      break;
    //ByteOut nach links shiften
    ByteIO = ByteIO << 1;
  }
  return Fehler;
}
//-------------------------------------------------------------------

//*******************************************************************
int DataExchange::DataReadFromMC(void)
//*******************************************************************
{

  return ByteIO;
}
//-------------------------------------------------------------------


//*******************************************************************
int DataExchange::ControlSendToMC(unsigned int Flag)
//*******************************************************************
{
  time(&t_start);
  for(;;)
  {
    MsgFromMC = _inp(PORT+1);
    //MsgFromMC so umformen, daß an gesetzen Eingängen
    //eine "1" steht
    MsgFromMC = MsgFromMC ^ 128;
    MsgFromMC = MsgFromMC & 248;
    MsgFromMC = ~MsgFromMC;
    MsgFromMC = MsgFromMC - 7;

    //Feststellen des Taktes vom Mikrocontroller
    if((MsgFromMC & MCTAKT) == MCTAKT)
      TaktMC = HIGH;
    else
      TaktMC = LOW;

    //Ist das Bit erfolgreich angekommen, muß der TaktMC
    //wechseln und gleich dem TaktPC werden.
    if((Flag < 8) & (TaktMC == TaktPC))
    {
      Fehler = NO;
      break;
    }
    //Prüfen, ob Byte vom Mikrocontroller vollständig eingelesen wurde
    //Falls ja erfolgt Rückmeldung an MC
    if((Flag == 8) & ((MsgFromMC & MCBYTEOK) == MCBYTEOK))
    {
      Fehler = NO;
      MsgToMC = PCBYTEOK + CONNECT;
      _outp(PORT, MsgToMC);
      Sleep(50);
      //Weiter Sendebereitschaft PC anzeigen
      MsgToMC = CONNECT;
      _outp(PORT, MsgToMC);
      break;
    }

    //Bei Zeitüberschreitung Fehlermeldung
    time(&t_aktuell);
    if(t_aktuell - t_start > 5)
    {
      Fehler = YES;
      cout << "\nFehler bei Bit = " << Flag << "\n";
      break;
    }
  }
  return Fehler;
}
//-------------------------------------------------------------------


cpp-Datei  &#8222;DataExchange.cpp&#8220;:

#include "DataExchange.h"


//*******************************************************************
void main(void)
//*******************************************************************
{
  int Fehler, ByteOut, Flag;
  DataExchange DatenSenden;
  _outp(0x378, 0);
  cout << "\nDaten senden (1 = senden)? = ";
  cin >> Flag;
  if(Flag == 1)
  {
    Fehler = DatenSenden.ConnectToMC();
    if(Fehler == 1)
    {
      cout << "\nKeine Verbindung zum Mikrocontroller!\n";
      DatenSenden.DisconnectMC();
      cout << "\nProgramm beendet.\n";
      return;
    }
  }
  if(Flag == 1)
  {

    for(;;)
    {
      cout << "\nBei Zahlen > 255 und < 0 erfolgt Programmabbruch!\n";
      cout << "\n\nEingabe Zahl < 256 = ";
      cin >>   ByteOut;
      if((ByteOut > 255) || (ByteOut < 0))
        break;

      Fehler = DatenSenden.DataToSend(ByteOut);
      if (Fehler == 1)
      {
        cout << "\nFehler bei Datenuebertragung!\n";
        DatenSenden.DisconnectMC();
        cout << "\nProgramm beendet.\n";
        return;
      }
    }
  }
  DatenSenden.DisconnectMC();
  cout << "\nProgramm beendet.\n";
  return;
};
//-------------------------------------------------------------------


Assembler-Datei für Mikrocontroller &#8222;PCtoMC.asm&#8220;:


;Programm zur Eingabe von 8Bit-Zahlen vom PC zum Mikrocontroller
;Das MSB-Bit wird zuerst eingelesen

;Sendeleitungen vom PC zum Mikrocontroller:
;X0: Datenleitung (Data0)
;X1: Taktsignal (Data1). Das erste Bit wird mit HIGH-Pegel gesendet. Bei 
den
;    folgenden Daten wird das Taktsignal jeweils zwischen HIGH und
;    LOW umgeschaltet. Auch im LOW-Takt wird ein Bit gesendet!
;X2: Byte vollständig gesendet (Data2)
;X3: Empfangsbereitschaft beim MC auslösen durch HIGH-Pegel. Dieser 
bleibt
;    ständig auf HIGH (Data3)


;Sendeleitung vom Mikrocntroller zum PC:
;X4: Datenleitung (ERROR), noch nicht benutzt
;X5: Taktsignal des Mikrocontrollers, zu Beginn der Sendebereitschaft
;    auf LOW. Dient zur Synchronisation mit PC (SELECT)
;X6: Byte vollständig empfangen  (PAPEREMPTY)
;X7: Mikrocontroller ist empfangsbereit. Bleibt ständig auf HIGH 
(ACKNOWLEDGE)

.include "4414def.inc"


;Benötigte Register:
.def Temp = R16
.def Count = R17

.def MsgPC = R18    ;Datensatz des aktuellen PC-Taktes
.def MsgPCOld = R19    ;Datensatz des vorherigenn PC-Taktes
.def MsgMC = R20    ;Datensatz des aktuellen MC-Taktes

.def ByteIO = R22    ;aktuell empfangenes Byte


;Benötigte Konstanten
.equ PCExch =        0b00001000  ;PC ist sendebereit
.equ MCExch =        0b10000000  ;MC ist empfangsbereit
.equ MCTakt =       0b00100000 ;Takt MC ist HIGH
.equ PCTakt =        0b00000010 ;Takt PC HIGH
.equ PCByteOK =      0b00000100 ;Byte vom PC erfolgreich gesendet
.equ MCByteOK =      0b01000000  ;Byte vom MC erfolgreich empfangen
.equ DataPC =        0b00000001 ; Datensignal

.equ BYTE =        0b00001000 ;Länge des Bytes = 8 Bit


;*********************************************************************** 
********
;Initialisierung
Initial:
    ;Port A wird als Ein- und Ausgang für die PC-Kommunikation genutzt
    ;PINs 0-3 als Eingänge, PINs 4-8 als Ausgänge des Controllers
    LDI Temp, 0b11110000
    OUT DDRA, Temp

    ;PORT B als Ausgang für Ausgabe des Bytes
    LDI Temp, 0xFF
    OUT DDRB, Temp
    ;PORT D als Ausgang
    OUT DDRD, Temp

    ;Alle Ports auf Null setzen
    LDI Temp, 0x00
    OUT PORTA, Temp
    OUT PORTB, Temp
    OUT PORTD, Temp
;----------------------------------------------------------------------- 
--------


;*********************************************************************** 
********
;Hauptprogramm

MAIN:  ;Abfrage des I/O-Ports im Polling-mode
    IN MsgPC, PINA
  ;Prüfen, ob Bit 3 gesetzt ist
  ANDI MsgPC, PCExch
  CPI MsgPC, PCExch
  BRNE  Main
  ;PC Sendebereitschaft anzeigen
  LDI MsgMC, MCExch
  OUT PORTA, MsgMC

  ;Rücksetzen Register
  LDI MsgPC, 0x00
  LDI MsgPCOld, 0x00
  LDI ByteIO, 0x00
  LDI Count, 0x00
  LDI Temp, 0x00
  LDI MsgMC, 0x00



GetBit: ;Bitweises Einlesen
  IN MsgPC, PINA
  ;Sendebereitschaft PC prüfen, prüfen, ob Bit 3 gesetzt ist
  MOV Temp, MsgPC
  ANDI Temp, PCExch
  CPI Temp, PCExch
  BRNE  Main


  ;Überprüfung Taktsignal durch Vergleich MsgPCOld/MsgPC
  ;Zuerst mit XOR auf ungleiche Pegel prüfen
  MOV Temp, MsgPCOld
  EOR Temp, MsgPC
  ;Wenn Bit 1 "1" ist war das Taktsignal in MsgFromPCOld ungleich
        ;MsgFromPCNew und ein neues Bit liegt vor
  ANDI Temp, PCTakt
  CPI Temp, PCTakt
  BRNE GetBit

  ;Einlesen des Bits, dazu ByteIO nach links schieben
  LSL ByteIO
  CLC  ;Carry-Flag sicherheitshalber löschen
  INC Count
  MOV Temp, MsgPC
  ANDI Temp, DataPC
  ADD ByteIO, Temp
  OUT PORTD, ByteIO  ;Ausgabe Zwischenergebnis

  ;Sichern MsgPC
  MOV MsgPCOld, MsgPC

  ;Rückmeldung MC an PC durch Taktwechsel
  ;Alle anderen Bits löschen
  ANDI MsgMC, MCTakt
  LDI Temp, MCTakt
  EOR MsgMC, Temp

  ;Bit 7 für Sendebereitschaft erhalten
  LDI Temp, MCExch
  ADD MsgMC, Temp

  OUT PORTA, MsgMC

  CPI Count, BYTE
  BRNE GetBit

  ;Byte vollständig eingelesen, Meldung an PC. Sendebereitschaft bleibt 
erhalten
  LDI MsgMC, MCExch
  LDI Temp, MCByteOK
  ADD MsgMC, Temp
  OUT PORTA, MsgMC

PCOK:  ;Meldung PC abwarten
  In MsgPC, PINA
  ANDI MsgPC, PCByteOK
  CPI MsgPC, PCByteOK
  BRNE  PCOK

  ;Byte ausgeben
  OUT PORTB, ByteIO


  RJMP Main
;----------------------------------------------------------------------- 
--------

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.