// **************************************************************** // Includes // **************************************************************** #include #include #include #include #include #include "ls7266r1.h" #include "uart.h" #include "steps_lookup.h" // **************************************************************** // LCD Setup // **************************************************************** // LCD PORT = B (0x18) #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; }