Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC18F4620 Technical questions

Status
Not open for further replies.

Aleks

Member
One more guys. I'm not used to PIC's (AVR user) and I still have some difficulty getting around PICs. My question is, can I get 3 PWM outputs from this micro (PIC18F4620) for driving 3 servo motors ?

The servos have a pulse width range from 500uS to 2600uS and I need some decent resolution out of it. As I've read through the datasheet 2 PWM modules only, can they be used for driving three separate servos ?

The tON time (the angle of the servos) will be given via the UART.

Regards !
 
The hardware PWM is poorly suited for driving servos. Better off to stick with software and use interrupts.

And yes that PIC has only two PWM modules, just like the ATmega328.
 
Last edited:
The hardware PWM is poorly suited for driving servos.

Actually, the PWM module is particularly well suited for driving servos with a jitter free, high resolution, interrupt tolerant pulse. In this case however, two PWM modules are not enough to drive three servos, that is unless the OP is willing to add an additional IC, in which case each PWM module (and IC) could drive eight servos.
 
Last edited:
If I may, I'd like to supplement my previous post...

I just remembered that I wrote a demo program last January for 4 servos using PWM pulse steering on a 16F1823. The pulse steering feature can be found on several newer PIC devices. The program is written in assembly language with C code comments.

Food for thought...

Regards, Mike

Code:
;******************************************************************
;                                                                 *
;   Filename: 16F1823 Servo Steering.asm                          *
;     Author: Mike McLaren, K8LH                                  *
;    (C)2012: Micro Application Consultants                       *
;           : All Rights Reserved                                 *
;       Date: 29-Jan-12                                           *
;                                                                 *
;   16F1823 four channel PWM "Servo Steering" experiment          *
;                                                                 *
;                                                                 *
;      MPLab: 8.80    (tabs=8)                                    *
;      MPAsm: 5.43                                                *
;                                                                 *
;******************************************************************

        #include <P16F1823.INC>
        radix dec
        errorlevel -302
        list st=off

  __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF
  __CONFIG _CONFIG2, _BORV_LO & _LVP_OFF & _PLLEN_OFF
;
; _PWRTE_OFF    default
; _CP_OFF       default
; _CPD_OFF      default
; _BOREN_ON     default
; _CLKOUTEN_OFF default
; _IESO_ON      default
; _FCMEN_ON     default
;
; _WRT_OFF      default
; _STVREN_ON    default
;

;--< variables >---------------------------------------------------

        cblock  0x020           ; bank 0 ram
servo:8                         ; 500..2500 (usecs)
width:2                         ; isr work variable
frame                           ; frame counter, 0..20
steer                           ; steering bit mask
index                           ; servo channel index, 0..3
        endc
;
;  servo[0] -> RC5 (pin 5)
;  servo[1] -> RC4 (pin 6)
;  servo[2] -> RC3 (pin 7)
;  servo[3] -> RC2 (pin 8)
;

;******************************************************************
;  reset vector                                                   *
;******************************************************************
        org     0x0000
v_reset
        banksel ANSELA          ; bank 3                          |B3
        clrf    ANSELA          ; set digital I/O                 |B3
        bra     init            ;                                 |B3

;******************************************************************
;  interrupt vector                                               *
;******************************************************************
    org    0x0004
;
;  void interrupt()             // 250-uS (1000 cycle) interrupts
;  { pir1.TMR2IF = 0;           //
;    if(width >= 250)           //
;      ccpr1l = 250;            //
;    else                       //
;      ccpr1l = width;          //
;    width -= ccpr1l;           //
;
;    pstr1con = steer | (1<<STR1SYNC);
;
v_int
        bcf     PIR1,TMR2IF     ; clear TMR2 interrupt flag       |B0
        movlw   low(250)        ;                                 |B0
        subwf   width+0,W       ;                                 |B0
        movlw   high(250)       ;                                 |B0
        subwfb  width+1,W       ;                                 |B0
        movf    width+0,W       ;                                 |B0
        skpnc                   ; borrow? yes, skip, else         |B0
        movlw   250             ;                                 |B0
        banksel CCPR1L          ; bank 5                          |B5
        movwf   CCPR1L          ; duty cycle for next frame       |B5
        movlb   0               ; bank 0                          |B0
        subwf   width+0,F       ;                                 |B0
        movlw   0               ;                                 |B0
        subwfb  width+1,F       ;                                 |B0
        movf    steer,W         ;                                 |B0
        iorlw   1<<STR1SYNC     ;                                 |B0
        banksel PSTR1CON        ;                                 |B5
        movwf   PSTR1CON        ; steering for next frame         |B5
        movlb   0               ; bank 0                          |B0
;
;    if(--frame == 0)           // if end of 5 ms period
;    { frame = 20;              // reset 5 ms counter and
;      if(!(steer >>= 1))       // if last channel
;        steer = 8;             // reset for channel 0
;      width = servo[index];    // new servo 'width'
;      index++; index.2 = 0;    // next channel index, 0..3
;    }
;  }
;
        decfsz  frame,F         ; next servo? yes, skip, else     |B0
        retfie                  ;                                 |B0

        movlw   20              ; twenty 250 us periods           |B0
        movwf   frame           ; reset 5-msec counter            |B0
        lsrf    steer,F         ; last channel?                   |B0
        skpnc                   ; no, skip, else                  |B0
        bsf     steer,3         ; reset to '00001000'             |B0
        lslf    index,W         ; index 0..3 -> 0..6              |B0
        addlw   servo           ; add 'servo' array address       |B0
        movwf   FSR0L           ;                                 |B0
        clrf    FSR0H           ;                                 |B0
        moviw   FSR0++          ; width = servo[index]            |B0
        movwf   width+0         ;                                 |B0
        moviw   FSR0++          ;                                 |B0
        movwf   width+1         ;                                 |B0
        incf    index,F         ; bump index, 1..4                |B0
        bcf     index,2         ; 0..3 inclusive                  |B0
        retfie                  ;                                 |B0

