LudoMTR (Part 6)

Part 1, 2, 3, 4, 5, 6

Here is an improved version of LudoMTR. The speed change ratio can be controlled by a separate potiometer. A synchronisation signal allows better signal display on scope: my RIGOL DS1502E dislikes triggering displays on complex signal! An LED is attached to the thread; this LED glows at a frequency which depends on the actual speed. An other LED glows when the speed is at a steady state (Set point reached by interia controller).

The steady state LED blinks while we would expect a stable glow when the speed as reached its set point. The reason for that is the reference voltage for the analog input of the speed setting. The excessive current sunk from the ATMEGA processor disturbs the +5V a lot as shown below. Thus the instability of the analog input signal for the speed setting. Even a bypass capacitor does not help much. As long as the application works, we do not really care, do we?

Here is the code:

/*

	Copyright (C) 2012 Didier Longueville

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

/* Current flows */
#define CUR_REVERSE -1 /* Current flows from port D to port B */
#define CUR_NONE 0
#define CUR_FORWARD 1 /* Current flows from port B to port D */
/* Set pins */
#define speedSettingPin 0
#define rateOfChangePin 1
#define pushButtonPin 2
#define synchPin 3
#define steadyStateLedPin 4
#define maskD 0xFC /* Port D digital pins 2 to 7 */
#define maskB 0x3F /* Port B  digital pins 8 to 13 */
/* Set defaut parameter values */
#define speedMax 1250
#define speedMin 250

long lastCycleTime = micros();
long targetCycleInterval; 
long currentCycleInterval; 
char currentDirection = CUR_FORWARD; /* Default current direction */
int rateOfChange; /* ppm */

void setup()
{
	/* Set ports */
	DDRB |= (maskB); /* Rotor Pole B */
	DDRD |= (maskD); /* Rotor Pole D */
	DDRC &= ~(1 << pushButtonPin); /* Set push button pin as an input pin */
	PORTC |= (1 << pushButtonPin); /* Bias push button pin */
	DDRC |= (1 << steadyStateLedPin); /* Set steady state led pin as an output pin*/
	DDRC |= (1 << synchPin); /* Set synchronization pin as an output pin*/
	analogReference(DEFAULT);
	setCurrent(CUR_NONE);
	setSpeed();
	currentCycleInterval = targetCycleInterval;
	/* For diag purpose */
	Serial.begin(115200);
}

void loop()
{
	PORTC ^= (1 << synchPin);
	setSpeed();
	setRateOfChange();
	if ((~PINC >> pushButtonPin) & 0x01) {
		/* Force immediate setting of speed */
		currentCycleInterval = targetCycleInterval;
	}
	if (currentCycleInterval == targetCycleInterval) {
		PORTC |= (1 << steadyStateLedPin);	/* Turn on steady state led */
	}
	else {
		PORTC &= ~(1 << steadyStateLedPin);	/* Turn off steady state led */
		long stepSize = (currentCycleInterval * rateOfChange) / 1000000UL;
		if (currentCycleInterval < targetCycleInterval) {
			currentCycleInterval += stepSize;
			if (currentCycleInterval > targetCycleInterval) currentCycleInterval = targetCycleInterval;
		}
		else if (currentCycleInterval > targetCycleInterval) {
			currentCycleInterval -= stepSize;
			if (currentCycleInterval < targetCycleInterval) currentCycleInterval = targetCycleInterval;
		}
	}
	/* Set next cycle time */
	long nextCycleTime = (lastCycleTime + currentCycleInterval);
	/* Wait next pulse */
	long now;
	do
		now = micros();
	while(now < nextCycleTime);
	/* Set current flow */
	setCurrent(currentDirection);
	/* Flip current direction for next pulse */
	currentDirection *= -1; 
	/* Record last pulse time */
	lastCycleTime = now;
	/* Set pulse stop time */
	long pulseStopTime = (lastCycleTime + long((currentCycleInterval << 1) / 3));
	/* Wait until pulse duration has elapsed */
	do
		now = micros();
	while(now < pulseStopTime);
	/* Cancel current */
	setCurrent(CUR_NONE);
};

void setSpeed(void)
{
	targetCycleInterval = 30000000UL / map(analogRead(speedSettingPin),0, 1023, speedMin, speedMax);
};

long setRateOfChange()
{
	rateOfChange = (map(analogRead(rateOfChangePin),0, 1023, 50, 1000));
};

void setCurrent(char value)
/* Set current flow between PORTB and PORTD pins */
{
 if (value == CUR_NONE) {
	/* Set pins as input pins */
	DDRB &= ~(maskB);
	DDRD &= ~(maskD); 
 }
 else {
	/* Set pins as output pins */
	DDRB |= (maskB);
	DDRD |= (maskD);  
	 switch(value) {
		case CUR_REVERSE:
			PORTB &= ~(maskB);		
			PORTD |=  (maskD);		
			break;
		case CUR_FORWARD:
			PORTB |=  (maskB);			
			PORTD &= ~(maskD);	
			break;
		}
	}
 };

Leave a Reply

You must be logged in to post a comment.