FREE Servo RC Controller code [ALMOST WORKING]

General discussion on mikroC.
Author
Message
spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

great

#31 Post by spookyrufus » 09 Jun 2008 09:26

Great. I'm astonished.
I don't know how many communities/forums out there have 'superusers' like xor.
And yes, your solution is as simple as hard (for me) to find.
I'm finding really difficult to move from PC programming to uc programming, and *really* helpful the use of this forum.

Thanks a lot guys, I do appreciate.

spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

Does not work

#32 Post by spookyrufus » 13 Jun 2008 12:29

I've tested your code ut it does not work at all :oops:
Even if I initialize the array ServoPos, servos are tying to reach a position outside bounds, and seems really jitty.
Maybe I'm missing something?

xor
Posts: 5465
Joined: 18 May 2005 00:59
Location: NYC
Contact:

#33 Post by xor » 13 Jun 2008 21:02

Okay.... I thought I could be super smooth in mC and found there are some things I could not do in mC. The errors I made just squeaked through and compiled... ouch! I have now resolved the original issues and the code below is working as it should.

Code: Select all

/*
//'*******************************************************************************
//'  Program to Control 12- 50Hz Servos @ 16 Positions Each With USART Updates
//'*******************************************************************************
//'           Code compiled with mikroC 8.2 and tested on 16F887 @ 8MHz
//'           By Warren Schroeder  June 5, 2008
//'*******************************************************************************
//'*******************************************************************************
//'
//'           Each USART RX Byte:
//'              Servo ID        = Upper 4 bits  (0 to 11)   12 Servos
//'              Servo Position  = Lower 4 bits  (0 to 15)   16 Positions
//'
//'   HITECH-HS422 50Hz Servo: 940us to 2140us for min and max servo rotation
//'                            16 positions (940us= Position#0 + (15 x 80us))
//'                            Position#7 = 1500us Center
//'
//'       Timer1 Setup for 1us ticks  (Prescaler=2)
//'
//'       CCP1 is set up for Special Event Compare Mode
//'       On Compare-Match between TIMER1 and CCPR1L:CCPR1H registers
//'       CCP1IF is Set (=1) and TIMER1 is RESET (=0)
//'
//'
//'*******************************************************************************
//'*******************************************************************************
*/

#define Servo0  PORTB.f0
#define Servo1  PORTB.f1
#define Servo2  PORTB.f2
#define Servo3  PortB.f3
#define Servo4  PORTB.f4
#define Servo5  PORTB.f5
#define Servo6  PORTB.f6
#define Servo7  PORTB.f7
#define Servo8  PORTD.f0
#define Servo9  PORTD.f1
#define Servo10 PORTD.f2
#define Servo11 PORTD.f3

unsigned int register volatile
	CCPR1			 absolute 0x0015               ;
unsigned short AllOn                       ;
unsigned short frame80                     ;
unsigned short t0                          ;
unsigned short t1                          ;
unsigned short t2                          ;
unsigned short ServoPos[12]                ;  //  12 Servo Position Array from RX
unsigned short ServoWrk[12]                ;  //  12 Servo Position Work Array


void interrupt() {
    if (AllOn) {                              //  If AllOn flag=true then
           PORTB = 255                     ;  //  All PORTB servos ON
           PORTD = 15                      ;  //  All PORTD servos ON
           AllOn = ~AllOn                  ;  //  reset AllOn flag
           frame80 = 0                     ;  //  80us frame counter
           CCPR1 = 940                     ;  //  940us = 0 position
           for (t2=0;t2<12;t2++) {            //  load work array from USART RX array
              ServoWrk[t2] = ServoPos[t2  ];  //
           }
    }                                         //
    else {                                    //
           CCPR1 = 80                      ;  //  80us frame delay (x 15 total = 1200us)
           FSR = (unsigned short)&ServoWrk ;  //  servo pointer.. point to first servo pos
           if (INDF == 0) Servo0  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo1  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo2  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo3  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo4  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo5  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo6  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo7  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo8  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo9  = 0      ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo10  = 0     ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter
           FSR++                           ;  //  point to next servo
           if (INDF == 0) Servo11  = 0     ;  //  turn servo OFF on 0
           INDF--                          ;  //  decrement position counter

           if (++frame80 == 16) {             //  finished 15 80us position periods?
               CCPR1 = 17900               ;  //  load remaining time for 20ms interrupt
               AllOn = ~AllOn              ;  //  turn ON all servos at next 20ms interrupt
           }
    }
    PIR1.CCP1IF = 0                        ;  //  clear CCP1 interrupt flag
}


