0
\$\begingroup\$

I have created a processing program (Java) with which a programmer can use a GUI to make a program for an Arduino using logic function blocks. It looks like this:

enter image description here

Ofcourse it still needs some work. I try to make it userfriendly. The mouse above only show color if you can click a button. And a text will always appear what the mouse click will do.

I have not really found suitable function block GUIs for arduino which I also liked. So I thought it would be neat to make a simple one myself.

This 'program' generates the below functional source code. The code itself is not to be altered by humans. I use hardcoded elements like the amount of blocks, the type array and the links list.

Despite the code works I do have a small problem with the structure. It contains more information than it should. For instance, memory is used to contain the pin value which is used only by inputs and outputs.

AND and OR gates do not have input pins...

The 'delay' logic gate needs a constant and a uint32_t to... well to create a delayed action. But again, neither the inputs, outputs, OR gates or the AND gates need a 32 bit variable.

const int nBlocks = 5 ; 

enum blockTypes
{
       AND = 1,
        OR, 
         M, 
       DEL, 
       NOT, 
     INPUT_PIN,
    OUTPUT_PIN,
} ;
const int typeArray[] = {
    6, 6, 6, 2, 7, } ;   // hardcoded array which tells which blocks are OR gates or AND gates etc.

typedef struct blox
{
    uint8_t  IN1 : 1 ;  // generic for most blocks
    uint8_t  IN2 : 1 ;  // generic for most blocks
    uint8_t  IN3 : 1 ;  // generic for most blocks
    uint8_t    Q : 1 ;  // generic for most blocks

    uint8_t  pin : 5 ; // only inputs and output types need this?
    uint8_t type : 4 ; // 16 combinations
    //uint32_t        oldTime ;  // bad idea to use this amount of memory per block if only delays need it?
    //const uint32_t  interval ; // perhaps couple a function pointers or obj pointer to it?
} FunctionBlock ;

FunctionBlock block [ nBlocks ] ;

In the setup all items are properly initialized. The block types are coupled to the object array, that what is input/output get their pin numbers, the hardware is initialized and and unused AND gate inputs are set to 1 etc.

void setup()
{
    block[0].pin = 1 ;
    block[1].pin = 2 ;
    block[2].pin = 3 ;
    block[3].pin = 4 ;

    for( int i = 0 ; i < nBlocks ; i ++ )
    {
        block[i].type = typeArray[i] ;

        switch( block[i].type )
        {
        case AND: 
            block[i].IN1 = block[i].IN2 = block[i].IN3 = 1 ; // force all AND gate INs to be 1 in case of unused things
            break ;

        case INPUT_PIN:
            pinMode( block[i].pin, INPUT_PULLUP ) ;
            break ;

        case OUTPUT_PIN:
            pinMode( block[i].pin, OUTPUT ) ;
            break ;

        case DEL:       // idk do something clever with adding timers or something
            break ;
        }
    }
}

The main loop is pretty straight forward. One for-loop checks all types and handles the logic for all individual function blocks. And below the for-loop there are hard coded links between the Q of one block and an IN of another block.

void loop()
{
/***************** UPDATE FUNCTION BLOCKS *****************/
    for( int i = 0 ; i < nBlocks ; i ++ )
    {
        switch( block[i].type )
        {
        case AND: 
            block[i].Q = block[i].IN1 & block[i].IN2 & block[i].IN3 ;
            break ;

        case OR: 
            block[i].Q = block[i].IN1 | block[i].IN2 | block[i].IN3 ;
            break ;

        case M: 
            if(      block[i].IN3 ) block[i].Q = 0 ; // R
            else if( block[i].IN1 ) block[i].Q = 1 ; // S
            break ; 

        case NOT: 
            block[i].Q = !block[i].IN2 ; 
            break ;

        case INPUT_PIN: 
            block[i].Q = digitalRead( block[i].pin ) ;
            break ;

        case OUTPUT_PIN: 
            digitalWrite( block[i].pin, block[i].IN2 ) ;
            break ;

        // case DEL: for( int i = 0 ; i < n_blocks  ; i ++ )
        //     {
        //         if( block[i].Q != block[i].IN )                                   // if new state changes
        //         {
        //             if( millis() - block[i].oldTime >= block[i].interval )         // keep monitor if interval has expired
        //             {
        //                 block[i].Q = block[i].IN ;                                // if so, adopt the new state
        //             }
        //         }
        //         else
        //         {
        //             block[i].oldTime = millis() ;                                      // if new state does not change, keep setting oldTime
        //         }
        //     }
        //     break ;
        }
    }

/***************** UPDATE LINKS *****************/
    block[3].IN2 = block[1].Q ;  // hardcoded list of all links.
    block[3].IN1 = block[0].Q ;
    block[3].IN3 = block[2].Q ;
    block[4].IN2 = block[3].Q ;
} ;

These links correspond with the shown GUI. Blocks[0-2] are the 3 input pins, block[3] is the OR gate and block[4] is the output pin.

If something changes it will propably take several loop cycles before all blocks are updated.

As you can see, the delay block is still in comments. It does work as it is, but like I said before I do not want to waste so much memory for every last block because 1 item needs 4 bytes more memory.

Besides these elements I also want to add analog stuff. So I need to upgrade this code. (analog here being everything which can be more than '0' or '1' like analog input pin, comparators, the map() function, servo motors etc)

What do you guys think?

How do I solve that particular issue with the structure and memory. I haven't used inheritence before in C++, I did in Java. I am leaning to use classes and use inheritence but I would not know if that is the best approach here?

\$\endgroup\$
5
  • 4
    \$\begingroup\$ This questions is really interesting, but at the moment I'm not sure it belongs on Code Review. You say the generated code is working, but there are blocks of code that are commented out which indicate the code isn't ready for review yet. You are also asking questions about code that isn't implemented yet (structure and memory). Please re-read How do I ask a good question?. \$\endgroup\$
    – pacmaninbw
    Sep 21, 2022 at 14:12
  • 2
    \$\begingroup\$ You say you have created a processing program in Java, but that doesn't appear to be posted. We review code, not general approaches without code. What is it you're looking for? \$\endgroup\$
    – Mast
    Sep 21, 2022 at 20:05
  • \$\begingroup\$ The commented code is commented out after it was tested. This project is only halfway as I still want to add the 'analog' componenents. This arduino code as it is now, does work with the exception of the delay which I disabled. I do need a solution for the struct/memory problem. Should I ask on SO instead? \$\endgroup\$
    – bask185
    Sep 21, 2022 at 20:08
  • \$\begingroup\$ @Mast I need a solution for the struct. I cannot stuff all different function blocks in a single structure without throwing away massive amounts of memory. For the Java program I do not need a review. The Java program is merely a tool to get the final code \$\endgroup\$
    – bask185
    Sep 21, 2022 at 20:10
  • \$\begingroup\$ Prior to C++, there were unions in addition to structs. With C++, why not take an object oriented approach? Blocks without an output are pointless. Blocks without inputs are boring: Start with one each. Derive blocks with more inputs and/or outputs, with different behaviour. Ponder combinatorial explosion. \$\endgroup\$
    – greybeard
    Sep 25, 2022 at 12:16

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.