CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Controlling position of stepper motor
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
bliztkrieg



Joined: 23 Jul 2018
Posts: 20

View user's profile Send private message

Controlling position of stepper motor
PostPosted: Wed Nov 07, 2018 12:09 am     Reply with quote

Hey guys I'm trying to control the position of stepper motor but couldn't get the hang of it. I have done the part where you have to slowly increase and decrease the frequency for smooth transitions. Now I'm stuck at controlling the position of the motor accurately. Right now whenever i run my code the motor always stops at a different position which shouldn't be the case. Can anyone please take a look at my code and point me in the right direction.

Code:

#include <18f252.h>
#use delay(clock=20000000)
#fuses NOBROWNOUT, NOPROTECT, HS, NOLVP, NOWDT

int16 tmrval[] = {53035,55535,60535,64285,64702,64950,65085,65178,65230,65277,65310,65340};
int8 steps = 0;
int1 flag = FALSE, tmrInt = FALSE, atSpeed = FALSE, rDown = FALSE, rUp = TRUE;
unsigned int16 pulsesup = 4627, pulsesdown = 5415;
unsigned int32 set_pos = 20000, desired_pos = 0, position = 0;
#INT_TIMER3
void tmr3_isr()
{
   tmrInt = TRUE;
}
   

#INT_TIMER1
void tmr1_isr()
{
   if(flag)
   {
      set_timer1(tmrval[steps]);
   }
   output_toggle(PIN_C2);
}

#INT_EXT
void ext0_isr()
{
   if(atSpeed && !rDown && rUp)
   {
    position++;
   }
}

void main()
{
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   setup_timer_3(T3_INTERNAL | T3_DIV_BY_8);
   ext_int_edge(0, L_TO_H);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_TIMER1); 
   enable_interrupts(INT_TIMER3); 
   enable_interrupts(GLOBAL);
   output_low(PIN_C4); // en
   desired_pos = set_pos - (pulsesup + pulsesdown);
   
   while(1)
   {
      output_high(PIN_C5); //direction signal
     
      if(tmrInt)
      {
         if(atSpeed)
         {
            if(rUp)
            {
               output_high(PIN_A2);
               output_low(PIN_A1);
               output_low(PIN_A0);
            }
            if(position >= (desired_pos-1250))
            {
               if(!rDown && rUp)
               {
                  position = 0;
                  rUp = FALSE;
                  rDown = TRUE;
                  atSpeed = FALSE;
               }
            }
            if (desired_pos==0)
            {
               delay_ms(1000);
               desired_pos = set_pos - (pulsesup + pulsesdown);
               if(!rUp && rDown)
               {
                  enable_interrupts(INT_TIMER1);
                  rUp = TRUE;
                  rDown = FALSE;
                  atSpeed = FALSE;
               }
            }
          }                           
         
         else if(rUp && !atSpeed)
         {
            steps++;
            output_high(PIN_A0);
            output_low(PIN_A1);
            output_low(PIN_A2);
            flag = TRUE;
            if(steps == 11)
            {
               steps = 11;
               atSpeed = TRUE;
            }
         }
         
         else if(rDown && !atSpeed)
         {   
            output_high(PIN_A1);
            output_low(PIN_A0);
            output_low(PIN_A2);
            if(steps >= 1)
               steps--;
            else steps = 0;
            flag = TRUE;
            if(steps == 0)
            {
               desired_pos = 0;
               steps = 0;
               atSpeed = TRUE;
               disable_interrupts(INT_TIMER1);
            }
         }
         tmrInt = FALSE;
      }
   }
}


Last edited by bliztkrieg on Wed Nov 07, 2018 4:27 am; edited 1 time in total
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 4:02 am     Reply with quote

I'm having some difficulty trying to decode what you're trying to do.
Yes, it's odd that you get different results each time you run the code.
I'd expect the same wrong result each time.

Please explain:-

What kind of stepper are you driving.
(Is it some sort of module with power drivers?)
How you think your system works.
The pin connections.