void CCP1_Setup() {
    CCP1CON      = 11         ;  //  CCP1 Compare MODE with special event trigger; resets Timer1 on match
    CCPR1        = 65000      ;  //  preload for 65ms delay before servo startup
    T1CON        = 16         ;  //  Timer1 Prescaler = 2 = 1us ticks
    PIE1.CCP1IE  = 1          ;  //  Enable CCP1 interrupt
    PIR1.CCP1IF  = 0          ;  //  Clear CCP1 Interrupt Flag
    INTCON       = 192        ;  //  Global & Peripheral interrupts enabled
    T1CON.TMR1ON = 1          ;  //  Start Timer1...
}



void main() {

    ANSEL   = 0               ;   //  disable adc's
    ANSELH  = 0               ;   //  disable adc's
    CM1CON0 = 0               ;   //  disable comparators
    CM2CON0 = 0               ;   //  disable comparators
    PORTB   = 0               ;
    PORTD   = 0               ;
    TRISB   = 0               ;
    TRISD   = 0               ;
    AllOn   = 255             ;   //  all servos ON flag
    

    USART_INIT(19200)                 ;
    CCP1_Setup()                      ;
    
    
         for (t0=0;t0<12;t0++) {         //  pre-load servo array with some values
             ServoPos[t0] = t0        ;  //
          }
          
          
    while(1) {
       if (USART_DATA_READY) {           // test for RX byte
          t0 = USART_READ()            ; // save new RX byte
          t1 = t0 >> 4                 ; // extract servo ID from RX byte
          ServoPos[t1] =  t0 & 15      ; // save Position Value per ID
        }
    }

}
EDIT: Fine tuned 50Hz period at end of ISR:

Code: Select all

