www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Fahrsteller auf dem 8051 mit Simulator funkt. nicht


Autor: 655432 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

ich hoffe ihr könnt mir weiterhelfen...

Ich bin gerade dabei einen Praktikumsversuch zu bewältigen und hänge an 
einer Stelle.

Ich möchte mit zwei Schalter (Bestandteile des Simulators) dazu benutzen 
eine Geschwindigkeit zu erhöhen und zu veringern. Dieser Fahrsteller hat 
16 Stufen (0..15). Der Schalter P4.0 erhöht die Geschwindigkeit in 
Einerschritten und der Schalter P4.7 verringert die Geschwindigkeit in 
Einerschritten, der Wertebereich 0..15 daf aber nicht verlassen werden.

Die Fahrstufen sollen zunächst als einfache Binärzahl (auch im 
Simulator) am Port P4.5 ... P4.2 binär ausgegeben werden.

Bei mir klemmt es jetzt an dem Unterprogramm "speedAdjust:". Nach meinem 
Verständnis (und das reicht noch nicht soweit) müsste schon etwas 
ausgegeben werden.

So sieht das Programm bis jetzt aus. Danke für eure Hilfe im Voraus.
#include <PWB2000.h>        // verwendete HW bekannt geben

// Funktionen veröffentlichen
  public  speedInit, speedAdjust, speedDisplay, checkSwitch, wait50ms

// Interface zu den Funktionen im ROM
lcdWrite code  0x8199        // R7=Row, DPTR=XDATA Buffer, show 16 chars 

// Defines
sbit SW_DWN = P4^7;          // switch downgrade speed
sbit SW_UP = P4^0;          // switch accellerate speed
#define SW_MASK 0x81        // switch @ port P4 (1000 0001)
// P4: SW_UP - [speed (4 LEDs)] - SW_DWN

#define SW_DEBOUNCE_MS 50      // wait time after (possible) change in ms
#define LCD_SIZE 16          // chars each LCD line
#define LCD_TOTAL_SIZE (2*LCD_SIZE)  // and totally
#define WAIT1MS  250          // @ 12MHz and 12 OscCycles
 
  bseg at 0
          // save last state of switch
 
  dseg at  8      // behind register bank 0
          // actual speed (0 - 15)
          // but ASCII-Hi-Digit '0'...'1'
          // but ASCII-Low-Digit '0'...'9' 
 
  xseg at 0x1000      // muss auf Adresse modulo 256 beginnen
lcdLine0: ds  LCD_SIZE    // [####------------]
lcdLine1: ds  LCD_SIZE    // [04              ]
 
  cseg at  0x200      // Lücke zu main sollte groß genug sein



////////////////////////////////////////
// speedInit - Grundeinstellungen
// Wert wird nach Starten des Programms geladen
// Destroy: ?
//////////////////////////////////////// 
speedInit:
  mov  p4, #SW_MASK    
  mov b, p4     ; Variable b initialisieren        
  ret
 
////////////////////////////////////////
// wait50ms - Schalterentprellung
// 50ms warten, nachdem Schalter betätigt
// Destroy: A, R0, R1 
//////////////////////////////////////// 
wait50ms:

  mov r1, #SW_DEBOUNCE_MS
  auSchl:    ; Dauer: 501µs * 50 * 2 = 50,1 ms
  mov r0, #WAIT1MS
  innSchl:  ; Dauer: 250µs * 2 + 1µs = 501µs
       djnz r0, innSchl   ; 2µs
      djnz r1, auSchl     ; 2µs
  ret
  
////////////////////////////////////////
// slowdown - Register2 Minus 1
// wird von checkSwitch aufgerufen
// Destroy: A, R2
//////////////////////////////////////// 
slowdown:

  dec r2
  mov a, r2      
  ret              

////////////////////////////////////////
// min - setzt R2 = 0
// wird von slowdown aufgerufen
// Destroy: R2
//////////////////////////////////////// 
min:

  mov r2, #0    ; nach Programmstart Stufe 0 aktiv      
  ret             

////////////////////////////////////////
// speedup - Register2 Plus 1
// wird von checkSwitch aufgerufen
// Destroy: A, R2
//////////////////////////////////////// 
speedup:

  inc r2
  mov a, r2       
  ret            

