/* Displays a graphical voltmeter on a 480 by 320 TFT LCD screen, using the UTFT libraries. Uses two 16 channel Multiplexers to interogate each cell of the battery in turn, using pin a0 as input, using pins 3,4,5 and 6 to select which cell, and pin 2 as latch. Uses port manipulation to set control pins and latch pin for mux chips. Displays cell number, voltage and a bar graph for quick comparison. Voltages less that a low threshohold or above a high theshhold are shown on the bar graph in red otherwise in green. A buzzer sounds on pin 7 if above or below threshold The current time and the 16 voltages are logged into a datalogger file on the SD card. If the unit is powered on without any cells attached, a start up routine allows the contents of the log file to be output to the serial monitor, or for the data log to be cleared Sound audible alarm when threshold crossed on any cell Dave Glover 10/11/2015 */ // This program requires the UTFT library. // #include // Declare which fonts we will be using extern uint8_t hallfetica_normal[]; extern uint8_t SmallFont[]; // Specify the model of TFT screen and pins used UTFT myGLCD(HX8357B, 38, 39, 40, 41); // This program uses SPI to update the SD card on the TFT Sheild #include #include //select the pin for the SD card update const int chipSelect = 53; //Create variables and constants for use in main code. //int variables int sensorValue = 0; // variable to store the value coming from the sensor int thisLine = 0; int thisHeight; int barLength; int lineHeight; int incomingByte = 0; // for incoming serial data int noOfCells; int needToBeep; int beepPin = 7; //byte for use in loop and PORTD bitwise shift int thisCell = 0; byte muxCell = 0; //floats for voltages float voltage; float totalVoltage; float lowTotVoltage; float highTotVoltage; //constants const long intervalDisplay = 2000; const long intervalLog = 10000; const float lowCellVoltage = 1.9; const float highCellVoltage = 3.65; const int graphStart = 45; const int lastLine = 455; //unsigned longs for time calculations unsigned long currentMillis; unsigned long previousMillis = 0; unsigned long previousMillisLog = 0; // strings String dataString = ""; String titleString = ""; int response = 0; // Set up function void setup() { Serial.begin(9600); //find the last none zero pin between A0 and A15 //to determine the number of cells in the battery noOfCells = 0; //set digital pins 6,5,4,3 and 2 as output, leave pins 7,1 and 0 as they are DDRD = DDRD | B01111100; //read the input from each cell, to determine the number of cells attached for (thisCell = 0; thisCell < 16; thisCell++) { //shift this cell left 3 bits to create cell number in pins 6,5,4,3 and set latch pin 2 to low (on) muxCell = (thisCell << 3); PORTD = (muxCell); //read the value of this cell sensorValue = analogRead(0); //set the latch pin (D2) high (off) PORTD = B00000100; if (sensorValue > 0) { noOfCells = thisCell + 1; } } //set up variables based on number of cells lineHeight = 384 / noOfCells; highTotVoltage = (highCellVoltage) * float(noOfCells); lowTotVoltage = (lowCellVoltage) * float(noOfCells); titleString += String(noOfCells); titleString += " Cell Voltmeter"; //initialise the LCD screen, and paint constant features myGLCD.InitLCD(PORTRAIT); myGLCD.clrScr(); myGLCD.fillScr(VGA_NAVY); myGLCD.setColor(VGA_WHITE); myGLCD.setBackColor(VGA_NAVY); myGLCD.setFont(hallfetica_normal); //headings myGLCD.print(titleString, CENTER, 0); myGLCD.print("Cell Volts", 0, 23); //bar graph scale top myGLCD.setFont(SmallFont); myGLCD.print("0...", 160, 28); myGLCD.print("1...", 192, 28); myGLCD.print("2...", 224, 28); myGLCD.print("3...", 256, 28); myGLCD.print("4...", 288, 28); //bar graph scale lower myGLCD.print("0...", 160, 430); myGLCD.print("1...", 192, 430); myGLCD.print("2...", 224, 430); myGLCD.print("3...", 256, 430); myGLCD.print("4...", 288, 430); //bar graph scale total voltage myGLCD.print("0....", 160, lastLine - 11); myGLCD.print(String(noOfCells), 192, lastLine - 11); myGLCD.print("..", 208, lastLine - 11); myGLCD.print(String(noOfCells * 2), 224, lastLine - 11); myGLCD.print("..", 240, lastLine - 11); myGLCD.print(String(noOfCells * 3), 256, lastLine - 11); myGLCD.print("..", 272, lastLine - 11); myGLCD.print(String(noOfCells * 4), 288, lastLine - 11); myGLCD.print("..", 304, lastLine - 11); myGLCD.setFont(hallfetica_normal); //initialse the SD card pinMode(53, OUTPUT); if (!SD.begin(chipSelect)) { // Serial.println("Card failed, or not present"); // don't do anything more: return; } // if no cells are detected, then it is assumed that the device is connected to a PC with // a serial monitor, where logs may be displayed or cleared if (noOfCells == 0) { Serial.println ("Enter P to print log, or C to clear log, or X to exit"); //loop until X is entered while (response != 88) { while (Serial.available() == 0) ; // Wait here until input buffer has a character { response = Serial.read(); //if P is entered display entire log if (response == 80) { File dataFile = SD.open("datalog.txt"); if (dataFile) { while (dataFile.available()) { Serial.write(dataFile.read()); } dataFile.close(); } else { Serial.println ("no log file to print"); } } else { if (response == 67) { //if C is entered clear log, if it exists Serial.println("C"); File dataFile = SD.open("datalog.txt"); if (SD.exists("datalog.txt")) { SD.remove("datalog.txt"); Serial.println("log file removed"); } else { Serial.println("no log file exists"); } } } } } while (1==1){} } } // main processing loop void loop() { // if it is the right intervalDisplay since the last display, display it all again //get the time currentMillis = millis(); //switch off need to beep needToBeep = 0; if (currentMillis - previousMillis >= intervalDisplay) { // save the last time you blinked the LED previousMillis = currentMillis; // zeroise the total voltage totalVoltage = 0; // initialis the datalogger string dataString = String(currentMillis / 1000); //set the first line position thisHeight = graphStart; //loop through pins inout cells for (thisCell = 0; thisCell < noOfCells; thisCell++) { //shift this cell left 3 bits to create cell number in pins 6,5,4,3 and set latch pin 2 to low (on) muxCell = (thisCell << 3); PORTD = (muxCell); //read the next cell through pin a0 //read it 10 times and take an avdrage sensorValue = 0; for (int counter = 0; counter < 10; counter++) { sensorValue += analogRead(0); delay (5); } //set the latch pin (D2) high (off) PORTD = B00000100; //average the sensor value sensorValue = sensorValue / 10; //calculate the voltage based on the pin value, pin voltage and number of bits voltage = (((sensorValue * 5.00) / 1024.00)); //increment the total voltage totalVoltage = totalVoltage + voltage; // add voltage to data string dataString += ","; dataString += String(voltage); //calculate the bar length barLength = int(voltage * 32); //print the cell number myGLCD.printNumI(thisCell + 1, 0, thisHeight, 2); //clear the last bar off the screen myGLCD.setColor(VGA_NAVY); myGLCD.fillRect(160, thisHeight + 1, 319, thisHeight + lineHeight - 2); //if voltage is above or below threshold show in red if (voltage < lowCellVoltage or voltage > highCellVoltage) { myGLCD.setColor(VGA_RED); //If any cell is outside thresholds, set the need to beep needToBeep = 1; } //othewise in green else { myGLCD.setColor(VGA_GREEN); } //draw the bar in chosen colour myGLCD.fillRect(160, thisHeight + 1, barLength + 160, thisHeight + lineHeight - 2); //reset the fill colour to white myGLCD.setColor(VGA_WHITE); //print the voltage value myGLCD.printNumF(voltage, 2, 60, thisHeight, '.', 5, ' '); //work out the y co-ordinate for the next line thisHeight += lineHeight; } //end of FOR loop //when all pins are processed, show total voltage myGLCD.print("Tot", 0, lastLine); myGLCD.printNumF(totalVoltage, 2, 60, lastLine); //show bar graph for total voltage //clear the last bar off the screen myGLCD.setColor(VGA_NAVY); myGLCD.fillRect(160, lastLine + 1, 319, lastLine + lineHeight - 2); //if total voltage is above or below threshold show in red if (totalVoltage < lowTotVoltage or totalVoltage > highTotVoltage) { myGLCD.setColor(VGA_RED); } //othewise in green else { myGLCD.setColor(VGA_GREEN); } //calculate bar length barLength = int((totalVoltage / noOfCells) * 32.00); //show bar graph for total voltage myGLCD.fillRect(160, lastLine + 1, barLength + 160, lastLine + lineHeight - 2); //reset colour to white myGLCD.setColor(VGA_WHITE); //If any cell was above or below threshold //beep at 512 hertz on buzzer pin for a portion of the display interval if (needToBeep == 1) { tone(beepPin, 512, intervalDisplay / 2); } if (currentMillis - previousMillisLog >= intervalLog) { // save the last time logged previousMillisLog = currentMillis; // open the data logger file. note that only one file can be open at a time, // so you have to close this one before opening another. File dataFile = SD.open("datalog.txt", FILE_WRITE); // if the file is available, write to it: if (dataFile) { dataFile.println(dataString); dataFile.close(); // print to the serial port too: // Serial.println(dataString); } // if the file isn't open, pop up an error: else { //Serial.println("error opening datalog.txt"); } } } }