Continue to Site

# Hardware ESC 8xSERVO CONTROL on PIC (Oshonsoft BASIC)

#### camerart

##### Active Member
Did I not write that?

Mike.
Hi M,
Yes you did, but it had a "but" in front of it, and I wanted to make sure.
That's good, I've now to make an SMD PCB for the HC164.
C.

#### Pommie

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

Mike.

#### camerart

##### Active Member
So, I did write that. The use of but was that I believe 1 chip can do everything.

Mike.
Hi M,
I'm overthinking, but to clarify, do you mean that the 4431 could control the SERVOs and GPS and QEI without the HC164?

C

#### Pommie

##### Well-Known Member
No, just 1 microcontroller but still needs the 164.

Mike.

#### camerart

##### Active Member
No, just 1 microcontroller but still needs the 164.

Mike.
Hi M,
Good, onwards and upwards.
C

#### 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
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.

In a way, yes!

#### 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
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){
}
}

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
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:

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){
}
}

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
174.8 KB · Views: 15
Last edited:

#### camerart

##### Active Member
Hi,
The 164s have arrived and I've stuck one on a PCB, with wires for connection.
Next wire it into the SERVO PCB.
C

#### 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:

#### camerart

##### Active Member
Write:
CCPR1H = test.HB
CCPR1L = test.LB
Hi J,
Yes, this works, but in the program at #274, and the earlier question, I think it needs to be written in one WORD, and this appears not to work.

C

Last edited:

#### Pommie

##### Well-Known 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.

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.

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

Replies
2
Views
791
Replies
29
Views
9K
Replies
2
Views
3K
Replies
4
Views
3K
Replies
82
Views
53K