5 Replies - 9308 Views - Last Post: 25 December 2009 - 01:23 PM Rate Topic: -----

#1 Lord Ra  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 24-December 09

C programming: delays and interrupts

Posted 24 December 2009 - 07:36 PM

Hi guys,

I would like to start by introducing myself. I am an engineering student in his second year and who is still improving his programming skills. I would say I am an intermediate programmer but obviously I will ocassionally need advice from you on where I could be going wrong and the possible ways I could fix mistakes or improve efficiency of my code.

Back on topic, below is the code, i've written to run 2 stepper motors at the same time in both directions using various speeds and using a PIC16F648A. The code is working but the slight hiccup is when i test it on the test board. See for the first motor, the speed is being set using the delay_ms function whilst for the second motor, which is run by an interrupt uses RTTC INTERNAL time Divs.

Is there a method I could use to get equal time delays for both motors. I thought about using delay_us and delay_ns functions for the first motor in order to match the interrupt timer.

Here's the code so far:
#include<16F648A.h>
# fuses NOLVP, NOMCLR, INTRC, NOWDT, NOPROTECT, NOCPD
# use delay (clock=4M)//4MHz clock
# DEFINE SPEED1 20 // 15 RPM
# DEFINE SPEED2 10 // 30 RPM
# DEFINE SPEED3 5 // 60 RPM
# DEFINE SPEED4 2 // 120 RPM
/*Declare Global Variables*/
int LUTBLE[4]={0X09,0X0C,0X06,0X03};  
int tableindex1 = 0, tableindex2 = 0;


/*The struct below is for the pin layout*/
struct EE2A
{   
   int motor1_direction:1;
   int motor1_speed:2;
   int motor2_direction:1;   
   int motor2_speed:2;
   int unused:2; // 2 unused pins on Port A	 
   int motoutput1:4;// 4 outputs for motor1
   int motoutput2:4;// 4 outputs for motor2   
};

struct EE2A IOPort; //initialise struct for inputs
struct EE2A TrisPort; //initialise struct for outputs
#byte IOPort=0x05 //set inputs to PortA
#byte TrisPort=0x85 //Tris bits for PortA
#int_RTCC //Interrupt


void Timer0_isr()//Set the interrupt to run motor 2 when the timer overflows
{
   int increase2;   
   // if direction is true then assign positive value for forward motion
   // else assign negative value for reverse motion of motor
   // tableindex2 indicates the order in which the look-up-table is run
   increase2 = IOPort.motor2_direction ? 0x01 : 0xFF;
   tableindex2=(tableindex2 + increase2)%4;// value of increase2 determines direction
   IOPort.motoutput2=LUTBLE[tableindex2];
}	
   

void main()
{
   int stepdelay,increase1;
   // set pins on PIC to corresponding variables in the program
   TrisPort.motor1_direction=0b1;
   TrisPort.motor2_direction=0b1;
   TrisPort.motor1_speed=0b11;
   TrisPort.motor2_speed=0b11;
   TrisPort.motoutput1=0b0000;
   TrisPort.motoutput2=0b0000;
   enable_interrupts(INT_RTCC); //enable the interrupts
   enable_interrupts(GLOBAL); //enable the global interrupts
   IOPort.motoutput1 = IOPort.motoutput2 = LUTBLE[0]; // Both motors use the same look up table for the step sequence
	  
   while (true) /* run forever*/
   {
	  if ((IOPort.motor2_speed)==0b00)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_16); //Time Delay between steps
		 }
	   if ((IOPort.motor2_speed)==0b01)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_32);  //Time Delay between steps
		 }
	  if((IOPort.motor2_speed)==0b10)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_64);  //Time Delay between steps
		 }
	  if((IOPort.motor2_speed)==0b11)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_128);  //Time Delay between steps
		 }
	  

			
	  //set up the speeds
	  if((IOPort.motor1_speed)==0b00)
		 {
			stepdelay=SPEED1;
		 }
	   if((IOPort.motor1_speed)==0b01)
		 {
			stepdelay=SPEED2;
		 }
	  if ((IOPort.motor1_speed)==0b10)
		 {
			stepdelay=SPEED3;
		 }
	  if ((IOPort.motor1_speed)==0b11)
		 {
			stepdelay=SPEED4;
		 }
		// if direction is true then assign positive value for forward motion
		// else assign negative value for reverse motion of motor   
	  increase1= IOPort.motor1_direction ?  0x01 : 0xFF;  
	  tableindex1=(tableindex1 + increase1)%4;
	  IOPort.motoutput1=LUTBLE[tableindex1];	 
	  Delay_ms(stepdelay);
   }	  
}
 
 
 


