Einlesen China-Schieblehre

Codeoptimierung

  • 1
  • 2
  • Seite 1 von 2
rbr50
 
Avatar
 
Betreff:

Einlesen China-Schieblehre

 · 
Gepostet: 30.01.2012 - 14:32 Uhr  ·  #1
Hallo zusammen,

ich habe eine 10EUR-China-Schieblehre an meiner Drehbank zur Anzeige des Durchmessers fest montiert. Bisher lese ich die Schieblehre mit Unterstützung von Hardware aus. Ich lese die Daten zuerst in ein Schieberegister ein. Wenn dann Zeit ist, lese ich das Schieberegister wieder aus. Das fand ich nicht so elegant und will nun mit dem Mega32 allein auskommen.

Code

program DrehbankDRO;

{$NOSHADOW}
{ $WG}                     {global Warnings off}

Device = mega32, VCC = 5;
{ $BOOTRST $01E00}         {Reset Jump to $01E00}

Define_Fuses
//  Override_Fuses;
  NoteBook       = A;
  COMport        = USB;
  LockBits0      = [];
  FuseBits0      = [];
  FuseBits1      = [SPIEN];
  FuseBits2      = [];
  Autorelease    = true;

Import SysTick, SysLEDblink, Serport;

From System Import  LongInt;

Define
  ProcClock      = 16000000;       {Hertz}
  SysTick        = 0.5;             {msec}
  StackSize      = 200, iData;
  FrameSize      = 200, iData;
  SysLEDblink    = 255;              {SysTicks}
  SysLedBlink0   = PortB, 7, low;
  SysLedBlink1   = PortB, 6, low;
//  SysLedBlink2   = PortB, 5, low;

  Serport        = 19200, Stop1;


Implementation

{$IDATA}

{--------------------------------------------------------------}
{ Type Declarations }


{--------------------------------------------------------------}
{ Const Declarations }

{--------------------------------------------------------------}
{ Var Declarations }
{$IDATA}

var

  DataPin[@PIND, 3]    : bit;
  ClockPin[@PIND, 2]   : bit;
  LED[@PortB, 5] : bit;
  RelPos         : LongInt;
  Flaggen           : byte;
  SteigenderINT[@Flaggen, 0]    : bit;
   NeueDaten[@Flaggen, 1]    : bit;

  {--------------------------------------------------------------}
{ functions }