CCPR1 = 17900               ;  //  load remaining time for 20ms
[color=darkred][b]xor[/b][/color]
[url=http://circuit-ed.com]CircuitED -[/url]

spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

#34 Post by spookyrufus » 14 Jun 2008 09:20

Ok tested again, still with no success. I'm now sure the problem is me, not your code or what else.
Just a reeeeeally stupid question:

This code:

Code: Select all

main(){
PORTB=0;
TRISB=0;
while(1){
  PORTB=255;
  delay_us(1500);
  PORTB=0;
  delay_us(18500);
}

}
Should produce the correct pwm frequency to drive one servo connected to *any* PORTB pin, right?

Because my servo still continues going all left, and hanging against his bounds.
WTF is wrong with me or my servos?

The circuit is the simplest it can be, with just the pic connected, a wire from any portb pin to servo's control pin, and power, all this on a small breadboard, using my stabilized power supply.

I start thinking about differences from Europe to US or stuff like that? WHY I CANT GET ANYWAY MY SERVOS MOVING RIGHT, except with my original 'jitty' code posted at the very beginning of this post.

Acetronics
Posts: 715
Joined: 27 Dec 2006 14:33
Location: Le Tréport , FRANCE

#35 Post by Acetronics » 14 Jun 2008 09:30

Hi, Spock

Did you try to use a separate power source for the servo ??? :? ( just Grounds ( µP and servo ) have to be linked.

a good reason for uninterrupted PIC resets ... :roll:

Alain

spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

Just tried

#36 Post by spookyrufus » 14 Jun 2008 10:13

Just tried. Exactly same results.
However, my power supply can output 30 V @ 5A, so I don't see where should be the problem in drivin a 300 mA servo and a nearly 0A pic.

Why all of my servos seems to work with my original code, and not with the more correct ones posted by god xor?

I can't say the differences in the two outputs, as I don't have a scope, but I can clearly see (using a LED!) that my code produces a visible flashing output, and xor one (just like the last snippet of code I posted) produces a mid dimmed light, as I think it should be. Well, this 'correct' output won't drive my servos anywhere else than a position outside its bounds.

I can post photos or videos of what I'm saying, if this is not clear enough. Cant believe its really happening.

Acetronics
Posts: 715
Joined: 27 Dec 2006 14:33
Location: Le Tréport , FRANCE

#37 Post by Acetronics » 14 Jun 2008 10:24

Just another question ... which PIC do you use ?

16F 887 like XOR ? :?:

spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

#38 Post by spookyrufus » 14 Jun 2008 10:58

Yes of course. I think I'm using exactly the same configuration.
16f877a-i/p , 8Mhz quartz

Charlie
Posts: 2744
Joined: 01 Dec 2004 22:29

#39 Post by Charlie » 14 Jun 2008 13:47

xor is using the 887 not 877a
Regards Charlie M.

spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

#40 Post by spookyrufus » 14 Jun 2008 13:53

oh. :oops:
All this time I was reading 16F877 instead of 16F887.
Great.
However, how can this be the problem? I think the two mcus are quite similar arent them?

Charlie
Posts: 2744
Joined: 01 Dec 2004 22:29

#41 Post by Charlie » 14 Jun 2008 13:59

However, how can this be the problem? I think the two mcus are quite similar arent them?
You will have to read the datasheet to know for sure.
Regards Charlie M.

xor
Posts: 5465
Joined: 18 May 2005 00:59
Location: NYC
Contact:

#42 Post by xor » 14 Jun 2008 16:20

The 2 PIC's are nearly identical and the code should work fine on any PIC with a CCPR1 module in the same memory slot. Otherwise, change the absolute address of CCPR1.

There is another difference with the '877A. You disable ADC's and Comparators like this:

Code: Select all

ADCON1 = 6;
CMCON  = 7;
I have a ton of 877A's around. Possibly later I will throw one on the board and run a test.
[color=darkred][b]xor[/b][/color]
[url=http://circuit-ed.com]CircuitED -[/url]

spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

thanks

#43 Post by spookyrufus » 14 Jun 2008 17:44

Thanks xor. I really cant believe I was reading 877 instead of 887 for all this time.
I've seen on the Datasheet that on the 877, the CCPR1 has the same address of the 887.

If you can post the list of modifications needed to run your code onto this mc.... that would be great!

spookyrufus
Posts: 71
Joined: 10 Jun 2006 13:45

GREAT

#44 Post by spookyrufus » 14 Jun 2008 17:59

Oh great I figured out how todo that myself.

These are the modifications needed in order to run xor's code onto a PIC 16F877A:

this piece of code:

Code: Select all

    ANSEL   = 0               ;   //  disable adc's
    ANSELH  = 0               ;   //  disable adc's
    CM1CON0 = 0               ;   //  disable comparators
    CM2CON0 = 0               ;   //  disable comparators 
will become:

Code: Select all

ADCON1 = 6;
CMCON  = 7;
That's it. I consider this post closed. Many many thanks to all who participated

xor
Posts: 5465
Joined: 18 May 2005 00:59
Location: NYC
Contact:

#45 Post by xor » 17 Jun 2008 17:31

Add this to your servo arsenal. Will test your servo outputs and requires only a small PIC (16F628A for example) and a 16x2 LCD.

http://www.mikroe.com/forum/viewtopic.php?p=77892
[color=darkred][b]xor[/b][/color]
[url=http://circuit-ed.com]CircuitED -[/url]

Post Reply

Return to “mikroC General”