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.

Hardware ESC 8xSERVO CONTROL on PIC (Oshonsoft BASIC)

Pommie

Well-Known Member
Most Helpful Member
So, I did write that. The use of but was that I believe 1 chip can do everything.

Mike.
 

camerart

Active Member
Hi,
I've been looking at how the 74HC164 works, and keep seeing reference to 74HC595.
I looked at the difference and saw this:
So, is the 74HC164 the best choice?
C.
=============================================
74HC595 vs. 74HC164

The 74HC164 differs from the 74HC595 in that it does not buffer the data (internal space was present on the 74HC595), therefore the LED FLASHES as it pulls the bits to the tip-toe, producing the flashing effect observed on the 74HC164 but not on the 74HC595.

To be more detailed:

  • The output of the 74HC595 has a latch, so it can remain unchanged during the shift; the output of the 74HC164 does not have a latch, so it changes every time a shift clock is created. This is the most significant distinction between the two.
  • To achieve a multi-chip cascade, the 74HC595 utilizes a specific Q7 pin; the 74HC164 cascades directly using output pin Q7.
  • When the enable OE is faulty, the output pin of the 74HC595 is a high impedance, but the 74HC164 has no enable pin.
  • The shift register is reset by the 74HC595. If you want to reset the LATCH register, you must load the contents of the shift register into the latch register on the rising edge of ST CP; that is to say, the 74HC595 reset is synchronous, but the 74HC164 reset is asynchronous.
  • The parallel-to-serial chip 74HC165 corresponds to the 74HC164.
======================================================
 

rjenkinsgb

Well-Known Member
Most Helpful Member
So, is the 74HC164 the best choice?
Yes, absolutely - for this specific application.

The idea is to shift one bit through, so it sets each output high in turn. The "flicker" if you like, but that is a sequence of servo pulses.

The clock input to shift it will come from the output compare pin so the timing is then purely hardware, and software delays cannot cause jitter - the software has plenty of time just to set up the next compare each time.


The 595 is ideal as as "output expander" for normal things like switching LEDs or relays, as you can shift data in without affecting the pins then transfer it to the latch once it's in the correct bit alignment.

It needs more control signals though so it can only be driven via a software routine, which means the likelihood of jitter again.
 

camerart

Active Member
Yes, absolutely - for this specific application.

The idea is to shift one bit through, so it sets each output high in turn. The "flicker" if you like, but that is a sequence of servo pulses.

The clock input to shift it will come from the output compare pin so the timing is then purely hardware, and software delays cannot cause jitter - the software has plenty of time just to set up the next compare each time.


The 595 is ideal as as "output expander" for normal things like switching LEDs or relays, as you can shift data in without affecting the pins then transfer it to the latch once it's in the correct bit alignment.

It needs more control signals though so it can only be driven via a software routine, which means the likelihood of jitter again.
Hi R,
Ah good!

Am I correct that it replaces the " servotemp = 1 << servocount 'Make up what is required on port B NEXT TIME " linein some way?
C.
 

camerart

Active Member
In a way, yes!
Hi R,
I've been looking at how the 74HC164 and 74HC595 work, and their differences.
One possible issue with the 74HC164 is as the BITs are filling the BYTE, if they don't fill fast enough, they have a momentary voltage, I am assuming that the PIC that clocks them is too fast to worry about. I notice the 74HC595 can be 'loaded' then trigger the output, and the 4431 has plenty of spare tracks if needed.

A possible problem: I have the SERVOS power voltage at 5V, but the PIC triggering them is 3.3V and this may need attention?
C.
 

Pommie

Well-Known Member
Most Helpful Member
This is code I think will work with a 164. RC0 should go to the data input (pins 1&2) and RC1 to clock (pin 8). The servos go to Qa to Qe.
Not tested as no hardware, comments welcome.
Code:
#include <xc.h>
#include "config.c"
#include <stdint.h>
#define _XTAL_FREQ 32000000
#define NUM_SERVOS 10

uint16_t servoPos[NUM_SERVOS];
uint32_t ms;
uint8_t count=0,servoCount;


void main(void) {
    OSCCON=0b01110000;      //8MHz
    PLLEN=1;                //x4=32MHz
    //setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    T2CON=0b01001110;       //pre=16 post=10
    PR2=49;
    TMR2IE=1;               //timer 2 interrupts enable
    T1CON=0;                //timer 1 stopped
    for(uint8_t i=0;i<NUM_SERVOS;i++){
        servoPos[i]=i*1000+8000; //1ms(8000) to 1.875(7/8ths - 15000)ms in 1/8th mS steps
    }
    TRISC=0b11111100;           //CCP0 & 1 output
    PEIE=1;
    GIE=1;
    while(1){
            //adjust servo positions here
    }
}


