This controller provides 54 On,Off and display select commands.

This number is limited by the size of the EEPROM and  program memories.

The commands are grouped into 10 areas, which are selected by the UP and Down buttons. The area is identified on the top line of the display.

Each area has multiple channels, which are selected by the Left and Right buttons. Each may design an Off, an On or a display select command. The channel is identified on the bottom line of the display.

The Center button initiates a transmission. When the controller is off, pressing the Center button initiates power on.

The controller is based on the rosette, originally made to control an RV generator.

Circuit Diagrams

A Controller with an OLED display for many projects

Circuit Diagram

The main board contains the Picaxe 18M2+ micro-controller, a DS18B20 digital temperature sensor, the transmitter and the power control circuit. It is connected by plug-in cables to the key rosette, the battery and the display, which uses I2C.

Power is switched by the PNP transistor and maintained by the microcontroller via the NPN transistor.

It is turned off after a timed interval after the last button press.

Program Declarations

#rem OLED_Control.bas   For the Universal OLED Transmitter

This is the hand-held controller with a 2x17 blue oled character display and rosette push-buttons

John Saunders 10/16/2020  All new memory usage. 11/1/2020 Added channel to Tower Display

2020/12/4 corrected table addresses in the Master Table fot LR East and Garden

2020/12/17 Corrected Clear outlet OFF code ("J")

2021/5/24 Changed bullseye to Houses

2022/6/4 Changed houses to Missions and added Gas Sensor


#endrem

#picaxe 18M2

rem Inputs:

symbol KeyOK        = pinC.2         'Keys are low when pressed

symbol KeyDown      = pinC.1

symbol KeyLeft      = pinC.0

symbol KeyRight     = pinC.6

symbol KeyUp        = pinC.7

symbol BatteryPort  = B.6       'FVR=2.048V, 2:1 divider

symbol TempPort     = B.7       'For DS18B20

symbol TP            = B.3        'TestPoint


rem outputs:

symbol TX_Port      = B.0       'Normally low

symbol KeepAlive    = B.5       'High keeps power on

symbol OLEDReset    = B.2       'Low resets


rem constants:

symbol NumAreas      = 10            'Size of area array

symbol TX_Preamble  = 20        'A long pulse before the serial transmission to trigger an interrupt

symbol TX_Ser_Setup = 10        'Gives time to execute the serial in command in the interrupt procedure

symbol IdleCountMax = 1300

symbol MasterAddr   = 45

symbol ChannelShift = 210

symbol CommandShift = 380

symbol SelectorShift = 400


rem variables:

symbol OnOff        = bit0          '1 is OFF, 0 is ON

symbol Row            = bit1         '1 is bottom row,0 is top row

symbol ColPos       = b1

symbol Scratch      = b2

symbol CharData     = b3

symbol DataAddr     = b4        'Base address in DATA of a channel array

symbol Tens         = b5

symbol Units        = b6

symbol ChanIx        = b7          'Index to a particular output-command combination for a receiver             

symbol NumChan      = b8        'Number of cbannels in a channel array               

symbol Decimals     = b9

symbol AreaIx        = b10        'Index into the channel array 

symbol CmdDisp        = b11       '2 is the display mode, 3 is Command Mode

symbol StrLen        = b12        'Number of bytes in a string 

symbol ChanAddr        = b13         ;Address in DATA of  channel data                       

symbol TableAddr    = w11          'Address in Table of the start of an channel string array  

symbol TableAddrLSB = b22           

symbol IdleCount    = w12       'For power down on idle

symbol DecData      = w13


#rem

RAM Allocation:

28-44  Display buffer

45 - 89 Area array.of NumArea areas sections. Each has 4 bytes:

byte 0  MS bit is the MS bit of TableAddr. The rest is NumChan. 

byte 1  Is the LS bits of TableAddr

byte 2  MS bit is the mode: o = Control, 1 is Display, rest is string length of the upper line

byte 3  DataAddr


DATA Allocation:

0 - 223 Channel arrays. There are  NumAreas number of arrays: Each has 

 NumChan sections each with:

     byte 0  Offset to be added to TableAddr to get the bottom line string  address

     byte 1  Key code for either Display or Control ON

     byte 2  Control only key code for off

 A single string for top line of StrLen bytes

#endrem


DATA     0,(0,"1","0", 8,"3","2", 19,"5","4", 31,"7","6", 44,"L","V",54,"Gazebo")  

