flyingbrick

Arduino stuff/ programing/so cheap

Recommended Posts

OK so got my arduino nano yesterday- I have one with header pins soldered to the bottom for breadboard setup and another with no pins that i will maybe use in the vehicle.

Yesterday was a write off as it took me AGES to actually get the unit communicating with the PC, and a few hours of head scratching tonight has got me far further than i thought possible.

 

First of all- the TFT requires 3.3v for the screens LED... great because the NANO doesnt have onboard 3.3v output. Instead  i have had to use a breadboard PSU which isn't a bad thing as it means i can use it to output 5v and 3.3v from a 9v when its not plugged into the PC

I started by getting some adafruit example code to run. Initially its like WTF IS THIS and i found the easiest way to figure it out was to DELETE code piece by piece to see what changed/failed and then work out why...

eventually i had it broken down to a triangle drawing command- figured out how they were manipulating it and changed the numbers to give some nice looking arrows.

And then headscratched some more to figure out the switch, delay, loop stuff. Extremely basic but momentous when i got to this point.

 

The arrows can become more fancy later.. im still trying to work out how to make it do more than one thing at a time etc etc.

 

 

 

  • Like 3

Share this post


Link to post
Share on other sites

 

 

I was showing my wife... she shook my hand, held back some lols and said 

 

congratulations you have rebuilt the wheel

 

what an egg

  • Like 4

Share this post


Link to post
Share on other sites
18 hours ago, flyingbrick said:

.. im still trying to work out how to make it do more than one thing at a time etc etc.

Right, (for you and for onlookers):

The trick here is that delay() is not your friend. While the processor is stuck in the buzz loop waiting for e.g 1000ms, there's 16.000 million processor cycles go un-used.

You need to use drop through code. To see one way to go about this, compare the file - examples - basic - blink code with the code in file - examples - digital -BlinkWithoutDelay.

As long as your code keeps coming back to check if it's time to 'blink', you can do other stuff in the background. etc.

  • Like 4

Share this post


Link to post
Share on other sites

Perfect thanks! Will try work this out tonight.

At the moment it's kinda cool because if you indicate AND use hazards it will alternate between the two.. however I knew this would cause issues with adding other icons.

Thanks man!

Share this post


Link to post
Share on other sites

OK @h4nd i could seriously use your help here.

I could not figure out how to get the no-delay style of things to work. I had it running poorly (can show code)

I realize that new button presses are not picked up until the end of the currently operating piece of code but this delay is not a problem in this situation (im making excuses)

So here is my new problem. When i run the last block of code and the button is held down it flashes the B because it is refreshing things over and over and over.

So is there an easy way of making it run once per button press? i'm guessing you know how these screens work- they hold the current picture unless you cover over it with something else so if it sends the red box then the letter B and then NOTHING ELSE until the button is released it'd be OK.

Quote

#include <Adafruit_GFX.h>    
#include <Adafruit_ST7735.h> 
#include <SPI.h>

#define TFT_CS     10
#define TFT_RST    8 
#define TFT_DC     9

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);


float p = 3.1415926;

const int hazardbuttonpin = 2;    
const int rightbuttonpin = 3;
const int leftbuttonpin = 4;
const int batbuttonpin = 5;

int buttonState1 = 0;   
int buttonState2 = 0;
int buttonState3 = 0;     
int buttonState4 = 0;