void __interrupt() inter(void){
    if(TMR2IE && TMR2IF){
        ms++;
        count++;
        if(count>=20){          //start every 20mS
            TMR1=0;             //zero timer 1
            T1CON=1;            //start timer 1
            count=0;
            CCP1CON=0b1000;     //CCP1 pin low and high on match - will be first pulse
            CCPR1=2000;         //start pulse in 0.25mS (2000 clock cycles)
            CCP1IE=1;           //enable CCP1 interrupts
            CCP1IF=0;           //ensure interrupt flag is clear
            servoCount=0;       //reset servoCount
            LATC0=1;            //connected to data in of shift register will clock in a high when CCP1 goes high
        }
        TMR2IF=0;
    }
    if(CCP1IE && CCP1IF){
        LATC0=0;                //clear the data in pin
        if(servoCount==9)       //have we done all servos?
            CCP1IE=0;           //yes so no more CCP1 interrupts   
        if(CCP1CON==0b1000){    //have we started the 4000 cycle pulse
            CCP1CON=0b1001;     //yes so end the pulse after 0.5mS
            CCPR1=CCPR1+4000;   //4000 cycles=0.5mS
        }else{
            CCP1CON=0b1000;     //No so output the timed gap          
            CCPR1=CCPR1+servoPos[servoCount++]-4000;   //will generate an interrupt when servo time is up
        }
        CCP1IF=0;
    }
}
It (I hope) outputs a 0.5mS pulse every servoTime.

Mike.
Edit, added a millisecond interrupt as it's useful.
 

rjenkinsgb

Well-Known Member
Most Helpful Member
One possible issue with the 74HC164 is as the BITs are filling the BYTE, if they don't fill fast enough, they have a momentary voltage, I am assuming that the PIC that clocks them is too fast to worry about.

That's not a problem, it is essential for how this setup works!

Look at the actual RC signal waveforms I posted earlier on:

RC_Waveforms.jpg


The shift register moves a single bit through to each output in turn - like the "Channel x Servo signals"

The PPM waveform at the top is from the PIC compare hardware rather than a radio receiver, shifting the bit each 1 - 2 mS as appropriate for each respective servo position.

Unless the outputs changes as the SR was clocked, there would not be any servo outputs!

For decades, Radio control receivers used to use a shift reg IC for the conversion back to servo pulses, before MCU based ones took over.


ps. If you need to translate to 5V power for the shift register, it should have been a 74HCT164
The HCT ones take TTL levels and 3.3V logic is perfect to feed those with the HCT device working on 5V.
 

camerart

Active Member
That's not a problem, it is essential for how this setup works!

Look at the actual RC signal waveforms I posted earlier on:

View attachment 140109

The shift register moves a single bit through to each output in turn - like the "Channel x Servo signals"

The PPM waveform at the top is from the PIC compare hardware rather than a radio receiver, shifting the bit each 1 - 2 mS as appropriate for each respective servo position.

Unless the outputs changes as the SR was clocked, there would not be any servo outputs!

For decades, Radio control receivers used to use a shift reg IC for the conversion back to servo pulses, before MCU based ones took over.


ps. If you need to translate to 5V power for the shift register, it should have been a 74HCT164
The HCT ones take TTL levels and 3.3V logic is perfect to feed those with the HCT device working on 5V.
Hi R,
Ok, good, I'm getting the idea.

Regarding HC v HCT. The PICoutputs 3.3v and has been moving the SERVO in the tests, so I can play a little, where I introduce 5V, perhaps the 164 will be triggered by 3.3V and be powered by 5V which will suit the SERVOS better, or I can get the HCTs later.
Thanks.
C
 

camerart

Active Member
This is code I think will work with a 164. RC0 should go to the data input (pins 1&2) and RC1 to clock (pin 8). The servos go to Qa to Qe.
Not tested as no hardware, comments welcome.
Code:
#include <xc.h>
#include "config.c"
#include <stdint.h>
#define _XTAL_FREQ 32000000
#define NUM_SERVOS 10

uint16_t servoPos[NUM_SERVOS];
uint32_t ms;
uint8_t count=0,servoCount;


