void hex_receiver::map (uint8_t a_code, void* p_object, base_data_receiver* p_receiver) { // Create a new mapping object hex_data_type_to_pointer* p_new_map = new hex_data_type_to_pointer; p_new_map->code = a_code; p_new_map->p_obj = p_object; p_new_map->p_rcvr = p_receiver; // If the map was successfully created, insert the mapping object into the linked // list of such objects. It seems easiest to put it in as the first item to be // found in the list if (p_new_map != NULL) { if (p_first_map == NULL) { p_new_map->p_next = NULL; } else { p_new_map->p_next = p_first_map; } p_first_map = p_new_map; HXR_DBG (p_serial, PMS ("HXR map: ") << p_first_map->p_obj << hex << p_first_map->code << endl); } else { // If the map wasn't successfully created, complain if debugging HXR_DBG (p_serial, PMS ("hex_receiver::map() alloc error ") << endl); } }
void task_brightness::run (void) { // Make a variable which will hold times to use for precise task scheduling TickType_t previousTicks = xTaskGetTickCount (); // Create an analog to digital converter driver object and a variable in which to // store its output. The variable p_my_adc only exists within this run() method, // so the A/D converter cannot be used from any other function or method adc* p_my_adc = new adc (p_serial); // Configure counter/timer 3 as a PWM for LED brightness. First set the data // direction register so that the pin used for the PWM will be an output. The // pin is Port E pin 4, which is also OC3B (Output Compare B for Timer 3) DDRE = (1 << 4); // To set 8-bit fast PWM mode we must set bits WGM30 and WGM32, which are in two // different registers (ugh). We use COM3B1 and Com3B0 to set up the PWM so that // the pin output will have inverted sense, that is, a 0 is on and a 1 is off; // this is needed because the LED connects from Vcc to the pin. TCCR3A |= (1 << WGM30) | (1 << COM3B1) | (1 << COM3B0); // The CS31 and CS30 bits set the prescaler for this timer/counter to run the // timer at F_CPU / 64 TCCR3B |= (1 << WGM32) | (1 << CS31) | (1 << CS30); // This is the task loop for the brightness control task. This loop runs until the // power is turned off or something equally dramatic occurs for (;;) { // Read the A/D converter from channel 1 uint16_t a2d_reading = p_my_adc->read_once(1); // Convert the A/D reading into a PWM duty cycle. The A/D reading is between 0 // and 1023; the duty cycle should be between 0 and 255. Thus, divide by 4 uint16_t duty_cycle = a2d_reading / 4; //print the Duty_Cycle in comparison to the Power Signal being pumped into set_power *p_serial <<PMS ("ADC Reading: ")<< a2d_reading <<dec <<endl <<PMS ("Power_Signal: ")<< duty_cycle <<dec <<endl; // Set the brightness. Since the PWM has already been set up, we only need to // put a new value into the duty cycle control register, which on an AVR is // the output compare register for a given timer/counter OCR3B = duty_cycle; //OCR1B = duty_cycle; // Increment the run counter. This counter belongs to the parent class and can // be printed out for debugging purposes runs++; // This is a method we use to cause a task to make one run through its task // loop every N milliseconds and let other tasks run at other times delay_from_for_ms (previousTicks, 1000); } }
emstream& operator << (emstream& serpt, hctl& hc20) { // Prints info to the serial port serpt << PMS ("This HCTL-2000 is using these pins:")<< dec << endl << PMS ("OE pin: ")<< hc20.get_oe_port() << ":" << hc20.get_oe_pin() << endl << PMS ("Sharable pins:") << endl << PMS ("SEL pin: ")<< hc20.get_sel_port() << ":" << hc20.get_sel_pin() << endl << PMS ("Data bus port: ") << hc20.get_data_port() << endl; return (serpt); }
void task_hctl_2000::run (void) { TickType_t prev = xTaskGetTickCount(); while (1) { uint16_t val = counter->read(); uint8_t low = counter->get_low(); uint8_t high = counter -> get_high(); *p_serial << PMS("Current encoder reading: ") << dec << val << " = " << bin << val << endl; *p_serial << PMS("High Bits: ") << dec << high << " = " << bin << high << endl; *p_serial << PMS("Low Bits: ") << dec << low << " = " << bin << low << endl; delay_from_for_ms(prev, 1); } }
void TaskBase::print_status (emstream& ser_dev) { ser_dev.puts (pcTaskGetTaskName (handle)); ser_dev.putchar ('\t'); if (strlen ((const char*)(pcTaskGetTaskName (handle))) < 8) { ser_dev.putchar ('\t'); } ser_dev << (uint8_t)(uxTaskPriorityGet (handle)) << PMS ("\t") << get_state () #if (INCLUDE_uxTaskGetStackHighWaterMark == 1) << PMS ("\t") << uxTaskGetStackHighWaterMark(handle) << PMS ("/") << (size_t)(get_total_stack ()) << PMS ("\t") #endif << PMS ("\t") << runs; }
int main (void) { // Disable the watchdog timer unless it's needed later. This is important because // sometimes the watchdog timer may have been left on...and it tends to stay on MCUSR = 0; wdt_disable (); // Configure a serial port which can be used by a task to print debugging infor- // mation, or to allow user interaction, or for whatever use is appropriate. The // serial port will be used by the user interface task after setup is complete and // the task scheduler has been started by the function vTaskStartScheduler() rs232* p_ser_port = new rs232 (9600, 1); *p_ser_port << clrscr << PMS ("ME405 Lab 1 Program") << endl; // Create the queues and other shared data items here p_print_ser_queue = new TextQueue (32, "Print", p_ser_port, 10); // The user interface is at low priority; it could have been run in the idle task // but it is desired to exercise the RTOS more thoroughly in this test program new task_user ("UserInt", task_priority (1), 260, p_ser_port); // Create a task which reads the A/D and adjusts an LED's brightness accordingly new task_brightness ("Bright", task_priority (2), 280, p_ser_port); // Here's where the RTOS scheduler is started up. It should never exit as long as // power is on and the microcontroller isn't rebooted vTaskStartScheduler (); }
/** @brief This overloaded operator prints information about a motor driver. * @details It prints out appropriate information about the motor driver being delivered in the parameter. * @param serpt Reference to a serial port to which the printout will be printed * @param a2d Reference to the motor driver which is being accessed * @return A reference to the same serial device on which we write information. * This is used to string together things to write with @c << operators */ emstream& operator << (emstream& serpt, motor_driver& motdrv) { // Prints info to serial serpt << PMS ("Motor Driver Input: ")<<endl; return (serpt); }
void hex_dump_memory (uint8_t* start_address, uint8_t* end_address, emstream* p_ser_dev) { uint8_t byte_count; // Counts through the bytes in a line uint8_t temp_byte; // Holds a byte temporarily and obviously // Find the end address for the dump. Since C++ doesn't allow us to add two // pointers together, we convert the pointers into equivalent integers (this is // non-portable and may need to be changed for other processors!), add those // together, then convert back into a pointer // Print DUMP_BYTES_PER_LINE bytes on each line *p_ser_dev << hex; while (start_address < end_address) { // Print the line address *p_ser_dev << (size_t)(start_address) << PMS (" "); // Show a line full of data in hexadecimal format for (byte_count = 0; byte_count < DUMP_BYTES_PER_LINE; byte_count++) { *p_ser_dev << (uint8_t)(*start_address++); p_ser_dev->putchar (' '); } // Show the same line full of data in text format p_ser_dev->putchar (' '); for (start_address -= DUMP_BYTES_PER_LINE; byte_count > 0; byte_count--) { temp_byte = *start_address++; if (temp_byte == 0xA5) { p_ser_dev->putchar (' '); } else if (temp_byte >= ' ' && temp_byte <= '~') { p_ser_dev->putchar (temp_byte); } else { p_ser_dev->putchar ('.'); } } // Put a return at the end of the line *p_ser_dev << endl; } *p_ser_dev << dec; }
emstream& operator << (emstream& serpt, adc& a2d) { // Right now this operator doesn't do anything useful. It should be made useful serpt << PMS ("The A/D converter registers have these settings:") << a2d.read_once (0) << endl << a2d.read_once (1) << endl << a2d.read_once (2) << endl << a2d.read_once (3) << endl << a2d.read_once (4) << endl << a2d.read_once (5) << endl << a2d.read_once (6) << endl << a2d.read_once (7) << endl; return (serpt); }
int main (void) { // Disable the watchdog timer unless it's needed later. This is important because // sometimes the watchdog timer may have been left on...and it tends to stay on MCUSR = 0; wdt_disable (); // Configure a serial port which can be used by a task to print debugging infor- // mation, or to allow user interaction, or for whatever use is appropriate. The // serial port will be used by the user interface task after setup is complete and // the task scheduler has been started by the function vTaskStartScheduler() rs232* p_ser_port = new rs232 (9600, 1); // print this identifier line. *p_ser_port << clrscr << PMS ("ME405 Lab 2 Motor Controller Program") << endl; //initialize the A/D converter for potentiometer control adc* p_main_adc = new adc (p_ser_port); // Create the queues and other shared data items here p_print_ser_queue = new TextQueue (32, "Print", p_ser_port, 10); motor_directive = new TaskShare<uint8_t> ("Motor Directive"); motor_power = new TaskShare<int16_t> ("Motor Power"); motor_select = new TaskShare<uint8_t> ("Motor Select"); //initialize to special value so no motor is affected yet motor_select -> put(NULL_MOTER); //initilaize two different motor driver pointers to pass into two tasks motor_driver* p_motor1 = new motor_driver(p_ser_port, &PORTC, &PORTC, &PORTB, &OCR1B, PC0, PC1, PC2, PB6); motor_driver* p_motor2 = new motor_driver(p_ser_port, &PORTD, &PORTD, &PORTB, &OCR1A, PD5, PD6, PD7, PB5); // The user interface is at low priority; it could have been run in the idle task // but it is desired to exercise the RTOS more thoroughly in this test program new task_user ("UserInt", task_priority (1), 260, p_ser_port); // Create tasks to control motors, given individual p_motors new task_motor ("Motor1", task_priority (2), 280, p_ser_port, p_motor1, p_main_adc, 1); new task_motor ("Motor2", task_priority (2), 280, p_ser_port, p_motor2, p_main_adc, 2); // Here's where the RTOS scheduler is started up. It should never exit as long as // power is on and the microcontroller isn't rebooted vTaskStartScheduler (); }
emstream& operator << (emstream& serpt, adc& a2d) { serpt << bin << PMS ("ADMUX : ") << ADMUX << PMS (" ADCSRA : ") << ADCSRA << dec << endl; return (serpt); }
void task_encoder::run (void) { // Make a variable which will hold times to use for precise task scheduling TickType_t previousTicks = xTaskGetTickCount (); // Configure counter/timer 1 as a PWM for Motor Drivers. // COM1A1/COM1B1 to set to non inverting mode. // WGM10 to set to Fast PWM mode (only half ughhhhh) TCCR1A |= (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1); // This is the second Timer/Counter Register // WGM12 (other half of Fast PWM) // CS11 Sets the presacler to 8 (010) TCCR1B |= (1 << WGM12) | (1 << CS11); // Create an analog to digital converter driver object and a variable in which to // store its output. The variable p_my_adc only exists within this run() method, // so the A/D converter cannot be used from any other function or method adc* p_adc = new adc (p_serial); //** CREATE THE MOTOR DRIVERS **// // create a pointer to a motor driver object and pass it addresses to PORTC, PORTB, OC1B and Pin Values for PC0, PC2, and PB6 as the PWM motor_driver* p_motor1 = new motor_driver(p_serial, &PORTC, &PORTC, &PORTB, &OCR1B, PC0, PC1, PC2, PB6); // create a pointer to a motor driver object and pass it addresses to PORTD, PORTB, OC1A and Pin Values for PD5, PD7, and PB5 as the PWM motor_driver* p_motor2 = new motor_driver(p_serial, &PORTD, &PORTD, &PORTB, &OCR1A, PD5, PD6, PD7, PB5); // The loop to contunially run the motors while (1) { // Read the A/D converter from channel 1 uint16_t a2d_reading = p_adc->read_once(1); // Convert the A/D reading into a PWM duty cycle. The A/D reading is between 0 // and 1023; the duty cycle should be between 0 and 255. Thus, divide by 4 uint16_t duty_cycle = a2d_reading / 4; int16_t power = ((int16_t)duty_cycle * 1); //doesn't let the duty_cycle go to 0 because then the power is 0. if (duty_cycle == 0) {duty_cycle++;} //From 00 - 64 we want to decrease forwards //From 65 - 128 we want to increase backwards //From 129 - 192 we want to set both outs to high to set holding brake //From 193 - 255 we want to set both outs to low so that they don't affect the motor if (duty_cycle <= 64) { //forwards start from high speed to go to low speed power = 255 - (4 * duty_cycle); p_motor1->set_power(power); p_motor2->set_power(duty_cycle); } else if (duty_cycle > 64 && duty_cycle <= 128) { //backwards start from low speed to go to high speed power = -4 * (duty_cycle - 64); p_motor1->set_power(power); p_motor2->set_power(-1 * duty_cycle); } else if ( duty_cycle > 128 && duty_cycle <= 192) { //power stopping power = 4 * (duty_cycle - 128); p_motor1->brake(power); p_motor2->brake(power); } else { //free wheeling p_motor1->brake(); p_motor2->brake(); } *p_serial << PMS ("Duty_Cycle: ") << duty_cycle << dec << endl << PMS ("Power_Signal: ") << power << dec << endl; // Increment the run counter. This counter belongs to the parent class and can // be printed out for debugging purposes runs++; // This is a method we use to cause a task to make one run through its task // loop every N milliseconds and let other tasks run at other times delay_from_for_ms (previousTicks, 10); } }
void print_task_list (emstream* ser_dev) { // Print the first line with the top of the headings *ser_dev << PMS ("Task\t\t \t ") #if (INCLUDE_uxTaskGetStackHighWaterMark == 1) << PMS ("\tStack") #endif << endl; // Print the second line with the rest of the headings *ser_dev << PMS ("Name\t\tPri.\tState") #if (INCLUDE_uxTaskGetStackHighWaterMark == 1) << PMS ("\tFree/Total") #endif << PMS ("\tRuns") << endl; // Print the third line which shows separators between headers and data *ser_dev << PMS ("----\t\t----\t-----") #if (INCLUDE_uxTaskGetStackHighWaterMark == 1) << PMS ("\t----------") #endif << PMS ("\t----") << endl; // Now have the tasks each print out their status. Tasks form a linked list, so // we only need to get the last task started and it will call the next, etc. if (last_created_task_pointer != NULL) { last_created_task_pointer->print_status_in_list (ser_dev); } // Have the idle task print out its information *ser_dev << PMS ("IDLE\t\t0\t-\t") #if (INCLUDE_uxTaskGetStackHighWaterMark == 1) << uxTaskGetStackHighWaterMark (xTaskGetIdleTaskHandle ()) << PMS ("/") << configMINIMAL_STACK_SIZE << PMS ("\t\t-") #endif << endl; }
int main (void) { // Disable the watchdog timer unless it's needed later. This is important because // sometimes the watchdog timer may have been left on...and it tends to stay on MCUSR = 0; wdt_disable (); // MAKE RESET INTERRUPT // time_stamp the_time_now; // Configure a serial port which can be used by a task to print debugging infor- // mation, or to allow user interaction, or for whatever use is appropriate. The // serial port will be used by the user interface task after setup is complete and // the task scheduler has been started by the function vTaskStartScheduler() rs232* p_ser_port = new rs232 (9600, 1); // print this identifier line. *p_ser_port << clrscr << PMS ("ME405 Lego Car Comms Test") << endl; // set up USART0 on E0 and E1 for external comms // rs232* p_ser_bt = new rs232(0, 0); // UCSR0A |= (1 << U2X0); // set the double-speed bit // UBRR0 = 16; // set baud rate to 115200 //initialize the A/D converter for potentiometer control // adc* p_main_adc = new adc (p_ser_port); // Create the queues and other shared data items here p_print_ser_queue = new TextQueue (32, "Print", p_ser_port, 10); /// Start Shares Motor Variables motor_setpoint = new TaskShare<int16_t> ("Motor SetPoint"); motor_directive = new TaskShare<uint8_t> ("Motor Directive"); motor_power = new TaskShare<int16_t> ("Motor Power"); // Start Shares Encoder Variables encoder_count = new TaskShare<int32_t> ("Encoder Pulse Count"); encoder_ticks_per_task = new TaskShare<int16_t> ("Encoder Pulse Per Time"); // Start Shares IMU variables data_read = new TaskShare<uint32_t> ("imu data"); // Start Shares Steering Variables steering_power = new TaskShare<int16_t> ("Steering Power"); // Start Shares oystick Position Variables x_joystick = new TaskShare<int16_t> ("X Joystick Position"); y_joystick = new TaskShare<int16_t> ("Y Joystick Position"); // Start Shares Gear Variables gear_state = new TaskShare<int16_t> ("Shift State"); // new task_encoder ("EncoderControl", task_priority(5), 280, p_ser_port, p_hctl); new task_receiver ("REC", task_priority(5), 300, p_ser_port); //*p_ser_port << "Waiting.." << endl; //initialize to special value so no motor is affected yet //**DROPPING SUPPORT 2 MOTORS// //motor_select -> put(NULL_MOTER); // //initilaize two different motor driver pointers to pass into two tasks // motor_driver* p_motor1 = new motor_driver(p_ser_port, &PORTC, &PORTC, &PORTB, &OCR1B, PC0, PC1, PC2, PB6); // //USE TIMER AND COUNTER 3 // // this is steering // servo_driver* p_steering_servo = new servo_driver(p_ser_port, &TCCR3A, &TCCR3B, &ICR3, &OCR3A, 8, 20000, PE3); // // this is shifting // //encoder_driver* p_encoder1 = new encoder_driver(p_ser_port, &EICRB, &EIMSK, &DDRE, ISC60, ISC70, INT6, INT7, PE6, PE7); // servo_driver* p_shift_servo = new servo_driver(p_ser_port, &TCCR3A, &TCCR3B, &ICR3, &OCR3B, 8, 20000, PE4); // // make instance of hctl_driver to count external ticks from hctl chip // hctl_driver* p_hctl = new hctl_driver(p_ser_port, &PORTA, &PORTC, 7, &PORTC, 6); // // make instance of imu_driver to be able to link to the BNO055 // imu_driver* p_imu = new imu_driver(p_ser_port, &PORTD, &DDRD, 0, 1); // // temp method to read from IMU // int8_t tempsss = p_imu -> readIMU(0, 1); // shift_driver* p_local_shift = new shift_driver(p_ser_port, &EICRB, &EIMSK, &PORTE, ISC50, INT5, PE5); // // Create tasks to control motors, encoders, and IMUs // new task_user ("UserInt", task_priority (1), 260, p_ser_port); // new task_motor ("MotorControl", task_priority (2), 280, p_ser_port, p_motor1, p_main_adc, 1); // //start encoder and give the highest priority // new task_encoder ("EncoderControl", task_priority(5), 280, p_ser_port, p_hctl); // new task_steering ("SteeringControl", task_priority(3), 280, p_ser_port, p_steering_servo, 1); // new task_shift ("ShiftControl", task_priority(4), 280, p_ser_port,p_shift_servo, 1, p_local_shift); // // create a new PID manager for the motor, with K values of: // // Proportional = 1, Integral = 0, Derivative = 0, Windup = 0 // // And the default saturation limits // new task_pid ("PID", task_priority(4), 280, p_ser_port, motor_setpoint, encoder_ticks_per_task, motor_power, 1024, 0, 0, 0, -1023, 1023); vTaskStartScheduler (); }
/** * @brief This method runs when the 'task_user' is called. * * @details This method runs inifitely when the task is called so all logic * is contained in here. A for(;;) loop runs until it gets to the * end where it delays for 1 ms to allow other lower level * priority tasks a chance to run. */ void task_user::run (void) { time_stamp a_time; // Holds the time so it can be displayed number_entered = 0; // Holds a number being entered by user // for (;;) { switch (state) { // Initialize first task where we wait for case (0): printMainMenu(); // If the user typed a character, read if (hasUserInput()) { // In this switch statement, we respond to different characters as commands typed in by the user switch (char_in) { // The 't' command asks what time it is right now case ('m'): *p_serial << PMS("->Selected: ") << char_in; *p_serial << endl << endl << PMS ("\t->Switching to Motor Module..") << endl << PMS ("\t->Clearing Registers and Menus..") << endl << PMS ("\t->Intializing Motors..") << endl; // Reset the visible menu flag resetMenus(); // Sets the variable to true so it doesn't go into single module yet in_main_motor_module = true; // go to case 1 over all transition_to(1); break; // Enter encoder test module case ('e'): *p_serial << PMS("->Selected: ") << char_in; *p_serial << ATERM_CLEAR_SCREEN << ATERM_CURSOR_TO_YX(1, 1) << PMS ("\t->Switching to Encoder Module..") << endl << PMS ("\t->Clearing Registers and Menus..") << endl << PMS ("\t->Intializing Encoder..") << endl << endl; // Reset the visible menu flag resetMenus(); // Sets the variable to true so it doesn't go into single module yet in_encoder_module = true; // go to case 1 over all transition_to(3); break; // The 't' command asks what time it is right now // Enter encoder test module case ('i'): *p_serial << PMS("->Selected: ") << char_in; *p_serial << ATERM_CLEAR_SCREEN << ATERM_CURSOR_TO_YX(1, 1) << PMS ("\t->Switching to IMU Module..") << endl << PMS ("\t->Clearing Registers and Menus..") << endl << PMS ("\t->Intializing IMU..") << endl << endl; // Reset the visible menu flag resetMenus(); // Sets the variable to true so it doesn't go into single module yet in_imu_module = true; // go to case 1 over all transition_to(4); break; // The 't' command asks what time it is right now case ('t'): *p_serial << (a_time.set_to_now ()) << endl; break; // The 's' command asks for version and status information case ('s'): show_status (); break; // The 'd' means drive control case ('d'): *p_serial << PMS("->Selected: ") << char_in; *p_serial << ATERM_CLEAR_SCREEN << ATERM_CURSOR_TO_YX(1, 1) << PMS ("\t->Switching to Drive Mode..") << endl << endl; transition_to(5); in_drive_mode = true; resetMenus(); break; //case ('d'): // The 'h' command is a plea for help; '?' works also case ('h'): case ('?'): print_help_message (); break; // The 'n' command runs a test of entering a number case ('n'): while (char_in != 'q') { *p_serial << PMS ("Enter decimal numeric digits, " "then RETURN or ESC") << endl; getNumberInput(); *p_serial << endl << endl << PMS("\t->You Entered: ") << number_entered << endl; } break; // A control-C character causes the CPU to restart case (3): *p_serial << PMS ("Resetting AVR") << endl; wdt_enable (WDTO_120MS); for (;;); break; // If character isn't recognized, ask What's That Function? default: *p_serial << '"' << char_in << PMS ("\": WTF?") << endl; break; }; // End switch for characters } // End if a character was received break; // End of state 0 // Motor Control BASE module case (1): if (in_main_motor_module) //first time here run menu and get input { // prints the menu for this module printMotorMenu(); // user is going to input motor number or q getNumberInput(); if (char_in == 'q') { *p_serial << PMS("->Selected: ") << char_in << endl << endl << endl << PMS("\t->Returning to Mission Control.. ") << endl << PMS("\t->Releasing Motors..") << endl << PMS("\t->Resetting AVR..") << endl; //wdt_enable (WDTO_120MS); //for (;;); //break; //release motors //motor_select->put(1); //motor_directive -> put(FREEWHEEL); // // no longer in this module, leaving in_main_motor_module = false; transition_to(0); resetMenus(); break; //reset menu flag //resetMenus(); // set the transition & wait for break //transition_to(0); } // if the number entered is valid else if (isValidMotor(number_entered)) { // re print user input and give them confirmation message. *p_serial << endl << endl << PMS("\t->Switching to Control of Motor ") << number_entered << dec << PMS(".") << endl << PMS ("\t->Return to the Main Motor Module to swap Motors.") << endl; // set local motor select value local_motor_select = number_entered; //reset menus resetMenus(); //set flag to off so we can go into the single motor module in_main_motor_module = false; // go back to the top of this menu // since in_main_motor_module flag is set off, we will go into single motor control when this state reloops transition_to(1); } else { *p_serial << PMS("Try Again. ") << endl; in_main_motor_module = true; } break; } if (!in_main_motor_module) //already were here now we go deeper { printSingleMotorOptions(); // They now select the motor task if (hasUserInput()) { switch (char_in) { case ('s'): *p_serial << PMS("->Selected: ") << char_in << endl; *p_serial << endl << PMS ("Enter the Power Value (-255 to 255);") << endl << PMS(" *Note: Negative Values = Reverse") << endl; //motor_directive -> put(1); getNumberInput(); //setPower(motor_select->get(), number_entered); setMotor(local_motor_select, (int16_t)number_entered, SETPOWER); *p_serial << endl << endl << PMS ("\tPower set at ") << number_entered << PMS(". ") << endl; resetMenus(); printDashBoard(); //now that operation is complete, ask for more *p_serial << endl << PMS("->Choose Motor ") << local_motor_select << PMS(" operation: ") << PMS("\t(Press 'o' for options)") << endl; break; case ('b'): *p_serial << PMS("->Selected: ") << char_in << endl; *p_serial << PMS ("\t->Enter the Brake Force(0 - 255)") << endl; getNumberInput(); *p_serial << endl << endl << PMS ("\tBrake set at ") << number_entered << PMS(". ") << endl; setMotor(local_motor_select, number_entered, BRAKE); resetMenus(); printDashBoard(); //now that operation is complete, ask for more *p_serial << endl << PMS("->Choose Motor ") << local_motor_select << PMS(" operation: ") << PMS("\t(Press 'o' for options)") << endl; break; case ('f'): *p_serial << PMS("->Selected: ") << char_in << endl; *p_serial << PMS ("\t->Releasing Motor..") << endl; setMotor(0, 0, FREEWHEEL); resetMenus(); printDashBoard(); //now that operation is complete, ask for more *p_serial << endl << PMS("->Choose Motor ") << local_motor_select << PMS(" operation: ") << PMS("\t(Press 'o' for options)") << endl; break; case ('p'): *p_serial << endl << PMS("->Selected: ") << char_in << endl << PMS("\t->Entering Potentiometer Control... ") << endl; *p_serial << PMS ("\t->Potentiometer Activated.") << endl << endl; *p_serial << endl << endl << PMS ("\t->Press 'q' to return to the Motor ") << local_motor_select << PMS(" Control") << endl << PMS ("\t->Press 'r' to refresh the DashBoard ") << endl; transition_to(2); resetMenus(); break; case ('o'): resetMenus(); printSingleMotorOptions(); break; case ('q'): *p_serial << PMS("->Selected: ") << char_in << endl << PMS(" Returning to Main Motor Module.. ") << endl; transition_to(1); resetMenus(); in_main_motor_module = true; break; default: *p_serial << endl << PMS("'") << char_in << PMS ("' is not a valid entry.") << endl; *p_serial << endl << PMS("->Choose Motor ") << local_motor_select << PMS(" operation: ") << endl; break; } } } break; //Potentiometer Mode case (2): if (hasUserInput()) { if (char_in == 'q') { *p_serial << endl << PMS("->Selected: ") << char_in << endl; transition_to(1); resetMenus(); break; // } if (char_in == 'r') { *p_serial << endl << PMS("->Selected: ") << char_in << endl; resetMenus(); printDashBoard(); *p_serial << endl << endl << PMS ("\t->Press 'q' to return to the Motor ") << local_motor_select << PMS(" Control") << endl << PMS ("\t->Press 'r' to refresh the DashBoard ") << endl; } } setMotor(local_motor_select, motor_power -> get(), POTENTIOMETER); printDashBoard(); break; //for use later [3,4] case (3): if (in_encoder_module) { printEncoderModuleOptions(); if (hasUserInput()) switch (char_in) { case ('q'): *p_serial << ATERM_CLEAR_SCREEN << ATERM_BKG_WHITE << PMS("->Selected: ") << char_in << endl << endl << endl << PMS("\t->Returning to Mission Control.. ") << endl << PMS("\t->Releasing Encoder..") << endl; transition_to(0); in_main_motor_module = true; in_encoder_module = false; resetMenus(); *p_serial << ATERM_CLEAR_SCREEN << ATERM_CURSOR_TO_YX(1, 1) << endl; break; case ('r'): //constant refreshing already transition_to(1) in_imu_module = true; break; default: break; } } break; case (4): if (in_imu_module) { printIMUModuleOptions(); if (hasUserInput()) switch (char_in) { case ('q'): *p_serial << ATERM_CLEAR_SCREEN << PMS("->Selected: ") << char_in << endl << endl << endl << PMS("\t->Returning to Mission Control.. ") << endl << PMS("\t->Releasing IMU..") << endl; transition_to(0); in_imu_module = false; resetMenus(); break; default: break; *p_serial << ATERM_CLEAR_SCREEN; } case ('r'): break; default: break; } } break; // Drive Mode case (5): if (in_drive_mode) { printDriveModeOptions(); // printDashBoard(); if (hasUserInput()) switch (char_in) { case ('q'): *p_serial << ATERM_CLEAR_SCREEN << PMS("->Selected: ") << char_in << endl << endl << endl << PMS("\t->Returning to Mission Control.. ") << endl << PMS("\t->Releasing Drive Mode..") << endl; transition_to(0); in_drive_mode = false; resetMenus(); break; case ('s'): *p_serial << endl << PMS("Input Power Value for Motor: ") << endl; getNumberInput(); setMotor(0, (int16_t)number_entered, SETPOWER); *p_serial << endl << endl << PMS ("\tPower set at ") << number_entered << PMS (". ") << endl << endl << PMS ("Printing DashBoard.. ") << endl << endl; resetMenus(); printDashBoard(); break; case ('r'): *p_serial << PMS ("Printing DashBoard.. ") << endl << endl; resetMenus(); printDashBoard(); break; default: break; } int16_t x_direction = y_joystick -> get(); int16_t map_x = x_direction - 526; if (x_direction > 526) { map_x = 2 * (x_direction - 526); } else { map_x = -2 * (526 - x_direction); } motor_setpoint -> put(map_x); motor_directive -> put(SETPOWER); // *p_serial // << ATERM_CURSOR_TO_YX(19, 1) // << ATERM_ERASE_IN_LINE(0) // << gear_state -> get() // << PMS ("\t\t") // << motor_setpoint -> get() // << PMS("\t") // << PMS("\t") // << motor_power -> get() // << PMS("\t") // << PMS("\t") // << encoder_count -> get() // << PMS("\t") // << ATERM_CURSOR_TO_YX(23, 1) // << ATERM_ERASE_IN_LINE(0) // << steering_power -> get() // << PMS(" \t") // << encoder_ticks_per_task -> get() // << PMS("\t") // << PMS("\t") // << x_joystick -> get() // << PMS("\t") // << PMS("\t") // << y_joystick -> get() // << PMS("\t"); *p_serial << encoder_ticks_per_task -> get() << endl; } break; //JoyStick test case (6): break; default: *p_serial << PMS ("Illegal state! Resetting AVR") << endl; wdt_enable (WDTO_120MS); for (;;); break; } // End switch state runs++; // Increment counter for debugging // No matter the state, wait for approximately a millisecond before we // run the loop again. This gives lower priority tasks a chance to run delay_ms (5); }
void task_brightness::run (void) { // Make a variable which will hold times to use for precise task scheduling TickType_t previousTicks = xTaskGetTickCount (); // Create an analog to digital converter driver object and a variable in which to // store its output. The variable p_my_adc only exists within this run() method, // so the A/D converter cannot be used from any other function or method adc* p_my_adc = new adc (p_serial); //** CREATE THE MOTOR DRIVERS **// // create a pointer to a motor driver object and pass it addresses to PORTC, PORTB, OC1B and Pin Values for PC0, PC2, and PB6 as the PWM motor_driver* p_motor1 = new motor_driver(p_serial, &PORTC, &PORTC, &PORTB, &OCR1B, PC0, PC1, PC2, PB6); // create a pointer to a motor driver object and pass it addresses to PORTD, PORTB, OC1A and Pin Values for PD5, PD7, and PB5 as the PWM motor_driver* p_motor2 = new motor_driver(p_serial, &PORTD, &PORTD, &PORTB, &OCR1A, PD5, PD6, PD7, PB5); // Configure counter/timer 3 as a PWM for LED brightness. First set the data // direction register so that the pin used for the PWM will be an output. The // pin is Port E pin 4, which is also OC3B (Output Compare B for Timer 3) DDRE = (1 << 4); // To set 8-bit fast PWM mode we must set bits WGM30 and WGM32, which are in two // different registers (ugh). We use COM3B1 and Com3B0 to set up the PWM so that // the pin output will have inverted sense, that is, a 0 is on and a 1 is off; // this is needed because the LED connects from Vcc to the pin. TCCR3A |= (1 << WGM30) | (1 << COM3B1) | (1 << COM3B0); // The CS31 and CS30 bits set the prescaler for this timer/counter to run the // timer at F_CPU / 64 TCCR3B |= (1 << WGM32) | (1 << CS31) | (1 << CS30); // Configure counter/timer 1 as a PWM for Motor Drivers. // COM1A1/COM1B1 to set to non inverting mode. // WGM10 to set to Fast PWM mode (only half ughhhhh) TCCR1A |= (1 << WGM10) | (1 << COM1A1) | (1 << COM1B1); // This is the second Timer/Counter Register // WGM12 (other half of Fast PWM) // CS11 Sets the presacler to 8 (010) TCCR1B |= (1 << WGM12) | (1 << CS11); // This is the task loop for the brightness control task. This loop runs until the // power is turned off or something equally dramatic occurs for (;;) { // Read the A/D converter from channel 1 uint16_t a2d_reading = p_my_adc->read_once(1); // Convert the A/D reading into a PWM duty cycle. The A/D reading is between 0 // and 1023; the duty cycle should be between 0 and 255. Thus, divide by 4 uint16_t duty_cycle = a2d_reading / 4; int16_t power = ((int16_t)duty_cycle * 1); //doesn't let the duty_cycle go to 0 because then the power is 0. if(duty_cycle == 0){duty_cycle++;} //From 00 - 64 we want to decrease forwards //From 65 - 128 we want to increase backwards //From 129 - 192 we want to set both outs to high to set holding brake //From 193 - 255 we want to set both outs to low so that they don't affect the motor if(duty_cycle <= 64) { //forwards start from high speed to go to low speed power = 255 - (4 * duty_cycle); p_motor1->set_power(power); p_motor2->set_power(duty_cycle); } else if(duty_cycle > 64 && duty_cycle <= 128) { //backwards start from low speed to go to high speed power = -4 * (duty_cycle - 64); p_motor1->set_power(power); p_motor2->set_power(-1*duty_cycle); } else if( duty_cycle > 128 && duty_cycle <= 192) { //power stopping power = 4 * (duty_cycle - 128); p_motor1->brake(power); p_motor2->brake(power); } else { //free wheeling p_motor1->brake(); p_motor2->brake(); } //print the Duty_Cycle in comparison to the Power Signal being pumped into set_power *p_serial <<PMS ("Duty_Cycle: ")<< duty_cycle <<dec <<endl <<PMS ("Power_Signal: ")<< power <<dec <<endl; // Set the brightness. Since the PWM has already been set up, we only need to // put a new value into the duty cycle control register, which on an AVR is // the output compare register for a given timer/counter OCR3B = duty_cycle; //OCR1B = duty_cycle; // Increment the run counter. This counter belongs to the parent class and can // be printed out for debugging purposes runs++; // This is a method we use to cause a task to make one run through its task // loop every N milliseconds and let other tasks run at other times delay_from_for_ms (previousTicks, 10); } }
bool hex_receiver::decode (uint16_t char_in) { // If we get a return character, expect that it will be followed by the // beginning of some useful data and reset the decoder if ((char_in == '\n') || (char_in == '\r')) { decoder_state = 0; } else { switch (decoder_state) { // State 0: We haven't received any characters yet; the first one is // the first character of the type code. Reset everything to // condition at start of reading process case (0): good_data = false; computed_crc = 0xFFFF; type_code = ascii_to_nibble (char_in) << 4; p_data = NULL; decoder_state = 1; break; // State 1: Get the second nibble of the command code case (1): type_code |= ascii_to_nibble (char_in); decoder_state = 2; HXR_DBG (p_serial, hex << PMS ("Code: ") << type_code << endl); // OK, we have the code; use it to get a pointer to the object into // which we'll be writing the data p_map = p_first_map; while (p_map != NULL) { // If debugging, show what we're looking at HXR_DBG (p_serial, PMS ("HXR ptr: ") << p_map << endl); // If we have a matching code, get the corresponding data pointer if (p_map->code == type_code) { p_data = (uint8_t*)(p_map->p_obj); HXR_DBG (p_serial, PMS (" dptr: ") << p_data << endl); break; } else { HXR_DBG (p_serial, PMS ("HXR ") << hex << p_map->code << PMS (" != ") << type_code << endl); } // If no match found, go to the next item in the list p_map = p_map->p_next; } break; // State 2: Get the first nibble of the package size case (2): size = ascii_to_nibble (char_in) << 4; decoder_state = 3; break; // State 3: Get the second nibble of the package size case (3): size |= ascii_to_nibble (char_in); HXR_DBG (p_serial, PMS (" size: ") << size << hex << endl); decoder_state = 4; break; // State 4: Get the first nibble of whatever is next case (4): num_in = ascii_to_nibble (char_in) << 4; decoder_state = 5; break; // State 5: Get the second nibble of whatever is next. If this isn't // the last item of data, go back to state 4 for another byte case (5): num_in |= ascii_to_nibble (char_in); if (p_data != NULL) { HXR_DBG (p_serial, hex << p_data << "<-" << num_in << endl); *p_data++ = num_in; } // Update a cyclic reduncancy check (fancy checksum) for the data computed_crc = _crc_ccitt_update (computed_crc, num_in); if (--size > 0) { decoder_state = 4; } else { decoder_state = 6; } break; // State 6: Get the first nibble of the checksum case (6): received_crc = (uint16_t)(ascii_to_nibble (char_in) << 4); decoder_state = 7; break; // State 7: Get the second nibble of the checksum case (7): received_crc |= ascii_to_nibble (char_in); received_crc <<= 4; decoder_state = 8; break; // State 8: Get the third nibble of the checksum case (8): received_crc |= ascii_to_nibble (char_in); received_crc <<= 4; decoder_state = 9; break; // State 9: Get the last nibble of the checksum and check the CRC case (9): received_crc |= ascii_to_nibble (char_in); decoder_state = 0; HXR_DBG (p_serial, PMS (":") << received_crc << endl); if (received_crc == computed_crc) { good_data = true; } else { HXR_DBG (p_serial, endl << PMS ("Bad CRC:") << hex << received_crc << PMS (",") << computed_crc << dec << endl); } break; // We should never get here. Wait for a return, then reset default: // Code just before the state machine detects reset characters break; }; } return (good_data); }