////////////////////////////////////////
// max - setzt R2 = 15
// wird von speedup aufgerufen
// Destroy: R2
//////////////////////////////////////// 
max:
  mov r2, #15    ; maximal 16 Fahrstufen    
  ret              

////////////////////////////////////////
// checkSwitch - Schalterstellung testen
// (SW_DWN hat Priorität gegenüber SW_UP)
// Return R2: -1 slow down, 0 steady, 1 speed up
// Destroy: A, B, C
////////////////////////////////////////
checkSwitch:
  xrl a, b
  jbc acc.0, speedup
  jbc acc.7, slowdown
  ret         

/***************************************
** speedAdjust - neue Geschwindigkeit einstellen
** Variablen speed, speedAscH und speedAscL sowie P4 aktualisieren
** Destroy: A, PSW, P4
***************************************/
speedAdjust:

  mov P4, a  ; Inhalt von a nach P4    
  ret          

/***************************************
** speedDisplay - Ausgabe auf dem LCD
** Destroy: A, R4, R5, R6 , DPTR, P2, R0
** Call: lcdWrite, zerstört weitere Register
***************************************/
speedDisplay:          
      
  ret            
  
  end  

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

ohne mir jetzt dein ganzes Programm angesehen zu haben, so hast du doch 
bereits grundlegende Fehler in deinem geposteten Code. Die Stelle:

checkSwitch:
  xrl a, b
  jbc acc.0, speedup
  jbc acc.7, slowdown
  ret

ist fehlerhaft, weil du dort mit einem JUMP hinspringst. Die 
entsprechenden Funktionen SPEEDUP und SLOWDOWN werden aber mit einem RET 
beendet, was dir den Stackpointer verhagelt. Merke: Ein Unterprogramm, 
welches durch ein RET beendet wird, MUSS immer mit einem CALL 
aufgerufen werden, niemals mit einem JUMP.

Die korrekte Implementierung müsste eher folgendermassen lauten (ohne 
Gewähr):

checkSwitch:
      xrl a, b
      jnb acc.0, cs1
      inc r2
      jmp cs2
cs1:  jnb acc.7,cse
      dec r2
cs2:  mov a,r2
cse:  ret

Mit dieser Variante fallen die beiden Routinen SPEEDUP und SLOWDOWN 
komplett raus, was mir persönlich besser gefällt, da mit einem 
Unterprogramm zwei zusammenhängende Funktionen bedient werden. Bei 
größeren Funktionen sieht es natürlich anders aus.

Du kannst auch mit einzelnen Routinen arbeiten, aber dann musst du wie 
bereits gesagt, mit CALL arbeiten!!!

Ralf

Autor: 655432 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es funktioniert immer noch nicht. Wenn ich auf Port 4.1 (Schalter S0) 
drücke wie im Anhang gezeigt sollte eigentlich mit den LED's links 
daneben (Kreise über den Schaltern S1 bis S6) die Binärzahl angezeigt 
werden. Wenn ich auf den Schalter ganz links drücke sollte die Binärzahl 
wieder inkrementiert werden.

Immer wenn der Schalter S1 oder S7 logisch 1 ist, soll die Binärzahl 
incr. bzw. decr. werden. Habe das Programm nochmal umgeändert:
#include <PWB2000.h>        // verwendete HW bekannt geben

// Funktionen veröffentlichen
  public  speedInit, speedAdjust, speedDisplay, checkSwitch, wait50ms

// Interface zu den Funktionen im ROM
lcdWrite code  0x8199        // R7=Row, DPTR=XDATA Buffer, show 16 chars 

// Defines
sbit SW_DWN = P4^7;          // switch downgrade speed
sbit SW_UP = P4^0;          // switch accellerate speed
#define SW_MASK 0x81        // switch @ port P4 (1000 0001)
// P4: SW_UP - [speed (4 LEDs)] - SW_DWN

