LogoChip: PWM Motor Control

Built-In PWM

A while back, John sent me some code that he and Tom had been using to test the pulse-width modulation (PWM) capabilities of the hardware underlying the LogoChip. I read through the PIC18F2320 datasheet over the weekend and learned how it does PWM; and between John and Tom’s sample code and the information in the datasheet, tonight I got a motor running at variable speed under software control.

To use the PIC’s PWM, you configure the Timer 2 counter for the modulation frequency (period, actually), then set the output port into PWM mode and configure the duty cycle. Sounds simple; it’s really just a matter of finding all the control registers and the proper bits. Because the PWM is implemented in the chip’s hardware, it keeps running at the last-set duty cycle (== motor speed) even if you’re doing something else or your program stops running, so you can set and forget.

I’d like to measure the PWM output frequency and confirm what the Timer 2 counter and prescalar are doing, but my frequency counter is giving me weird results and I have no idea how far out of calibration my scope is, so that’ll have to wait for another day. When I hook a speaker to the output, it sounds well below 440Hz, but the frequency counter is trying to tell me it’s 2+kHz. Feh.

Huh, when I calculate the frequency (if I’m doing it right), I come up with ~2.4kHz. My speaker is a piezo and it sounded funny, so maybe that’s outside its range and the frequency counter was right on?

The Code

After I got over the excitement of just getting it to work at all, I wanted it to do more than let me manually set a speed for my motor, so there are a couple of extra procedures at the bottom (pwm-speedup and pwm-slowdown) to ramp the speed from slow to fast and back down to slow. They add to the code length, but they’re not critical for implementing PWM.

Here’s the program:

Here’s the code:

;   Keith Neufeld
;   08-Mar-2006
;
;   LogoChip program to demo motor speed control with PIC PWM output.
;   Uses PWM channel 1 on port C2.  Duty cycle values determined with
;   NPN transistor driver with 9V motor supply.

constants [
    [CCP1CON $fbd]                      ;   capture/compare/PWM 1 control reg
    [T2CON $fca]                        ;   timer 2 control register
        [TMR2ON 2]                              ;   timer 2 enable bit
        [T2CKPS1 1]                             ;   timer 2 prescale bit 1
    [CCPR1L $fbe]                       ;   C/C/P 1 register low byte
    [PR2 $fcb]                          ;   timer 2 period register

    [pwm-port-ddr portc-ddr]            ;   PWM 1 outputs on port C2
    [pwm-bit 2]

    [period 255]                        ;   default timer period to use
    ;[low-duty 110]                     ;   lowest duty cycle for my motor to
    [low-duty 10]                       ;   start from a stop
    [high-duty 255]                     ;   highest possible cycle
]

;   Initialize PWM by configuring timer 2 for PWM period and enabling PWM mode.
to pwm-init
    clearbit pwm-bit pwm-port-ddr       ;   set PWM port to output

    ;write T2CON 6                      ;   set timer 2 on, prescalar 16
    setbit T2CKPS1 T2CON                ;   set timer 2 prescalar to 16
    write PR2 period                    ;   set timer period highest possible
    setbit TMR2ON T2CON                 ;   turn on timer 2

    write CCP1CON 12                    ;   set PWM mode
    ;write CCPR1L 128                   ;   set 50% duty cycle
end

;   Set PWM period and duty cycle.
to pwm-set :period :duty
    write PR2 :period                   ;   set timer period
    write CCPR1L :duty                  ;   set PWM duty cycle
end

;   Disable PWM by shutting off timer 2.
to pwm-off
    pwm-set 0 0                         ;   disable PWM by setting duty cyc to 0
    clearbit TMR2ON T2CON               ;   and turn off timer 2
end

;   Enable PWM and ramp up to highest speed at :increment / 255ths
;   per 1/10 second.
global [duty]
to pwm-speedup :increment
    setduty low-duty
    pwm-set period duty
    repeat ((high-duty - low-duty) / :increment) [
        wait 1
        setduty duty + :increment
        pwm-set period duty
    ]
    setduty high-duty
end

;   Enable PWM and ramp down from highest speed at :increment / 255ths
;   per 1/10 second.
to pwm-slowdown :increment
    setduty high-duty
    pwm-set period duty
    repeat ((high-duty - low-duty) / :increment) [
        wait 1
        setduty duty - :increment
        pwm-set period duty
    ]
    setduty low-duty
end

2 Responses to “LogoChip: PWM Motor Control”

  1. albert says:

    i want to ask something to you….it’s about my project. title is motor control…i want to use pwm to control the speed of motor.. can i use your program in my project??are this program is suitable to my project???

  2. Keith Neufeld says:

    Albert, you’re welcome to use this if it looks helpful to you. It’s written in LogoChip Logo, but you may be able to translate it to whatever language you’re using for your project.

Leave a Reply