![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Test session
Dependencies: FatFileSystem MCP23017 WattBob_TextLCD mbed
Fork of Assignment_2_herpe by
Revision 4:48761259552a, committed 2017-03-14
- Comitter:
- xouf2114
- Date:
- Tue Mar 14 14:46:43 2017 +0000
- Parent:
- 3:5883d1a2c5b0
- Commit message:
- Test of Assignment 2
Changed in this revision
--- a/XG_2.cpp Tue Mar 07 17:20:46 2017 +0000 +++ b/XG_2.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -31,7 +31,7 @@ PwmOut servo(p21); // Servo output DigitalOut TestPin(p20); // Pin only used to test program and measure time SDFileSystem sd(p5, p6, p7, p8, "sd"); // The pinout on the mbed Cool Components workshop board - +DigitalIn switch_pin(p14, PullDown); //===================================================================================== // Internal objects declaration @@ -47,7 +47,6 @@ //===================================================================================== const int SampFreq = 100; // Sampling frequency is 10kHz (100us) - //===================================================================================== // Variables declaration //===================================================================================== @@ -196,38 +195,17 @@ // Tasks //===================================================================================== -// Task 1: Measure TTL input frequency +// Task 1: Measure the freqeuncy of a 3.3v square wave signal void Task1() { +task 1 + timer.reset(); - - // If the input signal is low, wait for a rising edge to start counting - if (TTL == 0) - { - WaitRisEdge(); // Call subroutine to wait for rising edge - timer.start(); // Start timer - while(TTL == 1) // Keep counting as long as signal is high - { - wait_us(SampFreq); - } - } - - // If the input signal is high, wait for a falling edge to start counting - else if (TTL == 1) - { - WaitFalEdge(); // Call subroutine to wait for falling edge - timer.start(); // Start timer - while(TTL == 0) // Keep counting as long as signal is high - { - wait_us(SampFreq); - } - } - - timer.stop(); // Stop counting when signal changes - period = timer.read_us()*2; // Convert the time into a period - frequency = 1000000/period; // Convert the period into a frequency -} - + while(freqCountPin == 0) {} + timer.start(); + while(freqCountPin == 1) {} + timer.stop(); + frequency = 2000000 / timer.read_us() // Task 2: display the measured frequency on LCD screen
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/check_task.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,73 @@ +/** + * The following task checks the digital inputs on pin11 and pin12 + * it also checks for "errors" and save the error code to the state. + * If pin12 is 1, it schedules the counting task. + * + * Author: Jacob Baungard Hansen + */ + +#include "check_task.h" + +/** + * + * @param starting_offset when the task should but run first + * @param frequency_ms the frequency in ms of how often the task should run + */ +CheckTask::CheckTask(int starting_offset, int frequency_ms, + State * state, TaskManager * tm) + : Task(starting_offset, frequency_ms) { + + this->state = state; + this->tm = tm; + this->counting_task = new CountingTask(0, 1800); + this->counting_scheduled = 0; + this->digital_in_1 = new DigitalIn(p11); + this->digital_in_2 = new DigitalIn(p12); + +} + +/* + * Simple destructor + */ +CheckTask::~CheckTask() { + delete this->counting_task; + delete this->digital_in_1; + delete this->digital_in_2; +} + +/** + * The function that is run at the specified frequency. + */ +void CheckTask::action() { + + // get the digital values + int switch_1 = digital_in_1->read(); + int switch_2 = digital_in_2->read(); + + // save to the state + this->state->set_digital_1(switch_1); + this->state->set_digital_2(switch_2); + + // check possible error codes + if (switch_1 == 1 && (this->state->get_avg_analog_1() > this->state->get_avg_analog_2() ) ) { + this->state->set_error(3); + } else { + this->state->set_error(0); + } + + // schedule or deschedule counting task as appropriate + if (switch_2 == 1 && this->counting_scheduled == 0) { + // schedule binary LED task + this->counting_scheduled = 1; + // set the binary LED task next run + int next_run = this->get_next_run_ms()+300; + this->counting_task->set_next_run_ms(next_run); + // add task to task manager + this->tm->add_task(this->counting_task); + } else if (switch_2 == 0) { + // delete task from task manager + this->tm->remove_task(this->counting_task); + this->counting_scheduled = 0; + } + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/counting_task.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,51 @@ +/** + * This task do a binary count on the 4 mbed LEDs + * + * Author: Jacob Baungard Hansen + */ + +#include "counting_task.h" + +/** + * + * @param starting_offset when the task should but run first + * @param frequency_ms the frequency in ms of how often the task should run + */ +CountingTask::CountingTask(int starting_offset, int frequency_ms) + : Task(starting_offset, frequency_ms) { + + this->count = 0; + + this->led1 = new DigitalOut(LED1); + this->led2 = new DigitalOut(LED2); + this->led3 = new DigitalOut(LED3); + this->led4 = new DigitalOut(LED4); + + +} + +CountingTask::~CountingTask() { + delete this->led1; + delete this->led2; + delete this->led3; + delete this->led4; +} + +/** + * The function that is run at the specified frequency. + */ +void CountingTask::action() { + + // simple way to get the bits + std::bitset<4> bits(this->count); + + // set the result + this->led1->write(bits[3]); + this->led2->write(bits[2]); + this->led3->write(bits[1]); + this->led4->write(bits[0]); + + // don't overflow + this->count = (this->count+1) % 16; + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freq_task.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,47 @@ +/** + * Task for getting the frequency from digital input on pin13. + * The frequency is calculated by counting the number of rises + * on the pin. This is done using an interupt handler. + * + * Author: Jacob Baungard Hansen + */ +#include "freq_task.h" + +FrequencyTask::FrequencyTask(int starting_offset, int frequency_ms, + State * state) + : Task(starting_offset, frequency_ms) { + + this->state = state; + this->count = 0; + this->interrupt = new InterruptIn(p13); + +} + +FrequencyTask::~FrequencyTask() { + delete this->interrupt; +} + +/** + * This is called by the interupt, simply adds one to the count + */ +void FrequencyTask::counter() { + this->count++; +} + +void FrequencyTask::action() { + // reset the count + this->count=0; + // Enable the iterrupt + this->interrupt->rise<FrequencyTask>(this, &FrequencyTask::counter); + // wait for a specied amout of time + wait_ms(SAMPLE_LENGTH_MS); + // disable interrupts + this->interrupt->rise(NULL); + //interupt.rise<FrequencyTask>(this, NULL); This crashes, should report bug to ARM + int freq = 0; + if (this->count > 0) { + freq = count/(SAMPLE_LENGTH_MS*0.001); + } + + this->state->set_freq(freq); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lcd_helper.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,85 @@ +/** + * Mostly just a wrapper around the LCD display. + * + * Author: Jacob Baungard Hansen + */ + +#include "lcd_helper.h" + +/** + * Constructor setups the LCD Display + * and writes initial values needed for this project. + */ +LCDHelper::LCDHelper() { + + this->par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip + this->lcd = new WattBob_TextLCD(par_port); // initialise 2*26 char display + par_port->write_bit(1,BL_BIT); // turn LCD backlight ON + + lcd->cls(); // clear display + + this->print("Fr d1 d2 ", "a1 a2 e "); + +} + +LCDHelper::~LCDHelper() { + delete this->par_port; + delete this->lcd; +} + +/** + * Clears the display and prints one line + */ +void LCDHelper::print(std::string line1) { + this->print(line1, std::string()); +} + +/** + * Clears the display and prints two lines + */ +void LCDHelper::print(std::string line1, std::string line2) { + lcd->cls(); // clear display + + lcd->locate(0,0); // set cursor to location (0,0) - top left corner + lcd->printf(line1.c_str()); + + // only print line2 if it contains data + if (!line2.empty()) { + lcd->locate(1,0); // set cursor to location (1,0) - bottom left corner + lcd->printf(line2.c_str()); + } +} + +void LCDHelper::clear() { + lcd->cls(); // clear display +} + +/** + * + * + * @Param state pointer to state object + */ +void LCDHelper::print_state(State * state) { + lcd->locate(0,3); + lcd->printf("%d", state->get_freq()); + + lcd->locate(0,10); + lcd->printf("%d", state->get_digital_1()); + + lcd->locate(0,15); + lcd->printf("%d", state->get_digital_2()); + + lcd->locate(1,3); + // printf is very slow at converting from float to int + int avg_analog_1 = (int) floor( state->get_avg_analog_1() + 0.5); + lcd->printf("%d", avg_analog_1); + + lcd->locate(1,8); + // printf is very slow at converting from float to int + int avg_analog_2 = (int) floor( state->get_avg_analog_2() + 0.5); + lcd->printf("%d", avg_analog_2); + + lcd->locate(1,12); + lcd->printf("%d", state->get_error() ); + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,66 @@ +/** + * Main class for the project. + * The main class instantiates all the tasks and schedules them + * correctly using the TaskManager object. + * + * As writing to the SDCard occasionally hits +50ms in timing, there was several issue + * with the schedule purposed in the original assignment. As a result the timings have changed. + * + * Action 2 (reading digital values) have been discarded. The values are only used + * in the Action 5, as a result we might as well read them "Just In Time". + * However if desired it could have been scheduled starting at 600ms with a freqency of 600ms + * + * The schedule is as follows: + * Action 1 (frequency) 1200ms + * Action 2 (get digital input) disabled, see above + * Action 3 (read analog in) 600ms + * Action 4 (Print to LCD) 1200ms + * Action 5 (checks) 600ms + * Action 5.1 (binary counting) 1800ms + * Action 6 (SDCard) 4800ms + * + * Author: Jacob Baungard Hansen + */ + +#include "task.h" +#include "lcd_helper.h" +#include "demo_task.h" +#include "task_manager.h" +#include "state.h" +#include "lcd_task.h" +#include "update_analog_task.h" +#include "check_task.h" +#include "freq_task.h" +#include "SDFileSystem.h" +#include "sdcard_task.h" + +int main() { + + LCDHelper * lcd_helper = new LCDHelper(); + + State * state = new State(); + + TaskManager * tm = new TaskManager(100, lcd_helper); + + UpdateAnalogTask * analog_task = new UpdateAnalogTask(100, 600, state); + CheckTask * check_task = new CheckTask(200, 600, state, tm); + FrequencyTask * freq_task = new FrequencyTask(300, 1200, state); + LCDTask * lcd_task = new LCDTask(400, 2400, lcd_helper, state); + SDCardTask * sd_task = new SDCardTask(4800, 4800, state); + + tm->add_task(check_task); + tm->add_task(analog_task); + tm->add_task(lcd_task); + tm->add_task(freq_task); + tm->add_task(sd_task); + + tm->start(); + + delete lcd_helper; + delete lcd_task; + delete analog_task; + delete freq_task; + delete sd_task; + delete tm; + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sdcard.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,66 @@ +/** + * Task that logs the state to a file on the SD card in csv format + * + * Author: Jacob Baungard Hansen + */ + +#include "sdcard_task.h" + +/** + * + * @param starting_offset when the task should but run first + * @param frequency_ms the frequency in ms of how often the task should run +* @param state pointer to the state object to print + */ +SDCardTask::SDCardTask(int starting_offset, int frequency_ms, + State * state) + : Task(starting_offset, frequency_ms) { + + this->state = state; + // mount the file system + this->sd = new SDFileSystem(p5, p6, p7, p8, "sd"); + + // set the folder + this->folder = "/sd/embedded"; + + // ensure folder exists + struct stat s = {0}; + + if (!stat(folder.c_str(), &s)) { } + else { + mkdir(folder.c_str(), 0777); + } + + // set file to log to + this->file.append(folder); + file.append("/data.csv"); + + // clear previous data and set headers + FILE *fp = fopen(file.c_str(), "w"); + if(fp == NULL) { + error("Could not open file for write\n"); + } + fprintf(fp, "frequency,digital1,digital2,analog1,analog2\n"); + fclose(fp); + +} + +SDCardTask::~SDCardTask() { + delete this->sd; +} + +void SDCardTask::action() { + + // ensure file can be opened + FILE *fp = fopen(file.c_str(), "a"); + if(fp == NULL) { + error("Could not open file for write\n"); + } + // print current state + fprintf(fp, "%d,%d,%d,%f,%f\n", this->state->get_freq(), this->state->get_digital_1(), + this->state->get_digital_2(), this->state->get_avg_analog_1(), + this->state->get_avg_analog_2()); + fclose(fp); + + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,17 @@ + +/** + * Base objects for all tasks to be executed by the TaskManager + * + * Author: Jacob Baungard Hansen + */ + +#include "task.h" + +/** + * @param starting_offset when the task should be run first + * @param frequency_ms the frequency in ms of how often the task should run + */ +Task::Task(int starting_offset, int frequency_ms) { + this->next_run_ms=starting_offset; + this->frequency_ms = frequency_ms; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/task_manager.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,157 @@ +/** + * This class manages all the tasks and ensures they are correctly executed. + * It contains various error reporting for schedule issues. + * + * Currently it checks for tasks inside the called interrupt, delaying the tasks + * execution slightly. This gets worse with an increasing number of tasks. + * As such this should only used with a small number of tasks. + * + * Author: Jacob Baungard Hansen + */ + +#include "task_manager.h" + +/** + * + * @param ticker_freq_ms how often we should check for tasks + */ +TaskManager::TaskManager(int ticker_freq_ms) { + this->current_time=0; + this->ticker_freq_ms = ticker_freq_ms; +} + +/** + * + * @param ticker_freq_ms how often we should check for tasks + * @param lcd pointer to LCDHelper object, used to display errors + */ +TaskManager::TaskManager(int ticker_freq_ms, LCDHelper * lcd) { + this->current_time=0; + this->ticker_freq_ms = ticker_freq_ms; + this->lcd = lcd; +} + +// empty +TaskManager::~TaskManager() {} + +/** + * Checks if any tasks needs to run, and if so run them. + * Also checks for any scheduling conflicts, and ensures + * the tasks execution time is not too long. + */ +void TaskManager::find_and_run(){ + // start timer + t.start(); + + // increase current time + this->current_time += this->ticker_freq_ms; + + // if no tasks, give an error + if (this->tasks.empty()) { + this->schedule_error("No tasks"); + this->stop(); + } + + Task * task_to_run = NULL; + // check if there's any tasks to run this timetamp + for (unsigned int i=0; i<this->tasks.size(); i++) { + if (this->tasks[i]->get_next_run_ms() == this->current_time) { + if (task_to_run == NULL ) { + task_to_run = this->tasks[i]; + } else { // if more than one task this timestamp, it is an error + this->schedule_error("Conflict"); + this->stop(); + break; + } + } + } + + // run the found task, if any + if (task_to_run != NULL) { + task_to_run->increment_next_run(); + task_to_run->action(); + } + + // Ensure task didn't take too long + // asume messuring code taskes at least 2ms. + t.stop(); + if (t.read_ms() > (this->ticker_freq_ms)-2) { + this->schedule_error("Task too long"); + this->stop(); + } + // reset timer for next timeaaround + t.reset(); + +} + +/** + * Prints a scheduling error + * + * @param msg message to print on line2 of lcd display + */ +void TaskManager::schedule_error(std::string msg) { + if (this->lcd != NULL) { + this->lcd->print("Schedule error:", msg); + } + this->stop(); +} + +/** + * Adds a task to the exeuction cycle + * + * @param task pointer to the task to add + */ +void TaskManager::add_task(Task * task) { + // we need to ensure that the frequency for the task + // and the ticker frequency is a match + if (task->get_frequency_ms() % this->ticker_freq_ms != 0) { + this->schedule_error("Bad task freq"); + } + // first possible slot for a task to run is at ticker_freq_ms (maybe this should be changed) + // ensure tasks do not start earlier + else if (task->get_next_run_ms() < this->ticker_freq_ms) { + this->schedule_error("start<tickerfreq"); + } + // add task + else { + this->tasks.push_back(task); + } +} + +/** + * Removes a task to the exeuction cycle + * + * @param task pointer to the task to remove + */ +void TaskManager::remove_task(Task * task) { + for (unsigned int i=0; i<this->tasks.size(); i++) { + if (this->tasks[i] == task) { + this->tasks.erase(this->tasks.begin()+i); + break; + } + } +} + +/** + * Starts running + */ +void TaskManager::start() { + timestamp_t in_us = this->ticker_freq_ms*1000.0; + // need to change priority in case of using + // interupts in the activities. + // a bit nasty + NVIC_SetPriority(TIMER3_IRQn, 200); + this->ticker.attach_us<TaskManager>(this, &TaskManager::find_and_run, in_us); + + while(1) {} +} + +/** + * Stops running + */ +void TaskManager::stop() { + this->ticker.detach(); + // might not want this in a general case (not sure) + // although for this case it seems appropiate. + while(1) {} +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/update_analog_task.cpp Tue Mar 14 14:46:43 2017 +0000 @@ -0,0 +1,25 @@ +#include "update_analog_task.h" + +/** + * + * @param starting_offset when the task should but run first + * @param frequency_ms the frequency in ms of how often the task should run + * @param state pointer to the state object + */ +UpdateAnalogTask::UpdateAnalogTask(int starting_offset, int frequency_ms, + State * state) + : Task(starting_offset, frequency_ms) { + + this->state = state; + this->analog_in_1 = new AnalogIn(p17); + this->analog_in_2 = new AnalogIn(p18); +} + +UpdateAnalogTask::~UpdateAnalogTask() { + delete this->analog_in_1; + delete this->analog_in_2; +} + +void UpdateAnalogTask::action() { + this->state->update_analog(this->analog_in_1->read(), this->analog_in_2->read()); +} \ No newline at end of file