{--------------------------------------------------------------}
procedure SendEsc;
begin
  Write(serout, #27 );
  Write(serout, '[' );
end;

{--------------------------------------------------------------}
procedure Term_Send(c : char);
begin
  Write(serout, c);
end;
{--------------------------------------------------------------}
procedure Term_Erase_Screen;
begin
  SENDESC;                             // Send escape sequence start
  Term_Send( '2' );
  Term_Send( 'J' );
end;

//***************************
// Set cursor position
//
// Top-left is (1,1)
//***************************
procedure Term_Set_Cursor_Position( row, column : byte);
begin
  SENDESC;                                        // Send escape sequence start

  Write(serout, bytetostr(row) );              // Convert row byte
  Term_Send( ';' );
  Write(serout, bytetostr(column) );           // Convert column byte
  Term_Send( 'H' );
end;
{--------------------------------------------------------------}


//***************************
// Send 'clear end of line' sequence
//***************************
procedure Term_Erase_to_End_of_Line;
begin
  SENDESC;                             // Send escape sequence start

  Term_Send( 'K' );
end;

{--------------------------------------------------------------}

procedure InitPorts;
begin
  PortC:= %11000000;
  DDRC:=  %00000011;
  DDRD:=  %00000000;
  DDRB:=  %11100000;
  PortB:=  %11100000;

end InitPorts;

{--------------------------------------------------------------}


Interrupt INT0;
//wird angesprungen bei der steigenden Flanke eines neuen 2x24 Datenpaketes
//*** Interrupt wird erst nach ~800uSec wieder verlassen! ***
var
  bitval         : LongInt;
  b              : byte;
  BitZaehler     : byte;
begin

  NeueDaten:= false;
  GICR:= GICR and %10111111;  //Int0 aus
  BitZaehler:= 0;
  RelPos:= 0;
  while BitZaehler < 24 do //das erste 24er Paket ist nutzlos, da ABS-Position
    repeat
    until ClockPin = false; //auf fallende Flanke warten
    inc (BitZaehler);
    repeat
    until ClockPin = true;
  endwhile;
  
  bitval:= 1;
  BitZaehler:= 0;
  while BitZaehler < 24 do
    repeat
    until ClockPin = false; //auf fallende Flanke warten
    inc (BitZaehler);
    if DataPin = true then
      b:= 1;
      RelPos:= RelPos or  bitval;
    else
      b:= 0;
    endif;
    repeat
    until ClockPin = true; //auf steigende Flanke warten
    bitval:= bitval shl 1;
  endwhile;
  //Jetzt höchstwertiges Bit prüfen, wenn 1, dann 2er-Komplement
  //bilden.
  if  b = 1 then
    RelPos:= (RelPos or %11111111100000000000000000000000);
  endif;

  NeueDaten:= true;
  Toggle(LED);

end;



{--------------------------------------------------------------}
{ Main Program }
{$IDATA}

begin
  InitPorts;
  EnableInts;
  SysLEDflashOn(0);
  Term_Erase_Screen;
  Term_Set_Cursor_Position(2, 5);
  Write(serout, 'Digitalanzeige die Zweite...');


  loop
    TCNT1H:= 0;
    TCNT1L:= 0;
    TCCR1B:= %00000001;   //Timer1 mit Vortieler 1 starten. Ein Incremenr = 0,0625usec
    while TCNT1L < 200 do    //auf Clock Low für min. 12,5uSec us warten, dann sind wir vor Beginn eines Datagramm
         if ClockPin = true then // Flankenwechsel auf Clock, wir sind mitten im Datagram
        TCNT1H:= 0;              // also Timer zurücksetzen und weiterwarten
        TCNT1L:= 0;              // das Warten kann im schlimmsten Fall ~1mSec dauern
      endif;
    endwhile;

    TCCR1B:= %00000000;   //Timer1 stopp

    //Hier sind wir vor einem neuem Datagramm.
    //Im FastMode dauert es jetzt etwa 20mSec,
    //im NormalMode etwa 300mSec, bis das neue Datagramm kommt
    //Pollen würde das System dichtmachen, daher setzten wir einen INT
    //INT0 auf steigende Flanke Clockleitung triggern
    MCUCR := MCUCR or %00000011;      //MCU Control, Bit1=1, Bit0=1 --> INT0 auf steigende Flanke
    incl(SteigenderINT);
    GICR:= GICR or %01000000;         //Bit6 --> INT0 enable
    //Das Einelsen passiert komplett im Interrupt
    

    if NeueDaten then
      Term_Set_Cursor_Position(4, 5);
      Term_Erase_to_End_of_Line;
      RelPos:=RelPos*127;         //Schieblehre hat ein internes Format,
      RelPos:=RelPos div 2048;    //hier umrechnen auf Millimeter
      relpos:=relpos* (-1);       //und Anzeige invertieren
      Write(serout, longtostr(RelPos :6:2));
      NeueDaten:= false;
    endif;
  endloop;

end DrehbankDRO.



Es funktioniert auch soweit. Aber ich glaube, das ich durch mein Pollen auf Beginn des Paketes und das Einlesen innerhalb des Interrupts das System schon soweit "dicht" gemacht habe, dass ich nicht viel anderes mehr machen kann.

Eigentlich sollte noch ein Drehzahlmesser, eine I2C-Realtimeclock und ein grafisches Display mit dran. Mit einem INT0, der 800uSec belegt ist, wird das nichts, denke ich.

Also endlich meine Frage: Kann ich es besser machen? Oder bringt alle Optimierung nur marginal was? Dann sollte ich einfach einen 2. µC für Diplay usw. nehmen, gekoopelt mit dem "Mess-µC" per SPI?

Vielen Dank für Anregungen und Grüße aus Petershagen!

Rolf
Der an diesem Beitrag angefügte Anhang ist entweder nur im eingeloggten Zustand sichtbar oder die Berechtigung Deiner Benutzergruppe ist nicht ausreichend.
miparo
Schreiberling
Avatar
Geschlecht:
Herkunft: Germany
Alter: 59
Beiträge: 988
Dabei seit: 09 / 2007
Betreff:

Re: Einlesen China-Schieblehre

 · 
Gepostet: 30.01.2012 - 16:35 Uhr  ·  #2
Hi rbr50,
das hast Du bestimmt schon gelesen ?
http://www.mikrocontroller.net/topic/21917

Gruß
miparo
rbr50
 
Avatar
 
Betreff:

Re: Einlesen China-Schieblehre

 · 
Gepostet: 30.01.2012 - 16:51 Uhr  ·  #3
Hallo miparo,

Zitat

das hast Du bestimmt schon gelesen ?
http://www.mikrocontroller.net/topic/21917


ja, habe ich. Und noch reichlich andere Seiten. Daraus ist letztendlich obiges Prog. entstanden. Es funktioniert ja auch. Schnell genug, um im Fastmode die Schieblehre zu lesen, zu wandeln und über die sierielle zu schicken. Problem wird es mit weiterer Peripherie wie Display, Uhr (für die Betriebsstunden der Drehbank) usw. geben. Denn der INT0 dauert mindesten 800µSec.

Ich glaube, viel schneller kriegt man das Prog nicht. Daher werde ich für Display usw. einen weiteren µC nehmen.Wollte ich sowieso schon immer mal ausprobieren. ;-)

