Forum: Mikrocontroller und Digitale Elektronik Division von 32 Bitzahl durch Subtraktion


von Lukas G. (lukas88)


Lesenswert?

Hallo users,

Für eine Geschwindigkeitsmessung/Berechnung brauche ich eine Division. 
Nähmlich den Radumfang von 216.769893cm durch die gemessene Zeit 
200.7040ms das Resultat wird alle 1 sec per UART gesendet...

Meine momentaner testcode zur division:
1
;Register
2
3
.def    mcover  = r16 ; Mainclock overflow bei 1 sec (255)
4
.def    t1      = r17 ; temp Register
5
.def    stat    = r18 ; Statusregister
6
.def    z2      = r19 ; Timer für Warteschleifen
7
.def    z3      = r20 ; Impulszähler
8
.def    zeichen = r21 ; UART senderegister
9
.def    mcl     = r24 ; Mainclock low
10
.def    mch     = r25 ; Mainclock high
11
12
13
;Konstanten
14
.equ    PD          = PORTD
15
.equ    DD          = DDRD
16
17
.equ    PB          = PORTB
18
.equ    DB          = DDRB
19
20
.equ    F_CPU       = 4000000 ; Systemtakt in Hz
21
.equ    BAUD        = 9600    ; Baudrate
22
23
24
25
26
; Berechnungen 
27
.equ UBRR_VAL   = ((F_CPU+BAUD*8)/(BAUD*16)-1)  ; clever runden
28
.equ BAUD_REAL  = (F_CPU/(16*(UBRR_VAL+1)))     ; Reale Baudrate
29
.equ BAUD_ERROR = ((BAUD_REAL*1000)/BAUD-1000)  ; Fehler in Promille
30
 
31
.if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))       ; max. +/-10 Promille Fehler
32
  .error "Systematischer Fehler der Baudrate grösser 1 Prozent und damit zu hoch!"
33
.endif
34
35
;Vektoren
36
.org 0x0000
37
    rjmp    configurations
38
.org 0x0004
39
    rjmp    timer2_overflow
40
41
;Interrupts
42
43
44
    
45
timer2_overflow:
46
47
    cpi         mcl,low(15625)
48
    brsh        highbit
49
    rjmp        next_i
50
highbit:
51
    cpi         mch,high(15625)
52
    brsh        one_second_done
53
    rjmp        next_i
54
one_second_done:
55
    ldi         stat,1
56
    cbi         PB,1
57
    cpi         mcover,255 ; Maximal 255 sekunden (4.25 min)
58
    breq        mcover_zero
59
    inc         mcover
60
    rjmp        set_zero
61
mcover_zero:
62
    clr         mcover
63
    inc         mcover
64
set_zero:
65
    ldi         mcl,low(1) ; Mainclock zähler auf 1
66
    ldi         mch,high(0)
67
    sbi         PB,1
68
next_i:
69
    adiw        mcl,1
70
reti
71
72
;Sprungprgramme:
73
74
   
75
lcd_number16:
76
; Million
77
78
; Million
79
80
lcd_100mil:
81
82
        ldi     t1, '0'-1
83
lcd_mil100:
84
        inc     t1
85
        subi    R26,low(100000000)
86
        sbci    R27,BYTE2(100000000)
87
        sbci    R28,BYTE3(100000000)
88
        sbci    R29,BYTE4(100000000)
89
        brcc    lcd_mil100
90
        subi    R26,low(-100000000)
91
        sbci    R27,BYTE2(-100000000)
92
        sbci    R28,BYTE3(-100000000)
93
        sbci    R29,BYTE4(-100000000)
94
        mov     zeichen,t1
95
        rcall   serout
96
97
98
lcd_10mil:
99
100
        ldi     t1, '0'-1
101
lcd_mil10:
102
        inc     t1
103
        subi    R26,low(10000000)
104
        sbci    R27,BYTE2(10000000)
105
        sbci    R28,BYTE3(10000000)
106
        sbci    R29,BYTE4(10000000)
107
        brcc    lcd_mil10
108
        subi    R26,low(-10000000)
109
        sbci    R27,BYTE2(-10000000)
110
        sbci    R28,BYTE3(-10000000)
