Ryan Tseng
/
Display
main.cpp
- Committer:
- kagelump
- Date:
- 2012-06-18
- Revision:
- 0:b669c97da2c0
File content as of revision 0:b669c97da2c0:
// Display Test #include "KS0108.h" #include "calsolimage.h" #include "MyPhone_20.h" #include "MyPhone_40.h" #include "rtos.h" // Declare each of the things you're going to use // The display KS0108 display(p23,p21,p22,p20,p24,p25,p17,p18,p19,p30,p29,p28,p27,p26); // The button on the breadboard DigitalIn topButton(p13); // For printing things to the computer Serial pc(USBTX,USBRX); // Timers Timer timer; Timer testTimer; //Methods void readFromCAN(); void setupScreen(); void updateBattery(int newVoltage); void updateBatteryGraphic(int newPercentage, int percentage); void printCenteredInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits); void printCenteredInt(int newInt, int oldInt, int leftLimit, int rightLimit, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits); void printRightJustifiedInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits); // Constants //Maximum voltage for battery = 151.2 V (4.2V per cell, 36 cells total) const double MaxVoltage = 151.2; //Minimum voltage for battery = 108 V (3V per cell, 36 cells total) const double MinVoltage = 108; // Mutex and screen state Mutex screen_mutex; CAN can(p9, p10); int demo = 0; //Speed: int from 0 to 999, in mph int speed = 0, newSpeed = 0; //Voltage: int from MinVoltage to MaxVoltage, in volts int voltage = MinVoltage, newVoltage = MinVoltage; //Current: int from 0 to 9999, in milliAmps int amperage = 0, newAmperage = 0; //Union type to make float to char conversion easier (used to read CAN messages) typedef union _data { float f[2]; char s[8]; } floatchar; //Union type to make int to char conversion easier (used to read CAN messages) typedef union _data2 { uint16_t i[4]; char s[8]; } intchar; /* Input thread - Modifies state variables based on input */ void input_runner(void const *argument) { while (true) { // If top button is pressed, don't accept other input if (!topButton) { // Debounce wait Thread::wait(100); if (!topButton) { screen_mutex.lock(); demo++; if (demo > 1) { demo = 0; } screen_mutex.unlock(); } // Don't accept other input while button is pressed while(!topButton) { Thread::wait(100); } } } } // This is where your programs starts running int main() { // Initialize variables** int current_demo = demo; topButton.mode(PullUp); // Display CalSol logo display.FullScreenBMP(pic); Thread::wait(200); timer.start(); // Start the button thread Thread button_thread(input_runner); // Main thread while(1) { // First, check if the state has changed, if so, wipe the screen int changed = 0; screen_mutex.lock(); if (current_demo != demo) { changed = 1; } current_demo = demo; screen_mutex.unlock(); // Wipe the screen if (changed) { display.ClearScreen(); changed = 0; } // Now run the actual program switch(current_demo) { // Demo 0: Just display the CalSol logo case 0: if(timer.read_ms() > 500) { display.FullScreenBMP(pic); timer.reset(); } break; // Demo 1: Display a mock speedometer, with battery level case 1: //Initialize variables speed = newSpeed = 60; amperage = newAmperage = 900; voltage = newVoltage = MaxVoltage; setupScreen(); testTimer.start(); //Display values as they are being changed while (true) { /* This part tests the printing //Randomly selects values between appropriate ranges. speed = (int)(rand()%200); amperage = (int)(rand()%1000); voltage = (int)(rand()%100); //Changes values from 1 to 3 or 4 digits to test proper spacing and erasing with changing num of digits if (testTimer.read_ms()%1000 == 0) { switch ((testTimer.read_ms()/1000)%4) { case 0: //1 digit newSpeed = (int)(rand()%9)+1; newAmperage = (int)(rand()%9)+1; break; case 3: //2 digits newSpeed = (int)(rand()%90)+10; newAmperage = (int)(rand()%90)+10; break; case 2: //3 digits newSpeed = (int)(rand()%900)+100; newAmperage = (int)(rand()%900)+100; break; case 1: //4 digits newSpeed = (int)(rand()%90)+100; newAmperage = (int)(rand()%900)+1000; break; default: break; } }*/ //Keeps screen from updating too much if (testTimer.read_ms()%1000==0) { /* More printing testing //Randomly increases or decreases values within a small range newSpeed += (int)((rand()%5)-2); newAmperage += (int)((rand()%21)-10); newVoltage += (int)((rand()%3)-1); //Keeps voltage between allowed values if (newVoltage < MinVoltage || newVoltage > MaxVoltage) newVoltage = MaxVoltage; */ readFromCAN(); updateBattery(newVoltage); //Updates speed display.SelectFont(MyPhone_40, BLACK, ReadData); printCenteredInt(newSpeed, speed, 12, 16, 15, 23, 1, 3); speed = newSpeed; //Updates amperage display.SelectFont(MyPhone_20, BLACK, ReadData); printCenteredInt(newAmperage, amperage, 76, 40+8, 8, 11, 1, 4); amperage = newAmperage; } } break; default: break; } } } void setupScreen() { //Draws grid lines to separate the screen. //Dimensions: (Speed) 70x64, (Battery) 57x42, (Amperage) 57x22 display.HLineShort(71, 42, 57, BLACK); display.VLineShort(71, 0, 64, BLACK); //This covers the stray black pixel... display.SetPixel(71-5, 42, WHITE); //Draws the outline for battery graphic. Dimensions: 40x24, 4x8 display.RoundRectangle(82, 4, 40, 24, 4, BLACK); display.EmptyRectangle(78, 12, 78+4, 12+8, BLACK); //Prints MPH display.SelectFont(System5x7, BLACK, ReadData); display.GotoXY(26, 48); display.PrintString("MPH"); //Print mAmp display.SelectFont(System5x7, BLACK, ReadData); display.GotoXY(114, 24+24); display.PrintString("mA"); //Prints the percent sign display.GotoXY(108, 24+8); display.PrintString("%"); //Draws initial shaded box for battery display.FullRectangle(86+(int)(((double)(100-((newVoltage - MinVoltage)/(MaxVoltage - MinVoltage)*100))/100.0)*32), 4+4, 86+32, 4+24-4, BLACK); } //This exists to fix the problem with the percentage printing that was occuring for unknown reasons. //Writes an int to the screen right-justified over another int. void printRightJustifiedPercentage(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits) { for (int digits = maxDigits; digits > 0; digits--) { if (newInt >= (int)pow(10.0, digits-1)) { //Instead of checking if digits need to be erased, all digits will be erased //Erases digits that will not be covered by new text. display.FullRectangle(startX, startY, startX + (charWidth+charSpacing) * (maxDigits - digits), startY + charHeight, WHITE); display.GotoXY(startX + (charWidth+charSpacing) * (maxDigits - digits), startY); //Break out of loop. digits = -1; } } display.PrintNumber(newInt); } //Writes an int to the screen center-justified over another int. void printCenteredInt(int newInt, int oldInt, int startX, int startY, int charWidth, int charHeight, int charSpacing, int maxDigits) { for (int digits = maxDigits; digits > 0; digits--) { //If current value has "digits" number of digits if (newInt >= (int)pow(10.0, digits-1)) { //If previous value had more digits than current value if (oldInt >= (int)pow(10.0, digits)) { //Erases all possible digits that could be on screen. //**First parameter should logically be startX, but it starts erasing 1 pixel too far to the right for some reason. ??? display.FullRectangle(startX-1, startY, startX + maxDigits*(charWidth+charSpacing), startY + charHeight, WHITE); } display.GotoXY(startX + 0.5*((maxDigits - digits)*charWidth + (maxDigits - digits - 1)*charSpacing), startY); //Break out of loop. digits = -1; } } display.PrintNumber(newInt); } //Updates the battery graphic and prints corresponding percentage or voltage. void updateBattery(int newVoltage) { //These are needed for the battery graphic, even if the values won't be displayed. int percentage = (voltage - MinVoltage)/(MaxVoltage - MinVoltage)*100; int newPercentage = (newVoltage - MinVoltage)/(MaxVoltage - MinVoltage)*100; //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. display.SetPixel(88, 32, WHITE); // ** 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 //Prints percentage display.SelectFont(System5x7, BLACK, ReadData); printRightJustifiedPercentage(newPercentage, percentage, 88, 32, 5, 7, 1, 3); //Prints voltage -- currently NOT IN USE /*display.SelectFont(System5x7, BLACK, ReadData); display.GotoXY(108, 24+8); display.PrintString("V"); display.SelectFont(System5x7, BLACK, ReadData); printRightJustifiedInt(newVoltage, voltage, 88, 32, 5, 7, 1, 3);*/ updateBatteryGraphic(newPercentage, percentage); percentage = newPercentage; voltage = newVoltage; } //Changes shaded area of graphic to reflect current battery level. Dimensions 32x16 void updateBatteryGraphic(int newPercentage, int percentage) { //Stores x-coordinates of shaded part of battery. int barX = 86+(int)(((double)(100-percentage)/100.0)*32); int newBarX = 86+(int)(((double)(100-newPercentage)/100.0)*32); //Draws increase in percentage. if (newBarX < barX) { display.FullRectangle(newBarX, 4+4, barX, 4+24-4, BLACK); } //Draws decrease. else { display.FullRectangle(86, 4+4, newBarX, 4+24-4, WHITE); } } //***This method has NOT BEEN TESTED. //Gets information about speed, voltage, current, and battery life through CAN. void readFromCAN() { const int speedID = 0x403; const int voltageAmperageID = 0x523; //Gets message from CAN. CANMessage msg; can.read(msg); int id = msg.id; switch (id) { case voltageAmperageID: //contains four messages: voltage 1 and 2 in volts, current 1 and 2 in mA. each is an int (2 bytes) //Read & store amperage value. intchar amp_data; for (int i = 0; i < 2; i++){ amp_data.s[i] = msg.data[i]; } amperage = amp_data.i[0]; //***is this correct? //Read & store voltage/battery life value. floatchar volt_data; for (int i = 0; i < 2; i++){ volt_data.s[i] = msg.data[i+4]; } voltage = volt_data.f[0]; //***should this be reading voltage 1 or voltage 2? (volt1.f[0 or 1]) break; case speedID: //** This packet actually contains motor velocity in rpm as well as vehicle velociy in m/s. How do I get only the second part? floatchar speed_data; for (int i = 0; i < 4; i++) { speed_data.s[i] = msg.data[i]; } //Conversion factor: 1 m/s = 2.23693629 mph speed = (speed_data.f[2])*2.23693629; //** should this be a combination of f[2] and f[3]? break; default: break; } }