void main(void) {
    OSCCON=0b01110000;      //8MHz
    PLLEN=1;                //x4=32MHz
    //setup 1mS interrupt = 8,000,000/16 = 500,000/10 = 50,000 set PR2=49 = 50,000/50 = 1000 = 1mS
    T2CON=0b01001110;       //pre=16 post=10
    PR2=49;
    TMR2IE=1;               //timer 2 interrupts enable
    T1CON=0;                //timer 1 stopped
    for(uint8_t i=0;i<NUM_SERVOS;i++){
        servoPos[i]=i*1000+8000; //1ms(8000) to 1.875(7/8ths - 15000)ms in 1/8th mS steps
    }
    TRISC=0b11111100;           //CCP0 & 1 output
    PEIE=1;
    GIE=1;
    while(1){
            //adjust servo positions here
    }
}


void __interrupt() inter(void){
    if(TMR2IE && TMR2IF){
        ms++;
        count++;
        if(count>=20){          //start every 20mS
            TMR1=0;             //zero timer 1
            T1CON=1;            //start timer 1
            count=0;
            CCP1CON=0b1000;     //CCP1 pin low and high on match - will be first pulse
            CCPR1=2000;         //start pulse in 0.25mS (2000 clock cycles)
            CCP1IE=1;           //enable CCP1 interrupts
            CCP1IF=0;           //ensure interrupt flag is clear
            servoCount=0;       //reset servoCount
            LATC0=1;            //connected to data in of shift register will clock in a high when CCP1 goes high
        }
        TMR2IF=0;
    }
    if(CCP1IE && CCP1IF){
        LATC0=0;                //clear the data in pin
        if(servoCount==9)       //have we done all servos?
            CCP1IE=0;           //yes so no more CCP1 interrupts 
        if(CCP1CON==0b1000){    //have we started the 4000 cycle pulse
            CCP1CON=0b1001;     //yes so end the pulse after 0.5mS
            CCPR1=CCPR1+4000;   //4000 cycles=0.5mS
        }else{
            CCP1CON=0b1000;     //No so output the timed gap        
            CCPR1=CCPR1+servoPos[servoCount++]-4000;   //will generate an interrupt when servo time is up
        }
        CCP1IF=0;
    }
}
It (I hope) outputs a 0.5mS pulse every servoTime.

Mike.
Edit, added a millisecond interrupt as it's useful.
Hi M,
MEI and AI have been translating your CODE.

Here is the first draft. Some of it doesn't compile, and shown by !!!!!!!!!!! or ?????????? or commented out

Please check every dot and dash, as there will most probably be mistakes big or small.

Thanks.
C
 

Attachments

  • 18F4431 32MHz XTL REMOTE_SLAVE 164 250123 1000.bas
    3.6 KB · Views: 16

camerart

Active Member
C can you confirm that doing CCPR1 = 0x55AA writes 0x55 to CCPR1H and 0xaa CCPR1L?

Mike.
Edit, can Ian Rogers or ericgibbs confirm this?
Hi M,
I tried this test, and it looks as if CCPR1H is not being written to.
C
================================
Dim test As Word
test = 0x55aa

CCPR1 = test
=================================
 

Attachments

  • CCPR1.jpg
    CCPR1.jpg
    174.8 KB · Views: 15
Last edited:

jjw

Member
Hi M,
I tried this test, and it looks as if CCPR1H is not being written to.
C
================================
Dim test As Word
test = 0x55aa

CCPR1 = test
=================================
Write:
CCPR1H = test.HB
CCPR1L = test.LB
 
Last edited:

Pommie

Well-Known Member
Most Helpful Member
For
CCPR1=CCPR1+servoPos[servoCount++]-4000; //will generate an interrupt when servo time is up

You can do,
Code:
test.HB=CCPR1H
test.LB=CCPR1L
test=test+servoPos(servoCount)
test=test-4000
CCPR1H=test.HB
CCPR1L=test.LB
servoCount-servoCount+1

OR, much better solution,
switch to C. :D

Mike.
 

camerart

Active Member
For
CCPR1=CCPR1+servoPos[servoCount++]-4000; //will generate an interrupt when servo time is up

You can do,
Code:
test.HB=CCPR1H
test.LB=CCPR1L
test=test+servoPos(servoCount)
test=test-4000
CCPR1H=test.HB
CCPR1L=test.LB
servoCount-servoCount+1

OR, much better solution,
switch to C. :D

Mike.
Hi M,
Ok, I'll try the top suggestion first
Then try the lower suggestion, See you in 12 years ;)
C
 

Latest threads

New Articles From Microcontroller Tips

Top