Forum: Mikrocontroller und Digitale Elektronik Programmoptimierung


von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

wie schon einige male hier erwähnt, bin ich gerade dabei eine Temperatur 
Mess und Regelungssteuerung zu bauen (es sollen dann mal in einem 
Versuchshaus verschiedene Grenzflächentemperaturen und Feuchtigkeiten 
gemessen werden).
Die Hauptarbeit wir in Java passieren, ich benutze den mc nur als 
Interface zum PC. Klappt auch alles soweit, das Protokoll ist so, das 
ich verschiednen Strings sende mit vorgeschaltetem Multiplexer und dann 
den jeweiligen ADC-Wert empfange (über temperaturabhängigen Widerstand). 
Gebaut habe ich es mit dem Atmega8L8.

Ich habe jedoch noch das Problem, dass manchmal noch undefnierbare 
Zeichen gesendet werden, habe ich noch einen Haken im Programm, bzw. was 
könnte ,man besser machen? , hier der Code:
1
.include "m8def.inc"
2
 
3
.def temp1     = r16
4
.def sensornr  = r17         ; allgemeines temp Register, zur kurzfristigen Verwendung
5
.def multinr   = r18         ; allgemeines temp Register, zur kurzfristigen Verwendung
6
.def adlow     = r20         ; Ergebnis vom ADC / Mittelwert der 256 Messungen
7
.def adhigh    = r21         ; Ergebnis vom ADC / Mittelwert der 256 Messungen
8
.def messungen = r22         ; Schleifenzähler für die Messungen
9
.def ztausend  = r23         ; Zehntausenderstelle des ADC Wertes
10
.def tausend   = r24         ; Tausenderstelle des ADC Wertes
11
.def hundert   = r25         ; Hunderterstelle des ADC Wertes
12
.def zehner    = r26         ; Zehnerstelle des ADC Wertes
13
.def zeichen   = r27         ; Zeichen zur Ausgabe auf den UART
14
15
 
16
.equ F_CPU = 1000000                            ; Systemtakt in Hz
17
.equ BAUD  = 4800                               ; Baudrate
18
 
19
; Berechnungen
20
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  
21
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     
22
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  
23
 
24
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))      
25
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
26
.endif
27
 
28
.org 0x00
29
        rjmp main
30
 
31
.org URXCaddr
32
        rjmp int_rxc
33
 
34
; Schleife
35
main:
36
    
37
    ; Stackpointer initialisieren
38
 
39
    ldi     temp1, HIGH(RAMEND)
40
    out     SPH, temp1
41
    ldi     temp1, LOW(RAMEND)
42
    out     SPL, temp1
43
 
44
    ; Port B = Ausgang
45
   ; cbi = auf 0 setzen
46
  ; sbi = auf 1 setzen
47
    ldi     temp1, 0xFF
48
    out     DDRB, temp1
49
    ldi     temp1, 0xFF
50
    out     DDRD, temp1
51
;Vorbelegung auf Multi Kanal 0 -> String bei Temperatursenden
52
  ldi     multinr, '0'       ; Beginn des Strings
53
54
55
 
56
    ; Baudrate einstellen
57
 
58
    ldi     temp1, HIGH(UBRR_VAL)
59
    out     UBRRH, temp1                
60
    ldi     temp1, LOW(UBRR_VAL)
61
    out     UBRRL, temp1
62
 
63
    ; Frame-Format: 8 Bit
64
 
65
    ldi     temp1, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)
66
    out     UCSRC, temp1
67
 
68
    sbi     UCSRB, RXCIE                ; Interrupt bei Empfang
69
    sbi     UCSRB, RXEN                 ; RX (Empfang) aktivieren
70
    sbi     UCSRB, TXEN                 ; #TX einschalten
71
   
72
    sei                                 ; Interrupts global aktivieren
73
74
  
75
loop:
76
    rjmp loop                           ; Endlosschleife
77
 
78
; Interruptroutine: wird ausgeführt sobald ein Byte über das UART empfangen wurde
79
 
80
int_rxc:
81
    push    temp1                        ; temp auf dem Stack sichern
82
    in      temp1, sreg                  ; SREG sichern
83
    push    temp1
84
    
