![]() |
![]() |
![]() |
|
|
|||||||
| Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc. |
|
|
Thread Tools | Display Modes |
|
|
(permalink) |
|
BTW Mike, you're posting your graphics as large, low quality, JPG's, if you use GIF or PNG they will be much smaller and perfect quality. You should only use JPG for photo's.
|
|
|
|
|
|
|
(permalink) | |
|
Quote:
Mike |
||
|
|
|
|
|
(permalink) |
|
I am very new to RC stuff as well, but I noticed on my sons nitro car servos that there is a throttle trim, this is added to the 1-2ms pulse
How are the registers than control the servos manipulated? This will need to be taken into consideration when calculating the timings if a non-interupt method of control is implimented. As I understand it a servo window is defined as a 20MS time period (space) with the position information (nominally 1-2MS) (mark) contained within this time period, is this correct? I have an idea, but a bit more info on how you want to control the servos, i.e. rs232 etc and the correct timings would be good.
__________________
Regards MATT! |
|
|
|
|
|
|
(permalink) |
|
James,
Just got a chance to look at the 'HCT238 Data Sheet and you're right. It's a perfect match for modulating one of the eight output lines with a PWM signal driving E1. Thank you for the tip. My Crazy-8 PWM Servo controller concept just got a whole lot smaller by dumping that clumsy EPROM in favor of an 'HCT238. Cool! Regards, Mike ~~~~~~~~~~~~~ Nigel, I apologize for wasting server space. I just figured out why my PNG graphics were larger than JPG graphics. I was saving them from JPG to PNG. When I load the original graphics and save them immediately as PNG they're half the size of the JPG files. ![]() I suspect a 12F683 Servo controller with a bit-banged 1200 or 2400 baud serial interface might be somewhat limiting. An 'F628A or an 'F88 with built-in serial port is probably a better choice with the option of implementing the crystal oscillator if needed for stability. Here's the ISR "engine" with comments to help you understand the concept. So, would this work guys? Is it worth the extra chip? Code:
org h'0004'
ISR_Vector
;
; save main program context
;
movwf W_ISR ; save W-reg |B?
swapf STATUS,W ; doesn't change STATUS bits |B?
movwf S_ISR ; save STATUS reg |B?
clrf STATUS ; force bank 0 |B0
movf FSR,W ; |B0
movwf F_ISR ; save FSR |B0
bcf PIR1,TMR2IF ; clear TMR2 interrupt flag |B0
;
; setup 74HCT238 address lines to select this periods active
; Servo (duty cycle was set in previous PWM interrupt cycle).
;
; a minimum 96-usec window at the beginning of each interrupt
; where PWM is high and the 74HCT238 outputs are low provides
; more than enough time to setup the address lines before the
; PWM output goes active low.
;
movf PORTA,W ; read PORTA |B0
andlw b'11111000' ; preserve PORTA b7..b3 bits |B0
iorwf Servo,W ; Servo b2..b0 bits are used as |B0
movwf PORTA ; 74HCT238 a2..a0 address bits |B0
;
; increment Servo [0..7] for next PWM cycle
;
incf Servo,f ; increment servo |B0
bcf Servo,3 ; mod(Servo/8), [0..7] |B0
;
; we use the PWM off-time to drive the 74HCT238 E1 gate so
; we invert the PWM duty cycle by subtracting the servo duty
; cycle value of 50..300 (8-usec ticks) from the PWM period
; value of 312 (2496-usec PWM period / 8-usec).
;
; calculate inverse duty cycle for next PWM cycle
;
movf Servo,W ; servo number [0..7] |B0
addlw SArray ; add to array address |B0
movwf FSR ; setup indirect address |B0
clrf DutyHi ; |B0
movf INDF,W ; the Servo PWM value [000..250] |B0
addlw d'50' ; add 0.4-msec offset [050..300] |B0
skpnc ; carry? no, skip, else |B0
incf DutyHi,f ; increment duty cycle hi |B0
sublw low d'312' ; subtract from PWM period |B0
movwf DutyLo ; save inverse duty cycle lo |B0
movf DutyHi,W ; |B0
skpc ; borrow? |B0
incf DutyHi,W ; |B0
sublw high d'312' ; |B0
movwf DutyHi ; save inverse duty cycle hi |B0
;
; inverse duty cycle result is a value between 12 (PWM hi for
; 96-usecs and active low for 2400-usecs) and 262 (PWM hi for
; 2096-usecs and active low for 400-usecs).
;
; setup duty cycle registers for next PWM cycle
;
rrf DutyHi,f ; shift result |B0
rrf DutyLo,W ; |B0
movwf CCPR1L ; set 006..131 (16-usec ticks) |B0
bcf CCP1CON,CCP1X ; |B0
skpnc ; odd 8-us tick? no, skip, else |B0
bsf CCP1CON,CCP1X ; set the odd 8-usec tick |B0
;
; restore main program context
;
movf F_ISR,W ; |B0
movwf FSR ; restore FSR |B0
swapf S_ISR,W ; |B0
movwf STATUS ; restore STATUS |B?
swapf W_ISR,f ; don't screw up STATUS |B?
swapf W_ISR,W ; restore W-reg |B?
retfie ; return from interrupt |B?
Last edited by Mike, K8LH; 22nd July 2006 at 02:08 PM. |
|
|
|
|
|
|
(permalink) | |
|
Quote:
|
||
|
|
|
|
|
(permalink) |
|
I am using a PIC18F252 to control 12 servos(for a 4 legged bot). I am using MCC-18 and thought that I would just share my method -
Code:
#include <p18f252.h>
#include <timers.h>
#include <delays.h>
unsigned int servo[12];
char count=0, count1=0;
void interruptVectorHigh (void);
void main(void)
{
char i;
TRISB = 0x00;
TRISA = 0x00;
TRISC = 0x00;
PORTB = 0x00;
PORTA = 0x00;
PORTC = 0x00;
RCON = 0b000000000;
INTCON = 0b10100000;
OpenTimer0( TIMER_INT_ON & T0_16BIT & T0_SOURCE_INT & T0_PS_1_2 );
OpenTimer1( TIMER_INT_ON & T1_16BIT_RW & T1_SOURCE_INT & T1_PS_1_2 & T1_OSC1EN_OFF & T1_SYNC_EXT_OFF );
OpenTimer3( TIMER_INT_ON & T3_16BIT_RW & T3_SOURCE_INT & T3_PS_1_2 & T3_OSC1EN_OFF & T3_SYNC_EXT_OFF );
for(i=0;i<12;i++)
servo[i]=59400;
WriteTimer0(15535); //Trigger Interrupted after 20mS
WriteTimer1(65534); //This is just a small initial delay chosen at random.
WriteTimer3(65534);
while(1)
{
// centre - 59400
// left(anticlockwise) - 62770
// right(clockwise) - 56030
//add any code to move the servos here by assigning a value between 56030 and 62770 to servo[0] to servo[11]. the code enables automatic holding
}
}
#pragma code interruptVectorHigh = 0x08
void interruptVectorHigh (void)
{
_asm
goto interruptHandlerHigh
_endasm
}
#pragma code
#pragma interrupt interruptHandlerHigh
void interruptHandlerHigh()
{
if(INTCONbits.TMR0IF)
{
WriteTimer0(15535);
WriteTimer1(65534);
WriteTimer3(65534);
count = 0;
count1 = 0;
INTCONbits.TMR0IF = 0;
}
if(PIR1bits.TMR1IF == 1 && PIE1bits.TMR1IE == 1)
{
switch(count)
{
case 0: PORTBbits.RB0=1;
WriteTimer1(servo[0]);
break;
case 1: PORTBbits.RB0=0;
PORTBbits.RB1=1;
WriteTimer1(servo[1]);
break;
case 2: PORTBbits.RB1=0;
PORTBbits.RB2=1;
WriteTimer1(servo[2]);
break;
case 3: PORTBbits.RB2=0;
PORTBbits.RB3=1;
WriteTimer1(servo[3]);
break;
case 4: PORTBbits.RB3=0;
PORTBbits.RB4=1;
WriteTimer1(servo[4]);
break;
case 5: PORTBbits.RB4=0;
PORTBbits.RB5=1;
WriteTimer1(servo[5]);
break;
case 6: PORTBbits.RB5=0;
break;
}
count++;
PIR1bits.TMR1IF = 0;
PIE1bits.TMR1IE = 1;
}
if(PIR2bits.TMR3IF == 1 && PIE2bits.TMR3IE == 1)
{
switch(count1)
{
case 0: PORTAbits.RA5=1;
WriteTimer3(servo[6]);
break;
case 1: PORTAbits.RA5=0;
PORTAbits.RA4=1;
WriteTimer3(servo[7]);
break;
case 2: PORTAbits.RA4=0;
PORTAbits.RA3=1;
WriteTimer3(servo[8]);
break;
case 3: PORTAbits.RA3=0;
PORTAbits.RA2=1;
WriteTimer3(servo[9]);
break;
case 4:PORTAbits.RA2=0;
PORTAbits.RA1=1;
WriteTimer3(servo[10]);
break;
case 5:PORTAbits.RA1=0;
PORTAbits.RA0=1;
WriteTimer3(servo[11]);
break;
case 6:PORTAbits.RA0=0;
break;
}
count1++;
PIR2bits.TMR3IF = 0;
PIE2bits.TMR3IE = 1;
}
INTCONbits.GIE = 1;
}
|
|
|
|
|