#define SW_DEBOUNCE_MS 50      // wait time after (possible) change in ms
#define LCD_SIZE 16          // chars each LCD line
#define LCD_TOTAL_SIZE (2*LCD_SIZE)  // and totally
#define WAIT1MS  250          // @ 12MHz and 12 OscCycles
 
  bseg at 0
          // save last state of switch
 
  dseg at  8      // behind register bank 0
          // actual speed (0 - 15)
          // but ASCII-Hi-Digit '0'...'1'
          // but ASCII-Low-Digit '0'...'9' 
 
  xseg at 0x1000      // muss auf Adresse modulo 256 beginnen
lcdLine0: ds  LCD_SIZE    // [####------------]
lcdLine1: ds  LCD_SIZE    // [04              ]
 
  cseg at  0x200      // Lücke zu main sollte groß genug sein



////////////////////////////////////////
// speedInit - Grundeinstellungen
// Wert wird nach Starten des Programms geladen
// Destroy: ?
//////////////////////////////////////// 
speedInit:
  mov  p4, #SW_MASK    
  mov b, p4     ; Variable b initialisieren        
  ret
 
////////////////////////////////////////
// wait50ms - Schalterentprellung
// 50ms warten, nachdem Schalter betätigt
// Destroy: A, R0, R1 
//////////////////////////////////////// 
wait50ms:

  mov r1, #SW_DEBOUNCE_MS
  auSchl:    ; Dauer: 501µs * 50 * 2 = 50,1 ms
  mov r0, #WAIT1MS
  innSchl:  ; Dauer: 250µs * 2 + 1µs = 501µs
       djnz r0, innSchl   ; 2µs
      djnz r1, auSchl     ; 2µs
  ret          

////////////////////////////////////////
// checkSwitch - Schalterstellung testen
// (SW_DWN hat Priorität gegenüber SW_UP)
// Return R2: -1 slow down, 0 steady, 1 speed up
// Destroy: A, B, C
////////////////////////////////////////
checkSwitch:
      mov a, p4
       xrl a, b
       jnb acc.0, mar1 ; wenn p4.1 gleich Null springe zu mar1
      inc r2       ; inc r2
      jmp mar2
  mar1:  jnb acc.7, mar2
      dec r2
      mov a, r2
  mar2:  mov a, r2          
      ret        ; springe zu Unterprogramm speedAdjust

/***************************************
** speedAdjust - neue Geschwindigkeit einstellen
** Variablen speed, speedAscH und speedAscL sowie P4 aktualisieren
** Destroy: A, PSW, P4
***************************************/
speedAdjust:

      mov p4, a  ; Inhalt von a nach P4
          
      ret          

/***************************************
** speedDisplay - Ausgabe auf dem LCD
** Destroy: A, R4, R5, R6 , DPTR, P2, R0
** Call: lcdWrite, zerstört weitere Register
***************************************/
speedDisplay:          
      
  ret            
  
  end              
    

Hier ist noch das Hauptprogramm mit dem Aufruf der Unterfunktionen.


// Interface zu den Funktionen im ROM
lcdInit  code  0x8150      // initialize LCD, clear both lines

// Interface zu den Funktionen im Modul toy_speed
  extrn code( speedInit, speedAdjust, speedDisplay, checkSwitch, wait50ms )  // toy_speed.a51

// Hier reservieren wir Speicherplatz für den Stack
// Der Keil-Linker legt das Segment mit Namen Stack hinter alle anderen (Ausnahme: BitSegment)
stack  segment  idata
  rseg  stack
  ds  0x18      // soviel, damit Segment auf jeden Fall hinter BitSpeicher  

// ResetVector, hier starten Programm
  cseg  at 0
  jmp  main

// Platz für die VectorTable
// ...

  cseg  at 0x100
main:
  mov  sp, #(stack - 1)  // einmalige GrundEinstellungen ab hier vornehmen
  call  lcdInit
  call  speedInit

mainLoop:          // Endlos-Programm
  call  checkSwitch    // Schalter betätigt?
  call  speedAdjust    // falls ja, neue Geschwindigkeit an P4 einstellen
  call  speedDisplay  // und ggf. auf dem Display darstellen
  call  wait50ms    // Entprellzeit für Schalter abwarten
  jmp  mainLoop

  end

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

Bewertung
0 lesenswert
nicht lesenswert
Hier noch die Abbildung der Schaltfläche.

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.