85
    in      temp1, UDR                   ; UART Daten lesen
86
87
;Abfragen der UART-Eingabe:
88
;Multiplexer einstellen:
89
90
    cpi     temp1, '0'                  ; Multiplexer Kanal 0
91
    breq    int_multi_0                   
92
93
94
    cpi     temp1, '1'                  ; Multiplexer Kanal 1
95
    breq    int_multi_1                  
96
97
98
;Relaissteuerung für Temperatursteuerung
99
    cpi     temp1, 'r'                  ; Relais 1 auf 0
100
    breq    int_rxc_R0                   ; 
101
102
    cpi     temp1, 't'                  ; Relais 1 auf 1
103
    breq    int_rxc_R1                   ; 
104
105
106
107
;ADC Kanal auswählen
108
    cpi     temp1, 's'                  ; ADC1
109
    breq    int_rxc_S                   ; wenn  gleich, dann zu int_rxc_S
110
111
    cpi     temp1, 'a'                  ; ADC2
112
    breq    int_rxc_A                   ; wenn  gleich, dann zu int_rxc_A
113
114
115
;relais 1 auf PD4 schalten 2 Zustaände 1 oder 0
116
int_rxc_R0:
117
    cbi     PORTD, 4                    
118
    rjmp    int_rxc_2                   
119
120
121
int_rxc_R1:
122
123
    sbi     PORTD, 4                    
124
    rjmp    int_rxc_2                   
125
126
127
;Multiplexer Kanal 0 --> cbi = 0
128
int_multi_0:
129
    cbi     PORTB, 0                    
130
    cbi     PORTB, 1                   
131
    cbi     PORTB, 2
132
  ldi     multinr, '0'       ; Beginn des Strings
133
                    
134
    rjmp    int_rxc_2                   
135
136
137
;Multiplexer Kanal 1
138
int_multi_1:
139
    sbi     PORTB, 0                    
140
    cbi     PORTB, 1                   
141
    cbi     PORTB, 2
142
  ldi     multinr, '1'       ; Beginn des Strings
143
    rjmp    int_rxc_2             
144
145
146
int_rxc_S:
147
; nur wenn "S" aufgerufen wird, sende ich den ADC-Wert 0
148
;*************************************************************************************************    
149
;*************************************************************************************************    
150
;*************************************************************************************************    
151
     ldi temp1, (0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0)    
152
  ;ldi temp1, (1<<REFS0)
153
154
  out     ADMUX, temp1
155
    ldi     temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
156
    out     ADCSRA, temp1
157
  clr     temp1
158
159
  ldi     sensornr, 'T'       ; Beginn des Strings
160
    ;rcall   transmit
161
  rcall   AusgabeADC ; gehe zur Prozedur Ausgabe
162
  rjmp    int_rxc_2                   ; Zu int_rxc_2 springen
163
164
165
166
int_rxc_A:
167
; nur wenn "A" aufgerufen wird, sende ich den ADC-Wert 1
168
;*************************************************************************************************    
169
;*************************************************************************************************    
170
;*************************************************************************************************    
171
     ldi temp1, (0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0)    
172
  ;ldi temp1, (1<<REFS0)
173
174
  out     ADMUX, temp1
175
    ldi     temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
176
    out     ADCSRA, temp1
177
  clr     temp1
178
179
  ldi     sensornr, 'F'       ; Beginn des Strings
180
    ;rcall   transmit
181
  rcall   AusgabeADC ; gehe zur Prozedur Ausgabe
182
  rjmp    int_rxc_2                   ; Zu int_rxc_2 springen
183
184
185
186
187
188
AusgabeADC: ;allgemeine Routine zum Ausgeben eines ADC-Wertes
189
;ADC-Wert lesen
190
191
sample_adc:
192
    sbi     ADCSRA, ADSC        ; den ADC starten
193
 
194
 
195
wait_adc:
196
    sbic    ADCSRA, ADSC        ; wenn der ADC fertig ist, wird dieses Bit gelöscht
197
    rjmp    wait_adc
198
 
199
; ADC einlesen:
200
 
201
    in      adlow, ADCL         ; immer zuerst LOW Byte lesen
202
    in      adhigh, ADCH        ; danach das mittlerweile gesperrte High Byte