Vielen Dank fürs Lesen und Deine Zeit!

Rolf
miparo
Schreiberling
Avatar
Geschlecht:
Herkunft: Germany
Alter: 59
Beiträge: 988
Dabei seit: 09 / 2007
Betreff:

Re: Einlesen China-Schieblehre

 · 
Gepostet: 30.01.2012 - 19:19 Uhr  ·  #4
Hatte ich mir gedacht :(

Unschön ist ja nur das Du das komlett im INT0 behandelst.
Alternativ könntest Du ja auch nur den Status von Data im INT0 prüfen und außerhalb Flags setzten
und dadurch die Bits zusammen zählen.
So könnten alle anderen Teile schnell genug weiterarbeiten.

miparo
rbr50
 
Avatar
 
Betreff:

Re: Einlesen China-Schieblehre

 · 
Gepostet: 30.01.2012 - 20:21 Uhr  ·  #5
Hallo,

Zitat

Alternativ könntest Du ja auch nur den Status von Data im INT0 prüfen und außerhalb Flags setzten
und dadurch die Bits zusammen zählen.


Dabei sehe ich das Problem, dass der Interrupt bei Datenempfang alle 6µSec ausgelöst wird. Ich glaube, dann müsste schon Assembler her, für den Compiler scheint mir das zu knapp zu sein.

Aber eventuell gibt es noch die Alternative, nur "bei Bedarf" die Schieblehre auszulesen. Wenn z.B. der User die Uhr stellt. braucht man die Schieblehre nicht. Da muss ich nochmal überlegen. Und ansonsten eben 2µC.

Grüße aus Petershagen bei -6° !

Rolf
mc-electronic
Benutzer
Avatar
Geschlecht: keine Angabe
Herkunft: Sauerland NRW
Beiträge: 372
Dabei seit: 03 / 2008
Betreff:

Re: Einlesen China-Schieblehre

 · 
Gepostet: 31.01.2012 - 07:53 Uhr  ·  #6
Hallo rbr50,

ich denke schon, daß es auch in Pascal geht, das Clk Signal auf steigende Flanke im Interrupt zu behandeln, dann im Interrupt auf fallende Flanke umzustellen etc. Ich werte so PWM-Signale aus, das geht bei mir locker bis 25 kHz (bei Dir ist das ca. 3xmehr), ich habe allerdings mehr im Interrupt zu tun als Du. Du mußt ja nur das Data-Bit einlesen, mitzählen und in einer Schiebevariablen merken. Wenn genug Bits da sind, ist der Wert fertig.
Ich würde in der Interrupt-Routine keine Variablen anlegen:

[code]var
  bitval         : LongInt;
  b              : byte;
  BitZaehler     : byte; [/code]

sondern würde globale Variablen nehmen. Das Anlegen auf dem Frame kostet bei jedem Interrupt unnötige Zeit und wird bei globalen Variablen vermieden.

Gruß, Michael
miparo
Schreiberling
Avatar
Geschlecht:
Herkunft: Germany
Alter: 59
Beiträge: 988
Dabei seit: 09 / 2007
Betreff:

Re: Einlesen China-Schieblehre

 · 
Gepostet: 31.01.2012 - 11:18 Uhr  ·  #7
und dann noch einen xMega32U4 mit 64MHz dann hast'e noch Zeit für ein Tetris Spiel nebenbei :)
jomixl
Benutzer
Avatar
Geschlecht:
Beiträge: 229
Dabei seit: 02 / 2008
Betreff:

Re: Einlesen China-Schieblehre

 · 
Gepostet: 31.01.2012 - 14:19 Uhr  ·  #8
hat einer von euch eine Bezugsquelle für die Meßelektronik, ich möchte eigentlich keine Messschieber schlachten .....

grüsse joachim
  • 1
  • 2
  • Seite 1 von 2
Gewählte Zitate für Mehrfachzitierung:   0

Registrierte in diesem Topic

Aktuell kein registrierter in diesem Bereich

Die Statistik zeigt, wer in den letzten 5 Minuten online war. Erneuerung alle 90 Sekunden.
MySQL Queries: 8 · Cache Hits: 14   138   152 · Page-Gen-Time: 0.020565s · Speichernutzung: 2 MB · GZIP: ein · Viewport: SMXL-HiDPI