I hope you guys can help me out here.

Kind regards and Merry Christmas!!

Cheers,

Ra

Is This A Good Question/Topic? 0
  • +

Replies To: C programming: delays and interrupts

#2 GenHornet18  Icon User is offline

  • Darken the Radar

Reputation: 36
  • View blog
  • Posts: 629
  • Joined: 19-October 09

Re: C programming: delays and interrupts

Posted 24 December 2009 - 08:07 PM

So to be clear here (I am by no means an engineer, although the code is well enough documented I can understand it):

1.) you want both of these motors to run in opposite directions?
2.) your running an infinite loop and delaying it by a certain amount of time in order to get different speeds from the motors?
Was This Post Helpful? 1
  • +
  • -

#3 GWatt  Icon User is offline

  • member icon

Reputation: 276
  • View blog
  • Posts: 3,075
  • Joined: 01-December 05

Re: C programming: delays and interrupts

Posted 24 December 2009 - 08:38 PM

I'm not at all familiar with the hardware in use, but I have just finished a course dealing with similar territory. (We used an embedded arm system grafted onto an RC children's toy)

From what I read you have to motors that you want to move at the same speed (albeit reversed) and they're not doing that. Since your code has a nonzero runtime the delay for your 1st motor (loop controlled) will be slightly off from your 2nd motor (interrupt controlled.) The interrupts will happen when they please, while the loop controlled motor must wait till the loop gets around to it.
To get the timing exact you will have to play around with timer delay to get the value just so.

However, I do have some suggestions which you might find more immediately helpful. You should use arrays to store your SPEED values and RTCC_DIV_ values. You can go from this:
if ((IOPort.motor2_speed)==0b00)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_16); //Time Delay between steps
		 }
	   if ((IOPort.motor2_speed)==0b01)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_32);  //Time Delay between steps
		 }
	  if((IOPort.motor2_speed)==0b10)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_64);  //Time Delay between steps
		 }
	  if((IOPort.motor2_speed)==0b11)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_128);  //Time Delay between steps
		 }

to this:
int rtcc_values[] = {RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128};

// other code here

SETUP_TIMER_0(RTCC_INTERNAL | rtcc_values[IOPort.motor2_speed] );


Since the IOPort.motor2_speed values are from 0 to 3 they make perfect array indexes, and you should take advantage of that. Motor 1 appears to have the same speed values and therefore should be treated the same way.
Was This Post Helpful? 1
  • +
  • -

#4 Lord Ra  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 24-December 09

Re: C programming: delays and interrupts

Posted 24 December 2009 - 09:04 PM

View PostGenHornet18, on 24 Dec, 2009 - 07:07 PM, said:

So to be clear here (I am by no means an engineer, although the code is well enough documented I can understand it):

1.) you want both of these motors to run in opposite directions?
2.) your running an infinite loop and delaying it by a certain amount of time in order to get different speeds from the motors?

Thanks for the reply. I wasn't precise enough in my first post. I'll detail further:

1. No. The goal is to get both motors working at the same time. I tested it and they both work at the same time. For instance, I can have one motor doing a particular speed and direction whilst the second motor can be running in a different direction at another speed. There are 4 speeds and 2 directions for each motor and they are controlled by buttons which the user will switch on and off as necessary.

2, Yes that's correct. The infinite loop is for testing purposes. Should these motors be used in an embedded system, the structure of the code would change and the sensors readings would determine if motors are on or off. This particular stepper motor will turn a step of 1.8 degrees, a delay and then the next step. The smaller the delay, the faster the motor will go and vice versa.

