Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: mbed WattBob_TextLCD MCP23017
main.cpp
00001 // XAVIER HERPE Assignment 2 00002 // 5th year Robotics & Cybertronics 00003 // Heriot-Watt University 00004 00005 #include "mbed.h" 00006 #include "MCP23017.h" 00007 #include "WattBob_TextLCD.h" 00008 #include "SDFileSystem.h" 00009 #include "FATFileSystem.h" 00010 00011 #define BACK_LIGHT_ON(INTERFACE) INTERFACE->write_bit(1,BL_BIT) 00012 #define BACK_LIGHT_OFF(INTERFACE) INTERFACE->write_bit(0,BL_BIT) 00013 00014 // Pointers to LCD screen and SD card 00015 MCP23017 *par_port; // pointer to 16-bit parallel I/O chip 00016 WattBob_TextLCD *lcd; // pointer to 2*16 character LCD object 00017 FILE *fp; // Pointer to SD card object 00018 00019 00020 //===================================================================================== 00021 // I/O ports allocation 00022 //===================================================================================== 00023 DigitalIn TTL(p17); // TTL input for frequency measurement 00024 DigitalIn switch_1(p18); // Switch 1 input 00025 DigitalIn switch_2(p19); // Switch 2 input 00026 DigitalIn switch_off(p11); // Switch used to close SD file and stop cyclic executive 00027 AnalogIn analogue_in_1(p15); // POT value 00028 AnalogIn analogue_in_2(p16); // LDR value 00029 PwmOut servo(p21); // Servo output 00030 DigitalOut TestPin(p20); // Pin only used to test program and measure time 00031 SDFileSystem sd(p5, p6, p7, p8, "sd"); // The pinout on the mbed Cool Components workshop board 00032 00033 00034 //===================================================================================== 00035 // Internal objects declaration 00036 // ==================================================================================== 00037 BusOut LEDs(LED4, LED3, LED2, LED1); // Address the four LEDs to a single bus 00038 Timer timer; // Timer used to measure frequency in task 1 00039 Timer DoNothing; // Timer used to measure how long the program does nothing 00040 Ticker ticker; // Ticker used as clock for cyclic executive program 00041 00042 00043 //===================================================================================== 00044 // Constants declaration 00045 //===================================================================================== 00046 const int SampFreq = 100; // Sampling frequency is 10kHz (100us) 00047 00048 00049 //===================================================================================== 00050 // Variables declaration 00051 //===================================================================================== 00052 00053 // Variables for cyclic executive program 00054 long int ticks = 0; // Used to define what task to call in the cyclic executive program 00055 int NoTask = 0; // Used to return how long the program does nothing in ms 00056 int NoTaskCount = 0; // Variable incremented until one total cycle of 10 seconds is reached 00057 00058 // Variables for tasks 1 and 2 00059 int period = 0; // Returned period of the TTL input signal 00060 int frequency = 0; // Returned frequency of the TTL signal 00061 00062 // Varibles for task 4 00063 int switch_1_val = 0; // Used to return how many times the switch is high 00064 int switch_2_val = 0; 00065 bool switch_1_state = 0; // Used to define whether the debounced switch is ON or OFF 00066 bool switch_2_state = 0; 00067 00068 // Variables for task 5 00069 float analogue_1_val = 0; // Used to return the filtered analogue input 00070 float analogue_2_val = 0; 00071 00072 int analogue_1_int = 0; // Used to convert float to int (results in quicker display on LCD in task 6) 00073 int analogue_2_int = 0; 00074 00075 // Variable for task 7 00076 int LogCount = 0; // Used to define logging number 00077 00078 // Variable used for task 8 00079 int BinCount = 0; // Used to increment a binary display on LEDs. Goes from 0 to 15 and then is reset 00080 bool BinEnable = 0; // Used to tell task 5 to display binary pattern on LEDs every 1.5s 00081 int IncCheck = 0; // Check increment to see if 6 cycles have elapsed to light LEDs ( 6 * 250us = 1.5s) 00082 00083 00084 //===================================================================================== 00085 // Task declaration 00086 //===================================================================================== 00087 00088 void CyclEx(); 00089 00090 void Task1(); // Measure TTL input frequency 00091 void Task2(); // Show frequency on LCD screen 00092 void Task3(); // Show speed on servo dial 00093 void Task4(); // Read and debounce two digital inputs 00094 void Task5(); // Read and filter two analogue inputs 00095 void Task6(); // Display digital and analogue inputs on LCD screen 00096 void Task7(); // Log speed, analogue and digital inputs on SD card 00097 void Task8(); // Display error message on LCD screen and display binary pattern on LEDs 00098 00099 void WaitRisEdge(); // Subroutine to detect rising edge 00100 void WaitFalEdge(); // Subroutine to detect falling edge 00101 00102 void Stop(); // Close log file and stop cyclic executive 00103 00104 00105 //===================================================================================== 00106 // Main program 00107 //===================================================================================== 00108 00109 int main() 00110 { 00111 00112 // LCD Screen Initialisation 00113 par_port = new MCP23017(p9, p10, 0x40); // initialise 16-bit I/O chip 00114 lcd = new WattBob_TextLCD(par_port); // initialise 2*26 char display 00115 par_port->write_bit(1,BL_BIT); // turn LCD backlight ON 00116 lcd->cls(); // clear display 00117 00118 // EXEL log file initialisation 00119 fp = fopen("/sd/log.xls", "w"); // pointer to log in text file called "log". (Use "a" to not delete file) 00120 fprintf(fp, "This file is the property of Xavier Herpe, the French\n\n"); 00121 00122 // DoNothing timer reset 00123 DoNothing.reset(); 00124 00125 // Internal ticker set to 25ms. Every 25ms, the scheduler is called and selects the task to run 00126 ticker.attach(&CyclEx, 0.025); // Period set to 25ms 00127 while(1)// Run until system shuts down 00128 { 00129 00130 } 00131 } 00132 00133 // Where tasks are scheduled based on an EXEL sheet 00134 void CyclEx() 00135 { 00136 // Stop timer when a new task starts 00137 DoNothing.stop(); 00138 00139 if(ticks % 80 == 4) // Occures every 80 clock cycles (2 seconds). Starts with an offset of 4 clock cycles 00140 { 00141 Task1(); 00142 } 00143 00144 else if(ticks % 200 == 8) // Occures every 200 clock cycles (5 seconds). Starts with an offset of 8 clock cycles 00145 { 00146 Task2(); 00147 } 00148 else if(ticks % 240 == 7) // Occures every 240 clock cycles (6 seconds). Starts with an offset of 7 clock cycles 00149 { 00150 Task3(); 00151 } 00152 else if(ticks % 4 == 0) // Occures every 4 clock cycles (0.1 seconds). Starts with an offset of 0 clock cycles 00153 { 00154 Task4(); 00155 } 00156 else if(ticks % 10 == 1) // Occures every 10 clock cycles (0.25 seconds). Starts with an offset of 1 clock cycles 00157 { 00158 Task5(); 00159 } 00160 else if(ticks % 40 == 3) // Occures every 40 clock cycles (1 seconds). Starts with an offset of 3 clock cycles 00161 { 00162 Task6(); 00163 } 00164 else if(ticks % 400 == 10) // Occures every 400 clock cycles (10 seconds). Starts with an offset of 10 clock cycles 00165 { 00166 Task7(); 00167 } 00168 else if(ticks % 160 == 6) // Occures every 160 clock cycles (4 seconds). Starts with an offset of 6 clock cycles 00169 { 00170 Task8(); 00171 } 00172 00173 if (switch_off == 1) // Pin used to log data on SD card and stop Cyclic executive program 00174 { 00175 Stop(); 00176 } 00177 ticks++; 00178 00179 // Start timer when one task is ended 00180 DoNothing.start(); 00181 NoTaskCount++; 00182 00183 // When one full cycle of 10 seconds is finished, return how long the program was doing nothing (lazy program) 00184 if (NoTaskCount == 400) 00185 { 00186 NoTask = DoNothing.read_ms(); 00187 NoTaskCount = 0; 00188 DoNothing.reset(); 00189 } 00190 } 00191 00192 00193 //===================================================================================== 00194 // Tasks 00195 //===================================================================================== 00196 00197 // Task 1: Measure TTL input frequency 00198 void Task1() 00199 { 00200 timer.reset(); 00201 00202 // If the input signal is low, wait for a rising edge to start counting 00203 if (TTL == 0) 00204 { 00205 WaitRisEdge(); // Call subroutine to wait for rising edge 00206 timer.start(); // Start timer 00207 while(TTL == 1) // Keep counting as long as signal is high 00208 { 00209 wait_us(SampFreq); 00210 } 00211 } 00212 00213 // If the input signal is high, wait for a falling edge to start counting 00214 else if (TTL == 1) 00215 { 00216 WaitFalEdge(); // Call subroutine to wait for falling edge 00217 timer.start(); // Start timer 00218 while(TTL == 0) // Keep counting as long as signal is high 00219 { 00220 wait_us(SampFreq); 00221 } 00222 } 00223 00224 timer.stop(); // Stop counting when signal changes 00225 period = timer.read_us()*2; // Convert the time into a period 00226 frequency = 1000000/period; // Convert the period into a frequency 00227 } 00228 00229 00230 00231 // Task 2: display the measured frequency on LCD screen 00232 void Task2() 00233 { 00234 lcd->cls(); // clear display 00235 lcd->locate(0,0); // set cursor to location (0,0) - top left corner 00236 lcd->printf("%d Hz",frequency); // print the frequency calculated in task 1 00237 } 00238 00239 00240 00241 // Task 3: show speed on servo output dial 00242 void Task3() 00243 { 00244 servo.period(0.02); // servo requires a 20ms period 00245 // To rotate the servo from -90 to +90 degrees, the pulse width must varies between 600us to 2300us 00246 // The pulse width is calculated from the speed measured in task one 00247 // 50Hz is equivalent to -90 degrees and 100Hz is equivalent to 90 degrees 00248 // 1Hz change is equal to 34us pulse width change, so pulse width = ((frequency - 50)*34) + 600 00249 servo.pulsewidth_us(2300-((frequency - 50)*34)); 00250 wait_ms(1); // Leave the servo some time to reach its position 00251 } 00252 00253 00254 00255 // Task 4: Read two digital inputs (debounced) 00256 void Task4() 00257 { 00258 switch_1_val = 0; 00259 switch_2_val = 0; 00260 00261 // Read each switch three consecutive times with 100us between readings 00262 for(int i=0; i<3; i++) 00263 { 00264 if (switch_1 == 1) // Increment variable if switch 1 is pressed 00265 { 00266 switch_1_val++; 00267 } 00268 00269 if (switch_2 == 1) // Increment variable if switch 2 is pressed 00270 { 00271 switch_2_val++; 00272 } 00273 00274 wait_us(SampFreq); 00275 } 00276 // Check how many times switch 1 has been high 00277 // if it has been high more than twice, then switch 1 state = 1 00278 if (switch_1_val > 1) 00279 { 00280 switch_1_state = 1; 00281 } 00282 else 00283 { 00284 switch_1_state = 0; 00285 } 00286 00287 // Check how many times switch 1 has been high 00288 // if it has been high more than twice, then switch 2 state = 1 00289 if (switch_2_val > 1) 00290 { 00291 switch_2_state = 1; 00292 } 00293 00294 else 00295 { 00296 switch_2_state = 0; 00297 } 00298 } 00299 00300 00301 00302 // Task 5: Read two analogue inputs (filtered) 00303 void Task5() 00304 { 00305 analogue_1_val = 0; // Reset variables 00306 analogue_2_val = 0; 00307 00308 // Takes four readings of each analogue input. Readings occure every 0.1ms 00309 // Because the analogue.read() function returns a value from 0 to 1, 00310 // we need to multiply the readings by 3.3 to cover 0V to 3.3V 00311 for(int i=0; i<4;i++) 00312 { 00313 analogue_1_val = analogue_1_val + (analogue_in_1*3.3); 00314 analogue_2_val = analogue_2_val + (analogue_in_2*3.3); 00315 wait_us(SampFreq); 00316 } 00317 00318 analogue_1_val = (analogue_1_val / 4); 00319 analogue_2_val = (analogue_2_val / 4); 00320 00321 analogue_1_int = analogue_1_val * 10; // Convert floating point into an integer to reduce display delay 00322 analogue_2_int = analogue_2_val * 10; 00323 00324 // This section of task 5 is used to take over part of task 8. 00325 // Since the LEDs pattern has to be incremented every 1.5s, the pattern is 00326 // incremented every 6 cycles, which correspond to 1.5s. 00327 if(BinEnable == 1) 00328 { 00329 IncCheck++; 00330 00331 if(IncCheck == 6) // Corresponds to 1.5s. Increment binary pattern 00332 { 00333 LEDs = BinCount; 00334 BinCount++; 00335 IncCheck = 0; 00336 00337 if (BinCount > 15) // Used to reset variable once maximum 4-bit binary value is reached 00338 { 00339 BinCount = 0; 00340 } 00341 } 00342 } 00343 } 00344 00345 00346 00347 // Task 6: Display analogue and digital values on LCD screen 00348 void Task6() 00349 { 00350 // lcd->cls(); // clear display (takes too long) 00351 lcd->locate(0,0); // set cursor to location (0,0) - top left corner 00352 lcd->printf("%d %d%d%d",analogue_1_int,analogue_2_int,switch_1_state,switch_2_state); 00353 } 00354 00355 00356 00357 // Task 7: Log values on SD card 00358 void Task7() 00359 { 00360 LogCount++; //Used to print the logging number in file. Starts from 1 00361 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); 00362 } 00363 00364 00365 00366 // Task 8: Show error message and light LEDs 00367 void Task8() 00368 { 00369 // If switch_1 = 1 and POT value > 3V, display error message 00370 if(switch_1_state == 1 && analogue_1_val > 3) 00371 { 00372 //lcd->cls(); // clear display 00373 lcd->locate(0,0); // set cursor to location (0,0) - top left corner 00374 lcd->printf(".ERREUR"); 00375 } 00376 00377 // If switch 2 is high, return a command to task 5 to do the incrementing pattern every 1.5 seconds 00378 if(switch_2_state == 1) 00379 { 00380 BinEnable = 1; 00381 } 00382 00383 // If switch 2 is low, stop sending a command to task 5 and light off LEDs 00384 else 00385 { 00386 LEDs = 0; 00387 BinEnable = 0; 00388 BinCount = 0; 00389 } 00390 } 00391 00392 00393 00394 // Stop function to stop cyclic executive and close log file 00395 void Stop() 00396 { 00397 ticker.detach(); 00398 fprintf(fp, "\n The program did nothing for %d ms, which corresponds to %d percent of the time \n",NoTask, NoTask/100); 00399 fprintf(fp, "\n PROGRAM STOPPED"); 00400 fclose(fp); 00401 00402 } 00403 00404 00405 00406 //===================================================================================== 00407 // Subroutines 00408 //===================================================================================== 00409 00410 // Wait for rising edge 00411 void WaitRisEdge() 00412 { 00413 // As soon as it gets high, the subroutine will end and the timer will start 00414 while(TTL == 0) 00415 { 00416 wait_us(SampFreq); 00417 } 00418 } 00419 00420 00421 // Wait for falling edge 00422 void WaitFalEdge() 00423 { 00424 // As soon as it gets low, the subroutine will end and the timer will start 00425 while(TTL == 1) 00426 { 00427 wait_us(SampFreq); 00428 } 00429 }
Generated on Mon Jul 25 2022 10:14:47 by
1.7.2