Mike

Can you remove unneeded code and add useful comments?
bliztkrieg



Joined: 23 Jul 2018
Posts: 20

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 4:20 am     Reply with quote

Mike Walne wrote:
I'm having some difficulty trying to decode what you're trying to do.
Yes, it's odd that you get different results each time you run the code.
I'd expect the same wrong result each time.

Please explain:-

What kind of stepper are you driving.
(Is it some sort of module with power drivers?)
How you think your system works.
The pin connections.

Mike

Can you remove unneeded code and add useful comments?


code without comments
Code:
#include <18f252.h>
#use delay(clock=20000000)
#fuses NOBROWNOUT, NOPROTECT, HS, NOLVP, NOWDT

int16 tmrval[] = {53035,55535,60535,64285,64702,64950,65085,65178,65230,65277,65310,65340};
int8 steps = 0;
int1 flag = FALSE, tmrInt = FALSE, atSpeed = FALSE, rDown = FALSE, rUp = TRUE;
unsigned int16 pulsesup = 4627, pulsesdown = 5415;
unsigned int32 set_pos = 20000, desired_pos = 0, position = 0;
#INT_TIMER3
void tmr3_isr()
{
   tmrInt = TRUE;
}
   

#INT_TIMER1
void tmr1_isr()
{
   if(flag)
   {
      set_timer1(tmrval[steps]);
   }
   output_toggle(PIN_C2);
}

#INT_EXT
void ext0_isr()
{
   if(atSpeed && !rDown && rUp)
   {
    position++;
   }
}

void main()
{
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   setup_timer_3(T3_INTERNAL | T3_DIV_BY_8);
   ext_int_edge(0, L_TO_H);
   enable_interrupts(INT_EXT);
   enable_interrupts(INT_TIMER1); 
   enable_interrupts(INT_TIMER3); 
   enable_interrupts(GLOBAL);
   output_low(PIN_C4); // en
   desired_pos = set_pos - (pulsesup + pulsesdown);
   
   while(1)
   {
      output_high(PIN_C5); //direction signal
     
      if(tmrInt)
      {
         if(atSpeed)
         {
            if(rUp)
            {
               output_high(PIN_A2);
               output_low(PIN_A1);
               output_low(PIN_A0);
            }
            if(position >= (desired_pos-1250))
            {
               if(!rDown && rUp)
               {
                  position = 0;
                  rUp = FALSE;
                  rDown = TRUE;
                  atSpeed = FALSE;
               }
            }
            if (desired_pos==0)
            {
               delay_ms(1000);
               desired_pos = set_pos - (pulsesup + pulsesdown);
               if(!rUp && rDown)
               {
                  enable_interrupts(INT_TIMER1);
                  rUp = TRUE;
                  rDown = FALSE;
                  atSpeed = FALSE;
               }
            }
          }                           
         
         else if(rUp && !atSpeed)
         {
            steps++;
            output_high(PIN_A0);
            output_low(PIN_A1);
            output_low(PIN_A2);
            flag = TRUE;
            if(steps == 11)
            {
               steps = 11;
               atSpeed = TRUE;
            }
         }
         
         else if(rDown && !atSpeed)
         {   
            output_high(PIN_A1);
            output_low(PIN_A0);
            output_low(PIN_A2);
            if(steps >= 1)
               steps--;
            else steps = 0;
            flag = TRUE;
            if(steps == 0)
            {
               desired_pos = 0;
               steps = 0;
               atSpeed = TRUE;
               disable_interrupts(INT_TIMER1);
            }
         }
         tmrInt = FALSE;
      }
   }
}
bliztkrieg



Joined: 23 Jul 2018
Posts: 20

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 4:22 am     Reply with quote

@Mike
I am counting the number of pulses to keep track how much steps i have taken and since i know how many pulses are there while deceleration im running that piece of code so the motor should stop on the same position every time. but it is not the case. Driver im using is MX-2H304D
diode_blade



