PIC Controlled clock movement hack?

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
My son has been having a blast creating circuits, soldering them, and doing some light programming (12 year old, just learning to control things in C without a real deep understanding of what is happening still). He built a circuit to control a 360 degree servo mechanically attached to the adjustment wheel of a clock mechanism. The goal was to make the hands move fairly fast (slightly over 2 hours per real minute) and at one point rotate it at 1 hour per 2 seconds.

He managed to get the hour per 2 seconds point working using the hacked servo (modified to be 360 rotation). The issue he is having is with the slower movement. He has tried a lot of different PWM values but he can't get a smooth/slow rotation....or even consistent. I am afraid what he is trying to do isn't actually even possible?

It looks like inertia may be working against him...at 1500 uS pulse (with 15mS between pulses) the servo is held at center. at ~1460 uS it will move usually, but it's a big jump...2-3 minutes tick off at a time. He can't get a smooth movement until about 1420 uS or so of on time and then it is moving faster than they want.

Any ideas?
 

THE_RB

Joined Feb 11, 2008
5,438
A continuous rotation RC servo is the wrong tool for the job, it will be erratic and have very poor speed control at very low RPMs.

Since you already have a PIC micro the ideal motor is a stepper motor which can do a flawless perfect speed, ideal for clocks. :)

Check out ebay for some really cheap little $5 stepper motors and drivers. Alternatively, you can get free steppers from inside any old bubblejet printer, and drive them with a few transistors or a common ULN2003 or ULN2083 IC.

Here is a stepper motor clock I made for fun, it has one "hand" and takes exactly 6 hours for ONE rotation, it is very accurate!

 

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
Awesome, I have ordered 3 stepper motors with driver boards (never hurts to have spares...).

Any pointers on some sample C Code for microchips to drive them? I would like to find him a start point to work with. My only experience with steppers was in a mini cnc build and I don't interface with them really...it was a kit and then controlled by the PC
 

John P

Joined Oct 14, 2008
2,026
Here is a video which shows a project I set up as a result of a discussion here. The question was how a clock could be made with a second hand which would take 60 steps to complete a revolution, if the motor driving it had 48 steps per revolution.

If you have a student of the dark art of electronics there, you might ask him why the motor makes a whining sound 4 steps out of 5 and is silent on the 5th. Maybe the LEDs on the breadboard offer a clue to what's happening?

http://www.youtube.com/watch?v=EGwNYo69y2o
 

THE_RB

Joined Feb 11, 2008
5,438
According to the clock in the picture, is it 12:35 am, 6:35 pm, 12:35 pm, 6:35 am, or none of the above?
YES. :D

It's a 6 hour clock face as you guessed, with either 12:00 at the top or 6:00 at the top.

In use you always know which of the 6hour cycles you are in, ie if near lunchtime you know it says 12:35, or if the sun's coming up you know its 6:35 in the morning. Some of the earliest mechanical clocks had a single moving hand.

Tigthwad said:
...
Any pointers on some sample C Code for microchips to drive them? I would like to find him a start point to work with. My only experience with steppers was in a mini cnc build and I don't interface with them really...it was a kit and then controlled by the PC
There are some C code examples for timing on this page;
http://www.romanblack.com/one_sec.htm
That can give exact seconds from any xtal value, and done fairly easily in any timed event like a timer interrupt or by testing a timer bit.

The beauty of the functions is that neither the xtal freq or the freq of the timed event matters, you just change two numbers and they will still make perfect average seconds for clock type use.
 

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
Is there any reason this:

Rich (BB code):
C code for a 1 second period with a 1MHz timer (4MHz xtal); 

	// uses 1 variable; unsigned long bres
	// gets here every TMR0 int (every 256 ticks)

	bres += 256;	// add 256 ticks to bresenham total

	if(bres >= 1000000)	// if reached 1 second!
	{
		bres -= 1000000;	// subtract 1 second, retain error
		do_1sec_event();	// update clock, etc
	}