DATA    22,(0,"m","J",12,"X","N", 21,"d","9",31,"j","T",40,"Garden")                                       

DATA    41,(0,"R","G",12,"S","U", 19,"b","f", 30,"E","F", 42,"K","8",51,"LR West")  

DATA    64,(0,"C", 12,"D", 22,"A", 28,"E", 37,"B",45,"rgb Display") 

DATA    86,(0,"c", 15,"d", 27,"a", 43,"b", 56,"e",69,"f",78,"Atmosphere")                     

DATA   110,(0,"I","C", 12,"d","9", 16,"P","l", 29,"M","g", 37,"Y","W",47,"LR East")            

DATA   133,(0,"j",8,"k", 17,"l", 25,"m", 34,"n", 40,"o",47,"Tower Display")                                                           

DATA   159,(0,"K", 4,"L", 8,"M", 19,"N", 27,"O", 40,"P",47,"Red LED Display")  '

DATA   187,(0,"i","k", 9,"a","c", 15,"A","H", 23,"D","H", 33,"e","H",42,"Garage")    

DATA   210,(0,"g",11,"Gas Sensor  ")


DATA    254,(1,2)                'ChanIx,AreaIx


 #rem

 TABLE Allocation:

 0-500 Botton line strings in the same sequence as in the Channel array. No nulls

#endrem


rem receiver strings:                      

TABLE    0,("Owl Spit","Cherub Pour","Strip Lights","String Lights","28V Output")         

TABLE   58,("Clear Outlet","Clear Tip","Clear Ring","Girl Pump")               

TABLE   99,("Ceiling Lamp","Speaker","Floor Light","Shelf Lights","Pineapple")             

TABLE  152,("Temperatures","Humidities","Garage","Barometer","Voltages")             

TABLE  198,("Ext Temperature","Ext Humidity","Room Temperature","Room Humidity","Solar Current","Barometer")

TABLE  277,("Hanging Lamp","Eggs","Circle Lights","Missions","Flashing  ")

TABLE  336,("Color On","Color Off","Tower On","Tower Off","PWM On","PWM Off")            

TABLE  384,("Date","Time","Temperature","Humidity","Solar Current","Battery")               

TABLE  432,("Pole Lamp","Flower","Cube Red","Cube Green","Cube Blue")   

TABLE  479,("Air Quality")



The method of determining memory positionsa is as follows.

The area string and the control codes are in EEPROM. This also indirectly points to the location in program memory where the command string is located. 

These are loaded into RAM on program start by the TABLE keyword.

This is a 3- step procedure.

The start of the command string list for an area is set in init in the Master table. This also gives the number of commands for the area and where to find the area string.

Init and Main

Init:

HIGH KeepAlive

SETFREQ m4

GOSUB tempAndVolts

DO UNTIL KeyOK = 1  'View the status display while the center key is depressed

    PAUSE 100

LOOP

READ 254, ChanIx, AreaIx

LET IdleCount = 0

rem  field values are:1=no of fields in DATA line(*128 if display),2=address in TABLE (less 256 if Display)

rem ,3=No of chars in area,(*128 if <10),4=DATA address

rem               Gazebo     Garden       LR West     rgb Display  Atmosphere     LR East       Tower Display  Red LED Display     Garage       Gas Sensor

POKE MasterAddr, 5,0,$85,0, 4,58,$85,22, 5,99,$86,41, 5,152,10,64, 6,198,9,86, $85,21,$86,110, $86,80,12,133, $86,128,14,159, $85,176,$85,187,$81,223,11,210

GOSUB DispChannel

GOSUB DispArea


main:

IF KeyUp = 0 THEN 

    INC AreaIx

    IF AreaIx >= NumAreas THEN

        LET AreaIx = 0

    ENDIF

    LET ChanIx = 0

    GOSUB DispArea

    GOSUB DispChannel

    DO 

        PAUSE 100

    LOOP   UNTIL KeyUp = 1  

ENDIF


IF KeyDown = 0 THEN

    LET IdleCount = 0

    IF AreaIx > 0 THEN

        DEC AreaIx

    ELSE

        LET AreaIx = NumAreas - 1

    ENDIF

    LET ChanIX = 0

    GOSUB DispArea

    GOSUB DispChannel

    DO

        PAUSE 100

    LOOP   UNTIL KeyDown = 1   