Joined: 18 Aug 2014
Posts: 55
Location: Sheffield, South Yorkshire

View user's profile Send private message Send e-mail

PostPosted: Wed Nov 07, 2018 5:11 am     Reply with quote

I made a sample polishing machine using 3 stepper motors, 1 for the polishing tape, 1 for turning the chuck and 1 for the linear actuator polishing Arm (from Oozenest), I used the threes ccp PWM ouputs to drive the stepper driver boards and fed the signals back into the the CCP compare modules, the way the program worked was to initiate the travel stepper and it's relavent interrupt, then the chuck stepper interrupt move the chuck stepper a few steps then the move the tape stepper with its interrupt enabled, then it re-enabled the travel arm itnterrupt to drive the travel arm stepper back the other way.
I stored various values in the Chips EEPROM so using a four button keypad and menu system i could select various polish sample lengths (all based on the amount of pulses delivered to the stepper from the PIC) which was setup using a setup sample subroutine.

Code:


//============================== SAMPLE POLISHING MACHINE PROGRAM =====================================//
// CURRENT SOFTWARE VERSION V3
// THE MAIN HARDWARE
// C-Beam Linear Actuator Kit
//  - Actuator Length: 250mm
// 3 - OFF NEMA23 Stepper Motors
// - Model: 2303HS280AW - 175oz ..
// DRV8825 stepper driver boards 3-off
// CONTROL BOARD MIKROE READY FOR PIC
// 40 PIN DEVICE BOARD
//=====================================================================================================//
//Processor include
//Fuses
//Timing settings
//pin definitions (pin select if applicable)
//I/O definitions (#use rs232, I2c etc.)
//Then include library files
//Then the code.
//LAST SOFTWARE MOD DATE 16-4-18

#nolist
#include "18F46K22.h"
#list
#device *=8
// DEVICE FUSE SETTINGS
#define device_clock 16M
#use delay(clock=device_clock)
//#device WRITE_EEPROM = NOINT


#fuses HSH,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOLVP,NOBROWNOUT,NOHFOFST
#fuses NOPUT,NOIESO,NOFCMEN,NOEBTR,NOEBTRB,NOCPB,NOPBADEN
#fuses NOWRTC,NOWRT,NOSTVREN,PLLEN,CCP3E0,CCP2C1,TIMER3B5




//--------------------------------------------------------------
// CAN'T USE THE FOLLOWING
// A4,A5,E0,E1,A2,A3 LCD PINS
// D1,D3,C1,C0,C2,B5 PWM O/P and CCP I/P PINS
// D4,D5,D6,D7 KEYPAD
// B0,B2,B3,C3,C4,C6 DRIVER BOARD CONTROL
// POLISH TRAVEL PIN DEFINES
// AVAILABLE PINS
// D0,D2,
// C5,C7
// B1,B4,B6,B7

//Driver board control PINS

//Actuator Travel Motor Pin defines.

#define rset_trav LATB4  //white/red
#define step_trav LATC1  //red/grn
#define direc_trav LATB2 //white/blk

//====================================//

// CHUCK MOTOR PIN DEFINES

#define rset_ch LATB3
#define step_ch LATD3
#define direc_ch LATC3

//==================================//

// TAPE MOTOR DEFINES

#define rset_tape LATC4
#define step_tape LATD1
#define direc_tape LATC6
//SAME COLOURS as Above

//==========================================//
// PINS USED SO FAR
// LCD DISPLAY
// DATA: A4,A5,E0,E1
// CONTROL: RS A2: EN A3
// PWM O/P'S D1 PWM 4: C1 PWM 2: D3 PWM3 
// TIMER I/P's
// FOR CCP   B5:T3     C0:T1     C2:T5
//           ccp3      ccp1      ccp5
//           tape      travel    chuck

//=========================================//


I hard wired the PWM pins back into the timer capture pins for each one to count and compare pulses used to drive each stepper.

Code:

#use pwm(CCP2,timer=2,PWM_OFF,frequency=750Hz, duty=25,stream=travel ) /* working */
#use pwm(output=LATD1,timer=4,PWM_OFF,frequency=750Hz, duty=45,stream=tape)
#use pwm(output=LATD3,timer=6,PWM_OFF,frequency=150Hz, duty=25,stream=chuck)   /* working */

#use fast_io(A)//using fast I/o so set each tris bit suit for inputs
#use fast_io(B)//keep all unsed ports pins as output and drive low
#use fast_io(C)
#use fast_io(D)
#use fast_io(E)
//I USED FAST I/O AND SET THE TRIS REGISTERS ACCORDINGLY
// DEFINE TIMER ON BITS
#bit t0_on =T0CON.7
#bit t2_on =T2CON.2
#bit t4_on =T4CON.2
#bit t6_on =T6CON.2

void setup_interrupts(void)
{
clear_interrupt(INT_CCP5);
clear_interrupt(INT_CCP3);
clear_interrupt(INT_CCP1);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL); // All interrupts ON
}


//=====================================================================
// SET THE CCP MODULES UP IN COMPARE MODE
// THESE WILL REACT TO THE AMOUNT SET TO THE PWM PULSES COMING IN
// AND GENERATE AN APPROPRIATE INTERRUPT IN TURN
// ALSO SETS UP THE TIMER MODULES THAT ARE USED
// WITH THE CCP MODULES
 
//=====================================================================

void CCP_Timer_setup(void)
{
setup_timer_0(T0_INTERNAL|T0_DIV_1|T0_OFF);
setup_timer_1(T1_EXTERNAL_SYNC|T1_DIV_BY_1);
setup_timer_3(T3_EXTERNAL_SYNC|T1_DIV_BY_1);
setup_timer_5(T5_EXTERNAL_SYNC|T1_DIV_BY_1);
setup_ccp1(CCP_COMPARE_INT|CCP_USE_TIMER1_AND_TIMER2|CCP_COMPARE_RESET_TIMER); // Interrupt on compare mode Tape count
setup_ccp3(CCP_COMPARE_INT|CCP_USE_TIMER3_AND_TIMER4|CCP_COMPARE_RESET_TIMER); // Interrupt on compare mode polish count
setup_ccp5(CCP_COMPARE_INT|CCP_USE_TIMER5_AND_TIMER6|CCP_COMPARE_RESET_TIMER); // Interrupt on compare mode chuck count


t2_on=false;   //TURN ALL PWM TIMERS OFF
t4_on=false;
t6_on=false;
set_timer1(0); // ZERO ALL TIMERS
set_timer3(0);
set_timer5(0);
}


#int_ccp1
void rset_ccp1(void)
{
pwm_off(travel);//SWITCH OF THE TRAVEL
t2_on=false;
output_toggle(direc_trav);
disable_interrupts(INT_CCP1);
 clear_interrupt(INT_CCP3);
            enable_interrupts(INT_CCP3);
      t4_on=true;   //turn on tape motor pwm drive
      #asm
      nop
      nop
      #endasm 
      set_timer4(0);
      pwm_on(tape); 
//my code for setting up the tape travel would be below
//plus activating the ccp3 intterupt
}

//======================================================//
// WE GET HERE FROM THE ABOVE
//
#int_ccp3
void rset_ccp3(void)
{
pwm_off(tape);            //switch tape move off
t4_on=false;
disable_interrupts(INT_CCP3);
t6_on=true;                //TURN ON TIMER 4 FOR CCP5 COMPARE
#asm       // NOW MOVE THE CHUCK
nop
nop
#endasm
clear_interrupt(INT_CCP5);
enable_interrupts(INT_CCP5);
set_timer6(0);
pwm_on(chuck);  //turn on chuck pwm drive
}
//number of steps required for travel was selected from menu for the sample polish length

