Sponsors' sign designed and built by Jeff Paewai 2022.
This project is the electronics part of a large digital sign.
This has the sponsor's name on it, with a logo at one end. The entire sign was made out of LED track that is either red or white, as per the sponsor's logo. The sign is used at a Speedway where red light is banned during racing.
The controller has buttons to change the modes of the sign.
Mode 0 off
Mode 1 all on
Mode 2 reds off
Mode 3 Parade mode
The WOKWI simulator uses an infrared remote to illustrate the controls; however, the actual sign uses an RF remote.
Both RF and infrared codes are in this project, the RF, however, has been disabled as it doesn't work in WOKWI
The design is pretty straightforward with a 595 serial-to-parallel IC used to control eight outputs.
Using the buttons or the infrared remote control will switch the sign into different modes.
Mode 3 is the Parade mode, which cycles through each digit and is used at the beginning of each night vehicle parade.
I've added a voltage divider, which is not wired quite correctly, as the top half of the divider would be wired to the 12 V input to give the correct voltage measurement.
I have added a current sense which in the real project is connected to an ACS712 30A current sensor. This outputs 0.66 V per amp. again, I have just used a simple slider for illustration purposes, but in the real world version measures correctly the current passed to the sign.
There is an LCD Simply display the mode that the sign and various measurements. I am are currently working on a dual battery mode. This is hoped that the sign controller will switch over to a new battery if the old battery becomes exhausted.
// Setup 433.92Mhz Radio receiver onto D2
//#include <RCSwitch.h>
// RCSwitch mySwitch = RCSwitch();
// Receiver codes
unsigned long button_code[12] = {5330691,5330700,5330703,5330736};
// IR Receiver setup will be 433 radio
#include <IRremote.h>
#define PIN_RECEIVER 2
IRrecv receiver(PIN_RECEIVER);
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
#include <Keypad.h>
const byte ROWS = 5;
const byte COLS = 4;
char Keys[ROWS][COLS] =
{ // Setup a 4 button Keyboard
'A', 'B', 'C', 'D'};
byte rowPins[ROWS] = {9};
byte colPins[COLS] = {13,12,11,10};
Keypad keypad = Keypad( makeKeymap(Keys), rowPins, colPins, ROWS, COLS );
//Outputs 74595 MCU connections
#define clock 4
#define data 5
#define latch 3
#define vSense A0 // 12 Volt Divider to measure the battery
#define cSense A1 // ACS712 30A, 66mV per ampCurrent Sensor
long msTimer =500;
long currentMS = 0;
byte PradeStep[] = {0,192,224,240,248,252,254,255,0,255,0,255};
byte CurrentStep =0;
// Modes, Sign off 0, Sign on 1, reds on 2, reds off 3, fun mode 4
byte mode =0; // 0= off
void data_out(byte dataOut)
{ // Sent out a value to the 74595 Serial Resister
shiftOut(data, clock, LSBFIRST, dataOut );
shiftOut(data, clock, LSBFIRST, dataOut );
digitalWrite(latch, LOW);
delayMicroseconds(1);
digitalWrite(latch, HIGH);
delayMicroseconds(1);
digitalWrite(latch, LOW);
}
float currentUsed (void)
{ ////// Current Calc. using ACS712 30 A Current data sheet says 66mv per Amp.
int mVperAmp = 66;
int ACSoffSet = 2500;
int RawValue = analogRead(cSense); // reads 0-1024
float volts = (RawValue/1024.0)*5000; //
return ( (volts-ACSoffSet) / mVperAmp);
}
float vCalc(void)
{ // Calculates the Battery Voltage, R1=20K, R2=7692- Max Voltage is 20v
float vout = 0.0;
float vin = 0.0;
float R1 = 20000.0;
float R2 = 7692.0;
int senVal = analogRead(vSense);
vout = (senVal * 5.0) / 1024.0;
vin = vout / (R2/(R1+R2));
if (vin<0.09){ vin= 0.0;} // set zero if a faulse result is readback
return vin;
}
void LcdPrintS(byte x,byte y,String message)
{ // Print a string to the LCD at the coordinates
lcd.setCursor(x,y);
lcd.print(message);
}
void LcdPrintB(byte x,byte y,byte message)
{// Print a byte to the LCD at the coordinates
lcd.setCursor(x,y);
lcd.print(message);
}
void title(void)
{ // Acknowledgement for designer
lcd.clear();
LcdPrintS(0,0,"ENZED Sign CTRL");
LcdPrintS(0,1,"J Paewai (R)");
}
void changeMode( byte changeValue)
{
mode = changeValue;
}
void DisplayMode(void)
{// Displ;ays the woring mode
LcdPrintS(0,0,"Sign: ");
switch (mode){
case 0: LcdPrintS(5,0,"OFF ");break;
case 1: LcdPrintS(5,0,"ON ");break;
case 2: LcdPrintS(5,0,"Reds OFF ");break;
case 3: LcdPrintS(5,0,"Prade mode");break;
case 4: LcdPrintS(5,0,"Reserved ");break;
}
}
void DisplayVoltage(void)
{ // Display Battery voltage
LcdPrintS(0,1,"V:");
lcd.setCursor(2,1);
lcd.print(vCalc());
}
void DisplayCurrent(void)
{ // Display the current sensor value
LcdPrintS(9,1,"I:");
lcd.setCursor(11,1);
lcd.print(currentUsed());
}
void pradeMode(void)
{ // from the
if( currentMS < millis() ) {
data_out(PradeStep[CurrentStep]);
CurrentStep ++;
if(CurrentStep > 11) CurrentStep = 0;
currentMS = millis() + msTimer ;
}
}
void translateIR(){
switch (receiver.decodedIRData.command) {
case 104: data_out(0);changeMode(0); break; // All off
case 48: data_out(255);changeMode(1);break; // All On
case 24: data_out(63);changeMode(2);break; // Reds off
case 122: changeMode(3);break;
}
}
void translateRF()
{
if(mySwitch.getReceivedProtocol() == 1 && mySwitch.getReceivedBitlength() == 24) {
switch(mySwitch.getReceivedValue()) {
case 5330691: data_out(0);changeMode(0); break; // All off
case 5330700: data_out(255);changeMode(1);break; // All On
case 5330703: data_out(63);changeMode(2);break; // Reds off
case 5330736: changeMode(3);break; // Prade Mode
}
}
mySwitch.resetAvailable();
}
void setup()
{
/*
// 433 Radio Receiver setup
mySwitch.setProtocol(1);
mySwitch.setPulseLength(320);
mySwitch.setRepeatTransmit(15);
mySwitch.enableReceive(0); // Receiver on interrupt 0 => that is pin #2
*/
receiver.enableIRIn(); // Start the IR receiver
lcd.begin(20,4); // Configure LCD
lcd.clear(); // Clear screen jut incase of any lcd clitch
title(); // Acknowledgement
pinMode(vSense, INPUT); //Voltage Pin setup
pinMode(cSense, INPUT); //Current Sensor
//outputs 74595 MCU setups
pinMode(data,OUTPUT);
pinMode(clock,OUTPUT);
pinMode(latch,OUTPUT);
data_out(0); // Ensure All outputs are off
delay(2000);
lcd.clear(); // Clear screen jut incase of any lcd clitch
}
void loop ()
{
char key = keypad.getKey();
if (key)
{
switch(key)
{
case 'A':data_out(0);changeMode(0); break; // All Off
case 'B':data_out(255);changeMode(1);break; // All On
case 'C':data_out(63);changeMode(2);break; // Reds off
case 'D':changeMode(3);break; // Prade Mode
}
}
if (receiver.decode()) {
translateIR();
receiver.resume(); // Receive the next value
}
/* RF Remote code
// if(mySwitch.available()) {
translateRF();
}
*/
if(mode == 3) {pradeMode();}
DisplayMode();
DisplayVoltage();
DisplayCurrent();
}All ON
REDs off
Parade Mode
ROW
COLUMNS
ACS712 IC
Battery Voltage Sense
REDS 1
REDS 2
E
N
Z
E
D
Sign Edge
OFF
Current Sense SIM
1
2
3
4