![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Test session
Dependencies: FatFileSystem MCP23017 WattBob_TextLCD mbed
Fork of Assignment_2_herpe by
XG_2.cpp
- Committer:
- xouf2114
- Date:
- 2017-03-07
- Revision:
- 2:42d97c99e877
- Parent:
- 1:adcb8ab84d62
- Child:
- 3:5883d1a2c5b0
File content as of revision 2:42d97c99e877:
// XAVIER GOUESNARD // H00258183 // Assignment 2 // MSc Embeded Systems 2016/2017 // Heriot-Watt University #include "mbed.h" #include "MCP23017.h" #include "WattBob_TextLCD.h" #include "SDFileSystem.h" #include "FATFileSystem.h" #define BACK_LIGHT_ON(INTERFACE) INTERFACE->write_bit(1,BL_BIT) #define BACK_LIGHT_OFF(INTERFACE) INTERFACE->write_bit(0,BL_BIT) // Pointers to LCD screen and SD card MCP23017 *par_port; // pointer to 16-bit parallel I/O chip WattBob_TextLCD *lcd; // pointer to 2*16 character LCD object FILE *fp; // Pointer to SD card object //===================================================================================== // I/O ports allocation //===================================================================================== DigitalIn TTL(p17); // TTL input for frequency measurement DigitalIn switch_1(p18); // Switch 1 input DigitalIn switch_2(p19); // Switch 2 input DigitalIn switch_off(p11); // Switch used to close SD file and stop cyclic executive AnalogIn analogue_in_1(p15); // POT value AnalogIn analogue_in_2(p16); // LDR value 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 //===================================================================================== // Internal objects declaration // ==================================================================================== BusOut LEDs(LED4, LED3, LED2, LED1); // Address the four LEDs to a single bus Timer timer; // Timer used to measure frequency in task 1 Timer DoNothing; // Timer used to measure how long the program does nothing Ticker ticker; // Ticker used as clock for cyclic executive program //===================================================================================== // Constants declaration //===================================================================================== const int SampFreq = 100; // Sampling frequency is 10kHz (100us) //===================================================================================== // Variables declaration //===================================================================================== // Variables for cyclic executive program long int ticks = 0; // Used to define what task to call in the cyclic executive program int NoTask = 0; // Used to return how long the program does nothing in ms int NoTaskCount = 0; // Variable incremented until one total cycle of 10 seconds is reached // Variables for tasks 1 and 2 int period = 0; // Returned period of the TTL input signal int frequency = 0; // Returned frequency of the TTL signal // Varibles for task 4 int switch_1_val = 0; // Used to return how many times the switch is high int switch_2_val = 0; bool switch_1_state = 0; // Used to define whether the debounced switch is ON or OFF bool switch_2_state = 0; // Variables for task 5 float analogue_1_val = 0; // Used to return the filtered analogue input float analogue_2_val = 0; int analogue_1_int = 0; // Used to convert float to int (results in quicker display on LCD in task 6) int analogue_2_int = 0; // Variable for task 7 int LogCount = 0; // Used to define logging number // Variable used for task 8 int BinCount = 0; // Used to increment a binary display on LEDs. Goes from 0 to 15 and then is reset bool BinEnable = 0; // Used to tell task 5 to display binary pattern on LEDs every 1.5s int IncCheck = 0; // Check increment to see if 6 cycles have elapsed to light LEDs ( 6 * 250us = 1.5s) //===================================================================================== // Task declaration //===================================================================================== void CyclEx(); void Task1(); // Measure TTL input frequency void Task2(); // Show frequency on LCD screen void Task3(); // Show speed on servo dial void Task4(); // Read and debounce two digital inputs void Task5(); // Read and filter two analogue inputs void Task6(); // Display digital and analogue inputs on LCD screen void Task7(); // Log speed, analogue and digital inputs on SD card void Task8(); // Display error message on LCD screen and display binary pattern on LEDs void WaitRisEdge(); // Subroutine to detect rising edge void WaitFalEdge(); // Subroutine to detect falling edge void Stop(); // Close log file and stop cyclic executive //===================================================================================== // Main program //===================================================================================== int main() { // LCD Screen Initialisation par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip 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 // EXEL log file initialisation fp = fopen("/sd/log.xls", "w"); // pointer to log in text file called "log". (Use "a" to not delete file) fprintf(fp, "This file is the property of Xavier Gouesnard\n\n"); // DoNothing timer reset DoNothing.reset(); // Internal ticker set to 25ms. Every 25ms, the scheduler is called and selects the task to run ticker.attach(&CyclEx, 0.025); // Period set to 25ms while(1)// Run until system shuts down { } } // Where tasks are scheduled based on an EXEL sheet void CyclEx() { // Stop timer when a new task starts DoNothing.stop(); if(ticks % 80 == 4) // Occures every 80 clock cycles (2 seconds). Starts with an offset of 4 clock cycles { Task1(); } else if(ticks % 200 == 8) // Occures every 200 clock cycles (5 seconds). Starts with an offset of 8 clock cycles { Task2(); } else if(ticks % 240 == 7) // Occures every 240 clock cycles (6 seconds). Starts with an offset of 7 clock cycles { Task3(); } else if(ticks % 4 == 0) // Occures every 4 clock cycles (0.1 seconds). Starts with an offset of 0 clock cycles { Task4(); } else if(ticks % 10 == 1) // Occures every 10 clock cycles (0.25 seconds). Starts with an offset of 1 clock cycles { Task5(); } else if(ticks % 40 == 3) // Occures every 40 clock cycles (1 seconds). Starts with an offset of 3 clock cycles { Task6(); } else if(ticks % 400 == 10) // Occures every 400 clock cycles (10 seconds). Starts with an offset of 10 clock cycles { Task7(); } else if(ticks % 160 == 6) // Occures every 160 clock cycles (4 seconds). Starts with an offset of 6 clock cycles { Task8(); } if (switch_off == 1) // Pin used to log data on SD card and stop Cyclic executive program { Stop(); } ticks++; // Start timer when one task is ended DoNothing.start(); NoTaskCount++; // When one full cycle of 10 seconds is finished, return how long the program was doing nothing (lazy program) if (NoTaskCount == 400) { NoTask = DoNothing.read_ms(); NoTaskCount = 0; DoNothing.reset(); } } //===================================================================================== // Tasks //===================================================================================== // Task 1: Measure TTL input frequency void Task1() { 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 } // Task 2: display the measured frequency on LCD screen void Task2() { lcd->cls(); // clear display lcd->locate(0,0); // set cursor to location (0,0) - top left corner lcd->printf("%d Hz",frequency); // print the frequency calculated in task 1 } // Task 3: show speed on servo output dial void Task3() { servo.period(0.02); // servo requires a 20ms period // To rotate the servo from -90 to +90 degrees, the pulse width must varies between 600us to 2300us // The pulse width is calculated from the speed measured in task one // 50Hz is equivalent to -90 degrees and 100Hz is equivalent to 90 degrees // 1Hz change is equal to 34us pulse width change, so pulse width = ((frequency - 50)*34) + 600 servo.pulsewidth_us(2300-((frequency - 50)*34)); wait_ms(1); // Leave the servo some time to reach its position } // Task 4: Read two digital inputs (debounced) void Task4() { switch_1_val = 0; switch_2_val = 0; // Read each switch three consecutive times with 100us between readings for(int i=0; i<3; i++) { if (switch_1 == 1) // Increment variable if switch 1 is pressed { switch_1_val++; } if (switch_2 == 1) // Increment variable if switch 2 is pressed { switch_2_val++; } wait_us(SampFreq); } // Check how many times switch 1 has been high // if it has been high more than twice, then switch 1 state = 1 if (switch_1_val > 1) { switch_1_state = 1; } else { switch_1_state = 0; } // Check how many times switch 1 has been high // if it has been high more than twice, then switch 2 state = 1 if (switch_2_val > 1) { switch_2_state = 1; } else { switch_2_state = 0; } } // Task 5: Read two analogue inputs (filtered) void Task5() { analogue_1_val = 0; // Reset variables analogue_2_val = 0; // Takes four readings of each analogue input. Readings occure every 0.1ms // Because the analogue.read() function returns a value from 0 to 1, // we need to multiply the readings by 3.3 to cover 0V to 3.3V for(int i=0; i<4;i++) { analogue_1_val = analogue_1_val + (analogue_in_1*3.3); analogue_2_val = analogue_2_val + (analogue_in_2*3.3); wait_us(SampFreq); } analogue_1_val = (analogue_1_val / 4); analogue_2_val = (analogue_2_val / 4); analogue_1_int = analogue_1_val * 10; // Convert floating point into an integer to reduce display delay analogue_2_int = analogue_2_val * 10; // This section of task 5 is used to take over part of task 8. // Since the LEDs pattern has to be incremented every 1.5s, the pattern is // incremented every 6 cycles, which correspond to 1.5s. if(BinEnable == 1) { IncCheck++; if(IncCheck == 6) // Corresponds to 1.5s. Increment binary pattern { LEDs = BinCount; BinCount++; IncCheck = 0; if (BinCount > 15) // Used to reset variable once maximum 4-bit binary value is reached { BinCount = 0; } } } } // Task 6: Display analogue and digital values on LCD screen void Task6() { // lcd->cls(); // clear display (takes too long) lcd->locate(0,0); // set cursor to location (0,0) - top left corner lcd->printf("%d %d%d%d",analogue_1_int,analogue_2_int,switch_1_state,switch_2_state); } // Task 7: Log values on SD card void Task7() { LogCount++; //Used to print the logging number in file. Starts from 1 fprintf(fp, "Log: %d, Speed: %dHz, Switch_1: %d, Switch_2: %d, POT: %.2fVolts, LDR: %.2fVolts\n",LogCount,frequency,switch_1_state,switch_2_state,analogue_1_val,analogue_2_val); } // Task 8: Show error message and light LEDs void Task8() { // If switch_1 = 1 and POT value > 3V, display error message if(switch_1_state == 1 && analogue_1_val > 3) { //lcd->cls(); // clear display lcd->locate(0,0); // set cursor to location (0,0) - top left corner lcd->printf(".ERREUR"); } // If switch 2 is high, return a command to task 5 to do the incrementing pattern every 1.5 seconds if(switch_2_state == 1) { BinEnable = 1; } // If switch 2 is low, stop sending a command to task 5 and light off LEDs else { LEDs = 0; BinEnable = 0; BinCount = 0; } } // Stop function to stop cyclic executive and close log file void Stop() { ticker.detach(); fprintf(fp, "\n The program did nothing for %d ms, which corresponds to %d percent of the time \n",NoTask, NoTask/100); fprintf(fp, "\n PROGRAM STOPPED"); fclose(fp); } //===================================================================================== // Subroutines //===================================================================================== // Wait for rising edge void WaitRisEdge() { // As soon as it gets high, the subroutine will end and the timer will start while(TTL == 0) { wait_us(SampFreq); } } // Wait for falling edge void WaitFalEdge() { // As soon as it gets low, the subroutine will end and the timer will start while(TTL == 1) { wait_us(SampFreq); } }