//=====================================================//
// WE GET HERE FROM THE ABOVE
//
#int_ccp5
void rset_ccp5(void)
{
pwm_off(chuck);  // SWITCH THE CHUCK MOTOR OFF
disable_interrupts(INT_CCP5);
ccp_5=10;//reset number of steps reqired for next time for amount of //chuck movement
#asm
nop
nop
#endasm
set_timer5(0);
 clear_interrupt(INT_CCP5);//clear the int flag
t6_on=false;           
#asm
nop
nop
#endasm

t2_on=true;    //turn on
#asm
nop
nop
#endasm         // TURN TIMER 2 BACK ON FOR CCP1 COMPARE
  //CHANGE THE DIRECTION OF TRAVEL
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
set_timer2(0);
pwm_on(travel); //turn on travel stepper drive
 
}


For obvious reasons I have not included all the code I wrote for this but I hope it can help you.
Regards
Dave
bliztkrieg



Joined: 23 Jul 2018
Posts: 20

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 5:20 am     Reply with quote

@dave, i have done the same (almost) i mean my pulse signal is going to the external interrupt and i m counting the number for rising edges so that should be the total no. of pulses right ? The thing is i need to set the desired position and the motor should take steps accordingly. For example, distance from Point A to B is 1mm and the no. of steps required are 20000 so the motor should take 20000 steps to stop at exactly 1mm everytime
diode_blade



Joined: 18 Aug 2014
Posts: 55
Location: Sheffield, South Yorkshire

View user's profile Send private message Send e-mail

PostPosted: Wed Nov 07, 2018 5:32 am     Reply with quote

I created a setup routine selected on a LCD menu system using a 4 button pushbutton keypad, when in that routine it did the following

One pushbuutn drove the actuator arm one way another the opposite

Quote:

Select setup
|
|
MOVE Arm/Stepper to one end
|
|
Zero PULSE COUNT
|
|
Move Arm/Stepper Required amount
|
|
Store Count value



The just load that count value into the ccp for compare with the pulse count when you run in your main program

use your buttons if using a keypad to Move to a starting position

Zero the count

load your stored value
Run

Dave
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 6:04 am     Reply with quote

bliztkrieg wrote:
@Mike
I am counting the number of pulses to keep track how much steps i have taken and since i know how many pulses are there while deceleration im running that piece of code so the motor should stop on the same position every time. but it is not the case. Driver im using is MX-2H304D


How do you know your motor is not missing steps?

Mike
newguy



Joined: 24 Jun 2004
Posts: 1909

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 8:19 am     Reply with quote

Mike Walne wrote:

How do you know your motor is not missing steps?


I suspect the same as Mike. If you clock a stepper too fast, it stops stepping. Have you determined the maximum speed you can run your motor and backed off 10-20% from there?
temtronic



Joined: 01 Jul 2010
Posts: 9245
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 9:16 am     Reply with quote

I cringe when I see motor control with NO feedback ! Just counting pulses to the motor is not good enough, you really need feedback. Typically this is done using a quadrature encoder. They're cheap, reliable and easy to use.
Typically the motor will be driving another gear, a belt or swing an arm. Some kind of mechanical 'slop' between the motor and the 'end'. That has to be known and dealt with. Then there's the dreaded 'stepper hunting' or 'random dead space'. Every stepper will migrate to one of two random places at rest, the fewer the poles the worse the position.A lot of problems can be in the 'driver board'. The lack of power(current) and the stepper won't step. Over heat the driver and , yes, more missed steps. Change the load on the stepper, oops, a few more missed steps...hmm it's not where it's supposed to be.
Feedback...you really need feedback !

Jay
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 9:23 am     Reply with quote

There are several things in the code that may have 'issues'. For instance:
Code:

            if(position >= (desired_pos-1250))


What happens if 'desired_pos' is less than 1250?. Remember the variable is an unsigned integer, so will wrap... Sad

Then there is the huge waste of tmrInt. An entire interrupt handler existing, and being called (with all the overhead this implies), just to set a flag bit.

Don't. Don't enable this interrupt, and get rid of the handler. Then instead of testing for tmrInt, test for 'interrupt_active(INT_TIMER3)'. This will be set to true whenever this timer wraps. Instead of setting tmrInt to FALSE, clear_interrupt(INT_TIMER3).