203
 
204
;in ASCII umwandeln
205
; Division durch mehrfache Subtraktion
206
 
207
    ldi     ztausend, '0'-1     ; Ziffernzähler direkt als ASCII Code
208
Z_ztausend:
209
    inc     ztausend
210
    subi    adlow, low(10000)   ; -10,000
211
    sbci    adhigh, high(10000) ; 16 Bit
212
    brcc    Z_ztausend
213
                                    
214
    subi    adlow, low(-10000)  ; nach Unterlauf wieder einmal addieren
215
    sbci    adhigh, high(-10000); +10,000
216
 
217
    ldi     tausend, '0'-1      ; Ziffernzähler direkt als ASCII Code
218
Z_tausend:
219
    inc     tausend
220
    subi    adlow, low(1000)    ; -1,000
221
    sbci    adhigh, high(1000)  ; 16 Bit
222
    brcc    Z_tausend
223
                                    
224
    subi    adlow, low(-1000)   ; nach Unterlauf wieder einmal addieren
225
    sbci    adhigh, high(-1000) ; +1,000
226
 
227
    ldi     hundert, '0'-1      ; Ziffernzähler direkt als ASCII Code
228
Z_hundert:
229
    inc     hundert
230
    subi    adlow, low(100)     ; -100
231
    sbci    adhigh, high(100)   ; 16 Bit
232
    brcc    Z_hundert
233
                                    
234
    subi    adlow, low(-100)    ; nach Unterlauf wieder einmal addieren
235
    sbci    adhigh, high(-100)  ; +100
236
 
237
    ldi     zehner, '0'-1       ; Ziffernzähler direkt als ASCII Code
238
Z_zehner:
239
    inc     zehner
240
    subi    adlow, low(10)      ; -10
241
    sbci    adhigh, high(10)    ; 16 Bit
242
    brcc    Z_zehner
243
                                    
244
    subi    adlow, low(-10)     ; nach Unterlauf wieder einmal addieren
245
    sbci    adhigh, high(-10)   ; +10
246
 
247
    subi    adlow, -'0'         ; adlow enthält die Einer, Umwandlung in ASCII
248
 
249
;an UART Senden
250
 
251
    ;Senden beginnt mit T und endet mit X
252
    mov     zeichen, sensornr
253
  rcall   transmit
254
    mov     zeichen, multinr
255
  rcall   transmit
256
  mov     zeichen, ztausend   ; Zehntausender Stelle
257
    rcall   transmit
258
    mov     zeichen, tausend    ; Tausender Stelle ausgeben
259
    rcall   transmit    
260
    mov     zeichen, hundert    ; Hunderter Stelle ausgeben
261
    rcall   transmit
262
    mov     zeichen, zehner     ; Zehner Stelle ausgeben
263
    rcall   transmit
264
    mov     zeichen, adlow      ; Einer Stelle ausgeben
265
    rcall   transmit
266
    ldi     zeichen, 'X'       ; Ende des Strings
267
    rcall   transmit
268
    ldi     zeichen, ' '       ; Ende des Strings
269
    rcall   transmit
270
271
272
273
274
275
276
277
;*************************************************************************************************    
278
;*************************************************************************************************    
279
;*************************************************************************************************    
280
  rjmp    int_rxc_2                   ; Zu int_rxc_2 springen
281
282
283
284
; senden eines Strings
285
  
286
transmit:
287
    sbis    UCSRA,UDRE          ; Warten, bis UDR bereit ist ...
288
    rjmp    transmit
289
    out     UDR, zeichen        ; und Zeichen ausgeben
290
    ret
291
  
292
293
int_rxc_2:
294
;alles wieder herstellen
295
296
297
  pop     temp1
298
    out     sreg, temp1                  ; SREG wiederherstellen
299
    pop     temp1                        ; temp wiederherstellen
300
301
    reti                  ;wieder zurück

von holger (Gast)


Lesenswert?

>Ich habe jedoch noch das Problem, dass manchmal noch undefnierbare
>Zeichen gesendet werden,

Dann schliess besser mal einen Quarz an.

von Dirk P. (pfeiffy)


Lesenswert?

ok, können diese vom internen Quarz kommen?