111
        sbci    R29,BYTE4(-10000000)
112
        mov     zeichen,t1
113
        rcall   serout
114
115
lcd_mil:
116
117
        ldi     t1, '0'-1
118
lcd_mil1:
119
        inc     t1
120
        subi    R26,low(1000000)
121
        sbci    R27,BYTE2(1000000)
122
        sbci    R28,BYTE3(1000000)
123
        sbci    R29,BYTE4(10000000)
124
        brcc    lcd_mil1
125
        subi    R26,low(-1000000)
126
        sbci    R27,BYTE2(-1000000)
127
        sbci    R28,BYTE3(-1000000)
128
        sbci    R29,BYTE4(-10000000)
129
        mov     zeichen,t1
130
        rcall   serout
131
132
133
134
; Hunderttausender
135
lcd_ht:
136
137
        ldi     t1, '0'-1
138
139
lcd_ht1:
140
        inc     t1
141
        subi    R26,low(100000)
142
        sbci    R27,BYTE2(100000)
143
        sbci    R28,BYTE3(100000)
144
        brcc    lcd_ht1
145
        subi    R26,low(-100000)
146
        sbci    R27,BYTE2(-100000)
147
        sbci    R28,BYTE3(-100000)
148
        mov     zeichen,t1
149
        rcall   serout
150
151
zt:
152
; ** Zehntausender **
153
           ldi   t1, '0'-1
154
lcd_number1:
155
           inc   t1
156
           subi  R26, low(10000)
157
           sbci  R27, high(10000)
158
           sbci  R28, BYTE3(10000)
159
           brcc  lcd_number1
160
           subi  R26, low(-10000)
161
           sbci  R27, high(-10000)
162
           sbci  R28, BYTE3(-10000)
163
           mov   zeichen,t1
164
           rcall serout
165
          
166
 
167
; ** Tausender **
168
           ldi   t1, '0'-1
169
lcd_number2:
170
           inc   t1
171
           subi  R26, low(1000)
172
           sbci  R27, high(1000)
173
           brcc  lcd_number2
174
           subi  R26, low(-1000)
175
           sbci  R27, high(-1000)
176
           mov   zeichen,t1
177
           rcall serout
178
           
179
 
180
; ** Hunderter **
181
           ldi   t1, '0'-1
182
lcd_number3:
183
           inc   t1
184
           subi  R26, low(100)
185
           sbci  R27, high(100)
186
           brcc  lcd_number3
187
           subi  R26, (-100)
188
           mov   zeichen,t1          ; + 100 High-Byte nicht mehr erforderlich
189
           rcall serout
190
           
191
 
192
; ** Zehner **
193
           ldi   t1, '0'-1
194
lcd_number4:
195
           inc   t1
196
           subi  R26, 10
197
           brcc  lcd_number4
198
           subi  r26, -10
199
           mov   zeichen,t1
200
           rcall serout
201
        
202
 
203
; ** Einer **
204
           ldi   t1, '0'
205
           add   t1, R26
206
           mov   zeichen,t1
207
           rcall serout
208
209
           ldi  zeichen,0x7C
210
           rcall serout
211
212
serout:
213
214
    sbis    UCSRA,UDRE                  ; Warten bis UDR für das nächste
215
                                        ; Byte bereit ist
216
    rjmp    serout
217
    out     UDR, zeichen
218
    ret  ; zurück zum Hauptprogramm
219
220
221
divi:
222
223
divid_init:
224
225
    push    R24
226
    push    R25
227
    push    R26
228
    push    R27
229
230
    push    R28
231
    push    R29
232
    push    R30
233
    push    R31
234
   
235
    ldi     R24,low(216769893)
236
    ldi     R25,BYTE2(216769893)
237
    ldi     R26,BYTE3(216769893)
238
    ldi     R27,BYTE4(216769893)
239
240
241
    ldi     R28,low(2007040)
242
    ldi     R29,BYTE2(2007040)
243
    ldi     R30,BYTE3(2007040)
244
    ldi     R31,BYTE4(2007040)
245
246
    ldi     t1,'0'-1
247
   
248
div_1:
249
    inc     t1