I too suspect missed steps. The actual interrupt speed at full speed is very fast. 65536-65340, is only 196 instruction times. At 20MHz, 25510Hz. If this is for a full pole step (as opposed to microstepping), the motor will be producing very low torque at such a speed....
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Wed Nov 07, 2018 1:07 pm     Reply with quote

The quoted driver does micro-stepping, but he's not telling how he's got it set up, what each driver pin is doing (apart from direction), or his motor's steps per revolution.

Driving @ 25kHz a full stepping 200 step/rev motor will be doing over 100 revs/sec, that's a rather speedy 6000rpm.

Lots more info please.

Mike
bliztkrieg



Joined: 23 Jul 2018
Posts: 20

View user's profile Send private message

PostPosted: Thu Nov 08, 2018 3:45 am     Reply with quote

Ttelmah wrote:
There are several things in the code that may have 'issues'. For instance:
Code:

            if(position >= (desired_pos-1250))


What happens if 'desired_pos' is less than 1250?. Remember the variable is an unsigned integer, so will wrap... Sad

Then there is the huge waste of tmrInt. An entire interrupt handler existing, and being called (with all the overhead this implies), just to set a flag bit.

Don't. Don't enable this interrupt, and get rid of the handler. Then instead of testing for tmrInt, test for 'interrupt_active(INT_TIMER3)'. This will be set to true whenever this timer wraps. Instead of setting tmrInt to FALSE, clear_interrupt(INT_TIMER3).

I too suspect missed steps. The actual interrupt speed at full speed is very fast. 65536-65340, is only 196 instruction times. At 20MHz, 25510Hz. If this is for a full pole step (as opposed to microstepping), the motor will be producing very low torque at such a speed....


Desired pos is calculated in the beginning so it will not change and it is int32. OK that is a good approach to get rid of the timer3 interrupt. I'll try but everything seems so complicated. Can u suggest a different approach to control the position with ramp up and down scheme :(
bliztkrieg



Joined: 23 Jul 2018
Posts: 20

View user's profile Send private message

PostPosted: Thu Nov 08, 2018 3:47 am     Reply with quote

Mike Walne wrote:
The quoted driver does micro-stepping, but he's not telling how he's got it set up, what each driver pin is doing (apart from direction), or his motor's steps per revolution.

Driving @ 25kHz a full stepping 200 step/rev motor will be doing over 100 revs/sec, that's a rather speedy 6000rpm.

Lots more info please.

Mike

I'm running the motor at 10kHz freq. Driver I'm using is MX-2H304D with dip switches for stepping set to 00100 means 1600 step. There are 3 signals CP(pulses), DIR(direction), EN(enable).
Ttelmah



Joined: 11 Mar 2010
Posts: 19546

View user's profile Send private message

PostPosted: Thu Nov 08, 2018 4:15 am     Reply with quote

Quote:

Im running the motor at 10kHz freq


Er.

Your code for timer1, has:

Code:

#INT_TIMER1
void tmr1_isr()
{
   if(flag)
   {
      set_timer1(tmrval[steps]);
   }
   output_toggle(PIN_C2);
}


At the maximum (steps==11), the timer is loaded with 65340. At the clock you show, this will result in the the timer toggling the output pin at about 11000Hz. Higher than your quoted speed (allowing 30 instructions latency).

However the thing most likely to be causing problems is the jump in the speed ramp. You normally accelerate the motor linearly.
Your ramp gives step rates of:

Quote:

237.394359510018
249.227395075267
496.919101570264
1951.60031225605
2893.51851851852
4058.44155844156
5197.5051975052
6443.29896907217
7440.47619047619
8650.51903114187
9765.625
11061.9469026549

Now this has a three step very slow start, then a sudden jump in rate. Not linear.
As you have the code, with just one step at each speed, it is asking a lot for the motor to actually keep up....
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group