Can't be split into smaller increments to do perfect 1/2 or 1/4 second timing? Something like:
Rich (BB code):
C code for a half second period with a 1MHz timer (4MHz xtal); 

	// uses 1 variable; unsigned long bres
	// gets here every TMR0 int (every 256 ticks)

	bres += 256;	// add 256 ticks to bresenham total

	if(bres >= 500000)	// if reached .5 second!
	{
		bres -= 5000000;	// subtract .5 second, retain error
		do_halfsec_event();	// update clock, etc
	}
 

John P

Joined Oct 14, 2008
2,026
Can you get the frequency higher so that it only annoys dogs?
Ha ha. As far as I remember, I found that if you want hardware-based PWM output on a selectable pin of that processor (PIC16F690) you're limited in which pins can be used in combination. I couldn't get it to do what I needed in driving the outputs for 4 motor coils, and of course it was just a throwaway project designed to prove that it could be done. Maybe with extra hardware I could have used the built-in PWM, but the easy way to make it work was to do the PWM in software. That imposes a conflict over how much resolution you want the duty cycle to have, versus the frequency. I think I ended up with 400Hz, and that's what's audible. There would also be the issue of what frequency the ULN2003 driver would be capable of working at, before switching losses become a problem. It was definitely a "quick and dirty" design!
 

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
Here is what we have determined we need so far:

Motor being used has specs of:
Step angle: 5.625 x 1/64
Reduction ratio: 1/64

Total steps = 32,768 (8 rotations at 64 steps with a 1/64 reduction)
Total time = 480 seconds

For 10 seconds the step rate needs to be much faster...20,480 steps of the total taken in this time. The remainder of the steps will be split to a before/after scenario (a button press will start the 10 second speed portion).

Would we be better off counting steps or running an 8 minute timer that steps at the speed needed? We have some events (buzzer sounding) that happen at specific time intervals etc.

We are still trying to understand how to implement TMR0 (or 1 or 2) for the 16F628A chip and how to use interrupts...it's a dark art I think!
 

THE_RB

Joined Feb 11, 2008
5,438
You don't really have to use interrupts in such a simple application.

Just manually wait in your code for the the TMR0 int flag to be set, then clear the flag. If TMR0 is set to 1MHz that int flag will get set every 256 uS.

Like this;
Rich (BB code):
while(1)       // main operating loop
{
  while(INTCON.TMR0IF == 0) continue;   // wait for int flag
  INTCON.TMR0IF = 0;                // clear int flag
  // code gets here every 256 uS!
}
Maybe if you post your full code we can help with it?
 

John P

Joined Oct 14, 2008
2,026
I'm very dubious that the fast step rate you mentioned, over 2000/sec, is possible with that kind of motor. Must you really have that speed?
 

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
I'm very dubious that the fast step rate you mentioned, over 2000/sec, is possible with that kind of motor. Must you really have that speed?
I have the same concern. The requirements may be changed based on the hardware ability...it's part of a performance by my 12 year old sons group so the requirements can be adjusted as needed.
 

THE_RB

Joined Feb 11, 2008
5,438
Your original post specced "1 hour per 2 seconds" as maximum speed, so that is 1/12th of a rotation over two seconds, or 24 seconds per full rotation.

That gearmotor has 64:1 gearing so to get 24 seconds per final rotation requires 24/64 or 0.375 seconds per motor rotation.

I think that is do-able easy enough on that motor as it is only 2.67 motor rotations per second. It may not self start well at 2.67 RPS, you might need to accelerate it over a few steps.
 

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
The clock is being run using the adjustment wheel on the back. 1 revolution of the adjustment wheel = 1 hour on the clock. That means 1/2 rotation per second. This feels quite fast and maybe isn't possible with the gearing involved in the motor (the motor would be rotating at 32 times a second).

What is the proper way to code an acceleration? I know my CNC software uses a trapezoidal ramp at start/stop but I don't see the code behind that of course.
 

