Analog voltmeter using stepper motor and a Colour sensor(Draft)

 

Wiring Diagram

20121029-221000.jpg

20121029-220952.jpg

20121029-220944.jpg

Very simple use of a stepper motor, will update this post in a bit. The video seems to stop prematurely around 2/3 of the video on my laptop for some reason so just click on the tracker bar to watch the rest of it.


//
// dsPIC30F4011 Stepper motor powered analog Voltmeter
// Written by Gian Lorenzo
// Last updated 25-10-2012
//

#include <xc.h>
#include <libpic30.h>
#include <stdio.h>
#include <p30f4011.h>
#include <i2c.h>

// Configuration settings
_FOSC(CSW_FSCM_OFF & FRC_PLL16); // Fosc=16x7.5MHz, Fcy=30MHz
_FWDT(WDT_OFF);                  // Watchdog timer off
_FBORPOR(MCLR_DIS);              // Disable reset pin

// Function prototypes
void rotate(double degrees);	//	Rotate function
void step_forward();			//	Step forward function
void step_back();				// Step backward function
void setup();					// Setup configurations
unsigned int read_analog_channel(int channel);	// Read analog channel function
void pause(unsigned long ms);	// Pause in ms = (time in ms)*FCY/1000

// Global variable declarations
int t;
int voltage;
double svoltage;
double rotor_angle;
double step_angle;
long step_time;

int main()
{
	// Setup configurations
	setup();

	// Use initial position as angle origin
	rotor_angle = 0;

	// Stepper properties
	step_time = 120000L; // 4ms
	step_angle = 0.17578125; // 360.0 divided by 2048

	// Now rotate the stepper 6 degrees once every second
	while(1)
	{
		while(read_analog_channel(1)<500)
		{
			step_back();
		}
		rotor_angle = 0;
		while(1)
		{
			voltage = read_analog_channel(0);
			svoltage = voltage*(5/1023);
			if(rotor_angle<(voltage*step_angle)) 			{ 				step_forward(); 				printf("Voltage = %3f\n",svoltage); 			} 			else if(rotor_angle>(voltage*step_angle))
			{
				step_back();
			}
		}
	}

	return 0;
}

void rotate(double degrees)
{
	// The target angle is the current angle
	// plus the requested angle of rotation.
	double target_angle = rotor_angle + degrees;

	// Now keep stepping in the appropriate
	// direction until the target is reached.
	if (degrees > 0)
	{
		while(rotor_angle < target_angle) step_forward(); 	} 	else 	{ 		while(rotor_angle > target_angle) step_back();
	}
}

void step_forward()
{
	// Turn off the previous phase and turn
	// on the next one.
	if (LATD == 0b0001) LATD = 0b0010;
	else if (LATD == 0b0010) LATD = 0b0100;
	else if (LATD == 0b0100) LATD = 0b1000;
	else if (LATD == 0b1000) LATD = 0b0001;
	else LATD = 0b0001;

	// Increment the global angle tracker.
	rotor_angle = rotor_angle + step_angle;

	// Delay to allow rotor to move.
	__delay32(step_time);
}

void step_back()
{
	// Turn off the previous phase and turn
	// on the next one.
	if (LATD == 0b0001) LATD = 0b1000;
	else if (LATD == 0b0010) LATD = 0b0001;
	else if (LATD == 0b0100) LATD = 0b0010;
	else if (LATD == 0b1000) LATD = 0b0100;
	else LATD = 0b0001;

	// Decrement the global angle tracker.
	rotor_angle = rotor_angle - step_angle;

	// Delay to allow rotor to move.
	__delay32(step_time);
}
void setup()
{
    // Setup UART
	__C30_UART=2;
    U2BRG = 48;            // 38400 baud @ 30 MIPS
    U2MODEbits.UARTEN = 1; // Enable UART

    // Configure D ports as a digital outputs
    LATD = 0;
    TRISD = 0b11110000;

    // Configure analog inputs
    TRISB = 0x01FF;      /* Port B all inputs */
    ADPCFG = 0xFF00;     /* PORTB 0-7 are analog inputs */
    ADCON1 = 0;          /* Manually clear SAMP to end sampling, start conversion*/
    ADCON2 = 0;          /* Voltage reference from AVDD and AVSS */
    ADCON3 = 0x0005;     /* Manual Sample, ADCS=5 -> Tad = 3*Tcy = 0.1us */
    ADCON1bits.ADON = 1; /* Turn ADC ON */

    // Configure PWM
    // PWM period = Tcy * prescale * PTPER = 0.33ns * 64 * 9470 = 20ms
    PWMCON1 = 0x00FF; // Enable all PWM pairs in complementary mode
    PTCON = 0;
    _PTCKPS = 3;      // prescale=1:64 (0=1:1, 1=1:4, 2=1:16, 3=1:64)
    PTPER = 9470;     // 20ms PWM period (15-bit period value)
    PDC1 = 0;         // 0% duty cycle on channel 1 (max is 65536)
    PDC2 = 0;         // 0% duty cycle on channel 2 (max is 65536)
    PDC3 = 0;         // 0% duty cycle on channel 3 (max is 65536)
    PTMR = 0;         // Clear 15-bit PWM timer counter
    _PTEN = 1;        // Enable PWM time base

	/*// Configure I2c
	TRISFbits.TRISF2 = 1; // SDA
	TRISFbits.TRISF3 = 1; // SCL
	I2CCONbits.I2CSIDL = 1;	// Stop module in idle mode
	I2CCONbits.A10M = 0;	// 7-bit address
	I2CCONbits.DISSLW = 0;	// slew rate control for 400khz must be on
	I2CBRG = 45;		// 272 for 100kHz at FCY = 30MHz formula next line
							// I2CBRG = ((1/rate - 250ns)*FCY)-1
	I2CCONbits.I2CEN = 1;	// Enable i2c*/
}

unsigned int read_analog_channel(int channel)
{
    ADCHS = channel;          // Select the requested channel
    ADCON1bits.SAMP = 1;      // start sampling
    __delay32(30);            // 1us delay @ 30 MIPS
    ADCON1bits.SAMP = 0;      // start Converting
    while (!ADCON1bits.DONE); // Should take 12 * Tad = 1.2us
    return ADCBUF0;
}
void pause(unsigned long ms)
{
	__delay32(ms*30000L);
}

Advertisements