;******************************************************************
;  main.init                                                      *
;******************************************************************
;
;  void main()                  //
;  { ansela = 0;                // digital I/O
;    osccon = 0b01111010;       // intosc = 16 MHz
;    while(!oscstat.HFIOFS);    // wait for osc stable
;
init
        banksel OSCCON          ; bank 1                          |B1
        movlw   b'01111010'     ; 16-MHz (no pll)                 |B1
        movwf   OSCCON          ; setup 16-MHz INTOSC             |B1
waitfs  btfss   OSCSTAT,HFIOFS  ; stable? yes, skip, else         |B1
        bra     waitfs          ; branch and wait                 |B1
;
;  // configure ports
;
;    trisa = 0b00001000;        // RA3 input
;    trisc = 0b00000000;        // RC5-RC0 all outputs
;    lata = 0;                  //
;    latc = 0;                  //
;
        movlw   b'00001000'     ;                                 |B1
        movwf   TRISA           ; RA3/RX input, others outputs    |B1
        clrf    TRISC           ; RC5..RC0 outputs                |B1
        banksel LATA            ; bank 2                          |B2
        clrf    LATA            ;                                 |B2
        clrf    LATC            ;                                 |B2
;
;  // initialize program variables
;
;    unsigned char steer = 1;   //
;    unsigned char index = 0;   //
;    unsigned char frame = 1;   //
;    unsigned int width = 0;    //
;
;    unsigned int servo[] = { 1500, 1500, 1500, 1500 };
;
        movlb   0               ; bank 0                          |B0
        movlw   b'00000001'     ;                                 |B0
        movwf   steer           ; steer = 0b00000001              |B0
        clrf    index           ;                                 |B0
        clrf    width+0         ; width = 0                       |B0
        clrf    width+1         ;                                 |B0
        movlw   1               ;                                 |B0
        movwf   frame           ; frame = 1                       |B0
        movlw   1500%256        ;                                 |B0
        movwf   servo+0         ; servo[0] = 1500                 |B0
        movwf   servo+2         ; servo[1] = 1500                 |B0
        movwf   servo+4         ; servo[2] = 1500                 |B0
;       movwf   servo+6         ; servo[3] = 1500                 |B0
        movlw   1500/256        ;                                 |B0
        movwf   servo+1         ;                                 |B0
        movwf   servo+3         ;                                 |B0
        movwf   servo+5         ;                                 |B0
;       movwf   servo+7         ;                                 |B0
        movlw   500             ; servo[3] = 500                  |B0
        movwf   servo+6         ;                                 |B0
        clrf    servo+7         ;                                 |B0
;
;  // setup PWM for a 250 us (1000 cycle) period (16 MHz clock)
;
;    ccp1con = 0b00001100;      // active hi PWM mode
;    pstr1con = 1<<STR1SYNC;    // synchronous steering
;    ccpr1l = 0;                // 0% duty cycle initially
;    tmr2 = 0;                  // clear TMR2
;    t2con = 0b00000101;        // -0000--- TOUTPS post 1:1
;                               // -----1-- TMR2ON -> "on"
;                               // ------01 T2CKPS prescale 4
;                               // for 1 usec 'ticks'
;    pr2 = 250-1;               // 250 us interrupts
;    pie1.TMR2IE = 1;           // enable TMR2 interrupts
;    pir1 = 0;                  // clear peripheral int flags
;    intcon = 1<<GIE|1<<PEIE;   // enable interrupts
;
        banksel CCP1CON         ; bank 5                          |B5
        movlw   b'00001100'     ; 00------ P1M                    |B5
                                ; --00---- DC1B duty cycle lsb's  |B5
                                ; ----1100 CCP1M active hi PWM    |B5
        movwf   CCP1CON         ; setup module for active hi PWM  |B5
        movlw   1<<STR1SYNC     ;                                 |B5
        movwf   PSTR1CON        ; use synchronous steering        |B5
        clrf    CCPR1L          ; 0% duty cycle                   |B5
        banksel TMR2            ; bank 0                          |B0
        clrf    TMR2            ;                                 |B0
        movlw   b'00000101'     ; -0000--- TOUTPS post 1:1        |B0
                                ; -----1-- TMR2ON timer 2 "on"    |B0
                                ; ------01 T2CKPS prescale 4      |B0
        movwf   T2CON           ; for 1 usec (4 cycle) ticks      |B0
        movlw   250-1           ;                                 |B0
        movwf   PR2             ; for 250 us period               |B0
        banksel PIE1            ; bank 1                          |B1
        bsf     PIE1,TMR2IE     ; enable TMR2 interrupts          |B1
        banksel PIR1            ; bank 0                          |B0
        clrf    PIR1            ; clear all interrupt flags       |B0
        movlw   1<<GIE|1<<PEIE  ;                                 |B0
        movwf   INTCON          ; global & peripheral ints on     |B0

;******************************************************************
;  main.loop                              *
;******************************************************************
;
;    while(1);                  //
;  }
;
loop
        bra     loop            ;                                 |B0

;******************************************************************
    end
 
Last edited:
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top