von holger (Gast)


Lesenswert?

>ok, können diese vom internen Quarz kommen?

Es gibt keinen internen Quarz beim ATMega.
Sende doch mal dauernd nur ein Zeichen z.B. 'A'.
Wenn du dann Fehler bekommst ist der interne
Oszillator zu ungenau. Dann musst du den kalibrieren
oder besser gleich einen Quarz anschliessen.

von Quarzfinder (Gast)


Lesenswert?

Interner Quarz? Belege? Datenblatt? Gelesen? Woher?
Meinst du den RC-Schwinger den man noch kalibrieren muss damit er auf 
der gewünschten Frequenz schwingt und der mit der temperatur "furchtbar" 
wegdriftet..?
Interner Quarz also.

von Dirk P. (pfeiffy)


Lesenswert?

Äähm, ich habe mich nun entschlossen einen externen Quarz zu nehmen, ich 
hatte den auch schon dran. Nun noch die Fusebits einstellen über 
Burn-o-mat -> lief auch gut, nur... jetzt antwortet der Atmega8 nicht 
mehr ??????? warum verläßt er mich, er war doch noch so jung?????

--> das war der befehl:
C:\WinAVR-20100110\bin\avrdude.exe -C 
C:\WinAVR-20100110\bin\avrdude.conf -p m8 -P lpt1 -c alex  -u -U 
hfuse:w:0xD9:m -U lfuse:w:0xE7:m

hier der Programmer im  Conf:
programmer
  id    = "alex";
  desc = "Alex - Direct connection ISP";
  type = par;
  reset = 9;
  sck = 6;
  mosi = 7;
  miso = 10;
#  errled = <num> ;                          # pin number
  rdyled = 4;
#  pgmled = 4;
#  vfyled = 4;
;

von holger (Gast)


Lesenswert?

-U lfuse:w:0xE7:m

Du hast ihn auf ext. RC-Oscillator geflasht.

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,
ja das war ja meine Absicht, doch er antwortet nicht mehr!?

von hmmm (Gast)


Lesenswert?

Warum quälst du den Mikro mit rechnen und den UART mit ünnötiger 
Datenübertragung ;) ?

Umrechnen kann dein PC viel besser .. sogar in Java ;)

Aber aufpassen, Java kennt kein unsigned !

von Nico S. (nico22)


Lesenswert?

RC-Oscillator != Crystal Oscillator(=Quartz)

von holger (Gast)


Lesenswert?

>ja das war ja meine Absicht, doch er antwortet nicht mehr!?

Ein Quarz ist aber ein ext. Crystal Oscillator.

von Michael S. (Firma: electro-tester) (michael0307)


Lesenswert?

Hallo ,

RC-Oszillator != Quarz    // ;-)

siehe: AVR Fuses

Grüße....

Wir sind die Borg, Widerstand ist Spannung durch Stromstärke.

von Dirk P. (pfeiffy)


Lesenswert?

ist das die Ursache, dass der mc garnicht mehr antwortet? also vom 
avrdue garnicht mehr erkannt wird (rc=-1)?



@hmmm (komischer Name)
meinst u nur as hi und low-bite schicken, aber dennoch muss ich die 
Strings davorsetzen, damit das PC-Programm die Nachricht zuordnen kann 
(Protokoll)

von Nico S. (nico22)


Lesenswert?

Mit deiner Fuse-Einstellung kann der Mikrocontroller den Takt nicht 
verwerten. Kein Takt, keine laufende CPU. Keine laufende CPU, keine 
Reaktion.

von Dirk P. (pfeiffy)


Lesenswert?

OK, ich habe meinen Atmega beerdigt, war nicht der erste...
mit dem Mute der Verzweiflung habe ich nun einen neuen genommen und 
diesen mit Burn-o-mat und als crystal auf 3-8mhz und small output swing 
geändert, und er läuft und das Program tut auch das was es soll (im 
Moment nur einen Text senden).

Nun könnten wir wieder zum Programm kommen .... low und hi bite zum PC?

von Spess53 (Gast)


Lesenswert?

Hi

>Ich habe jedoch noch das Problem, dass manchmal noch undefnierbare
>Zeichen gesendet werden, habe ich noch einen Haken im Programm, bzw. was
>könnte ,man besser machen? , hier der Code:

