- LiTime Speicher und Akkus         
Ergebnis 1 bis 10 von 10

Thema: assembler: "kommazahlen" addieren

  1. #1
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    09.05.2004
    Ort
    Bielefeld / Paderborn
    Beiträge
    1.253

    assembler: "kommazahlen" addieren

    Anzeige

    Praxistest und DIY Projekte
    moin!


    für einen servocontroller brauch ich kommazahlen (um nicht nur die maximalpositionen bei einer pulslänge von 1 oder 2 anfahren zu können). das doofe ist, dass mein basic-compiler nur ganze zahlen bei einer wait-operation zulässt. ich hatte das so vor:

    Code:
             define var pls as byte   'variable für die pulslänge
             low rb.0
             let pls = 1
    pulse:
             wait 20
             high rb.0
             wait pls
             low rb.0               'einmal 20 ms low und dann high für pulslänge
             if rb.1 = high then goto increase  'wenn taste an rb.1 gedrückt
             goto pulse
    
    increase:
             let pls = pls + 0.1       'zu pls 0,1 addieren
             if pls > 2 then pls = 1      'pls nicht zu groß werden lassen
             wait 500             'kurze pause
             goto pulse
    das prog soll bei tastendruck den servo ein stück weiterfahren und bei endposition wieder an die anfangsposition gehen.
    der compiler macht allerdings aus dem "+0,1" "+1", wodurch mein servo bei tastendruck die jeweils andere endposition (1 oder 2) anfährt.
    jetzt hab ich mir überlegt, ich könnte das ganze in assembler vielleicht beheben, so dass ich den assembler-code direkt bearbeite und da eintrage, dass er nicht 1 sondern 0,1 dazuaddieren soll. der assembler-code den der compiler erstellt sieht an der stelle so aus:

    Code:
    ;ø~ø00039         let pls = pls + 0.1     'addiere 0,1ms zu pls
              movf      64,w
              movwf     16
              movf      64+1,w
              movwf     ARG0+1
              movlw     1
              movwf     18
              clrf      ARG1+1
              call      $$ADD16
              movf      16,w
              movwf     64
              movf      ERG+1,w
              movwf     64+1
              clrwdt    
    ;ø~ø00040                 'fertig
    das was hinter den kryptischen zeichen (zeilennummern vermute ich) steht, ist er basiccode, direkt drunter dann der assembler

    nun hab ich von assembler wenig ahnung und wollte mal die freaks hier fragen, was ich verändern muss.... hoffe ihr werdet schlau aus dem problem!

  2. #2
    Benutzer Stammmitglied
    Registriert seit
    02.06.2005
    Beiträge
    44
    Ich kenne den Befehlssatz für den Microcontroller nicht , aber:
    Können die Befehle die du nutzt überhaupt mit Kommazahlen umgehen?
    Als ich mich mal mit dem MIPS2000 beschäftigt habe, gabs extra Befehle+Register fuer float Operationen. Ganz einfach deshalb, weil Integerarithmetik und Floatarithmetik intern anders gehandhabt wird. So hat der MIPS dann auch ne extra Floatingpointeinheit neben der ALU für die Ganzahlarithmetik.

  3. #3
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    09.05.2004
    Ort
    Bielefeld / Paderborn
    Beiträge
    1.253
    naja, es würde vielleicht schon helfen, wenn der wait-befehl in assembler höher aufgelöst wäre (nicht 1ms sondern vielleicht 0,1 ms... oder 1 µs...) ich dachte wenn die "sprache" so hardwarenah ist, wäre das vielleicht möglich

  4. #4
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    Also, es ist logisch, dass du bei einem byte keine Kommas kannst (bytes gehen schon von Definition aus von 0 - 256 oder -128 - 12.

    Ansonsten kann der PIC selber gar keine Kommazahlen, außer vielleicht, wenn du für eine Zahl 2 Bytes definierst, einen für die Komma und einen für die Ganzzahl.

    Und das wait ist nur in Basic (zumindest guckt das hart danach aus) definiert, wenn du mal den Codeabschnitt posten könntest, den das Befehl "wait" generiert könnte ich dir vielleicht sagen, wie du es verschnellen könntest.
    MfG
    Mobius

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    09.05.2004
    Ort
    Bielefeld / Paderborn
    Beiträge
    1.253
    Code:
    ;ø~ø00026         wait 20
              movlw     20
              movwf     16
              movlw     0
              movwf     ERG+1
              movlw     165
              movwf     18
              call      $$WAIT
              clrwdt
    wäre ein 20 ms-wait. wirst du daraus schlau? ansonsten versuche ich es mal mit pulseout, der kann kürzere impulse, aber ist scheisse zu proggen, weil ich nicht genau weiss, was der für nen puls macht (nen oszi wäre hilfreich).

    edit:

    so ungefähr versteh ich den code, aber was heißt dieses '"ERG+1"

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    Also, ich bräuchte noch ein Codeschnipsel (such im Source-Code nach $$Wait). Dieser Teil Ladet nur einige Zahlen in den Register und ruft dann die Funktion $$Wait auf, welches, mMn den Register D'16' ausliest und dann so lange zu durchlaufen, bis es zu Ende ist.

    Das ERG ist wohl eine Zahl, die irgendwo im Asm-Quelltext vom Compiler definiert wurde.

    Ich hoffe nur, dass der Compiler den fertigen Asm-Quelltext nicht löscht, nachdem die Hex-File erstellt wurde.
    MfG
    Mobius

  7. #7
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    09.05.2004
    Ort
    Bielefeld / Paderborn
    Beiträge
    1.253
    Code:
    $$WAIT    movf      ERG,w
              iorwf     ERG+1,w
              jz        $$WEND
              movf      ARG1,w
              movwf     ARG1+1
    und der $$WEND:

    Code:
    $$WEND    retlw     0
    sooo. und nun schau mal, ob du das irgendwie schneller hinbekommst.

    wenn du kurz zeit hast, wäre ich auch über ein fertiges prog seeeeehr erfreut. ich will einfach nur an rb.0 nen servo mit nem puls zwischen 1 und 2 ms (100µs-schritte) ansteuern. die pulslänge soll über einen button an rb.4 jeweils um 100µs hochgesetzt werden. wenn pulslänge > 2000µs, dann pulslänge = 1000 µs

    wenn das wirklich jemand machen sollte *hoff*, dann hätte ich gerne die hex-datei. der pic ist nen 16F84A mit 4 mHz.

    ich denke das wäre das richtige. sag mir dann bitte, welchen wert ich da

  8. #8
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    OK, so schlau werd ich aus diesem Ding auch net :S

    Also, ich hab mich mal hingesetzt und etwas zusammengespielt:

    Code:
    ;usefull Macros and defines
    
    	list      p=16F84A            ; list directive to define processor
    	#include <p16F84A.inc>        ; processor specific variable definitions
    
    
    
    movlf MACRO register, literare
    	movlw literare
    	movwf register
    	ENDM
    
    #define clock D'156'
    
    ;memory
    CBLOCK 20h
    	c_timer  ;starts with 10 and ends with 20,
    			  ;and together with timer0 it'll 
    			  ;generate "interrupts" in an intervalle between 1ms
    			  ;and 2ms
    	t_timer
    	W_TEMP
    	STATUS_TEMP
    ENDC
    
    ;data
    org 0x000
    	goto main
    
    org 0x004
    	goto interrupt
    
    interrupt
    	;backup important registers
    	movwf W_TEMP 		 ; Copy W to TEMP register,
    	swapf STATUS, W 	 ; Swap status to be saved into W
    	movwf STATUS_TEMP 	 ; Save status to STATUS_TEMP register
    
    ISR
    	;Was it a PORTB-Interrupt?
    	btfsc INTCON,0
    	call  portb_int
    
    	;Was it the timer?
    	btfsc INTCON,2
    	call  timer_int
    
    	swapf STATUS_TEMP, W ; Swap nibbles in STATUS_TEMP register
    						 ; and place result into W
    	movwf STATUS 		 ; Move W into STATUS register
    						 ; (sets bank to original state)
    	swapf W_TEMP, F 	 ; Swap nibbles in W_TEMP and place result in W_TEMP
    	swapf W_TEMP, W 	 ; Swap nibbles in W_TEMP and place result into W
    	retfie
    
    ;the portb-interrupt function
    portb_int
    	bcf		INTCON,3
    	;test, if we have 20 in the c_timer register
    	movfw	c_timer
    	sublw	D'20'
    	BZ		port_is_null
    	incf	c_timer
    	return
    port_is_null
    	movlf	c_timer,D'10'
    	return
    
    
    ;the timer-interrupt function
    timer_int
    	bcf		INTCON,2
    	;test if t_temp = c_temp
    	movlf	TMR0,clock
    	movfw	t_timer
    	subwf	c_timer,W
    	BNZ		timer_not_ready
    	clrf	t_timer
    	banksel PORTA
    
    	btfss	PORTA,0
    	goto	set_it
    	bcf		PORTA,0
    	return
    
    set_it
    	bsf		PORTA,0
    	return
    
    timer_not_ready
    	incf	t_timer
    	return
    
    ;the main routine
    main
    	;Because we are using a 4MHz PIC, 
    	;we will get set timer0 to a prescale of 
    	;to get an overflow every 100µs.
    	movlf	c_timer,D'10'
    	banksel	OPTION_REG
    	clrf	OPTION_REG
    
    	;setup PORTB
    	banksel	PORTB
    	clrf	PORTB
    	clrf	PORTA
    	banksel	TRISB
    	movlf	TRISB,B'00010000' ;all Ports except rb.4 are outputs 
    							  ;and should be pulled to GND or VCC
    	clrf	TRISA
    	
    	;enable Interrupts for timer0 and Portb-changes
    	movlf	INTCON,B'10101000'
    
    	banksel	TMR0
    	movlf	TMR0,clock
    
    	;do nothing, interrupts make the rest
    loop
    	goto loop
    
    	end
    Das ganze Programm beruht auf eine etwas andere Art und Weise, wie du es machen wolltest:
    Ich benutzt den timer0 mit einem Prescale von 1 (d.h. alle 1 µs eine erhöhung des TMR0's) und lade 156 (d.h. 100 µs bis zu einem overflow) in den TRM0. Danach setzt ich zwei Interrupts, eines ist der Timer selber, das Andere PortB.4 low --> high (c_timer 10 --> 20).
    Wenn ein Timer interrupt passiert, checke ich mit einer Laufvariable von (10 --> 20 in 1er Schritten), wie viele µs ich schon hinter mir habe und wenn es = c_timer (counter_timer) ist, invertire ich das Bit PORTA.0 und lösche den t_timer register (temporary_timer). Wenn es dies nicht ist, erhöhe t_timer einfach um eines und verlasse den Interrupt.
    Wenn ein PortB-change interrupt auftritt, schaue ich, ob c_timer = 20 ist, wenn ja dann wird c_timer = 10, wenn nicht, erhöhe ich c_timer um eins (1).

    Dadurch dass der timer jeden 100µs überläuft und der software-prescale (ich nenn solche Laufvariablen halt so ) 10-20 ist, erreiche ich eine Wartezeit von 1 ms --> 2ms in 100µs Schritten.

    Leider habe ich mit Servos nicht viel am Hut, aber ich skiziere mal, was für einen Bild du mit einem Osci am Pin PORTA.0 erhälst (PortA musste ich deshalb wählen, weil beim Simulator irgendwie kein Interrupt ankam, wenn ich immer PORTB.0 verändert habe... interessant, ist aber so :-/ )
    Code:
    +-----1000µs-----+-----1000µs-----+-----1000µs-----+
                     |----------------|
    -----------------|                |-----------------
    MfG
    Mobius

    €dit: ich habe den Code nur im Simulator von MPLAB getestet, d.h. ich kann nicht wirklich viel über das Timing aussagen, außer, dass es stimmen müsste.

    €€dit: na, wieder einmal ein Beispiel gebracht, wie ein Code NICHT aussehen sollte ^^ Layout war noch nie meine Stärke gewesen...
    Angehängte Dateien Angehängte Dateien

  9. #9
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    09.05.2004
    Ort
    Bielefeld / Paderborn
    Beiträge
    1.253
    hey, das ganze is total nett von dir. aber ich glaube du hast da nen fehler gemacht. mit dem von dir skizzierten spannungsverlauf kannst du keinen servo steuern. das muss vielmehr so aussehen:

    Bild hier  
    da wo 1,5ms steht muss die pulslänge halt 1 - 2 ms betragen. 1,5 ist in diesem fall die servo-mittelstellung

    ich werd erstmal sehen, ob ich meinen eigenen code auf meinem 16f870 zum laufen bringe. ansonsten diskutieren wir an dieser stelle nochmal deinen code.

    nochmal danke für deine mühe!

  10. #10
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.10.2004
    Ort
    ferd. Waldmüllerg. 7/2
    Alter
    39
    Beiträge
    456
    oh... ja , wie gesagt, hatte keinen Schimmer, wie ein Servo anzusteuern sei ^_^ aber das ist keine Große Änderung, man muss nur eine weitere Variable einführen und in diesen 200 reinschreiben. Danach den Timer abwechselnd bis c_time und halt 200 rechnen lassen, das geht auch irgendwie (einfach abfragen, was auf dem PORTA.0 anliegt, ist's 0 dann 200, ansonsten c_time)...

    Keine Ursache, gestern war mir sowieso fast den ganzen Tag fad, da war es eine angenehme Abwechlung ^_^
    MfG
    Mobius

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

LiTime Speicher und Akkus