ENDIF


rem Change channel

IF KeyRight = 0 THEN

    LET IdleCount = 0

    IF OnOff = 0  OR CmdDisp = 2 THEN

        INC ChanIx

      IF ChanIx >= NumChan THEN

        LET ChanIx = 0

      ENDIF

      LET OnOff = 1

    ELSE 

      LET OnOff = 0

    ENDIF

    GOSUB DispChannel

    DO 

        PAUSE 100

    LOOP  UNTIL KeyRight = 1   

ENDIF 


IF KeyLeft = 0 THEN

    LET IdleCount = 0

    LET IdleCount = 0

    IF OnOFF = 1 OR CmdDisp = 2 THEN

       IF ChanIx > 0 THEN

         DEC ChanIx

       ELSE

         LET ChanIx = NumChan - 1

     ENDIF

     LET OnOff = 0

    ELSE

       LET OnOff = 1

    ENDIF

        GOSUB DispChannel

    DO 

        PAUSE 100

    LOOP UNTIL KeyLeft = 1    

ENDIF


IF KeyOK = 0 THEN           'Transmit a command

    LET IdleCount = 0

    POKE 44,CharData                          

    GOSUB WriteOLED

    HIGH TX_Port            'This pulse unlocks the receiver

    PAUSE TX_Preamble

    LOW TX_Port

    PAUSE TX_Ser_Setup

    IF CmdDisp = 3 THEN        'Command

        LET Scratch = ChanAddr + 2 - OnOff

        READ Scratch,CharData

        SEROUT TX_Port,N2400_4,("14L1776",CharData,13,10) 'The CR,LF is for debugging

    ELSE                    'Display

        LET Scratch = ChanAddr + 1

        READ Scratch,CharData

        SEROUT TX_Port,N2400_4,("14L1776O,",CharData,13,10)    

    ENDIF

      HI2COUT 0,($CF)

      HI2COUT $40,(CharData)

    DO 

        PAUSE 100

    LOOP UNTIL KeyOK = 1    

ENDIF

PAUSE 100

INC IdleCount                                                   

IF IdleCount < IdleCountMax THEN main                    'Exit on no activity

Write 254,ChanIx,AreaIx

LOW KeepAlive

END

Sub-Programs

tempAndVolts:

ReadTemp12 TempPort,DecData

GOSUB InitDisp

LET DecData = DecData + 880 **7373 -67        'Fahrenheit (32F to 257F)

HI2COUT 0,($80)                             'Start of first row

LET Decimals = 0

GOSUB WriteDec                              'Temperature

HI2COUT $40,($80,"F")

FVRSETUP FVR2048

ADCCONFIG 3

READADC10 BatteryPort,DecData

LET DecData = DecData * 2 / 5

HI2COUT 0,($89)                             'Column 9

LET Decimals = 2

GOSUB WriteDec                              'Volts

HI2COUT $40,("V")

RETURN


InitDisp:                                'From the TABLEsheet

HIGH OLEDReset

HI2CSETUP I2CMASTER,$78,i2cfast,i2cbyte            'The OLED Display

PAUSE 100

HI2COUT (0,0x2A);  //function set (extended command set)  

HI2COUT (0,0x71);  //function selection A  

HI2COUT ($40,0x0);  // TABLE(0x5C) = disable regulator (5V I/O)  

HI2COUT (0,0x28);  //function set (fundamental command set)  

HI2COUT (0,0x08);  //display off, cursor off, blink off  

HI2COUT (0,0x2A);  //function set (extended command set)  

HI2COUT (0,0x79);  //OLED command set enabled  

HI2COUT (0,0xD5);  //set display clock divide ratio/oscillator frequency  

HI2COUT (0,0x70);  //set display clock divide ratio/oscillator frequency  

HI2COUT (0,0x78);  //OLED command set disabled 

HI2COUT (0,0x08);  //extended function set (2-lines) 

HI2COUT (0,0x06);  //COM SEG direction  

HI2COUT (0,0x72);  //function selection B  

HI2COUT ($40,0x00);  //ROM CGRAM selection  A

HI2COUT (0,0x2A);  //function set (extended command set)  

HI2COUT (0,0x79);  //OLED command set enabled  

HI2COUT (0,0xDA);  //set SEG pins hardware configuration  

