************************************************************************************************* ************************************************************************************************* ** ** ** File.................: servo.asm ** ** Function.............: hc08 assembly code to drive a servo motor (futaba fb-s148) ** * Persons Responsible..: Kerwin Lumpkins ** ** Version..............: 1.00 ** ** Last Updated.........: 12/21/02 ** ** ** **Description: ** This program provides control for 1 hobby servo motor (unmodified). **The position to which the motor rotates is defined in this program\par **as being either forward or backward (each is about 40 degrees off a\par **a reference center postition) or centered. A servo rotates to a certain\par **arc in response to a PWM (pulse width modulated) signal of about 40 Hz \par **and with a duty cycle that varies depending on the position desired. The\par **rough waveform diagram below gives def of these terms.\par **\par ** 5 volts ------- ------- ** | | | | ** | | | | ** | | | | ** 0 volts __ _________________________ ________ ** ** < - - - - - - period - - - - - - - - - > **duty c is duty cycle, meaning how long the pulse is "on duty" or ON.\par **The period will be about 40 Hz so that the pulse is repeated about \par **40 times every second. For most servos the duty cycle will be about \par **1 - 3 ms. If you send it a 1 ms pulse, the servo will rotate Counter\par **Clockwise as far as it can. If you send a 3 ms pulse, you get a Clockwise\par **rotation. If you send it a value in the middle, it will rotate to the\par **center or ref position. If it's already there, it won't move at all of \par **course. 5 volts, 6 volts, whatever the servo runs on of course.\par **The program simply sends a pulse to the motor to rotate it to the desired position **The duty cycle time is determined by experimentation to get the best rotation\par **time siganl. Then I use an internal clock time of 2.4576 MHz (9.8304 MHz \par **external oscillator divided by 4 as spec'd by the HC08) to figure out\par **how many clock cycles I need to count to get that time.\par **Example: If I want to send a pulse of 1.75 ms. ** 2.4576 MHz = 407 ns / clock cycle (1/frequency) * ** 10^6 ns 1 clk cycle ** 1.75 ms * ------- * ------------- = 4301 clock cycles ** 1 ms 407 ns **4301 in decimal is 10CC in hex, so I need to set the counter that sets **the duty cycle to count to 10CC hex (T1CH0H = 0x10 and T1CH0L = CC). **Similarly, the modulus counter counts off the 40 Hz period. I set that **hex C000. ** ** ** ************************************************************************************************* ************************************************************************************************* * Equates * * * * These are the locations of various MCU registers for the 68HC908GPXX MCU. * ************************************************************************************************* pta equ $00 ;port a data register ptb equ $01 ;port b data register ptc equ $02 ;port c data register ptd equ $03 ;port d data register pte equ $08 ;port e data register ddra equ $04 ;port a data direction register ddrb equ $05 ;port b data direction register ddrc equ $06 ;port c data direction register ddrd equ $07 ;port d data direction register ddre equ $0C ;port e data direction register scc1 equ $13 ;sci control register 1 scc2 equ $14 ;sci control register 2 scc3 equ $15 ;sci control reg 3 scs1 equ $16 ;sci status reg 1 scs2 equ $17 ;sci status reg 2 scdr equ $18 ;sci data reg scbr equ $19 ;sci baud rate reg config2 equ $1E ;sci config reg 2 config1 equ $1f ;config register 1 t1sc equ $20 ;timer 1 status and control reg t1cnth equ $21 ;timer 1 counter reg high t1cntl equ $22 ;timer 1 counter reg low t1modh equ $23 ;timer 1 modulo reg high t1modl equ $24 ;timer 1 modulo reg low t1sc0 equ $25 ;timer 1 channel 0 status and control reg t1ch0h equ $26 ;timer 1 channel 0 reg high t1ch0l equ $27 ;timer 1 channel 0 reg low ram equ $40 ;start of ram flash equ $8000 ;start of flash ($b000 for GP20, $8000 for GP32) *******************Specific to this application equates************************ org ram secs rmb 1 ************************************************************************************************* * Interrupt Vectors * * * * Go to interrupt vector area and fill with init to prevent any interrupts from affecting the * * code. * ************************************************************************************************* org $ffdc ;fill interrupt vectors fdb init ;timebase vector address fdb init ;conversion complete vector address fdb init ;keyboard pin vector address fdb init ;sci transmit complete, empty vector address fdb init ;sci idle or receiver full vector address fdb init ;sci parity, framing, noise, overrun error address fdb init ;spi transmitter empty vector address fdb init ;spi full,over,fault vector address fdb init ;tim2 overflow vector address fdb init ;tim2 channel 1 vector address fdb init ;tim2 channel 0 vector address fdb init ;tim1 overflow vector address fdb init ;tim1 channel 1 vector address fdb init ;tim1 channel 0 vector address fdb init ;cgm (pll) vector address fdb init ;IRQ pin vector address fdb init ;swi instruction vector address fdb init ;reset vector address ************************************************************************************************* * Initialization * * * * This section clears variables, and sets up internal registers for the microcontroller * ************************************************************************************************* org flash ;start main code at the beginning of flash init mov #$01,config2 ;Osc disable on stop, SCI clock source internal mov #$01,config1 ;COP disabled, all other default ldhx #$0240 ;load HX with the end of memory location txs ;put the stack pointer at the end of memory clra ;clears A, X, and H regs clrx clrh ************************************************************************************************* * main Program * * This is the main section of the code. * ************************************************************************************************* * **************** timer module set for 4 MHz ********************** mov #$20,t1sc ;stop TIM counter mov #$36,t1sc ;keep stopped, and reset counter mov #$ef,t1modh ;high of mov #$f1,t1modl ;low set mov #$0b,t1ch0h ;channel counter reg hi to 0 mov #$84,t1ch0l ;channel counter reg low to 1 mov #$1e,t1sc0 ;unbuf output,toggle on overflow,set out on compare pwmloop: mov #$10,t1sc ;reset TIM counter, start up the pwm generator (start motor) mov #$FF,ddrb ;set port b data direction for output mov #$00,ptb ;init port b to be all bits are low lda #!10 ;delay for 1 second by loading accumulator with the jsr waits ;argument 10 then call waits routine. 10 * .1 sec = 1 second bra standby ;then branch always to standby waits: ***** delay for number of .1 seconds passed in A reg sta secs ;save the .1 sec counter wsloop: lda #!100 ; .1 sec = 100 ms\par bsr waitms ; wait that long\par dec secs ; dec .1 sec counter\par bne wsloop ;loop until 0\par rts waitms: ****** delay for number of miliseconds passed in A reg wmsolp: ldx #!250 ;number of loops for 1 ms delay wmsilp: decx ;decrement nop ; no op for a bit bne wmsilp ; dec deca bne wmsolp ; loop for spec'd number of ms rts standby: mov #$20,t1sc ;stop TIM counter, this stops the motor mov #$ff,ptb ;drive port b lines high lda #!10 ;wait a second jsr waits mov #$00,ptb ;then drive 'em low lda #!10 ;hold them there for a sec jsr waits bra pwmloop ;then branch back to pwm loop and start over, run a loop