250
    sub     R24,R28
251
    sbc     R25,R29
252
    sbc     R26,R30
253
    sbc     R27,R31
254
    brcc    div_1
255
    mov     R26,t1
256
    clr     R27
257
    clr     R28
258
    clr     R29
259
    rcall   lcd_number16
260
261
    pop     R31
262
    pop     R30
263
    pop     R29
264
    pop     R28
265
266
    pop     R27
267
    pop     R26
268
    pop     R25
269
    pop     R24
270
271
    
272
    ldi     stat,0
273
    rjmp    main
274
275
brucke:
276
    rjmp    divi
277
    
278
279
configurations:
280
281
    ldi         t1,HIGH(RAMEND) ;Stackpointer HIGH
282
    out         SPH,t1
283
284
    ldi         t1,LOW(RAMEND)  ;Stackpointer LOW
285
    out         SPL,t1
286
    
287
    ldi         t1,0x00 ;PortD als Eingang
288
    out         DD,t1
289
290
    ldi         t1,0xFF ;Pullups PortD aktivieren 
291
    out         PD,t1   
292
293
    ldi         t1,0xFF ;PortB als Ausgang
294
    out         DB,t1
295
296
    ldi         t1,0xFF ;PortB Pullups deaktiviert
297
    out         PB,t1
298
299
    ldi         t1,(1<<ISC01)|(1<<ISC00) ; Interrupt auf steigende flanke
300
    out         MCUCR,t1
301
302
    ldi         t1, HIGH(UBRR_VAL)
303
    out         UBRRH, t1
304
    ldi         t1, LOW(UBRR_VAL)
305
    out         UBRRL, t1
306
 
307
    ldi         t1,(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) ;Senden aktivieren UART
308
    out         UCSRC,t1
309
    
310
    sbi         UCSRB,TXEN
311
    
312
313
    ldi         t1,(0<<CS22)|(0<<CS21)|(1<<CS20) ; Timer2 teiler  1
314
    out         TCCR2,t1
315
316
    ldi         t1,(1<<TOIE2) ; Interrupt bei Timer Interrupt
317
    out         TIMSK,t1
318
319
    ldi         mcl,low(1) ; Mainclock zähler mit 1 vorladen
320
    ldi         mch,high(0)
321
       
322
    sei ; Aktiviere Interrupts
323
    
324
main:
325
    cpi         stat,1
326
    breq        brucke
327
    rjmp        main

Nun zum eigentlichen Problem. Bei der Ausgabe beim UART ist der Wert um 
48 zu hoch. Also anstatt 108 bekomme ich 156. Bis jetzt habe ich noch 
nicht nachvollziehen können ,WO sich diese 48 dazuaddieren...

Hab schon gedacht das der Timer mir die Zahlen durcheinander bringt, da 
ich die selben Register verwende, aber ist auch ohne Aktivierten Timer 
so.


Man könnte zwar jedes mal 48 subtrahieren, das wäre das Resultat auch 
korrekt, möchte aber schon wissen, woran es liegt...

mfg Wukas

von Nase (Gast)


Lesenswert?

Lukas G. schrieb:
> das Resultat wird alle 1 sec per UART gesendet...

Am Rande: Geht es dir explizit darum, in Assembler zu programmieren? 
Falls nicht, würde ich das angesichs der geforderten atemberaubenden 
Performance von 1 Übertragung/Sekunde in drei Zeilen C verpacken, 
einschließlich printf().

von Yalu X. (yalu) (Moderator)


Lesenswert?

Lukas G. schrieb:
> ldi     t1,'0'-1

Der ASCII-Code von '0' ist 48.

Dämmert was? :)

von Lukas G. (lukas88)


Lesenswert?

Yalu X. schrieb:
> Der ASCII-Code von '0' ist 48.
>
> Dämmert was? :)

Jep, es lag daran. War ja echt trivial. Sch wieder was gelernt...
 Danke vielmals

mfg Lukas

von Lukas G. (lukas88)


Lesenswert?

Nase schrieb:
> Am Rande: Geht es dir explizit darum, in Assembler zu programmieren?


Nein, aber ich habe mehr Erfahrung mit Assembler aus als mit C

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.