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


von 655432 (Gast)


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.
1
#include <PWB2000.h>        // verwendete HW bekannt geben
2
3
// Funktionen veröffentlichen
4
  public  speedInit, speedAdjust, speedDisplay, checkSwitch, wait50ms
5
6
// Interface zu den Funktionen im ROM
7
lcdWrite code  0x8199        // R7=Row, DPTR=XDATA Buffer, show 16 chars 
8
9
// Defines
10
sbit SW_DWN = P4^7;          // switch downgrade speed
11
sbit SW_UP = P4^0;          // switch accellerate speed
12
#define SW_MASK 0x81        // switch @ port P4 (1000 0001)
13
// P4: SW_UP - [speed (4 LEDs)] - SW_DWN
14
15
#define SW_DEBOUNCE_MS 50      // wait time after (possible) change in ms
16
#define LCD_SIZE 16          // chars each LCD line
17
#define LCD_TOTAL_SIZE (2*LCD_SIZE)  // and totally
18
#define WAIT1MS  250          // @ 12MHz and 12 OscCycles
19
 
20
  bseg at 0
21
          // save last state of switch
22
 
23
  dseg at  8      // behind register bank 0
24
          // actual speed (0 - 15)
25
          // but ASCII-Hi-Digit '0'...'1'
26
          // but ASCII-Low-Digit '0'...'9' 
27
 
28
  xseg at 0x1000      // muss auf Adresse modulo 256 beginnen
29
lcdLine0: ds  LCD_SIZE    // [####------------]
30
lcdLine1: ds  LCD_SIZE    // [04              ]
31
 
32
  cseg at  0x200      // Lücke zu main sollte groß genug sein
33
34
35
36
////////////////////////////////////////
37
// speedInit - Grundeinstellungen
38
// Wert wird nach Starten des Programms geladen
39
// Destroy: ?
40
//////////////////////////////////////// 
41
speedInit:
42
  mov  p4, #SW_MASK    
43
  mov b, p4     ; Variable b initialisieren        
44
  ret
45
 
46
////////////////////////////////////////
47
// wait50ms - Schalterentprellung
48
// 50ms warten, nachdem Schalter betätigt
49
// Destroy: A, R0, R1 
50
//////////////////////////////////////// 
51
wait50ms:
52
53
  mov r1, #SW_DEBOUNCE_MS
54
  auSchl:    ; Dauer: 501µs * 50 * 2 = 50,1 ms
55
  mov r0, #WAIT1MS
56
  innSchl:  ; Dauer: 250µs * 2 + 1µs = 501µs
57
       djnz r0, innSchl   ; 2µs
58
      djnz r1, auSchl     ; 2µs
59
  ret
60
  
61
////////////////////////////////////////
62
// slowdown - Register2 Minus 1
63
// wird von checkSwitch aufgerufen
64
// Destroy: A, R2
65
//////////////////////////////////////// 
66
slowdown:
67
68
  dec r2
69
  mov a, r2      
70
  ret              
71
72
////////////////////////////////////////
73
// min - setzt R2 = 0
74
// wird von slowdown aufgerufen
75
// Destroy: R2
76
//////////////////////////////////////// 
77
min:
78
79
  mov r2, #0    ; nach Programmstart Stufe 0 aktiv      
80
  ret             
81
82
////////////////////////////////////////
83
// speedup - Register2 Plus 1
84
// wird von checkSwitch aufgerufen
85
// Destroy: A, R2
86
//////////////////////////////////////// 
87
speedup:
88
89
  inc r2
90
  mov a, r2       
91
  ret            
92
93
////////////////////////////////////////
94
// max - setzt R2 = 15
95
// wird von speedup aufgerufen
96
// Destroy: R2
97
//////////////////////////////////////// 
98
max:
99
  mov r2, #15    ; maximal 16 Fahrstufen    
100
  ret              
101
102
////////////////////////////////////////
103
// checkSwitch - Schalterstellung testen
104
// (SW_DWN hat Priorität gegenüber SW_UP)
105
// Return R2: -1 slow down, 0 steady, 1 speed up
106
// Destroy: A, B, C
107
////////////////////////////////////////
108
checkSwitch:
109
  xrl a, b
110
  jbc acc.0, speedup
111
  jbc acc.7, slowdown
112
  ret         
113
114
/***************************************
115
** speedAdjust - neue Geschwindigkeit einstellen
116
** Variablen speed, speedAscH und speedAscL sowie P4 aktualisieren
117
** Destroy: A, PSW, P4
118
***************************************/
119
speedAdjust:
120
121
  mov P4, a  ; Inhalt von a nach P4    
122
  ret          
123
124
/***************************************
125
** speedDisplay - Ausgabe auf dem LCD
126
** Destroy: A, R4, R5, R6 , DPTR, P2, R0
127
** Call: lcdWrite, zerstört weitere Register
128
***************************************/
129
speedDisplay:          
130
      
131
  ret            
132
  
133
  end

von Ralf (Gast)


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

von 655432 (Gast)


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:
1
#include <PWB2000.h>        // verwendete HW bekannt geben
2
3
// Funktionen veröffentlichen
4
  public  speedInit, speedAdjust, speedDisplay, checkSwitch, wait50ms
