Xavier Herpe / Mbed 2 deprecated Assignment_2_herpe

Dependencies:   mbed WattBob_TextLCD MCP23017

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

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 }