//
****************************************************************
//
Includes
//
****************************************************************
#include <Mega32.h>
#include <stdio.h>
#include <string.h>
#include <lcd.h>
#include <math.h>
#include "ls7266r1.h"
#include "uart.h"
#include "steps_lookup.h"
//
****************************************************************
// LCD
Setup
//
****************************************************************
//
#asm
.equ __lcd_port=0x18
#endasm
#define LCDwidth 16 // 16 character width
//
****************************************************************
//
Instructions Setup
//
****************************************************************
// Instruction values
#define INST_ACCEL_TIME 0
#define INST_BASE_RATE 1
#define INST_CONV_UNITS 2
#define INST_STEADY_RATE 3
#define INST_BACKLASH 4
#define INST_SLIP_WAIT 5
#define INST_ENABLE_DRIVE 6
#define INST_ASSOC_LIMITS 7
#define INST_DIAL_INDICATOR 8
#define INST_LCD_CONTROL 9
#define INST_MID_STATUS 10
#define INST_USER_POSITION 11
#define INST_MULTIPLEXER_SET 12
#define INST_LOWER_SLIMIT 13
#define INST_UPPER_SLIMIT 14
#define INST_DECODER_A_POS 15
#define INST_DECODER_B_POS 16
#define INST_LOWER_HLIMIT 17
#define INST_UPPER_HLIMIT 18
#define INST_PROGRAM_DECODER 19
#define INST_TWEEK_MOTOR 20
#define INST_MOVE_INCREMENTAL 21
#define INST_MOVE_ABSOLUTE 22
#define INST_MOVE_MICROSTEP 23
// Limits on parameters
#define MIN_ACCEL_TIME 128
#define MAX_ACCEL_TIME 2048
#define MIN_BASE_RATE 200
#define MAX_BASE_RATE 2048
#define MIN_CONV_UNITS 0
#define MAX_CONV_UNITS 50000
#define MIN_STEADY_RATE 200
#define MAX_STEADY_RATE 5000
#define MIN_BACKLASH 0
#define MAX_BACKLASH 5000
// Return values
#define RTRN_OK 0
#define RTRN_NOT_VALID 1
#define RTRN_MOVE_STOPPED 2
#define RTRN_NOT_ENABLED 3
#define RTRN_SLIP_COMPENSATE 4
#define RTRN_INTERRUPT 5
#define RTRN_SOFTWARE_LIMIT 6
#define RTRN_CHKSUM_ERROR 7
// Macros to decode instructions
// If the MSB of an instruction is set, it is a
write instruction
#define IsWriteInstruction(a) (a
& 0x80)
#define IsReadInstruction(a) (~a
& 0x80)
#define GetInst(a) (a & 0x7f)
//
****************************************************************
// I/O
Setup
// ****************************************************************
// Port setup
// Motor direction port
#define MotorDir_DDR DDRD.6
#define MotorDir_OUT PORTD.6
// Motor step port
#define MotorStep_DDR DDRD.5
#define MotorStep_OUT PORTD.5
#define MotorStep_IN PIND.5
// Motor enable port
#define MotorEn_DDR DDRC.0
#define MotorEn_OUT PORTC.0
// Limit input ports
#define HCWLimit_DDR DDRD.2
#define HCWLimit_IN PIND.2
#define HCCWLimit_DDR DDRD.3
#define HCCWLimit_IN PIND.3
// Multiplexer port
#define MUXLSB_DDR DDRC.1
#define MUXLSB_OUT PORTC.1
#define MUXMSB_DDR DDRC.2
#define MUXMSB_OUT PORTC.2
// Output temporary storage
unsigned char output_buffer[7];
unsigned char lcd_buffer[16];
unsigned char lcd_buffer2[16];
// ****************************************************************
//
Software Setup
//
****************************************************************
// The address of this MID
#define MID_ADDR 0x80
// Slip variables
#define MAX_SLIP 200
#define MIN_SLIP 2
// Position in microsteps
signed long int
master_pos;
signed long decoder_a_pos, decoder_b_pos;
// Error handling variable
unsigned char error;
// Motor and MID move parameters
unsigned int accel_time, base_rate, steady_rate,
conv_units, backlash, slip_wait;
signed long int
user_position;
unsigned long dial_indicator_fine, lower_slimit,
upper_slimit;
unsigned char enable_drive, assoc_limits, lcd_control,
multiplexer_set;
// Current move parameters
unsigned char cur_direction;
unsigned int cur_base_rate, cur_steady_rate,
cur_backlashupsteps, cur_backlashdownsteps, cur_slipsteps, cur_slipwait;
unsigned long cur_accelsteps, cur_steadysteps,
cur_decelsteps, cur_rate, cur_accel_rate, cur_backaccel_rate;
signed int cur_slip;
// Motor state
enum motor_states {STATE_ACCEL,
STATE_STEADY, STATE_DECEL, STATE_BACKLASH_UP, STATE_BACKLASH_DOWN,
STATE_SLIPWAIT,
STATE_SLIPCOMPENSATE, STATE_MANUALMOVE, STATE_OFF} motor_state;
// Motor timer setup
#define Motor_TCCR TCCR1B
#define MOTORON 0b00001010
#define MOTOROFF 0b00001000
#define Motor_TCCR2 TCCR1A
#define OUTPUTON 0b01000000
#define OUTPUTOFF 0b00000000
//
****************************************************************
// Strings
Setup
// ****************************************************************
flash
char* string_welcome =
"Welcome!";
flash
char* string_accel =
"Accelerating";
flash
char* string_steady =
"Steady";
flash
char* string_decel =
"Decelerating";
flash
char* string_backlash =
"Backlash";
flash
char* string_slipwait =
"Slip Delay";
flash
char*
string_slipcompensate = "Slip Comp";
flash
char* string_manualmove
= "Manual Move";
flash
char* string_off =
"Move Done";
flash
char* string_slip =
"ERR: Motor Slip";
flash
char* string_cwhlimit =
"ERR: CW HLimit";
flash
char* string_ccwhlimit
= "ERR: CCW HLimit";
flash
char* string_slimit =
"ERR: SLimit Trig";
//
****************************************************************
//
Functions and tasks
//
****************************************************************
#define time_lcd 399
#define time_serial 49
#define time_checkmotor 99
unsigned char count_lcd, count_serial,
count_checkmotor;
void init(void);
void task_serial(void);
void task_lcd(void);
void task_checkmotor(void);
void task_error(void);
//
****************************************************************
// Limit
Interrupts
//
****************************************************************
// Clockwise limit
interrupt
[EXT_INT0] void
cw_limit(void)
{
//
If the motor is moving, and it is moving into the limit switch
if
((motor_state != STATE_OFF)&&(assoc_limits == cur_direction))
{
// Stop the motor
Motor_TCCR = MOTOROFF;
motor_state = STATE_OFF;
// Return an error
error = RTRN_INTERRUPT;
// Display error message on the LCD screen
strcpyf(lcd_buffer2,
string_cwhlimit);
}
}
// Counterclockwise limit
interrupt
[EXT_INT1] void
ccw_limit(void)
{
//
If the motor is moving, and it is moving into the limit switch
if
((motor_state != STATE_OFF)&&(assoc_limits != cur_direction))
{
// Stop the motor
Motor_TCCR = MOTOROFF;
motor_state = STATE_OFF;
// Return an error
error = RTRN_INTERRUPT;
// Display error message on the LCD screen
strcpyf(lcd_buffer2,
string_ccwhlimit);
}
}
//
****************************************************************
// Timer
interrupts
//
****************************************************************
// OS Timer interrupt
interrupt
[TIM0_COMP] void
t0_cmp(void)
{
if
(count_lcd > 0) count_lcd--;
if
(count_serial > 0) count_serial--;
if
(count_checkmotor > 0) count_checkmotor--;
}
// Motor timer interrupt
interrupt
[TIM1_COMPA] void
t1_cmpA(void)
{
//
Temporary variable
signed
int decoder_read;
//
Slip delay state
if
(motor_state == STATE_SLIPWAIT)
{
// Decrement the slip delay
if (cur_slipwait > 0) cur_slipwait--;
// If the slip delay is 0
if (cur_slipwait == 0)
{
// Read the real position from the decoder
decoder_read = LS_read_output(select_X);
// Calculate the discrepency between the position we read
and the
// our stored position, and the direction we need to move
to correct
// any slippage
cur_slip = decoder_read -
master_pos;
cur_slipsteps = abs(cur_slip);
cur_direction = (cur_slip >
0)? 1 : 0;
// Set our position to the real position
master_pos = decoder_read;
// If we have slipped more than the minimum tolerance
if (cur_slipsteps > MAX_SLIP)
{
// Stop the motor
motor_state = STATE_OFF;
Motor_TCCR = MOTOROFF;
// Return an error message
error =
RTRN_MOVE_STOPPED;
// Display error message on the LCD screen
strcpyf(lcd_buffer2,
string_slip);
}
// If we have slipped more than the maximum tolerance
else if
(cur_slipsteps > MIN_SLIP)
{
// Compensate for the slip
motor_state =
STATE_SLIPCOMPENSATE;
MotorDir_OUT =
cur_direction;
// Set the motor to minimum speed
OCR1A =
StepsToCycles[cur_base_rate - 200];
// Turn the motor on
Motor_TCCR2 = OUTPUTON;
// Display the current state on the LCD screen
strcpyf(lcd_buffer2,
string_slipcompensate);
}
else
{
// Turn of the motor
motor_state =
STATE_OFF;
// Display the current state on the LCD screen
strcpyf(lcd_buffer2,
string_off);
}
}
}
//
If we are on the falling edge
else
if (!MotorStep_IN)
{
// If the motor is on
if (motor_state != STATE_OFF)
{
// Add a step to the current position in the correct
// direction
if (cur_direction)
{
master_pos++;
dial_indicator_fine--;
}
else
{
master_pos--;
dial_indicator_fine++;
}
}
// If we have hit a software limit and are moving into it
if ((motor_state !=
STATE_MANUALMOVE)&&(((dial_indicator_fine >= upper_slimit)
&&(cur_direction ==
0))||((dial_indicator_fine <= lower_slimit)&&(cur_direction == 1))))
{
// Turn off the motor
Motor_TCCR = MOTOROFF;
// Return an error
error = RTRN_SOFTWARE_LIMIT;
// Display an error on the LCD screen
strcpyf(lcd_buffer2,
string_slimit);
}
// Handle the current motor state
else switch(motor_state)
{
// If we are accelerating
case STATE_ACCEL:
// Increment the current speed by a fixed point binary
number
cur_rate +=
cur_accel_rate;
// Set the timer compare match value to the current speed
OCR1A =
StepsToCycles[(cur_rate >> 16) - 200];
// Decrement the acceleration steps
if (cur_accelsteps > 0) cur_accelsteps--;
// If there are no acceleration steps left
if (cur_accelsteps == 0)
{
// Set the timer compare match value to the steady speed
OCR1A =
StepsToCycles[cur_steady_rate - 200];
// Go to the steady state
motor_state =
STATE_STEADY;
// Display the current state on the LCD screen
strcpyf(lcd_buffer2,
string_steady);
}
break;
// If we are in the steady state
case STATE_STEADY:
// Decrement the steady steps
if (cur_steadysteps > 0)
cur_steadysteps--;
// If there are no steady steps left
if (cur_steadysteps == 0)
{
// Set the speed to the steady speed
cur_rate = (unsigned long)(cur_steady_rate) << 16;
// Go to the deceleration state
motor_state =
STATE_DECEL;
// Display the current state on the LCD screen
strcpyf(lcd_buffer2,
string_decel);
}
break;
// If we are in the decelleration state
case STATE_DECEL:
// Decrement the current speed by a fixed point binary
number
cur_rate -=
cur_accel_rate;
// Set the timer compare match value to the current speed
OCR1A =
StepsToCycles[(cur_rate >> 16) - 200];
// Decrement the deceleration steps
if (cur_decelsteps > 0) cur_decelsteps--;
// If there are no decelration steps left
if (cur_decelsteps == 0)
{
// If the motor is going downward, backlash the motor
if (cur_direction == 0)
{
// Set the speed to the base speed
cur_rate = (unsigned long)(cur_base_rate) << 16;
// Go to the backlash up state
motor_state
= STATE_BACKLASH_UP;
// Display the current state on the LCD
screen
strcpyf(lcd_buffer2,
string_backlash);
// Reverse the direction of the motor
cur_direction
= 1;
MotorDir_OUT
= 1;
}
// Otherwise, go straight to compensating for slip
else
{
// Go to the slip delay state
motor_state
= STATE_SLIPWAIT;
// Display the current state on the LCD
screen
strcpyf(lcd_buffer2,
string_slipwait);
// Set the motor compare match value to 1
ms
OCR1A =
1992;
// Turn the motor output off
Motor_TCCR2
= OUTPUTOFF;
}
}
break;
// If we are in the backlash acceleration state
case STATE_BACKLASH_UP:
// Increment the current speed by a fixed point binary
number
cur_rate +=
cur_backaccel_rate;
// Set the timer compare match to the current speed
OCR1A =
StepsToCycles[(cur_rate >> 16) - 200];
// Decrement the backlash acceleration steps
if (cur_backlashupsteps > 0)
cur_backlashupsteps--;
// If there are no backlash acceleration steps left
if (cur_backlashupsteps == 0)
{
// Go to the backlash deceleration
station
motor_state =
STATE_BACKLASH_DOWN;
}
break;
// If we are in the backlash deceleration state
case STATE_BACKLASH_DOWN:
// Decrement the current speed by a fixed point binary
number
cur_rate -=
cur_backaccel_rate;
// Set the timer compare match to the current speed
OCR1A =
StepsToCycles[(cur_rate >> 16) - 200];
// Decrement the backlash deceleration steps
if (cur_backlashdownsteps > 0)
cur_backlashdownsteps--;
// If there are no backlash deceleration
steps left
if (cur_backlashdownsteps == 0)
{
// Go to the slip delay state
motor_state =
STATE_SLIPWAIT;
// Display the current state on the LCD screen
strcpyf(lcd_buffer2,
string_slipwait);
// Set the timer compare match to 1 ms
OCR1A = 1992;
// Turn off the motor output
Motor_TCCR2 =
OUTPUTOFF;
}
break;
// If we are in the slip compensation state
case STATE_SLIPCOMPENSATE:
// Decrement the slip compensation steps
if (cur_slipsteps > 0) cur_slipsteps--;
// If there are no slip compensation steps left
if (cur_slipsteps == 0)
{
// Go to the motor off state
motor_state =
STATE_OFF;
// Display the current state on the LCD screen
strcpyf(lcd_buffer2,
string_off);
}
break;
// If we are moving manually
case STATE_MANUALMOVE:
if (cur_slipsteps > 0) cur_slipsteps--;
if (cur_slipsteps == 0)
{
motor_state =
STATE_OFF;
strcpyf(lcd_buffer2,
string_off);
}
break;
// If the motor is off
case STATE_OFF:
// Turn off the motor interrupt
Motor_TCCR = MOTOROFF;
break;
}
}
}
//
****************************************************************
// Uart
utility functions
//
****************************************************************
// Parse the uart buffer into an unsigned integer
unsigned int Uart2UnsignedInt(void)
{
return
((unsigned int)(((unsigned int)uart_buffer[3])<<8) + (unsigned int)uart_buffer[2]);
}
// Parse the uart buffer into a signed integer
signed int Uart2SignedInt(void)
{
return
(signed int)( (signed int)(((signed int)uart_buffer[3])<<8) + (unsigned int)uart_buffer[2]);
}
// Parse the uart buffer into a signed long
signed long int
Uart2SignedLong(void)
{
return
(signed long int)(((0x80 && uart_buffer[4])? (signed long int)0xff000000
: (signed long int)0x00000000)
+
(unsigned long int)(((unsigned long int)
uart_buffer[4]) << 16)
+
(unsigned long int)(((unsigned long int)
uart_buffer[3]) << 8)
+
(unsigned long int)uart_buffer[2]);
}
// Place an unsigned character in the uart output
buffer
void UnsignedChar2Uart(unsigned char inst, unsigned char value)
{
output_buffer[0] = MID_ADDR;
output_buffer[1] = inst;
output_buffer[2] = RTRN_OK;
output_buffer[3] = value;
output_buffer[4] = 0x00;
output_buffer[5] = 0x00;
output_buffer[6] = (unsigned char)(output_buffer[0] + output_buffer[1] +
output_buffer[2] + output_buffer[3]);
}
// Place an unsigned integer in the uart output
buffer
void UnsignedInt2Uart(unsigned char inst, unsigned int value)
{
output_buffer[0] = MID_ADDR;
output_buffer[1] = inst;
output_buffer[2] = RTRN_OK;
output_buffer[3] = (value & 0xff);
output_buffer[4] = (value >> 8);
output_buffer[5] = 0x00;
output_buffer[6] = (unsigned char)(output_buffer[0] + output_buffer[1] +
output_buffer[2]
+ output_buffer[3]
+ output_buffer[4]);
}
// Place a signed long in the uart output buffer
void SignedLong2Uart(unsigned char inst, signed long int
value)
{
output_buffer[0] = MID_ADDR;
output_buffer[1] = inst;
output_buffer[2] = RTRN_OK;
output_buffer[3] = (value & 0xff);
output_buffer[4] = (value >> 8)
& 0xff;
output_buffer[5] = (value >> 16)
& 0xff;
output_buffer[6] = (unsigned char)(output_buffer[0] + output_buffer[1] +
output_buffer[2]
+ output_buffer[3] +
output_buffer[4] + output_buffer[5]);
}
// Place an instruction related error value in the
uart output buffer
void InstError2Uart(unsigned char inst, unsigned char err)
{
output_buffer[0] = MID_ADDR;
output_buffer[1] = inst;
output_buffer[2] = err;
output_buffer[3] = 0x00;
output_buffer[4] = 0x00;
output_buffer[5] = 0x00;
output_buffer[6] = (unsigned char)(output_buffer[0] + output_buffer[1] +
output_buffer[2]);
}
// Place a non-instruction related error in the uart
output buffer
void Error2Uart(unsigned char err)
{
output_buffer[0] = MID_ADDR;
output_buffer[1] = 0x00;
output_buffer[2] = err;
output_buffer[3] = 0x00;
output_buffer[4] = 0x00;
output_buffer[5] = 0x00;
output_buffer[6] = (unsigned char)(output_buffer[0] + output_buffer[2]);
}
// Write the output buffer to the UART
void Output2Uart(void)
{
unsigned
char a = 0;
for
(a = 0; a < 7; a++)
{
t_buffer[t_end] = output_buffer[a];
t_end = (t_end + 1) %
TRANSMIT_BUFFER_SIZE;
}
t_end = (t_end + 1) %
TRANSMIT_BUFFER_SIZE;
UCSRB.5 = 1;
}
//
****************************************************************
// Motor
setup function
//
****************************************************************
void SetupMove(unsigned char direction, unsigned long steps)
{
//
Turn off the motor and interrupts
Motor_TCCR = MOTOROFF;
Motor_TCCR2 = OUTPUTOFF;
motor_state = STATE_OFF;
//
Check the hardware limits, if one of them is engaged make sure we cannot
//
move into them. Associate the limits correctly with the orientations
if
(assoc_limits == 1)
{
if (((HCCWLimit_IN==0) && (direction
== 0))||((HCWLimit_IN==0) && (direction == 1)))
{
steps = 0;
return;
}
}
else
{
if (((HCWLimit_IN==0) && (direction ==
0))||((HCCWLimit_IN==0) && (direction == 1)))
{
return;
steps = 0;
}
}
//
If we are moving more than one step
if
(steps > 1)
{
// Setup the current move parameters
cur_direction
= direction;
cur_base_rate = base_rate;
cur_steady_rate = steady_rate;
cur_slipwait = slip_wait;
// Calculate the number of steps in each state
// Acceleration steps = change in step speed / acceleration
time / 2 + base speed * acceleration time
cur_accelsteps = (unsigned long)(steady_rate - base_rate) * (unsigned long)accel_time
/ (unsigned long)2000 + base_rate * accel_time / 1000;
cur_decelsteps = cur_accelsteps;
// Steady steps = Total steps - acceleration steps -
decelrations steps
// If we have no steady steps left, set it to zero
if
(2 * cur_accelsteps > steps)
cur_steadysteps = 0;
// If we are going down, add in backlash
else
if (cur_direction == 0)
cur_steadysteps = steps -
cur_accelsteps - cur_decelsteps + backlash;
// Otherwise neglect backlash
else
cur_steadysteps
= steps - cur_accelsteps - cur_decelsteps;
// Calculate acceleration rate
// Acceleration rate = (steady speed - base speed) /
acceleration steps
cur_accel_rate = ((unsigned long)(steady_rate - base_rate) << 16) /
cur_accelsteps;
// Change base speed into fixed point binary number
cur_rate = (unsigned long)(base_rate) << 16;
// Calculate backlash up and down steps
cur_backlashupsteps = backlash / 2;
cur_backlashdownsteps = backlash -
cur_backlashupsteps;
// Calculate backlash acceleration rate
cur_backaccel_rate = ((unsigned long)(steady_rate - base_rate) << 16) /
cur_backlashupsteps;
// Go to the acceleration state
motor_state = STATE_ACCEL;
// Print the current state on the LCD screen
strcpyf(lcd_buffer2, string_accel);
// Set the timer compare match value to the base speed
OCR1A = StepsToCycles[cur_base_rate
- 200];
// Set the direction
MotorDir_OUT = cur_direction;
// Reset the motor output
MotorStep_OUT = 0;
// Turn on the motor interrupt and output
Motor_TCCR2 = OUTPUTON;
Motor_TCCR = MOTORON;
}
}
//
****************************************************************
// OS and
task functions
// ****************************************************************
// Initialization function
void init(void)
{
//
Initialize the LCD
lcd_init(LCDwidth);
strcpyf(lcd_buffer2, string_welcome);
//
Initialize the LS chip
LS_init();
LS_write_RLD(select_XY, RLD_reset_BP |
RLD_reset_FLAGS);
LS_write_PRS(select_XY, 0);
LS_write_RLD(select_XY, RLD_trnsfr_PR0);
LS_write_RLD(select_XY, RLD_reset_BP |
RLD_reset_FLAGS | RLD_reset_CNTR);
LS_write_CMR(select_XY, CMR_quad_X1);
LS_write_IOR(select_XY, IOR_enable_AB |
IOR_LOL);
LS_write_preset(select_X, 1);
LS_write_RLD(select_XY,
RLD_trnsfr_PR);
//
Initialize the UART
uart_init(103);
uart_gets_int();
//
Setup the LS chip clock
//
The clock runs at 16 Mhz / ( 2 * 64 ) = 125 Khz
TCCR2 = 0b00011001;
OCR2 = 63;
DDRD.7 = 1;
//
Setup the motor counter and I/O ports
TCCR1B = MOTOROFF;
TCCR1A = OUTPUTOFF;
MotorDir_DDR = 1;
MotorStep_DDR = 1;
MotorEn_DDR = 1;
MotorEn_OUT = 1;
//
Setup the OS clock
//
The clock runs at 16 Mhz / (64 * 250) = 1 Khz
TCCR0=0b00001011;
OCR0=249;
//
Setup the timer interrupts
//
Interrupt on timer 0 and 1 compare match
TIMSK=0b00010010;
//
Setup the task times
count_lcd = time_lcd;
count_serial = time_serial;
count_checkmotor = time_checkmotor;
//
Setup multiplexer lines
MUXLSB_DDR = 1;
MUXMSB_DDR = 1;
//
Setup external interrupts for clockwise and counterclockwise
//
interrupts
MCUCR = 0b00001010;
GICR = 0b11000000;
HCWLimit_DDR = 0;
HCCWLimit_DDR = 0;
//
Setup variables
master_pos = 1;
lcd_control = 1;
accel_time = 1200;
base_rate = 400;
steady_rate = 1000;
backlash = 500;
conv_units = 2835;
assoc_limits = 1;
slip_wait = 500;
motor_state = STATE_OFF;
lower_slimit = (unsigned long)39 * (unsigned long)conv_units;
upper_slimit = (unsigned long)89 * (unsigned long)conv_units;
//
Turn on interrupts
#asm
sei
#endasm
}
// Entry point
void main(void)
{
//
Initialize
init();
//
Loop forever
while
(1)
{
// Motor checking task
if (count_checkmotor == 0) task_checkmotor();
// If the LCD is on, refresh the LCD
if ((lcd_control)&&(count_lcd == 0))
task_lcd();
// Serial input task
if (count_serial == 0) task_serial();
// If we have an error to return, return it
if (error > 0) task_error();
}
}
// LCD refreshing task
void task_lcd(void)
{
//
Reset the task time
count_lcd = time_lcd;
//
Print the current dial position to lcd buffer
sprintf(lcd_buffer,"Pos: %u",
(dial_indicator_fine + (conv_units / 2)) / conv_units);
//
Clear the LCD
lcd_clear();
//
Print the LCD buffers to the LCD
lcd_gotoxy(0,0);
lcd_puts(lcd_buffer);
lcd_gotoxy(0,1);
lcd_puts(lcd_buffer2);
}
// Serial input task
void task_serial(void)
{
//
Temporary variable
signed
long int tempSteps;
//
Reset the task time
count_serial = time_serial;
//
If we have recieved a full message
if
(uart_ready)
{
// If the checksum does not match the transmitted one,
transmit an error message
if ((unsigned
char)(uart_buffer[0]+uart_buffer[1]+uart_buffer[2]
+uart_buffer[3]+uart_buffer[4])!=uart_buffer[5])
InstError2Uart(uart_buffer[1],
RTRN_CHKSUM_ERROR);
// Otherwise, process the message
else switch(GetInst(uart_buffer[1]))
{
// Read or write the acceleration time
case INST_ACCEL_TIME:
if (IsWriteInstruction(uart_buffer[1]))
{
accel_time =
Uart2UnsignedInt();
if (accel_time < MIN_ACCEL_TIME)
accel_time =
MIN_ACCEL_TIME;
else if
(accel_time > MAX_ACCEL_TIME)
accel_time = MAX_ACCEL_TIME;
}
UnsignedInt2Uart(INST_ACCEL_TIME,
accel_time);
break;
// Read or write the base rate
case INST_BASE_RATE:
if (IsWriteInstruction(uart_buffer[1]))
{
base_rate =
Uart2UnsignedInt();
if (base_rate < MIN_BASE_RATE)
base_rate =
MIN_BASE_RATE;
else if
(base_rate > MAX_BASE_RATE)
base_rate =
MAX_BASE_RATE;
}
UnsignedInt2Uart(INST_BASE_RATE,
base_rate);
break;
// Read or write the conversion units
case INST_CONV_UNITS:
if (IsWriteInstruction(uart_buffer[1]))
{
conv_units =
Uart2UnsignedInt();
if (conv_units < MIN_CONV_UNITS)
conv_units =
MIN_CONV_UNITS;
else if
(conv_units > MAX_CONV_UNITS)
conv_units =
MAX_CONV_UNITS;
}
UnsignedInt2Uart(INST_CONV_UNITS,
conv_units);
break;
// Read or write the steady rate
case INST_STEADY_RATE:
if (IsWriteInstruction(uart_buffer[1]))
{
steady_rate =
Uart2UnsignedInt();
if (steady_rate < MIN_STEADY_RATE)
steady_rate
= MIN_STEADY_RATE;
else if
(steady_rate > MAX_STEADY_RATE)
steady_rate
= MAX_STEADY_RATE;
}
UnsignedInt2Uart(INST_STEADY_RATE,
steady_rate);
break;
// Read or write the backlash steps
case INST_BACKLASH:
if (IsWriteInstruction(uart_buffer[1]))
{
backlash =
Uart2UnsignedInt();
if (backlash < MIN_BACKLASH)
backlash =
MIN_BACKLASH;
else if
(backlash > MAX_BACKLASH)
backlash =
MAX_BACKLASH;
}
UnsignedInt2Uart(INST_BACKLASH,
backlash);
break;
// Read or write the slip delay time
case INST_SLIP_WAIT:
if (IsWriteInstruction(uart_buffer[1]))
{
slip_wait =
Uart2UnsignedInt();
}
UnsignedInt2Uart(INST_SLIP_WAIT,
slip_wait);
break;
// Enable or disable the drive
case INST_ENABLE_DRIVE:
if (IsWriteInstruction(uart_buffer[1]))
enable_drive = uart_buffer[2];
UnsignedChar2Uart(INST_ENABLE_DRIVE,
enable_drive);
break;
// Change the limit association
case INST_ASSOC_LIMITS:
if (IsWriteInstruction(uart_buffer[1]))
assoc_limits = uart_buffer[2];
UnsignedChar2Uart(INST_ASSOC_LIMITS,
assoc_limits);
break;
// Read or write the dial indicator value
case INST_DIAL_INDICATOR:
if (IsWriteInstruction(uart_buffer[1]))
{
dial_indicator_fine
= (unsigned long)Uart2UnsignedInt() * (unsigned long)conv_units;
}
UnsignedInt2Uart(INST_DIAL_INDICATOR,
(dial_indicator_fine + (conv_units / 2)) / conv_units);
break;
// Enable or disable the LCD screen
case INST_LCD_CONTROL:
if (IsWriteInstruction(uart_buffer[1]))
{
lcd_control = uart_buffer[2];
lcd_clear();
}
UnsignedChar2Uart(INST_LCD_CONTROL,
lcd_control);
break;
// Read the mid status
case INST_MID_STATUS:
UnsignedChar2Uart(INST_MID_STATUS,
0xff);
break;
// Read or write the user position
case INST_USER_POSITION:
if (IsWriteInstruction(uart_buffer[1]))
user_position = Uart2SignedLong();
SignedLong2Uart(INST_USER_POSITION,
user_position);
break;
// Read or write the multiplexer select value
case INST_MULTIPLEXER_SET:
if (IsWriteInstruction(uart_buffer[1]))
{
multiplexer_set =
uart_buffer[2];
MUXMSB_OUT =
(multiplexer_set & 0x02) >> 1;
MUXLSB_OUT =
multiplexer_set & 0x01;
}
UnsignedChar2Uart(INST_MULTIPLEXER_SET,
multiplexer_set);
break;
// Read or write the lower software limit
case INST_LOWER_SLIMIT:
if (IsWriteInstruction(uart_buffer[1]))
{
lower_slimit = (unsigned long)Uart2UnsignedInt() * (unsigned long)conv_units;
}
UnsignedInt2Uart(INST_LOWER_SLIMIT,
(lower_slimit + (conv_units / 2)) / conv_units);
break;
// Read or write the upper software limit
case INST_UPPER_SLIMIT:
if (IsWriteInstruction(uart_buffer[1]))
{
upper_slimit = (unsigned long)Uart2UnsignedInt() * (unsigned long)conv_units;
}
UnsignedInt2Uart(INST_UPPER_SLIMIT,
(upper_slimit + (conv_units / 2)) / conv_units);
break;
// Read or write decoder a position
case INST_DECODER_A_POS:
if (IsWriteInstruction(uart_buffer[1]))
{
decoder_a_pos =
Uart2SignedLong();
LS_write_preset(select_X,
decoder_a_pos);
LS_write_RLD(select_X,
RLD_trnsfr_PR);
}
SignedLong2Uart(INST_DECODER_A_POS,
decoder_a_pos);
break;
// Read or write decoder b position
case INST_DECODER_B_POS:
if (IsWriteInstruction(uart_buffer[1]))
{
decoder_b_pos
= Uart2SignedLong();
LS_write_preset(select_Y,
decoder_b_pos);
LS_write_RLD(select_Y,
RLD_trnsfr_PR);
}
SignedLong2Uart(INST_DECODER_B_POS,
decoder_b_pos);
break;
// Read the lower hardware limit with respect to limit
association
case INST_LOWER_HLIMIT:
if (assoc_limits)
UnsignedChar2Uart(INST_LOWER_HLIMIT,
HCWLimit_IN);
else
UnsignedChar2Uart(INST_LOWER_HLIMIT,
HCCWLimit_IN);
break;
// Read the upper hardware limit with respect to limit
association
case INST_UPPER_HLIMIT:
if (assoc_limits)
UnsignedChar2Uart(INST_LOWER_HLIMIT,
HCCWLimit_IN);
else
UnsignedChar2Uart(INST_LOWER_HLIMIT,
HCWLimit_IN);
break;
// Program the decoders
case INST_PROGRAM_DECODER:
if (IsWriteInstruction(uart_buffer[1]));
break;
// Tweek the motor to the current dial position
case INST_TWEEK_MOTOR:
if (IsWriteInstruction(uart_buffer[1]))
{
if (motor_state == STATE_OFF)
{
dial_indicator_fine
= (unsigned long)Uart2UnsignedInt() * (unsigned long)conv_units;
}
UnsignedInt2Uart(INST_TWEEK_MOTOR,
(dial_indicator_fine + (conv_units / 2)) / conv_units);
}
break;
// Move the dial indicator incrementally
case INST_MOVE_INCREMENTAL:
if (IsWriteInstruction(uart_buffer[1]))
{
tempSteps = (signed
long int)Uart2SignedInt() * conv_units;
SetupMove((tempSteps
> 0)? 0 : 1, labs(tempSteps));
}
break;
// Move the dial indicator to an absolute value
case INST_MOVE_ABSOLUTE:
if (IsWriteInstruction(uart_buffer[1]))
{
tempSteps = (unsigned long int)Uart2UnsignedInt()
* conv_units;
SetupMove((tempSteps
> dial_indicator_fine)? 0 : 1,
labs(dial_indicator_fine - tempSteps));
};
break;
// Move the motor incremental microsteps
case INST_MOVE_MICROSTEP:
if (IsWriteInstruction(uart_buffer[1]))
{
// Calculate the number of steps to move and the direction
tempSteps =
Uart2SignedLong();
cur_slipsteps =
labs(tempSteps);
cur_direction =
(tempSteps > 0)? 1 : 0;
// Make sure we are not moving into a hardware limit
if (((assoc_limits ==
1)&&(((HCCWLimit_IN==0) && (cur_direction == 0))
||((HCWLimit_IN==0)
&& (cur_direction == 1))))||
((assoc_limits
== 0)&&(((HCWLimit_IN==0) && (cur_direction == 0))
||((HCCWLimit_IN==0)
&& (cur_direction == 1)))))
{
// If we are, return an error
InstError2Uart(uart_buffer[1],
RTRN_INTERRUPT);
}
else
{
// Setup the current direction
MotorDir_OUT
= cur_direction;
// Set the motor
OCR1A =
StepsToCycles[0];
// Go to the manual move change
motor_state
= STATE_MANUALMOVE;
// Display the current state on the LCD
screen
strcpyf(lcd_buffer2,
string_manualmove);
// Turn on the motor output and interrupt
Motor_TCCR =
MOTORON;
Motor_TCCR2
= OUTPUTON;
// Return the number of steps moved
SignedLong2Uart(INST_MOVE_MICROSTEP,
tempSteps);
}
}
break;
// Otherwise, return an invalid command error
default:
InstError2Uart(uart_buffer[1],
RTRN_NOT_VALID);
break;
}
// Output the output buffer to the UART
Output2Uart();
// Get another input from the UART
uart_gets_int();
}
}
// Motor checking task
void task_checkmotor(void)
{
//
Reset the task time
count_checkmotor = time_checkmotor;
//
Read the decoder positions
decoder_a_pos = LS_read_output(select_X);
decoder_b_pos = LS_read_output(select_Y);
}
// Error transmision task
void task_error(void)
{
//
Put the error in the UART buffer
Error2Uart(error);
//
Output the output buffer to the UART
Output2Uart();
//
Reset the error variable
error = 0;
}