Einlesen China-Schieblehre

Codeoptimierung

  • 1
  • 2
  • Page 1 of 2
rbr50
 
Avatar
 
Subject:

Einlesen China-Schieblehre

 · 
Posted: 30.01.2012 - 14:32  ·  #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
Attachments
Datagramm
Filename: schieb.png
Filesize: 7.95 KB
Title: Datagramm
Information: Daten- und Clock eines kompletten Paketes
Download counter: 144
miparo
Administrator
Avatar
Gender:
Location: Germany
Age: 58
Posts: 959
Registered: 09 / 2007
Subject:

Re: Einlesen China-Schieblehre

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

Gruß
miparo
rbr50
 
Avatar
 
Subject:

Re: Einlesen China-Schieblehre

 · 
Posted: 30.01.2012 - 16:51  ·  #3
Hallo miparo,

Quote

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
Administrator
Avatar
Gender:
Location: Germany
Age: 58
Posts: 959
Registered: 09 / 2007
Subject:

Re: Einlesen China-Schieblehre

 · 
Posted: 30.01.2012 - 19:19  ·  #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
 
Subject:

Re: Einlesen China-Schieblehre

 · 
Posted: 30.01.2012 - 20:21  ·  #5
Hallo,

Quote

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
Gender: n/a
Location: Sauerland NRW
Posts: 372
Registered: 03 / 2008
Subject:

Re: Einlesen China-Schieblehre

 · 
Posted: 31.01.2012 - 07:53  ·  #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
Administrator
Avatar
Gender:
Location: Germany
Age: 58
Posts: 959
Registered: 09 / 2007
Subject:

Re: Einlesen China-Schieblehre

 · 
Posted: 31.01.2012 - 11:18  ·  #7
und dann noch einen xMega32U4 mit 64MHz dann hast'e noch Zeit für ein Tetris Spiel nebenbei :)
jomixl
Benutzer
Avatar
Gender:
Posts: 225
Registered: 02 / 2008
Subject:

Re: Einlesen China-Schieblehre

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

grüsse joachim
  • 1
  • 2
  • Page 1 of 2
Selected quotes for multi-quoting:   0

Registered users in this topic

Currently no registered users in this section

The statistic shows who was online during the last 5 minutes. Updated every 90 seconds.
MySQL Queries: 16 · Cache Hits: 15   135   150 · Page-Gen-Time: 0.030034s · Memory Usage: 2 MB · GZIP: on · Viewport: SMXL-HiDPI