This post has been edited by Lord Ra: 24 December 2009 - 09:23 PM

Was This Post Helpful? 0
  • +
  • -

#5 Lord Ra  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 14
  • Joined: 24-December 09

Re: C programming: delays and interrupts

Posted 24 December 2009 - 09:22 PM

View PostGWatt, on 24 Dec, 2009 - 07:38 PM, said:

I'm not at all familiar with the hardware in use, but I have just finished a course dealing with similar territory. (We used an embedded arm system grafted onto an RC children's toy)

Cheers man, for the quick reply. The end goal is an autonomous robot that follows a line using sensors. We're being taught to program the motors using Microcontrollers.

Quote

From what I read you have to motors that you want to move at the same speed (albeit reversed) and they're not doing that.

Sorry, I wasn't clear enough in my first post. At this stage, i'm testing using a test board that has two motors and loads of buttons that I can use as inputs.

Quote

Since your code has a nonzero runtime the delay for your 1st motor (loop controlled) will be slightly off from your 2nd motor (interrupt controlled.) The interrupts will happen when they please, while the loop controlled motor must wait till the loop gets around to it.
To get the timing exact you will have to play around with timer delay to get the value just so.

Actually, this statement here, means that when the 2 input speed buttons for the second motor are at 00, then the interrupt will run the second motor at the defined delay:
if ((IOPort.motor2_speed)==0b00)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_16); //Time Delay between steps
		 }


Quote

However, I do have some suggestions which you might find more immediately helpful. You should use arrays to store your SPEED values and RTCC_DIV_ values. You can go from this:
if ((IOPort.motor2_speed)==0b00)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_16); //Time Delay between steps
		 }
	   if ((IOPort.motor2_speed)==0b01)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_32);  //Time Delay between steps
		 }
	  if((IOPort.motor2_speed)==0b10)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_64);  //Time Delay between steps
		 }
	  if((IOPort.motor2_speed)==0b11)
		 {
		 SETUP_TIMER_0(RTCC_INTERNAL|RTCC_DIV_128);  //Time Delay between steps
		 }

to this:
int rtcc_values[] = {RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128};

// other code here

SETUP_TIMER_0(RTCC_INTERNAL | rtcc_values[IOPort.motor2_speed] );


Since the IOPort.motor2_speed values are from 0 to 3 they make perfect array indexes, and you should take advantage of that. Motor 1 appears to have the same speed values and therefore should be treated the same way.

I appreciate the design using an array for storing speed values. It makes the code more compact and efficient
However I am not clear on how I could solve the problem of the slight difference in speeds of both motors when one is interrupt run and the other is run from a loop.

Is it possible to use the function SETUP_Timer to set up the step delay in the first motor?

Or can I just assign the values from the speed array as delays? For instance, for the first motor, if wrote something like:
int rtcc_values[] = {RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128};

// other code here

stepdelay=RTCC_DIV_16;
delay_ms(stepdelay);

Would the compiler be able to process it without any bugs? Because, I also observed that delay_ms function can only work with integers?

Cheers mate and thanks a lot for the advice.
Was This Post Helpful? 0
  • +
  • -

#6 debjit625  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 51
  • View blog
  • Posts: 446
  • Joined: 06-September 08

Re: C programming: delays and interrupts

Posted 25 December 2009 - 01:23 PM

I am a bit late to wish but welcome to DIC

As per me programming for an embedded system just doesnt count the programming style but also depends on the features from the MCU you get and last but not the least the hardware ,so if I was doing this stuff I would used the CCP module of PIC16F648A ,the last 'P' that is "Pulse Width Modulation" for controlling the speed of the motor that is totally independent from instruction cycle executation .i..e.. its runs parallel with the instruction cycle executation so their will be no time consumed
while processing any code,and most you can maintain the speed at a huge difference i.e.. more step resolutions.For direction of the motors use two H-Bridge.

I am not sure but if you dont know about PWM stuff then download the application note for CCP module from microchip's website

Good Luck and Merry Christmas
Was This Post Helpful? 1
  • +
  • -

Page 1 of 1