HI2COUT (0,0x00);  //set SEG pins hardware configuration  

HI2COUT (0,0xDC);  //function selection C  

HI2COUT (0,0x00);  //function selection C  

HI2COUT (0,0x81);  //set contrast control  

HI2COUT (0,0x7F);  //set contrast control  

HI2COUT (0,0xD9);  //set phase length  

HI2COUT (0,0xF1);  //set phase length  

HI2COUT (0,0xDB);  //set VCOMH deselect level  

HI2COUT (0,0x40);  //set VCOMH deselect level 

HI2COUT (0,0x78);  //OLED command set disabled  

HI2COUT (0,0x28);  //function set (fundamental command set) 

HI2COUT (0,0x01);  //clear display  

HI2COUT (0,0x80);  //set DDRAM address to 0x00  

HI2COUT (0,0x0C);  //display ON 

RETURN


WriteDec:

LET Units = DecData  //10  + "0"

LET Tens  = DecData   /10 //10 + "0"

LET DecData  = DecData  /100 //10 

IF DecData = 0 THEN

    LET DecData = " "

ELSE

    LET DecData = DecData + "0" 

ENDIF

SELECT Decimals

    CASE 1

        HI2COUT $40,(DecData,Tens,".",Units)

    CASE 2

        HI2COUT $40,(DecData,".",Tens,Units)

    ELSE

        HI2COUT $40,(" ",DecData,Tens,Units)

ENDSELECT

RETURN


GetData:

POKE 28," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "

rem Input is AreaIx and ChanIx, 

rem Output is NumChan,DataAddr,ChanAddr,TableAddr,CmdDisp,StrLen    

LET Scratch = AreaIx * 4 + MasterAddr   'Channel entry address

PEEK Scratch,NumChan,TableAddrLSB,CharData,DataAddr

IF CharData > 127  THEN

    LET CmdDisp = 3

ELSE

    LET CmdDisp = 2    

ENDIF

LET StrLen = CharData & $7F

LET ChanAddr = CmdDisp * ChanIx + DataAddr

READ ChanAddr,CharData                            'TableAddr offset

LET TableAddr = TableAddrLSB + CharData

IF NumChan > 127 THEN

    LET TableAddr = TableAddr + 256

ENDIF

LET NumChan = NumChan & $7F

RETURN


DispArea:

GOSUB GetData

'SERTXD ("AreaIx=",#AreaIx,",CmdDisp=",#CmdDisp,",DataAddr=",#DataAddr,",Strlen=",#Strlen,13,10)

LET Tens = NumChan * CmdDisp + DataAddr + 1

LET CharData = 16 - Strlen

LET ColPos = CharData / 2 + 28

FOR Units = 0 TO Strlen

    LET Scratch = Tens + Units

    READ Scratch,CharData

    LET bptr = ColPos + Units

        IF bptr < 28 OR bptr > 44 THEN

    SERTXD ("invalid area bptr=",#bptr,13,10)

        LET bptr=40

    exit

    ENDIF

    POKE bptr,CharData

NEXT 

LET Row = 0 

GOSUB WriteOLED

LOW TP

RETURN


DispChannel: 

GOSUB GetData 

'SERTXD ("ChanIx=",#ChanIx,",NumChan=",#NumChan,",TableAddr=",#TableAddr,",ChanAddr=",#ChanAddr,13,10)

READ ChanAddr,CharData

LET Scratch = ChanAddr + CmdDisp

READ Scratch,Tens

LET Tens = Tens - CharData - 1

FOR Units = 0 TO Tens

    READTABLE TableAddr,CharData

    LET bptr = 28 + Units

    IF bptr < 28 OR bptr > 44 THEN

        SERTXD ("invalid channel bptr=",#bptr,13,10)

        exit

    ENDIF

    POKE bptr,CharData

    INC TableAddr

NEXT 

INC bptr

IF OnOff = 0 AND CmdDisp = 3 THEN

    POKE bptr," ","O","F","F"

ENDIF

IF OnOff = 1 AND CmdDisp = 3 THEN

    POKE bptr," ","O","N"

ENDIF

LET Row = 1

GOSUB WriteOLED

LOW TP

RETURN


WriteOLED:

LET Scratch = Row * $40 + $80

HI2COUT 0,(Scratch)

LET bptr = 28

HI2COUT $40,(@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptrinc,@bptr)

RETURN