LEX_Threaded_Programming
Dependencies: Heater_V2 MODSERIAL Nanopb FastPWM ADS8568_ADC
main.cpp
- Committer:
- paullj
- Date:
- 2019-09-20
- Revision:
- 16:32b598af6f86
- Parent:
- 15:6d22fa5a66ab
- Child:
- 17:d86e749ae9be
File content as of revision 16:32b598af6f86:
#include "mbed.h" #include "pb.h" #include "pb_decode.h" #include "pb_encode.h" #include "MODSERIAL.h" #include "ADS8568_ADC.h" #include "Heater.h" #include "FastPWM.h" #include "memspcr.pb.h" #include <vector> #include <iterator> #define BUFFER_SIZE 8192 #define LED_PULSE_PERIOD 1000 // ticks, 84kHz when CPU clock is 84MHz #define LED_PULSE_WIDTH 100 // ticks, 10% duty cycle Heater * heater; float r_gradient; //setpoint setting MODSERIAL pc(PA_9, PA_10, BUFFER_SIZE); //mcu TX, RX, BUFFER_SIZE byte TX and RX buffers ADS8568_ADC adc(PB_15, PB_14, PB_13, PB_12, PC_15, PC_0, PC_1, PC_2, PC_3); I2C i2c(PB_7, PB_8); //SDA, SCL Timer timer; DigitalIn adc_busy(PA_8); //Busy interrupt sig# //Pressure Control DigitalOut pump(PA_2); AnalogIn pressure_1(PA_5); //set up pressure read averaging float pressure_fAvg = 0.1; // rolling average float pressure_in = 0.0; float pressure_out = 0.0; float pressure_set = 0.46; float pressure_hys = 0.02; float pressure_set_low = pressure_set - pressure_hys/2; float pressure_set_high = pressure_set + pressure_hys/2; //Heater Control FastPWM drive_main(PC_9); FastPWM drive_lysis(PC_8); FastPWM guard_main(PC_7); FastPWM guard_lysis(PC_6); int heater_ID_main = 1; int heater_ID_lysis = 2; int i_port_main = 0; int i_port_lysis = 2; int v_port_main = 1; int v_port_lysis = 3; int heater_ID = 0; //Illumination LED Control //Indicator LEDs DigitalOut hb_led(PC_13); //Red DigitalOut led_0(PC_4); //Green DigitalOut led_1(PC_5); //Red //Camera and LED drive DigitalOut camTrigger(PB_2); //Trigger camera DigitalOut ledDrive(PB_4); //Drive LED for fluorescence detection //User buttons DigitalIn user_0(PB_0); DigitalIn user_1(PB_1); BusOut converts(PC_0, PC_1, PC_2, PC_3); //Threads Thread heater_control(osPriorityHigh); Thread logging_thread(osPriorityAboveNormal); Thread pressure_thread(osPriorityAboveNormal); //Tickers Ticker heat_tick; Ticker pressure_tick; Ticker log_tick; //Flags EventFlags flags; //Flags: // 0 => update heater // 1 => log state // 2 => read pressure bool triggered_flag; bool status = true; //Configuration data memspcr_ExperimentConfiguration exp_config = memspcr_ExperimentConfiguration_init_zero; int buffer_length; size_t message_length; uint8_t buffer[BUFFER_SIZE]; //Functions for reading and decoding the message__________________________________________________ void read_message() { if (pc.scanf("%d",&message_length) < 0){pc.printf("# Error reading message length");} size_t buffer_length = sizeof(buffer); if (message_length > buffer_length) { pc.printf("# Message length exceeds buffer. \n Input configuration file\n"); read_message(); return; } pc.printf("# Message is %d chars long, buffer length is %d\n",message_length,buffer_length); unsigned int c; for (int i = 0; i < message_length; i++) { pc.scanf("%02X",&c); buffer[i] = (char) c; } } void decode_message() { // Create a stream that reads from the buffer. pb_istream_t istream = pb_istream_from_buffer(buffer, message_length); //Now we are ready to decode the message. status = pb_decode(&istream, memspcr_ExperimentConfiguration_fields, &exp_config); // Check for errors... if (!status) { pc.printf("# Decoding failed: %s\n", PB_GET_ERROR(&istream)); } } bool decode_callback(pb_istream_t *stream, const pb_field_t *field, void **arg) { vector <memspcr_ThermalStep> * dest = (vector <memspcr_ThermalStep> *)(*arg); memspcr_ThermalStep result = memspcr_ThermalStep_init_zero; status = pb_decode(stream, memspcr_ThermalStep_fields, & result); if (!status) { pc.printf("# Decode callback failed\n"); } dest->push_back(result); //CHECK: Does result get copied into the vector? return true; } //Ticking functions_________________________________________________________________ void temp_trigger() { //This function triggers a temperature update. //N.B. update cannot be called directly from a ticker as tickers and //reading the ADC both rely on interrupts. flags.set(0x1); } void log_trigger() { flags.set(0x2); } void pressure_trigger() { flags.set(0x3); } //Other functions__________________________________________________________________ void temp_control() { while(1){ flags.wait_any(0x1,osWaitForever,true); heater->read(); heater->update(); } } void log_state() { while(1){ flags.wait_any(0x2,osWaitForever,true); //Output time, R_ref, R, error, error_integrated pc.printf("%10d,%10d,%10.6f,%10.6f,%10.6f,%10.6f\n", heater_ID, timer.read_ms(), heater->Get_R(), heater->Get_R_ref(), pressure_in, pressure_out); } } void pressure_control() { while(1){ flags.wait_any(0x3,osWaitForever,true); pressure_in = pressure_in*(1.0-pressure_fAvg) + pressure_1.read()*pressure_fAvg; //pressure_in = 0; //for (int i = 0; i < pressure_nAvg; i++) pressure_in += pressure_1.read(); //read pressure //pressure_in = pressure_in / pressure_nAvg; // pc.printf("%10.6f %10.6f %10.6f\n", pressure_set_low, pressure_set_high, pressure_in); if (pressure_in < pressure_set_low) { led_1 = 1; pump = 1; // pc.printf(" pump on\n"); } else if (pressure_in > pressure_set_high) { led_1 = 0; pump = 0; // pc.printf(" pump off\n"); } } } void set_point_routine(std::vector<memspcr_ThermalStep> profile) { int curr_time; vector <memspcr_ThermalStep>::iterator it_prev, it = profile.begin(); if (it->elapsed_time_ms != 0) { pc.printf("# Error: the first point in the profile should be at time 0.\n"); return; } it++; for (it_prev = profile.begin(); it < profile.end(); it ++, it_prev++){ triggered_flag = false; r_gradient = (it->resistance_set_point - it_prev->resistance_set_point)/(it->elapsed_time_ms - it_prev->elapsed_time_ms); while ((curr_time = timer.read_ms()) <= it->elapsed_time_ms){ heater->Set_ref(it_prev->resistance_set_point + r_gradient * (curr_time - it_prev->elapsed_time_ms)); if (!triggered_flag && (it->camera_offset_ms != 0) && (curr_time > it_prev->elapsed_time_ms + it->camera_offset_ms)) { //Start camera exposure and turn on LED if camera_offset_ms is non-zero camTrigger = 0; wait_us(10); camTrigger = 1; led_0 = 1; ledDrive = 1; triggered_flag = true; } wait_us(200); } //Stop camera exposure and turn off LED at end of time segment camTrigger = 0; led_0 = 0; ledDrive = 0; } } int main() { pc.baud(115200); adc.init(); buffer_length = sizeof(buffer)/sizeof(uint8_t); pc.printf("# Input configuration file\n"); //set up nanopb std::vector<memspcr_ThermalStep> profile; exp_config.profile.funcs.decode = decode_callback; exp_config.profile.arg = &profile; //read and decode configuration read_message(); pc.printf("# Message read\n"); decode_message(); pc.printf("# Message decoded\n"); Heater * heater_main = new Heater(i_port_main, v_port_main, & drive_main, & guard_main, & adc, adc_busy, exp_config.thermal); Heater * heater_lysis = new Heater(i_port_lysis, v_port_lysis, & drive_lysis, & guard_lysis, & adc, adc_busy, exp_config.thermal); //Select heater. Put control times in us for ticker functions if (exp_config.selected_heater == memspcr_ExperimentConfiguration_Heater_HEATER_1) { heater = heater_main; heater_ID = heater_ID_main; } else if (exp_config.selected_heater == memspcr_ExperimentConfiguration_Heater_HEATER_2) { heater = heater_lysis; heater_ID = heater_ID_lysis; } else { pc.printf("# Error - no heater has been selected\n"); return 1; } pc.printf("# Starting pressure control\n"); pressure_thread.start(& pressure_control); pressure_tick.attach_us(& pressure_trigger, 500000); pc.printf("# Waiting for start signal to begin temperature control (type in an s or press button 0)\n"); heater->Set_ref(0.0); heater_control.start(& temp_control); heat_tick.attach_us(& temp_trigger,exp_config.thermal.control_loop_interval_ms * 1000); while (pc.getcNb()!='s' && !user_0); pc.printf("# Start signal received\n"); logging_thread.start(& log_state); log_tick.attach_us(& log_trigger,exp_config.logging_interval_ms * 1000); pc.printf("# Starting routine\n"); pc.printf("# heater, time(ms), r, rSet, pIn, pOut\n"); timer.start(); set_point_routine(profile); //Turn off heat_tick.detach(); log_tick.detach(); wait(1); heater->turn_off(); pc.printf("# Finished\n"); return 0; }