Warum machst du die ganze Verarbeitung im RXC-Interrupt? Interrupts 
sollte man so kurz wie möglich machen. Es reicht, wenn deine 
Interruptroutine so aussieht:
1
int_rxc:
2
  in temp1,UDR
3
  reti

Die Bearbeitung erfolgt im Hauptprogramm:
1
    clr temp1
2
loop:
3
    test temp1
4
    breq loop
5
6
    ....              ;Bearbeitung
7
8
    clr temp1
9
    rjmp loop         ; Endlosschleife

MfG Spess

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

UART habe ich umgestellt auf reines Senden der high und low-byte - 
klappt.
Interrupt umstellen habe ich jetzt hier am Schreibtisch gemacht, ohne zu 
testen, wäre so der Weg?:
1
.include "m8def.inc"
2
 
3
.def temp1     = r16
4
.def sensornr  = r17         ; allgemeines temp Register, zur kurzfristigen Verwendung
5
.def multinr   = r18         ; allgemeines temp Register, zur kurzfristigen Verwendung
6
.def adlow     = r20         ; Ergebnis vom ADC / Mittelwert der 256 Messungen
7
.def adhigh    = r21         ; Ergebnis vom ADC / Mittelwert der 256 Messungen
8
.def zeichen   = r27         ; Zeichen zur Ausgabe auf den UART
9
10
 
11
.equ F_CPU = 4000000                            ; Systemtakt in Hz
12
.equ BAUD  = 9600                               ; Baudrate
13
 
14
; Berechnungen
15
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  
16
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     
17
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  
18
 
19
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))      
20
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
21
.endif
22
 
23
.org 0x00
24
        rjmp main
25
 
26
.org URXCaddr
27
        rjmp int_rxc
28
 
29
; Mainprogramm
30
main:
31
    
32
    ; Stackpointer initialisieren
33
 
34
    ldi     temp1, HIGH(RAMEND)
35
    out     SPH, temp1
36
    ldi     temp1, LOW(RAMEND)
37
    out     SPL, temp1
38
 
39
    ; Port B = Ausgang
40
    ; cbi = auf 0 setzen
41
    ; sbi = auf 1 setzen
42
    ldi     temp1, 0xFF
43
    out     DDRB, temp1
44
    ; Port B = Ausgang
45
    ldi     temp1, 0xFF
46
    out     DDRD, temp1
47
;Vorbelegung auf Multi Kanal 0 -> String bei Temperatursenden
48
    ldi     multinr, '0'       ; Beginn des Strings
49
50
51
 
52
    ; Baudrate einstellen
53
 
54
    ldi     temp1, HIGH(UBRR_VAL)
55
    out     UBRRH, temp1                
56
    ldi     temp1, LOW(UBRR_VAL)
57
    out     UBRRL, temp1
58
 
59
    ; Frame-Format: 8 Bit
60
 
61
    ldi     temp1, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)
62
    out     UCSRC, temp1
63
 
64
    sbi     UCSRB, RXCIE                ; Interrupt bei Empfang
65
    sbi     UCSRB, RXEN                 ; RX (Empfang) aktivieren
66
    sbi     UCSRB, TXEN                 ; TX (Senden) einschalten
67
   
68
    sei                                 ; Interrupts global aktivieren
69
70
int_rxc:
71
    push    temp1                        ; temp auf dem Stack sichern
72
    in      temp1, sreg                  ; SREG sichern
73
    push    temp1
74
    in      temp1, UDR                   ; UART Daten lesen
75
76
    reti ; raus aus dem Interrupt
77
78
    clr temp1  
79
;Schleife
80
loop:
81
 
82
; Interruptroutine: wird ausgeführt sobald ein Byte über das UART empfangen wurde
83
84
;Abfragen der UART-Eingabe:
85
;Multiplexer einstellen:
86
87
    cpi     temp1, '0'                  ; Multiplexer Kanal 0
88
    breq    int_multi_0                   
89
90
91
    cpi     temp1, '1'                  ; Multiplexer Kanal 1
92
    breq    int_multi_1                  