THE_RB

Joined Feb 11, 2008
5,438
The clock is being run using the adjustment wheel on the back. 1 revolution of the adjustment wheel = 1 hour on the clock. That means 1/2 rotation per second. This feels quite fast and maybe isn't possible with the gearing involved in the motor (the motor would be rotating at 32 times a second).
OK, there's no way that motor will do 32 revs/sec, not without pushing it's spec and going to a lot of trouble.

Just use a normal (ungeared) stepper motor, and you only need 0.5 RPS.

What is the proper way to code an acceleration? I know my CNC software uses a trapezoidal ramp at start/stop but I don't see the code behind that of course.
You won't need to accelerate the stepper motor now, since it only needs to start at 0.5 RPS which should be fine.
 

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
Hi all...I got my stepper motor (28BYJ-48) and driver board (UN2003 board from geeetech.com). I tried to get a simple rotation code running but it isn't working. I am using a 12F609 with pins 5,4,2,1 connected to pins 1,2,3,4 on the driver board. I am supplying 5v and ground on the board using the first 2 pins. The code as written lights an LED but the motor does nothing.

Any ideas?

Rich (BB code):
/* 
 * File:   StepMain.c
 * Author: Dad
 *
 * Created on March 8, 2013, 10:31 PM
 */
#define _XTAL_FREQ 1000000
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

__CONFIG(MCLRE_ON & CP_OFF & WDTE_OFF & FOSC_INTOSCIO);

#define I_O_OUT     0       // standard TRIS definitions
#define I_O_IN      1
#define P_ON        1       //
#define P_OFF       0
#define P1          GP5
#define P2          GP4
#define P3          GP2
#define P4          GP1
#define P1_TRIS     TRISIO5
#define P2_TRIS     TRISIO4
#define P3_TRIS     TRISIO2
#define P4_TRIS     TRISIO1

void forward()
{
P1 = P_ON;
__delay_ms(2);
P1 = P_OFF;

P1 = P_ON;
P2 = P_ON;
__delay_ms(2);
P1 = P_OFF;
P2 = P_OFF;

P2 = P_ON;
__delay_ms(2);
P2 = P_OFF;

P2 = P_ON;
P3 = P_ON;
__delay_ms(2);
P2 = P_OFF;
P3 = P_OFF;

P3 = P_ON;
__delay_ms(2);
P3 = P_OFF;

P3 = P_ON;
P4 = P_ON;
__delay_ms(2);
P3 = P_OFF;
P4 = P_OFF;

P4 = P_ON;
__delay_ms(2);
P4 = P_OFF;
}
/* Main program */
void main()
{
P1_TRIS = I_O_OUT;
P1 = P_OFF;
P2_TRIS = I_O_OUT;
P2 = P_OFF;
P3_TRIS = I_O_OUT;
P3 = P_OFF;
P4_TRIS = I_O_OUT;
P4 = P_OFF;


while (1)
{
    forward();
} // end while
} //end main
 

Thread Starter

Tigthwad

Joined Oct 27, 2009
31
I figured it out. There needed to be a jumper between 5v and vss on the stepper board. Not sure why you wouldn't have one there but I only discovered it by looking on youtube for examples of others using it.

Motor turns now, working to see what max speed I can do. Writing some code to try to ramp up the speed...not sure if that will help with overall speed.
 

THE_RB

Joined Feb 11, 2008
5,438
Looks like your code is using half stepping.

You can improve the code a lot (and simplify it!) by writing to the whole port at one time, instead of turning each pin on or off;

GPIO = 0b00000011;
delay_mS(2);

GPIO = 0b00000110;
delay_mS(2);

GPIO = 0b00001100;
delay_mS(2);

GPIO = 0b00001001;
delay_mS(2);

Those 4 steps gives you standard full-step "2 phase on" drive. Obviously you can add extra steps to make it into half-stepping.
 
Top