|
Bitte beachte die Copyrighthinweise.
Menüsteuerung mit Microcontroller
1 Aufgabenstellung
· Programmierung einer Menüsteuerung. Über wenige Tasten sollen die Zustände vieler Portleitungen geändert werden können.
Es wurde folgendes Menü realisiert:
Nach dem Start befindet man sich im Normalbetrieb (NB).
Durch das Drücken von Enter kommt man in das Menü 1. Mit der Taste kann nun der Zustand der Portleitung geändert (getoggelt) werden.
Durch nochmaliges Drücken von Enter kommt man in das nächste Menü und kann mit der Taste nun den Zustand der nächsten Portleitung ändern.
Hier wurden zwei Menüpunkte realisiert, man könnte diese Struktur natürlich auf viele Menüs bzw. z.B. mit einer dritten Taste auf Untermenüs erweitern. Theoretisch würde über eine Zeitsteuerung auch eine einzelne Taste reichen.
Durch abermaliges Drücken von Enter kommt man wieder in den Normalbetrieb.
3 Schaltung
Es wurde folgende Schaltung aufgebaut (die Werte der Widerstände wurden nicht notiert):
4 Programmierung in Assembler
4.1 Struktogramm
Die ständigen Warteschleifen (DJNZ) dienen der Entprellung der Tasten.
Menu2b.asm
;*********************************************************************
; Editor: Rosenauer Florian @ HTBLA Karlstein, Austria - Waidhofen/Th.
; Datum: 13/Mar/1998 Klasse/Gruppe/Kat.Nr : V-EA/-/--
;*********************************************************************
; Sprache : ASM fuer 80C537
; Programm Nr. : VEA Labor SteG
; Version : 0.11
; Kurzbeschreibung : Menuesteuerung mit MC
;
;
;*********************************************************************
#include 537.inc
Enter .equ P5.0
Taste .equ P5.1
Nb .equ P4.0
Aus1 .equ P4.2
Aus2 .equ P4.3
.org $0000
ljmp Start
Start .org $0100
mov R1,#$FF
clr Nb
jb Enter,Start
setb Nb
Loop djnz R1,Loop
mov R1,#$FF
Loop1 jnb Enter,Loop1
L3 djnz R1,L3
mov R1,#$FF
Weiter jnb Enter,Loop2
jb Taste,Weiter
L djnz R1,L
mov R1,#$FF
L6 jnb Taste,L6
cpl Aus1
ljmp Weiter
Loop2 djnz R1,Loop2
mov R1,#$FF
Loop3 jnb Enter,Loop3
L4 djnz R1,L4
mov R1,#$FF
Weiter1 jnb Enter,Loop4
jb Taste,Weiter1
L1 djnz R1,L1
mov R1,#$FF
L5 jnb Taste,L5
cpl Aus2
ljmp Weiter1
Loop4 djnz R1,Loop4
mov R1,#$FF
Loop5 jnb Enter,Loop5
ljmp Start
.end
Das Programm funktionierte einwandfrei lt. dem unter Punkt 2 erwähnten Prinzip.
5 Programmierung in C
Als nächstes wurde das gleiche Menüprinzip in C realisiert.
Menu2.c
/*************************************************************************
/* Editor: Florian Rosenauer @ HTBLA Karlstein, Austria-3830 Waidhofen
/* Datum: 13/Mar/1998 Klasse/Gruppe/Kat.Nr : V-EA/-/--
/*************************************************************************
/* Sprache : C51 fuer MC 80C537
/* Programm Nr. : Labor SteG
/* Kurzbeschreibung : Menu2b.asm in C
/*************************************************************************
*/
// const float VERSION = 1.01;
/************************************************************************/
#include <stdio.h>
#include <reg517.h>
/* BEGINN --- putchar von Sampl517 --- */
sbit enter = P5^0;
sbit taste = P5^1;
sbit nb = P4^0;
sbit aus1 = P4^1;
sbit aus2 = P4^2;
#define XON 0x11
#define XOFF 0x13
char putchar (char c) {
if (c == '\n') {
if (S1CON & 0x01) { /* RI*/
if (S1BUF == XOFF) {
do {
S1CON &= 0xFE; /* RI = 0 */
while (!(S1CON & 0x01)); /* RI */
}
while (S1BUF != XON);
S1CON &= 0xFE; /* RI = 0 */
}
}
while (!(S1CON & 0x02)); /* while (!TI); */
S1CON &= 0xFD; /* TI = 0 */
S1BUF = 0x0d; /* output CR */
}
if (S1CON & 0x01) {
if (S1BUF == XOFF) {
do {
S1CON &= 0xFE; /* RI = 0 */
while (!(S1CON & 0x01)); /* while (!RI) */
}
while (S1BUF != XON);
S1CON &= 0xFE; /* RI = 0 */
}
}
while (!(S1CON & 0x02)); /* while (!TI); */
S1CON &= 0xFD; /* TI = 0 */
return (S1BUF = c);
}
/* ENDE --- putchar von Sampl517 --- */
void main (void) {
//bit exit;
unsigned char delay;
/* BEGINN --- Serial 1 Init von Sampl517 --- */
/* initialize serial interface */
//#if 0
S0CON = 0x5A; /* S0CON */
BD = 1; /* internal Baudrate Generator */
PCON |= 0x80; /* 9600 Baud @ 12 MHz */
//#endif
S1REL = 0xD9; /* Reload Value */
S1CON = 0xB2; /* Init Serial Interface */
/* ENDE --- Serial 1 Init von Sampl517 --- */
// '#endif' wofuer ???
putchar('!');
while (1)
{
while (enter == 1)
nb = 0;
nb = 1;
for (delay=0;delay<=250;delay++); // Prellen abwarten
while (enter == 0);
for (delay=0;delay<=250;delay++); // Prellen abwarten
while (enter == 1)
{ if (taste != 1)
{ for (delay=0;delay<=250;delay++); // Prellen abwarten
while (taste == 0);
aus1 = !aus1;
}
}
for (delay=0;delay<=250;delay++); // Prellen abwarten
while (enter == 1)
{ if (taste != 1)
{ for (delay=0;delay<=250;delay++); // Prellen abwarten
while (taste == 0);
aus2 = !aus2;
}
}
for (delay=0;delay<=250;delay++); // Prellen abwarten
} //while (1)
} //main
Das Programm funktionierte jedoch nicht wie erwartet. Ein Wechsel vom Menü 1 mittels Enter in das Menü 2 war nicht möglich, das Toggeln von Zustand 1 jedoch funktionierte.
Vergleicht man das Flussdiagramm mit dem Struktogramm, so kann man erkennen, dass im C-Programm jeweils die Warteschleifen Loop3 und Loop4 vergessen wurden. Drückt man Enter, läuft das Programm zwar zu Menüpunkt 2, geht danach aber sofort zum Normalbetrieb und abermals in den Menüpunkt 1. Somit war ein Wechsel nicht möglich.
Erzeugter Assemblercode aus Menu2.lst
Der eigentlich Teil des Menüs ist fettgedruckt, der Rest ist nur die Initialisierung der Seriellen 1 für printf.
; FUNCTION main (BEGIN)
;---- Variable 'delay' assigned to Register 'R6' ----
; SOURCE LINE # 62
; SOURCE LINE # 69
0000 75985A MOV S0CON,#05AH
; SOURCE LINE # 70
0003 D2DF SETB BD
; SOURCE LINE # 71
0005 438780 ORL PCON,#080H
; SOURCE LINE # 73
0008 759DD9 MOV S1REL,#0D9H
; SOURCE LINE # 74
000B 759BB2 MOV S1CON,#0B2H
; SOURCE LINE # 78
000E 7F21 MOV R7,#021H
0010 120000 R LCALL _putchar
; SOURCE LINE # 80
; SOURCE LINE # 81
0013 ?C0023:
; SOURCE LINE # 82
0013 30F804 JNB enter,?C0024
; SOURCE LINE # 83
0016 C2E8 CLR nb
0018 80F9 SJMP ?C0023
001A ?C0024:
; SOURCE LINE # 84
001A D2E8 SETB nb
; SOURCE LINE # 85
001C E4 CLR A
001D FE MOV R6,A
001E ?C0025:
001E 0E INC R6
001F EE MOV A,R6
0020 D3 SETB C
0021 94FA SUBB A,#0FAH
0023 40F9 JC ?C0025
0025 ?C0028:
; SOURCE LINE # 87
0025 30F8FD JNB enter,?C0028
0028 ?C0029:
; SOURCE LINE # 88
0028 E4 CLR A
0029 FE MOV R6,A
002A ?C0030:
002A 0E INC R6
002B EE MOV A,R6
002C D3 SETB C
002D 94FA SUBB A,#0FAH
002F 40F9 JC ?C0030
0031 ?C0033:
; SOURCE LINE # 90
0031 30F813 JNB enter,?C0034
; SOURCE LINE # 91
0034 20F9FA JB taste,?C0033
; SOURCE LINE # 92
0037 E4 CLR A
0038 FE MOV R6,A
0039 ?C0036:
0039 0E INC R6
003A EE MOV A,R6
003B D3 SETB C
003C 94FA SUBB A,#0FAH
003E 40F9 JC ?C0036
0040 ?C0039:
; SOURCE LINE # 93
0040 30F9FD JNB taste,?C0039
0043 ?C0040:
; SOURCE LINE # 94
0043 B2E9 CPL aus1
; SOURCE LINE # 95
; SOURCE LINE # 96
0045 80EA SJMP ?C0033
0047 ?C0034:
; SOURCE LINE # 98
0047 E4 CLR A
0048 FE MOV R6,A
0049 ?C0041:
0049 0E INC R6
004A EE MOV A,R6
004B D3 SETB C
004C 94FA SUBB A,#0FAH
004E 40F9 JC ?C0041
0050 ?C0044:
; SOURCE LINE # 100
0050 30F813 JNB enter,?C0045
; SOURCE LINE # 101
0053 20F9FA JB taste,?C0044
; SOURCE LINE # 102
0056 E4 CLR A
0057 FE MOV R6,A
0058 ?C0047:
0058 0E INC R6
0059 EE MOV A,R6
005A D3 SETB C
005B 94FA SUBB A,#0FAH
005D 40F9 JC ?C0047
005F ?C0050:
; SOURCE LINE # 103
005F 30F9FD JNB taste,?C0050
0062 ?C0051:
; SOURCE LINE # 104
0062 B2EA CPL aus2
; SOURCE LINE # 105
; SOURCE LINE # 106
0064 80EA SJMP ?C0044
0066 ?C0045:
; SOURCE LINE # 108
0066 E4 CLR A
0067 FE MOV R6,A
0068 ?C0052:
0068 EE MOV A,R6
0069 D3 SETB C
006A 94FA SUBB A,#0FAH
006C 50A5 JNC ?C0023
006E 0E INC R6
006F 80F7 SJMP ?C0052
; SOURCE LINE # 110
; SOURCE LINE # 111
0071 22 RET
; FUNCTION main (END)
C51 COMPILER V5.02, MENU2 15/05/98 00:15:56 PAGE 6
Vergleicht man den nativen Assemblercode mit dem C51-Assemblercode so kann man feststellen, dass der Code an den meisten Stellen relativ ähnlich ist. Dies ist vermutlich darauf zurückzuführen, dass das C-Programm aufgrund des Assemblercodes programmiert wurde.
Der einzige größere Unterschied liegt in der Realisierung der Warteschleifen: Hier hat der Compiler mit INC-, SUBB- und JNC-Befehlen wesentlich komplizierteren Code generiert. Möglicherweise liegt dies daran, dass for-Schleifen verwendet wurden. Wahrscheinlich hätte der Compiler while-Schleifen besser übersetzt!
6 Interpretation der Messergebnisse
Microcontroller stellen eine einfache Möglichkeit dar, mit geringem Hardwareaufwand (Taster etc.) komplexe Funktionen zu realisieren.
Das Programm hätte eventuell noch durch eine Anzeige des aktuellen Menüpunkts verbessert werden können.