93
94
95
;Relaissteuerung für Temperatursteuerung
96
    cpi     temp1, 'r'                  ; Relais 1 auf 0
97
    breq    int_rxc_R0                   ; 
98
99
    cpi     temp1, 't'                  ; Relais 1 auf 1
100
    breq    int_rxc_R1                   ; 
101
102
103
104
;ADC Kanal auswählen
105
    cpi     temp1, 'a'                  ; ADC1
106
    breq    int_rxc_S                   ; wenn  gleich, dann zu int_rxc_S
107
108
    cpi     temp1, 's'                  ; ADC2
109
    breq    int_rxc_A                   ; wenn  gleich, dann zu int_rxc_A
110
    
111
    rjmp loop                           ; Endlosschleife
112
113
;relais 1 auf PD4 schalten 2 Zustände 1 oder 0
114
int_rxc_R0:
115
    cbi     PORTD, 4                    
116
    rjmp    int_rxc_2                   
117
118
119
int_rxc_R1:
120
121
    sbi     PORTD, 4                    
122
    rjmp    int_rxc_2                   
123
124
125
;Multiplexer Kanal 0 --> cbi = 0
126
int_multi_0:
127
    cbi     PORTB, 0                    
128
    cbi     PORTB, 1                   
129
    cbi     PORTB, 2
130
  ldi     multinr, '0'       ; Beginn des Strings
131
                    
132
    rjmp    int_rxc_2                   
133
134
135
;Multiplexer Kanal 1
136
int_multi_1:
137
    sbi     PORTB, 0                    
138
    cbi     PORTB, 1                   
139
    cbi     PORTB, 2
140
  ldi     multinr, '1'       ; Beginn des Strings
141
    rjmp    int_rxc_2             
142
143
144
int_rxc_S:
145
; nur wenn "S" aufgerufen wird, sende ich den ADC-Wert 0
146
;*******************************************************
147
     ldi temp1, (0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0)    
148
149
  out     ADMUX, temp1
150
    ldi     temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
151
    out     ADCSRA, temp1
152
  clr     temp1
153
154
  ldi     sensornr, 'T'       ; Beginn des Strings
155
  rcall   AusgabeADC ; gehe zur Prozedur Ausgabe
156
  rjmp    int_rxc_2                   ; Zu int_rxc_2 springen
157
158
159
160
int_rxc_A:
161
; nur wenn "A" aufgerufen wird, sende ich den ADC-Wert 1
162
;*******************************************************
163
     ldi temp1, (0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0)    
164
165
  out     ADMUX, temp1
166
    ldi     temp1, (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0)
167
    out     ADCSRA, temp1
168
  clr     temp1
169
170
  ldi     sensornr, 'F'       ; Beginn des Strings
171
  rcall   AusgabeADC ; gehe zur Prozedur Ausgabe
172
  rjmp    int_rxc_2                   ; Zu int_rxc_2 springen
173
174
175
AusgabeADC: ;allgemeine Routine zum Ausgeben eines ADC-Wertes
176
;ADC-Wert lesen
177
178
sample_adc:
179
    sbi     ADCSRA, ADSC        ; den ADC starten
180
 
181
 
182
wait_adc:
183
    sbic    ADCSRA, ADSC        ; wenn der ADC fertig ist, wird dieses Bit gelöscht
184
    rjmp    wait_adc
185
 
186
; ADC einlesen:
187
 
188
    in      adlow, ADCL         ; immer zuerst LOW Byte lesen
189
    in      adhigh, ADCH        ; danach das mittlerweile gesperrte High Byte
190
 
191
;an UART Senden
192
 
193
    ;Senden beginnt mit T und endet mit X
194
    mov     zeichen, sensornr   ;alphanumetrisch A-K
195
    rcall   transmit
196
    mov     zeichen, multinr    ;0 bis 7    
197
    rcall   transmit
198
    mov     zeichen, adlow      ; low-Wert ausgeben
199
    rcall   transmit
200
    mov     zeichen, adhigh     ; high-Wert ausgeben 
201
    rcall   transmit
202
    ldi     zeichen, 'X'       ; Ende des Strings
203
    rcall   transmit
204
    ldi     zeichen, ' '       ; Blank am Ende für Tests im Hypertemonal
