I'm currently attempting to replace delay() in my project so that i may perform other tasks while waiting on a particular event to fire.
The issue I'm having, is every example i've found using millis / elapsedmillis has everything inside the loop, where I'm trying to use it inside void buttons(). needless to say, either it's not going to work outside of loop, or I'm doing something ridiculous, and too tired, or too ignorant to see what i'm doing wrong..
The end goal is to have the button draw over the top of the existing one, wait 1000ms then draw the next button. (time interval will be changed later to sync with hardware spin down etc)
Here is the complete sketch, perhaps someone can show me a reliable way to replace delay in the buttons funciton:
#include <Adafruit_GFX.h>
#include <TouchScreen.h>
#include <stdint.h>
#include <SPI.h>
#include <SD.h>
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#include <elapsedMillis.h>
elapsedMillis timer0;
elapsedMillis sinceTime1;
elapsedMillis sinceTime2;
elapsedMillis sinceTime3;
#define debug = false;
//#define debug = true;
#if defined(__SAM3X8E__)
#undef __FlashStringHelper::F(string_literal)
#define F(string_literal) string_literal
#endif
// most mcufriend shields use these pins and Portrait mode:
uint8_t YP = A1; // must be an analog pin, use "An" notation!
uint8_t XM = A2; // must be an analog pin, use "An" notation!
uint8_t YM = 6; // can be a digital pin
uint8_t XP = 7; // can be a digital pin
uint8_t Landscape = 0;
uint16_t TS_LEFT = 120;
uint16_t TS_RT = 940;
uint16_t TS_TOP = 940;
uint16_t TS_BOT = 180;
#define MINPRESSURE 10
#define MAXPRESSURE 1000
// For better pressure precision, we need to know the resistance
// between X+ and X- Use any multimeter to read it
// For the one we're using, its 250 ohms across the X plate
TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
// Assign human-readable names to some common 16-bit color values:
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
int16_t BOXSIZE;
int16_t PENRADIUS = 3;
uint16_t oldcolor, currentcolor;
#define SD_SCK 13
#define SD_MISO 12
#define SD_MOSI 11
#define SD_CS 10
// In the SD card, place 24 bit color BMP files (be sure they are 24-bit!)
void setup() {
// Init TouchScreen
ts = TouchScreen(XP, YP, XM, YM, 300); //call the constructor AGAIN with new values.
BOXSIZE = tft.width() / 6;
tft.fillScreen(BLACK);
// put your setup code here, to run once:
Serial.begin(9600);
tft.reset();
uint16_t identifier = tft.readID();
if (identifier == 0x7789) {
//Serial.println(F("Found ST7789V LCD driver"));
TS_LEFT = 120; TS_RT = 940; TS_TOP = 940; TS_BOT = 180;
Landscape = 1;
} else {
//Serial.print(F("Unknown LCD driver chip: "));
//Serial.println(identifier, HEX);
return;
}
//Serial.print(F("Found LCD driver chip ID: "));
//Serial.println(identifier, HEX);
tft.begin(identifier);
//Serial.print(F("Initializing SD card..."));
if (!SD.begin(SD_CS, SD_MOSI, SD_MISO, SD_SCK)) {
Serial.println(F("failed!"));
return;
}
//Serial.println(F("OK!"));
tft.begin(identifier);
tft.setRotation(3);
BOXSIZE = tft.width() / 6;
tft.fillScreen(BLACK);
bmpDraw("splash.bmp", 80, 20);
delay(5000);
loadhome();
}
void loop() {
//DO STUFF HERE
//Testing Text stuff here
tft.setTextColor(BLACK);
tft.setTextSize(2);
tft.setCursor(15, 33);
tft.print("123.456");
tft.setTextColor(BLACK);
tft.setCursor(115, 33);
tft.print("543.210");
tft.setTextColor(BLACK);
tft.setCursor(215, 33);
tft.print("789.654");
buttons();
}
void loadhome(){
tft.setRotation(3);
BOXSIZE = tft.width() / 6;
tft.fillScreen(BLACK);
bmpDraw("cell.bmp", 10, 25);
bmpDraw("cell.bmp", 110, 25);
bmpDraw("cell.bmp", 210, 25);
bmpDraw("stop.bmp", 15, 175);
bmpDraw("locked.bmp", 90, 175);
bmpDraw("play.bmp", 165, 175);
bmpDraw("home.bmp", 240, 175);
bmpDraw("coolstp.bmp", 15, 105);
bmpDraw("spinstp.bmp", 240, 105);
tft.setTextColor(RED);
tft.setTextSize(3);
tft.setCursor(50, 3);
tft.print("X");
tft.setTextColor(RED);
tft.setCursor(150, 3);
tft.print("Y");
tft.setTextColor(RED);
tft.setCursor(250, 3);
tft.print("Z");
}
int homer = 0;
int play = 1;
int lock = 0;
int cool = 0;
int spin = 0;
const int interval = 1000;
unsigned long curMillis; //Current millis
void buttons(){
//Touchscreen stuff
TSPoint p = ts.getPoint();
// if sharing pins, you'll need to fix the directions of the touchscreen pins
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
p.x = map(p.x, TS_LEFT, TS_RT, 0, tft.width());
p.y = map(p.y, TS_TOP, TS_BOT, 0, tft.height());
/*
//Use to map buttons
//Be sure to mark out button code before use!!
if (p.z > MINPRESSURE && p.z < MAXPRESSURE) {
Serial.print(F("p.y ="));
Serial.print(p.y);
Serial.println("");
Serial.print(F("p.x ="));
Serial.print(p.x);
Serial.println("");
}
*/
// Begin Buttons
//Coolant Button
if (p.y > 110 && p.y < 170 && p.x > 250 && p.x < 300) { // if stop area is pressed
if(cool == 0){
bmpDraw("coolen.bmp", 15, 105);
//Serial.println(F("Coolant Button Pressed!"));
cool = 1;
} else {
bmpDraw("coolerr.bmp", 15, 105);
sinceTime1 = 0;
//delay(500); //replacing with millis()
if (sinceTime1 >= 1000) {
bmpDraw("coolstp.bmp", 15, 105);
//Serial.println(F("Coolant Button Pressed!"));
cool = 0;
}
}
}
//Stop Button
if (p.y > 185 && p.y < 235 && p.x > 250 && p.x < 300) { // if stop area is pressed
//Serial.println(F("Stop Button Pressed!"));
Serial.write(0x18);
Serial.print("\n");
}
//Lock Button
if (p.y > 185 && p.y < 235 && p.x > 182 && p.x < 234) { // if stop area is pressed
if(lock == 0){
Serial.print("$X\n");
bmpDraw("unlocked.bmp", 90, 175);
//Serial.println(F("Lock/Unlock Button Pressed!"));
lock = 1;
} else {
Serial.print("$X\n");
bmpDraw("locked.bmp", 90, 175);
//Serial.println(F("Lock/Unlock Button Pressed!"));
lock = 0;
}
}
//Play-Pause Button
if (p.y > 185 && p.y < 235 && p.x > 110 && p.x < 160) { // if stop area is pressed
if(play == 0){
Serial.print("~\n");
bmpDraw("play.bmp", 165, 175);
//Serial.println(F("Play/Pause Button Pressed!"));
play = 1;
} else {
Serial.print("!\n");
bmpDraw("pause.bmp", 165, 175);
//Serial.println(F("Play/Pause Button Pressed!"));
play = 0;
}
}
//Home Button
if (p.y > 185 && p.y < 235 && p.x > 35 && p.x < 90) { // if stop area is pressed
if(homer == 0){
bmpDraw("homeg.bmp", 240, 175);
//Serial.println(F("Home Button Pressed!"));
homer = 1;
} else {
Serial.print("$H\n");
bmpDraw("homey.bmp", 240, 175);
sinceTime2 = 0;
//delay(500); //replacing with millis()
if (sinceTime2 >= 1000) {
bmpDraw("homer.bmp", 240, 175);
}
//delay(500); //replacing with millis()
sinceTime2 = 0;
if (sinceTime2 >= 1000) {
//delay(750);
bmpDraw("homeg.bmp", 240, 175);
//Serial.println(F("Home Button Pressed!"));
}
homer = 1;
}
}
//Spindle Button
if (p.y > 110 && p.y < 170 && p.x > 35 && p.x < 90) { // if stop area is pressed
if(spin == 0){
bmpDraw("spinen.bmp", 240, 105);
//Serial.println(F("Spindle Button Pressed!"));
spin = 1;
} else {
bmpDraw("spinerr.bmp", 240, 105);
sinceTime3 = 0;
//delay(500); //replacing with millis()
if (sinceTime3 >= 1000) {
bmpDraw("spinstp.bmp", 240, 105);
//Serial.println(F("Spindle Button Pressed!"));
}
spin = 0;
}
}
}
#define BUFFPIXEL 15
void bmpDraw(char *filename, int x, int y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)
uint8_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t lcdidx = 0;
boolean first = true;
if((x >= tft.width()) || (y >= tft.height())) return;
//Serial.println();
//Serial.print(F("Loading image '"));
//Serial.print(filename);
//Serial.println('\'');
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.println(F("File not found"));
return;
}
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
read32(bmpFile);
//Serial.println(F("File size: "));
//Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
//Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
// Read DIB header
read32(bmpFile);
//Serial.print(F("Header size: "));
//Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
//Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
goodBmp = true; // Supported BMP format -- proceed!
// Serial.print(F("Image size: "));
// Serial.print(bmpWidth);
// Serial.print('x');
// Serial.println(bmpHeight);
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;
// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x+w-1, y+h-1);
for (row=0; row<h; row++) { // For each scanline...
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col=0; col<w; col++) { // For each column...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
// Push LCD buffer to the display first
if(lcdidx > 0) {
tft.pushColors(lcdbuffer, lcdidx, first);
lcdidx = 0;
first = false;
}
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
lcdbuffer[lcdidx++] = tft.color565(r,g,b);
} // end pixel
} // end scanline
// Write any remaining data to LCD
if(lcdidx > 0) {
tft.pushColors(lcdbuffer, lcdidx, first);
}
// Serial.print(F("Loaded in "));
//Serial.print(millis() - startTime);
//Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println(F("BMP format not recognized."));
}
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
My thinking was to time how long it takes the spindle to spin down and stop, use that time for the timer..
So an example would be, the spinde takes 5 seconds to slow down and stop, when user push the button, the command to stop the spindle is sent, the button is redrawn from green(on) to yellow(slowing) then to red(stopped) after 5secs. same for coolant, and homing.
I'm trying to use something other than delay, as i need serial to update the X, Y and Z positions. and have access to stop in case of emergency
– ArcAiN6 Jan 14 '16 at 00:08