Ryan Tseng / Mbed 2 deprecated Display

Dependencies:   KS0108 mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 // Display Test
00002 #include "KS0108.h"
00003 #include "calsolimage.h"
00004 #include "MyPhone_20.h"
00005 #include "MyPhone_40.h"
00006 #include "rtos.h"
00007 
00008 // Declare each of the things you're going to use
00009 
00010 // The display
00011 KS0108 display(p23,p21,p22,p20,p24,p25,p17,p18,p19,p30,p29,p28,p27,p26);
00012 // The button on the breadboard
00013 DigitalIn topButton(p13);
00014 // For printing things to the computer
00015 Serial pc(USBTX,USBRX);
00016 
00017 // Timers
00018 Timer timer;
00019 Timer testTimer;
00020 
00021 //Methods
00022 void readFromCAN();
00023 void setupScreen();
00024 void updateBattery(int newVoltage);
00025 void updateBatteryGraphic(int newPercentage, int percentage);
00026 void printCenteredInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits);
00027 void printCenteredInt(int newInt, int oldInt, int leftLimit, int rightLimit, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits);
00028 void printRightJustifiedInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits);
00029 
00030 // Constants
00031 
00032 //Maximum voltage for battery = 151.2 V (4.2V per cell, 36 cells total)
00033 const double MaxVoltage = 151.2;
00034 //Minimum voltage for battery = 108 V (3V per cell, 36 cells total)
00035 const double MinVoltage = 108;
00036 
00037 // Mutex and screen state
00038 Mutex screen_mutex;
00039 CAN can(p9, p10);
00040 int demo = 0;
00041 
00042 
00043 //Speed: int from 0 to 999, in mph
00044 int speed = 0, newSpeed = 0;
00045 //Voltage: int from MinVoltage to MaxVoltage, in volts
00046 int voltage = MinVoltage, newVoltage = MinVoltage;
00047 //Current: int from 0 to 9999, in milliAmps
00048 int amperage = 0, newAmperage = 0;
00049 
00050 
00051 //Union type to make float to char conversion easier (used to read CAN messages)
00052 typedef union _data
00053 {
00054     float f[2];
00055     char s[8];
00056 } floatchar;
00057 
00058 //Union type to make int to char conversion easier (used to read CAN messages)
00059 typedef union _data2
00060 {
00061     uint16_t i[4];
00062     char s[8];
00063 } intchar;
00064 
00065 
00066 /* Input thread - Modifies state variables based on input */
00067 void input_runner(void const *argument) {
00068     while (true) {
00069         // If top button is pressed, don't accept other input
00070         if (!topButton) {
00071             // Debounce wait
00072             Thread::wait(100);
00073             if (!topButton) {
00074                 screen_mutex.lock();
00075                 demo++;
00076                 if (demo > 1) {
00077                     demo = 0;
00078                 }
00079                 screen_mutex.unlock();
00080             }
00081             // Don't accept other input while button is pressed
00082             while(!topButton) {
00083                 Thread::wait(100);
00084             }
00085         }
00086     }
00087 }
00088 
00089 
00090 // This is where your programs starts running
00091 int main()
00092 {
00093   // Initialize variables**
00094   int current_demo = demo;
00095   topButton.mode(PullUp);
00096   // Display CalSol logo
00097   display.FullScreenBMP(pic);
00098   Thread::wait(200);
00099 
00100   timer.start();
00101   
00102   // Start the button thread
00103   Thread button_thread(input_runner);
00104   
00105   // Main thread
00106   while(1) {
00107     // First, check if the state has changed, if so, wipe the screen
00108     int changed = 0;
00109     screen_mutex.lock();
00110     if (current_demo != demo)
00111     {
00112         changed = 1;
00113     }
00114     current_demo = demo;
00115     screen_mutex.unlock();
00116     
00117     // Wipe the screen
00118     if (changed)
00119     {
00120         display.ClearScreen();
00121         changed = 0;
00122     }
00123     
00124     // Now run the actual program
00125     switch(current_demo)
00126     {
00127         // Demo 0: Just display the CalSol logo
00128         case 0:
00129             if(timer.read_ms() > 500)
00130             {
00131                 display.FullScreenBMP(pic);
00132                 timer.reset();
00133             }
00134             break;
00135         
00136         // Demo 1: Display a mock speedometer, with battery level
00137         case 1:
00138             //Initialize variables
00139             speed = newSpeed = 60;
00140             amperage = newAmperage = 900;
00141             voltage = newVoltage = MaxVoltage;
00142             
00143             setupScreen();
00144             testTimer.start();
00145             
00146             //Display values as they are being changed
00147             while (true)
00148             {
00149                 /* This part tests the printing
00150                 
00151                 //Randomly selects values between appropriate ranges.
00152                 speed = (int)(rand()%200);
00153                 amperage = (int)(rand()%1000);
00154                 voltage = (int)(rand()%100);
00155                 
00156                 //Changes values from 1 to 3 or 4 digits to test proper spacing and erasing with changing num of digits
00157                 if (testTimer.read_ms()%1000 == 0)
00158                 {
00159                     switch ((testTimer.read_ms()/1000)%4)
00160                     {
00161                         case 0: //1 digit
00162                             newSpeed = (int)(rand()%9)+1;
00163                             newAmperage = (int)(rand()%9)+1;
00164                             break;
00165                         case 3: //2 digits
00166                             newSpeed = (int)(rand()%90)+10;
00167                             newAmperage = (int)(rand()%90)+10;
00168                             break;
00169                         case 2: //3 digits
00170                             newSpeed = (int)(rand()%900)+100;
00171                             newAmperage = (int)(rand()%900)+100;
00172                             break;
00173                         case 1: //4 digits
00174                             newSpeed = (int)(rand()%90)+100;
00175                             newAmperage = (int)(rand()%900)+1000;
00176                             break;
00177                         default: break;
00178                     }
00179                 }*/
00180                 
00181                 //Keeps screen from updating too much
00182                 if (testTimer.read_ms()%1000==0)
00183                 {
00184                     /* More printing testing
00185                     
00186                     //Randomly increases or decreases values within a small range
00187                     newSpeed += (int)((rand()%5)-2);
00188                     newAmperage += (int)((rand()%21)-10);
00189                     newVoltage += (int)((rand()%3)-1);
00190                     
00191                     //Keeps voltage between allowed values
00192                     if (newVoltage < MinVoltage || newVoltage > MaxVoltage)
00193                         newVoltage = MaxVoltage;
00194                     */
00195                         
00196                     readFromCAN();
00197                     
00198                     updateBattery(newVoltage);
00199                     
00200                     //Updates speed
00201                     display.SelectFont(MyPhone_40, BLACK, ReadData);
00202                     printCenteredInt(newSpeed, speed, 12, 16, 15, 23, 1, 3);
00203                     speed = newSpeed;
00204                     
00205                     //Updates amperage
00206                     display.SelectFont(MyPhone_20, BLACK, ReadData);
00207                     printCenteredInt(newAmperage, amperage, 76, 40+8, 8, 11, 1, 4);
00208                     amperage = newAmperage;
00209                 }
00210             }
00211             break;
00212         default: break;
00213         }
00214     }
00215 }
00216 
00217 void setupScreen()
00218 {
00219     //Draws grid lines to separate the screen.
00220     //Dimensions: (Speed) 70x64, (Battery) 57x42, (Amperage) 57x22 
00221     display.HLineShort(71, 42, 57, BLACK);
00222     display.VLineShort(71, 0, 64, BLACK);
00223     
00224     //This covers the stray black pixel...
00225     display.SetPixel(71-5, 42, WHITE);
00226   
00227     //Draws the outline for battery graphic. Dimensions: 40x24, 4x8
00228     display.RoundRectangle(82, 4, 40, 24, 4, BLACK);
00229     display.EmptyRectangle(78, 12, 78+4, 12+8, BLACK);
00230     
00231     //Prints MPH
00232     display.SelectFont(System5x7, BLACK, ReadData);
00233     display.GotoXY(26, 48);
00234     display.PrintString("MPH");
00235     
00236     //Print mAmp
00237     display.SelectFont(System5x7, BLACK, ReadData);
00238     display.GotoXY(114, 24+24);
00239     display.PrintString("mA");
00240     
00241     //Prints the percent sign
00242     display.GotoXY(108, 24+8);
00243     display.PrintString("%");
00244     
00245     //Draws initial shaded box for battery
00246     display.FullRectangle(86+(int)(((double)(100-((newVoltage - MinVoltage)/(MaxVoltage - MinVoltage)*100))/100.0)*32), 4+4, 86+32, 4+24-4, BLACK);
00247 }
00248 
00249 //This exists to fix the problem with the percentage printing that was occuring for unknown reasons.
00250 //Writes an int to the screen right-justified over another int.
00251 void printRightJustifiedPercentage(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits)
00252 {
00253     for (int digits = maxDigits; digits > 0; digits--)
00254     {
00255         if (newInt >= (int)pow(10.0, digits-1))
00256         {
00257             //Instead of checking if digits need to be erased, all digits will be erased
00258             //Erases digits that will not be covered by new text.
00259             display.FullRectangle(startX, startY, startX + (charWidth+charSpacing) * (maxDigits - digits), startY + charHeight, WHITE);
00260             display.GotoXY(startX + (charWidth+charSpacing) * (maxDigits - digits), startY);
00261             //Break out of loop.
00262             digits = -1;
00263         }
00264     }
00265     display.PrintNumber(newInt);
00266 }
00267 
00268 //Writes an int to the screen center-justified over another int.
00269 void printCenteredInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits)
00270 {
00271     for (int digits = maxDigits; digits > 0; digits--)
00272     {
00273         //If current value has "digits" number of digits
00274         if (newInt >= (int)pow(10.0, digits-1))
00275         {
00276             //If previous value had more digits than current value
00277             if (oldInt >= (int)pow(10.0, digits))
00278             {
00279                 //Erases all possible digits that could be on screen.
00280                 //**First parameter should logically be startX, but it starts erasing 1 pixel too far to the right for some reason. ???
00281                 display.FullRectangle(startX-1, startY, startX + maxDigits*(charWidth+charSpacing), startY + charHeight, WHITE);
00282             }
00283             display.GotoXY(startX + 0.5*((maxDigits - digits)*charWidth + (maxDigits - digits - 1)*charSpacing), startY);
00284             //Break out of loop.
00285             digits = -1;
00286         }
00287     }
00288     display.PrintNumber(newInt);
00289 }
00290 
00291 //Updates the battery graphic and prints corresponding percentage or voltage.
00292 void updateBattery(int newVoltage)
00293 {
00294     //These are needed for the battery graphic, even if the values won't be displayed.
00295     int percentage = (voltage - MinVoltage)/(MaxVoltage - MinVoltage)*100;
00296     int newPercentage = (newVoltage - MinVoltage)/(MaxVoltage - MinVoltage)*100;
00297     
00298     //This line fixes the printing problem with the percentage that was caused by drawing shaded rectangle. Might have something to do with the method WriteInstruction(int, int) used by both methods.
00299     display.SetPixel(88, 32, WHITE);
00300     
00301     // ** Problem: after a while of letting it run, sometimes a 0 will show up 1 pxl to the right of the hundreds place. But it gets erased when voltage drops enough
00302     //Prints percentage
00303     display.SelectFont(System5x7, BLACK, ReadData);
00304     printRightJustifiedPercentage(newPercentage, percentage, 88, 32, 5, 7, 1, 3);
00305     
00306     //Prints voltage -- currently NOT IN USE
00307     /*display.SelectFont(System5x7, BLACK, ReadData);
00308     display.GotoXY(108, 24+8);
00309     display.PrintString("V");
00310     display.SelectFont(System5x7, BLACK, ReadData);
00311     printRightJustifiedInt(newVoltage, voltage, 88, 32, 5, 7, 1, 3);*/
00312     
00313     updateBatteryGraphic(newPercentage, percentage);
00314     
00315     percentage = newPercentage;
00316     voltage = newVoltage;
00317 }
00318 
00319 //Changes shaded area of graphic to reflect current battery level. Dimensions 32x16
00320 void updateBatteryGraphic(int newPercentage, int percentage)
00321 {
00322     //Stores x-coordinates of shaded part of battery.
00323     int barX = 86+(int)(((double)(100-percentage)/100.0)*32);
00324     int newBarX = 86+(int)(((double)(100-newPercentage)/100.0)*32);
00325     
00326     //Draws increase in percentage.
00327     if (newBarX < barX)
00328     {
00329         display.FullRectangle(newBarX, 4+4, barX, 4+24-4, BLACK);
00330     }
00331     //Draws decrease.
00332     else
00333     {
00334         display.FullRectangle(86, 4+4, newBarX, 4+24-4, WHITE);
00335     }
00336 }
00337 
00338 //***This method has NOT BEEN TESTED.
00339 
00340 //Gets information about speed, voltage, current, and battery life through CAN.
00341 void readFromCAN()
00342 {
00343     const int speedID = 0x403;
00344     const int voltageAmperageID = 0x523;
00345     
00346     //Gets message from CAN.
00347     CANMessage msg;
00348     can.read(msg);
00349     int id = msg.id;
00350     
00351     switch (id)
00352     {
00353         case voltageAmperageID: //contains four messages: voltage 1 and 2 in volts, current 1 and 2 in mA. each is an int (2 bytes)
00354             
00355             //Read & store amperage value.
00356             intchar amp_data;
00357             for (int i = 0; i < 2; i++){
00358                 amp_data.s[i] = msg.data[i];
00359             }
00360             amperage = amp_data.i[0]; //***is this correct?
00361             
00362             //Read & store voltage/battery life value.
00363             floatchar volt_data;
00364             for (int i = 0; i < 2; i++){
00365                 volt_data.s[i] = msg.data[i+4];
00366             }
00367             voltage = volt_data.f[0];   //***should this be reading voltage 1 or voltage 2? (volt1.f[0 or 1])
00368             break;
00369             
00370         case speedID:
00371             //** This packet actually contains motor velocity in rpm as well as vehicle velociy in m/s. How do I get only the second part?
00372             floatchar speed_data;
00373             for (int i = 0; i < 4; i++) {
00374                 speed_data.s[i] = msg.data[i];
00375             }
00376             //Conversion factor: 1 m/s = 2.23693629 mph
00377             speed = (speed_data.f[2])*2.23693629; //** should this be a combination of f[2] and f[3]? 
00378             break;
00379         default: break;
00380     }
00381 }