205
    rcall   transmit
206
207
208
;*************************************************************  
209
   rjmp    int_rxc_2                   ; Zu int_rxc_2 springen
210
211
; senden
212
  
213
transmit:
214
    sbis    UCSRA,UDRE          ; Warten, bis UDR bereit ist ...
215
    rjmp    transmit
216
    out     UDR, zeichen        ; und Zeichen ausgeben
217
    ret
218
219
int_rxc_2:
220
;alles wieder herstellen
221
222
    pop     temp1
223
    out     sreg, temp1                  ; SREG wiederherstellen
224
    pop     temp1                        ; temp wiederherstellen
225
226
    ret                  ;wieder zurück

von Dirk P. (pfeiffy)


Lesenswert?

oh je, dat lüppt so nicht habe ich festgestellt, kann mir einer einen 
Tip geben, was ich noch ändern muss?

Gruß
Pfeiffy

von spess53 (Gast)


Lesenswert?

Hi

>    sei                                 ; Interrupts global aktivieren

>int_rxc:
>    push    temp1                        ; temp auf dem Stack sichern
>    in      temp1, sreg                  ; SREG sichern
>    push    temp1
>    in      temp1, UDR                   ; UART Daten lesen
>
>    reti ; raus aus dem Interrupt

>    clr temp1
>;Schleife
>loop:

Was soll denn die Interruptroutine in deinem loop?

MfG Spess

von Holger P. (Gast)


Lesenswert?

Ich würde das versenden so machen:
1
;Senden beginnt mit T und endet mit X
2
  mov     zeichen, sensornr
3
  rcall   transmit
4
  mov     zeichen, multinr
5
  rcall   transmit
6
7
  in      adlow, ADCL         ; immer zuerst LOW Byte lesen
8
  in      adhigh, ADCH        ; danach das mittlerweile gesperrte High Byte
9
 
10
; in ASCII umwandeln
11
; Division durch mehrfache Subtraktion
12
 
13
    ldi     zeichen, '0'-1     ; Ziffernzähler direkt als ASCII Code
14
Z_ztausend:
15
    inc     zeichen
16
    subi    adlow, low(10000)   ; -10,000
17
    sbci    adhigh, high(10000) ; 16 Bit
18
    brcc    Z_ztausend
19
    rcall   transmit
20
                                    
21
    subi    adlow, low(-10000)  ; nach Unterlauf wieder einmal addieren
22
    sbci    adhigh, high(-10000); +10,000
23
 
24
    ldi     zeichen, '0'-1      ; Ziffernzähler direkt als ASCII Code
25
Z_tausend:
26
    inc     zeichen
27
    subi    adlow, low(1000)    ; -1,000
28
    sbci    adhigh, high(1000)  ; 16 Bit
29
    brcc    Z_tausend
30
    rcall   transmit
31
                                    
32
    subi    adlow, low(-1000)   ; nach Unterlauf wieder einmal addieren
33
    sbci    adhigh, high(-1000) ; +1,000
34
 
35
    ldi     zeichen, '0'-1      ; Ziffernzähler direkt als ASCII Code
36
Z_hundert:
37
    inc     zeichen
38
    subi    adlow, low(100)     ; -100
39
    sbci    adhigh, high(100)   ; 16 Bit
40
    brcc    Z_hundert
41
    rcall   transmit
42
                                    
43
    subi    adlow, low(-100)    ; nach Unterlauf wieder einmal addieren
44
    sbci    adhigh, high(-100)  ; +100
45
 
46
    ldi     zeichen, '0'-1       ; Ziffernzähler direkt als ASCII Code
47
Z_zehner:
48
    inc     zeichen
49
    subi    adlow, low(10)      ; -10
50
    sbci    adhigh, high(10)    ; 16 Bit
51
    brcc    Z_zehner
52
    rcall   transmit        
53
                                    
54
    subi    adlow, low(-10)     ; nach Unterlauf wieder einmal addieren
55
    sbci    adhigh, high(-10)   ; +10
56
 
57
    subi    adlow, -'0'         ; adlow enthält die Einer, Umwandlung in ASCII
58
    mov     zeichen,adlow
59
    rcall   transmit