void setup(void) {
 
tft.initR(INITR_BLACKTAB);  

  pinMode(hazardbuttonpin, INPUT);
  pinMode(rightbuttonpin, INPUT);
  pinMode(leftbuttonpin, INPUT);
  pinMode(batbuttonpin, INPUT);
  
 tft.fillScreen(ST7735_BLACK);
}
void loop() {

buttonState1 = digitalRead(hazardbuttonpin);
 if (buttonState1 == HIGH) {

  // indicate LEFT
  tft.fillTriangle(3, 25, 50, 3, 50, 47, ST7735_GREEN);
 // indicate RIGHT
  tft.fillTriangle (78, 3, 125, 25, 78, 47, ST7735_GREEN);
delay (700);
  // cover LEFT
  tft.fillTriangle(3, 25, 50, 3, 50, 47, ST7735_BLACK);
 // cover RIGHT
  tft.fillTriangle (78, 3, 125, 25, 78, 47, ST7735_BLACK);
delay (700);
 }

buttonState2 = digitalRead(rightbuttonpin);
 if (buttonState2 == HIGH) {
 // indicate RIGHT
  tft.fillTriangle (78, 3, 125, 25, 78, 47, ST7735_GREEN);
delay (700);
 // cover RIGHT
  tft.fillTriangle (78, 3, 125, 25, 78, 47, ST7735_BLACK);
delay (700);
 }

buttonState3 = digitalRead(leftbuttonpin);
 if (buttonState3 == HIGH) {
  // indicate LEFT
  tft.fillTriangle(3, 25, 50, 3, 50, 47, ST7735_GREEN);
delay (700);
 // cover LEFT
  tft.fillTriangle(3, 25, 50, 3, 50, 47, ST7735_BLACK);
delay (700);
 }


buttonState4 = digitalRead(batbuttonpin);
 if (buttonState4 == HIGH) {
 // indicate bat
  tft.fillRect (3, 113, 58, 44, ST7735_RED); 
 tft.drawChar(22, 121, 'B', ST7735_BLACK, ST7735_RED, 4);

 } else   tft.fillRect (3, 113, 60, 157, ST7735_BLACK);

 }

 

Share this post


Link to post
Share on other sites

You sure you want to do this? You could totally do it mechanically with VW semaphores. In fact, you'd be half finished by now:

Failing that:

I suggest a top level cleanup:

0/ yep, you can do interrrupts, for 'just when changed', but you prolly don't need to here

1/ pins are input by default, can just lose the code.

2/ depending on button presses, your code may take ~0ms to run, or 4200ms ( yep 4.2 seconds) + drawing time (was a bit sluggish? 1/10 seconds?)

So to rough it out:

Quote

#include <Adafruit_GFX.h>    
#include <Adafruit_ST7735.h> 
#include <SPI.h>

#define TFT_CS     10
#define TFT_RST    8 
#define TFT_DC     9

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS,  TFT_DC, TFT_RST);

const int hazardbuttonpin = 2;    
const int rightbuttonpin = 3;
const int leftbuttonpin = 4;
const int batbuttonpin = 5;

void setup(void)
{
 tft.initR(INITR_BLACKTAB);   
 tft.fillScreen(ST7735_BLACK);
}

unsigned long flashtime;
#define FLASH_INTERVAL 700

void loop()
{

    somevariableTypeFromTftLibrary colour;
    if (millis() > flashtime)           // will glitch after 49 days
    {   // it's time to do display stuff
        flashtime += FLASH_INTERVAL;    // setup for next time

        // set colour
        if ((millis()/700) & 1)           // on and off at 700ms (bitwise AND)
        {   // on
            colour = ST7735_GREEN;
        }
        else
        {
            colour = ST7735_BLACK;
        }
        
        // determine which to show
        if (digitalRead(hazardbuttonpin))
        {
            indicateLEFT(colour);
            indicateRIGHT(colour);
        }
        else // not hazard, is it Right?
        {
            if (digitalRead(rightbuttonpin))
            {
                indicateRIGHT(colour);
            }   
            else // not right, is it Left?
            {
                if (digitalRead(rightbuttonpin))
                {
                    indicateLEFT(colour);
                }
            }       
        }
        else // no turn signals
        {   // off
            indicateLEFT(ST7735_BLACK);
            indicateRIGHT(ST7735_BLACK);
        }
        
        // battery
        if(digitalRead(batbuttonpin))
        {
            // indicate bat
            tft.fillRect (3, 113, 58, 44, ST7735_RED); 
            tft.drawChar(22, 121, 'B', ST7735_BLACK, ST7735_RED, 4);
        } 
        else
        {
            tft.fillRect (3, 113, 60, 157, ST7735_BLACK);
        }
    }   // or just go on to do other stuff
    
    // other stuff
}