5
6
// Interface zu den Funktionen im ROM
7
lcdWrite code  0x8199        // R7=Row, DPTR=XDATA Buffer, show 16 chars 
8
9
// Defines
10
sbit SW_DWN = P4^7;          // switch downgrade speed
11
sbit SW_UP = P4^0;          // switch accellerate speed
12
#define SW_MASK 0x81        // switch @ port P4 (1000 0001)
13
// P4: SW_UP - [speed (4 LEDs)] - SW_DWN
14
15
#define SW_DEBOUNCE_MS 50      // wait time after (possible) change in ms
16
#define LCD_SIZE 16          // chars each LCD line
17
#define LCD_TOTAL_SIZE (2*LCD_SIZE)  // and totally
18
#define WAIT1MS  250          // @ 12MHz and 12 OscCycles
19
 
20
  bseg at 0
21
          // save last state of switch
22
 
23
  dseg at  8      // behind register bank 0
24
          // actual speed (0 - 15)
25
          // but ASCII-Hi-Digit '0'...'1'
26
          // but ASCII-Low-Digit '0'...'9' 
27
 
28
  xseg at 0x1000      // muss auf Adresse modulo 256 beginnen
29
lcdLine0: ds  LCD_SIZE    // [####------------]
30
lcdLine1: ds  LCD_SIZE    // [04              ]
31
 
32
  cseg at  0x200      // Lücke zu main sollte groß genug sein
33
34
35
36
////////////////////////////////////////
37
// speedInit - Grundeinstellungen
38
// Wert wird nach Starten des Programms geladen
39
// Destroy: ?
40
//////////////////////////////////////// 
41
speedInit:
42
  mov  p4, #SW_MASK    
43
  mov b, p4     ; Variable b initialisieren        
44
  ret
45
 
46
////////////////////////////////////////
47
// wait50ms - Schalterentprellung
48
// 50ms warten, nachdem Schalter betätigt
49
// Destroy: A, R0, R1 
50
//////////////////////////////////////// 
51
wait50ms:
52
53
  mov r1, #SW_DEBOUNCE_MS
54
  auSchl:    ; Dauer: 501µs * 50 * 2 = 50,1 ms
55
  mov r0, #WAIT1MS
56
  innSchl:  ; Dauer: 250µs * 2 + 1µs = 501µs
57
       djnz r0, innSchl   ; 2µs
58
      djnz r1, auSchl     ; 2µs
59
  ret          
60
61
////////////////////////////////////////
62
// checkSwitch - Schalterstellung testen
63
// (SW_DWN hat Priorität gegenüber SW_UP)
64
// Return R2: -1 slow down, 0 steady, 1 speed up
65
// Destroy: A, B, C
66
////////////////////////////////////////
67
checkSwitch:
68
      mov a, p4
69
       xrl a, b
70
       jnb acc.0, mar1 ; wenn p4.1 gleich Null springe zu mar1
71
      inc r2       ; inc r2
72
      jmp mar2
73
  mar1:  jnb acc.7, mar2
74
      dec r2
75
      mov a, r2
76
  mar2:  mov a, r2          
77
      ret        ; springe zu Unterprogramm speedAdjust
78
79
/***************************************
80
** speedAdjust - neue Geschwindigkeit einstellen
81
** Variablen speed, speedAscH und speedAscL sowie P4 aktualisieren
82
** Destroy: A, PSW, P4
83
***************************************/
84
speedAdjust:
85
86
      mov p4, a  ; Inhalt von a nach P4
87
          
88
      ret          
89
90
/***************************************
91
** speedDisplay - Ausgabe auf dem LCD
92
** Destroy: A, R4, R5, R6 , DPTR, P2, R0
93
** Call: lcdWrite, zerstört weitere Register
94
***************************************/
95
speedDisplay:          
96
      
97
  ret            
98
  
99
  end

Hier ist noch das Hauptprogramm mit dem Aufruf der Unterfunktionen.


1
// Interface zu den Funktionen im ROM
2
lcdInit  code  0x8150      // initialize LCD, clear both lines
3
4
// Interface zu den Funktionen im Modul toy_speed
5
  extrn code( speedInit, speedAdjust, speedDisplay, checkSwitch, wait50ms )  // toy_speed.a51
6
7
// Hier reservieren wir Speicherplatz für den Stack
8
// Der Keil-Linker legt das Segment mit Namen Stack hinter alle anderen (Ausnahme: BitSegment)
9
stack  segment  idata
10
  rseg  stack
11
  ds  0x18      // soviel, damit Segment auf jeden Fall hinter BitSpeicher  
12
13
// ResetVector, hier starten Programm
14
  cseg  at 0
15
  jmp  main
16
17
// Platz für die VectorTable
18
// ...
19
20
  cseg  at 0x100
21
main:
22
  mov  sp, #(stack - 1)  // einmalige GrundEinstellungen ab hier vornehmen
23
  call  lcdInit
24
  call  speedInit
25
26
mainLoop:          // Endlos-Programm
27
  call  checkSwitch    // Schalter betätigt?
28
  call  speedAdjust    // falls ja, neue Geschwindigkeit an P4 einstellen
29
  call  speedDisplay  // und ggf. auf dem Display darstellen
30
  call  wait50ms    // Entprellzeit für Schalter abwarten
31
  jmp  mainLoop
32
33
  end

von 655432 (Gast)


Angehängte Dateien:

Lesenswert?

Hier noch die Abbildung der Schaltfläche.

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.