60
61
    ldi     zeichen, 'X'       ; Ende des Strings
62
    rcall   transmit
63
    ldi     zeichen, ' '       ; Ende des Strings
64
    rcall   transmit

Spart dir Register

.def ztausend  = r23         ; Zehntausenderstelle des ADC Wertes
.def tausend   = r24         ; Tausenderstelle des ADC Wertes
.def hundert   = r25         ; Hunderterstelle des ADC Wertes
.def zehner    = r26         ; Zehnerstelle des ADC Wertes

und macht es übersichtlicher. Da du die allema nicht mehr brauchst.


Wow mein erster Tipp in ASM hier grins

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

@holg_i:
ja, ich hab die ganze ASCIIs ja schon rausgeworfen und sende nur noch hi 
und low byte (siehe letzte Mitteilung)

@spess53
ääähhm....ok, ich hab noch so meine Probleme mit Assembler, kannst du 
mir hier helfen? Es soll auf jedem Fall beim Empfang eines Strings über 
den UART was das high und low byte gesendet werden.

Gruß
Pfeiffy

von Karl H. (kbuchegg)


Lesenswert?

Dirk P. schrieb:

> @spess53
> ääähhm....ok, ich hab noch so meine Probleme mit Assembler, kannst du
> mir hier helfen?

Ich denke, dass dir hier nicht wirklich klar ist, wie das mit rcall etc 
funktioniert. Was ein Interrupt ist dürftest auch noch nicht durchschaut 
haben.

Warum machst du den Empfang per Interrupt? Musst du doch nicht. Machs 
doch erst mal konventionell mittels Polling.


Du hast da einen ziemlichen Saustall auf dem Stack angerichtet. Im 
Grunde bist du gar nicht soweit von einer richtigen Lösung entfernt, 
wenn du die Ablaufpfade erst mal richtig stellst. Sieh erst mal zu, dass 
du das in den Griff kriegst.

Wenn du sowieso schon Java kannst, dann versteh ich nicht, warum du dir 
dann hier mit Assembler eine Baustelle aufmachst, die mit C (dank deiner 
Java Vorkentnisse) nur 1/4 so groß wäre.

von Spess53 (Gast)


Angehängte Dateien:

Lesenswert?

Hi

>ääähhm....ok, ich hab noch so meine Probleme mit Assembler, kannst du
>mir hier helfen? Es soll auf jedem Fall beim Empfang eines Strings über
>den UART was das high und low byte gesendet werden.

Das sollte dich aber nicht hindern, das Programm im Simulator zu testen.

Ein paar Kleinigkeiten habe ich schon korrigiert.

MfG Spess

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,
klar Einarbeiten in Assemble, weiss ich ja (aber mir fehlt die Zeit!)- 
alles was ich in Assembler machen will ist diese Schnttstelle zum PC 
über die UART und damit die ADCs abfragen und noch einen Multiplexer 
davor. Mehr möchte ich garnicht. Es klappt ja so wie ichs progranmmiert 
habe, jetzt wollte ich es nur noch verbessern.

Gruß
Pfeiffy

von Dirk P. (pfeiffy)


Lesenswert?

noch eine Frage: wie kann ich im Simulator den Interrupt simulieren?

von spess53 (Gast)


Lesenswert?

Hi

>noch eine Frage: wie kann ich im Simulator den Interrupt simulieren?

Während der Simulation im I/O View das passende Interrupt Flag Bit 
setzen.

MfG Spess

von Mark B. (markbrandis)


Lesenswert?

Dirk P. schrieb:
> Hallo,
> klar Einarbeiten in Assemble, weiss ich ja

C und nicht Assembler ist für Deinen Anwendungsfall die richtige Wahl, 
wie Karl heinz Buchegger schon bemerkt hat.

von Dirk P. (pfeiffy)


Lesenswert?

Hallo,

ich lass das jetzt mal mit c, der code, den mir spess gegeben hat läuft 
einwandfrei und macht genau das, was er soll, nochmals danke!!!!
Ich wende mich nun der Verarbeitung und der Auswertung, wie auch dem 
Versuchsaufbau zu. Mit Java ist das eine tolle Sache, läuft schon 
wunderbar!!


Gruß
Pfeiffy

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.