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