You'll note, I replaced tabs with spaces, so it indents ok here, and in other editors. I've used non-K&R braces style,  to help make clear which 'else' belongs to which 'if'.

Of course, now you'll have to make up the indicateLEFT() and indicateRIGHT() subroutines, which will mean going to have a look at the TFT library to find out what data type the colour parameters is, but, you were going to have a squizz at the library, anyway, right? Just to make sure it hadn't been hammered together by dyslexic monkeys.

I've simplified a couple of things there. You could fix the millis rollover, but I'm assuming it won't matter. There can be good reason to read all your inputs into state variables for sync, or for later processing (filtering, etc), but I've just simplified it into similar named variables ditched them.

You'll need to have a think about resetting the display when the button changes state during an on / off, etc

You may want to tinker with the timing, so it starts immediately, not waiting for up to 1.4 seconds (worst case), but I'm just showing   a few alternatives.

If you just want to update on button presses, a usual ploy is to store the last button state, and compare to now, if different, store the new, and do that thing you needed, like update displays, or dump the caltrops, or whatever.

I know it's not a complete solution, I hope this gives some useful style pointers.

  • Like 2

Share this post


Link to post
Share on other sites

Thanks mate, very kind of you to spell it all out for me!

....now if only I wasn't stuck at work today.... 

Edit.

Have read through that quite a few times to try figure out how it works.

When you say read through the library- is the library opened in the Arduino editor like any other code?

When you say reset the screen during a button state change during on/off....what exactly do you mean? I have fillscreen black in the setup which kinda erases everything 

Share this post


Link to post
Share on other sites
9 hours ago, flyingbrick said:

When you say read through the library- is the library opened in the Arduino editor like any other code?

Should be in the Arduno\library folder? Maybe the arduino IDE will open it, or notepad++ or something...

Quote

When you say reset the screen during a button state change during on/off....what exactly do you mean? I have fillscreen black in the setup which kinda erases everything 

If the hazards pin changes from on to off during the 700ms after it draws the indicators 'on', then the code path for drawing the indicators 'off' won't be called. That's a bug...

Share this post


Link to post
Share on other sites
On 2017-7-28 at 22:23, h4nd said:

You sure you want to do this? You could totally do it mechanically with VW semaphores. In fact, you'd be half

Haha, I made a tutorial a few years ago on fixing these, rewinding the coil take 1200 loops

  • Like 2

Share this post


Link to post
Share on other sites

Thanks guys.

I have moved on to an oled screen.. FAR FAR FAR nicer than the TFT I was using- because the TFT has terrible viewing angle. @ajg193 thanks I'll look into those too

  • Like 1

Share this post


Link to post
Share on other sites

Hi @Scrubb. Is that directed at me or someone else?

 

@h4nd I could never get the drop-through code to work nicely and have moved onto trying other new things. I guess its not ever going to be a real issue for this code because its so basic AND there is nothing critical happening that will get upset if there is a small delay. (eg If the battery icon takes half a second to pop up- who cares)

I have tried using the software you suggested but i'm a real Barry these days- the basic normal IDE is so much easier for me to navigate round and learn in.

I haven't had a day off for a while so progress is slow but this is the code I now have working well enough to prove I can do it. No longer using external resistors, using an OLED rather than TFT and drawing the icons using the line command rather than triangles and squares.

Only two icons because they are being redone again once the larger OLED arrives.

Compared to the TFT the OLED seems to have an extremely slow communication speed with the arduino. Even the various Youtube tutorials show the same issue but offer no explanation. This is the reason for changing from SOLID objects to simple outlines- must be less data to send.

 

Quote


#define sclk 13
#define mosi 11
#define cs   10
#define rst  9
#define dc   8


#define    BLACK           0x0000
#define    BLUE            0x001F
#define    RED             0xF800
#define    GREEN           0x07E0


#include <Adafruit_GFX.h>
#include <Adafruit_SSD1331.h>
#include <SPI.h>

Adafruit_SSD1331 display = Adafruit_SSD1331(cs, dc, mosi, sclk, rst);

const int hazardbuttonpin = 4;
const int rightbuttonpin = 3;
const int leftbuttonpin = 2;
const int batbuttonpin = 5;

int buttonState1 = 0;
int buttonState2 = 0;
int buttonState3 = 0;
int buttonState4 = 0;

void setup(void) {

  display.begin();
  display.fillScreen(BLACK);

  pinMode(hazardbuttonpin, INPUT_PULLUP);
  pinMode(rightbuttonpin, INPUT_PULLUP);
  pinMode(leftbuttonpin, INPUT_PULLUP);
  pinMode(batbuttonpin, INPUT_PULLUP);
}

void loop() {

  buttonState4 = digitalRead(batbuttonpin);
  if (buttonState4 == LOW) {
    BATT();
  }

  buttonState4 = digitalRead(batbuttonpin);
  if (buttonState4 == HIGH) {
    HIDEBATT();
  }

  buttonState3 = digitalRead(leftbuttonpin); {
    if (buttonState3 == LOW)
      LEFT();


  }
}


void LEFT() {
  display.drawLine (1, 16, 35, 1, GREEN);
  display.drawLine (35, 1, 35, 10, GREEN);
  display.drawLine (35, 10, 40, 10, GREEN);
  display.drawLine (40, 10, 40, 22, GREEN);
  display.drawLine (40, 22, 35, 22, GREEN);
  display.drawLine (35, 22, 35, 32, GREEN);
  display.drawLine (35, 32, 1, 16, GREEN);
  delay (200);

  display.drawLine (1, 16, 35, 1, BLACK);
  display.drawLine (35, 1, 35, 10, BLACK);
  display.drawLine (35, 10, 40, 10, BLACK);
  display.drawLine (40, 10, 40, 22, BLACK);
  display.drawLine (40, 22, 35, 22, BLACK);
  display.drawLine (35, 22, 35, 32, BLACK);
  display.drawLine (35, 32, 1, 16, BLACK);
  delay (200);

}

void BATT() {

  display.drawLine (1, 64, 1, 36, RED);
  display.drawLine (1, 36, 5, 36, RED);
  display.drawLine (5, 36, 5, 33, RED);
  display.drawLine (5, 33, 8, 33, RED);
  display.drawLine (8, 33, 8, 36, RED);
  display.drawLine (8, 36, 40, 36, RED);
  display.drawLine (40, 36, 40, 33, RED);
  display.drawLine (40, 33, 43, 33, RED);
  display.drawLine (43, 33, 43, 36, RED);
  display.drawLine (43, 36, 48, 36, RED);
  display.drawLine (48, 36, 48, 64, RED);
  display.drawLine (48, 63, 1, 63, RED);
}

void HIDEBATT() {

  display.drawLine (1, 64, 1, 36, BLACK);
  display.drawLine (1, 36, 5, 36,  BLACK);
  display.drawLine (5, 36, 5, 33,  BLACK);
  display.drawLine (5, 33, 8, 33,  BLACK);
  display.drawLine (8, 33, 8, 36,  BLACK);
  display.drawLine (8, 36, 40, 36, BLACK);
  display.drawLine (40, 36, 40, 33,  BLACK);
  display.drawLine (40, 33, 43, 33,  BLACK);
  display.drawLine (43, 33, 43, 36,  BLACK);
  display.drawLine (43, 36, 48, 36, BLACK);
  display.drawLine (48, 36, 48, 64, BLACK);
  display.drawLine (48, 63, 1, 63,  BLACK);

 

and this is what it does.

 

  • Like 1

Share this post


Link to post
Share on other sites

that LCD will likely run on I2C, not SPI, and I2C is terribly slow. A lot of them offer SPI, so maybe see if it does? and potentially change it? or get an SPI screen?

Theres plenty you could change in your code to make it more bad-ass, but i would start with changing the battery functions etc to accept a single colour argument, so in your code you can write drawBatt(RED) and drawBatt(BLACK). That way you a) save on code and b ) if you change the icon later, or move it, you only have to change it in one place and it will always cover itself back up :) and you get to learn a new thing (if you dont already know how to do function arguments ) 

 

  • Like 2

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now