4L80e controller

A little background info, I've made a few things from Arduinos, but all of them have been from existing sketches that I've only tweaked, so I'm not well versed in ground up coding.

I'm wanting to use a Arduino to work as a stand alone controller for a 4L80e transmission.

There's several incarnations I'd like to work through on this. The first step would be just a "manual" controller. The second step would be a "automatic" mode. The third step would be the same "automatic" mode, only with some slight changes to the sequencing. The fourth step would be adding in some control over line pressure via PWM. (If the vehicle needs it, it's a heavy vehicle that isn't that powerful, full line pressure might not be an issue)

Some things I want to design into it would be:
4 mosfets to control the solenoids
LCD screen to display mode, RPM, gear indicator, as well as monitor trans temp.
2 buttons for upshift/downshift (paddle shift)
1 button to toggle through modes (Manual, Automatic, Tow)

Some things it will have to monitor:
Engine RPM, I can get a signal from the engine that provides 4 pulses per RPM.
Throttle Position, I can add a TPS sensor. (Pot)
MPH, I can add a VSS to the speedo cable output for road speed.
Transmission temp, the 4L80e has a internal sensor that varies voltage based on temp.

I know the sequence of shifting would go in this order.

Gear SolenoidA SolenoidB TCC
1 ON OFF OFF
2 OFF OFF OFF
3 OFF ON OFF
4 ON ON ON (but really needs about a second delay before on)

  • another side note is Park and Reverse, they both need the same values for gear 1.

The manual mode basically just needs to be able to allow the two buttons to cycle through that pattern up and down.

Some other considerations I need to make are related to safety. I need to not allow downshifting into 1 or 2 if speed or engine RPM are above a certain point. Or at least allow for the button to be pressed, but refrain from completing the shift until the speed or RPM are acceptable.

I've started with just trying to get the sequencing up code for "manual" use to working, but I haven't figured out the TCC delay. Nor how to get it to downshift with the other button. I've just reworked some code I found from someone else that was sequencing LEDs. I also know I need to add a lot more to get a display, have multiple modes, and actually sample those other inputs too. Then there's the whole automation/logic. But I'd be most appreciative to any help with this project. Seems there's a few people out there that have made things like this, but they won't turn loose of any of their code because they're wanting to make a product.

 #define buttonUP 2                     //Push Button for UP shift
 #define buttonDOWN 4                   //Push Button for Down shift
 #define solA 3                         //Solenoid A output
 #define solB 5                         //Solenoid B output
 #define TCC  6                         //TCC output
 #define modeswitch 7                   //Switch for tow/haul mode

 int state = 0;                         //integer to hold current state
 int old = 0;                           //interger to hold last state
 int buttonPoll = 0;                    //interger to hold button state


 void setup() {
  pinMode (buttonUP, INPUT);            //buttonUP set as input
  pinMode (buttonDOWN, INPUT);          //buttonDOWN set as input
  pinMode (modeswitch, INPUT);          //modeswitch set as input
  pinMode (solA, OUTPUT);               //Solenoid A set as output
  pinMode (solB, OUTPUT);               //Solenoid B set as output
  pinMode (TCC, OUTPUT);                //TCC set as output

  digitalWrite (solA, LOW);             //set intital state as off
  digitalWrite (solB, LOW);
  digitalWrite (TCC, LOW);
 
 }

void loop()  {

                                        //debouncing routine to read button
  buttonPoll = digitalRead(buttonUP);   //poll the state of buttonUP
 if(buttonPoll == 1){                   //check if buttonUPhas been pressed
   delay(50);                          //wait 50ms
   buttonPoll = digitalRead(buttonUP);  //poll state of buttonUP again
   if(buttonPoll == 0){                 //if it is 0 condsidered one press
    state = old + 1;                    //increase state by 1
   }}
   else{                                //if button has not been pressed
   delay(200);                          //wait 200ms
   }
   
   switch (state) {                     //react to button press & state
    case 1:                             //if state is 1
      digitalWrite(solA,HIGH);          //Solenoid A is ON
      digitalWrite (solB,LOW);          //Solenoid B is OFF
      digitalWrite (TCC,LOW);           //TCC is OFF
      old = state;                      //set old state as current state
      break;
     case 2:
       digitalWrite(solA,LOW);          //Solenoid A is OFF
       digitalWrite (solB,LOW);         //Solenoid B is OFF
       digitalWrite (TCC,LOW);          //TCC is OFF
       old = state;                     //set old state as current state
       break;
     case 3:
       digitalWrite(solA,LOW);          //Solenoid A is OFF
       digitalWrite (solB,HIGH);        //Solenoid B is ON
       digitalWrite (TCC,LOW);          //TCC is OFF
       old = state;                     //set old state as current state
       break;
     case 4:
       digitalWrite(solA,HIGH);          //Solenoid A is ON
       digitalWrite (solB,HIGH);         //Solenoid B is ON
       digitalWrite (TCC,LOW);           //TCC is OFF
       old = state;                      //set old state as current state
       break;
        }
 }
1 Like

What part of the world do you live in? And what make and model of vehicle is this for? Just asking so I can stay well clear if I spot you on the road. :smiley:

Just envisioning a 4 wheel drive Chevrolet hitting a hard jolting bump at about 60 and the tranny trying go into reverse or park.

Reverse and park must have the selector moved to those positions. NOT done via solenoids. Thanks for your concern.

Might consider moving some functionality to separate functions to make integrating things like kick-down or TCC un-lock easier. Maybe something like this (compiles, untested...)

#define NUM_FWD_GEARS               4       //#     number of forward speeds

#define BUTTON_READ_INTERVAL        50ul    //mS    time between up/down button reads

#define NO_PRESS                    0x00    //mask  bit mask for no buttons pressed
#define BUTTON_UP_PRESSED           0x01    //mask  bit mask for up button pressed
#define BUTTON_DOWN_PRESSED         0x02    //mask  bit mask for down button pressed

#define TCC_DELAY                   1000ul  //mS    after TCC is enabled, time delay before activation

const byte buttonUP = 2;                    //pin   Push Button for UP shift
const byte buttonDOWN = 4;                  //pin   Push Button for Down shift
const byte solA = 3;                        //pin   Solenoid A output
const byte solB = 5;                        //pin   Solenoid B output
const byte TCC  = 6;                        //pin   TCC output
const byte modeswitch = 7;                  //pin   Switch for tow/haul mode

byte
    gearSelection,
    lastGearSelection,
    lastUp,
    lastDn;
bool
    bTCCStatus;
unsigned long
    timeTCCSolenoid;

typedef struct structGearSolenoidProfiles
{
    byte    solenoid_A;
    byte    solenoid_B;
    bool    bEnableTCC;
    
}sGearSolenoidProfiles;

//
// How does Arduino know reverse, park or drive?
//
const sGearSolenoidProfiles GearSolenoidProfiles[NUM_FWD_GEARS] =
{
    {
        //1st
        .solenoid_A = HIGH,
        .solenoid_B = LOW,
        .bEnableTCC = false
    },
    {
        //2nd
        .solenoid_A = LOW,
        .solenoid_B = LOW,
        .bEnableTCC = false
    },
    {
        //3rd
        .solenoid_A = LOW,
        .solenoid_B = HIGH,
        .bEnableTCC = false
    },
    {
        //4th
        .solenoid_A = HIGH,
        .solenoid_B = HIGH,
        .bEnableTCC = true
    }
    
};//GearSolenoidProfiles[]

void setup() 
{
    pinMode( buttonUP, INPUT_PULLUP );
    lastUp = digitalRead( buttonUP );       //set initial button state
    pinMode( buttonDOWN, INPUT_PULLUP );
    lastDn = digitalRead( buttonDOWN );     //set initial button state
    
    pinMode( modeswitch, INPUT );           //modeswitch set as input
    
    pinMode( solA, OUTPUT );                //Solenoid A set as output
    pinMode( solB, OUTPUT );                //Solenoid B set as output
    pinMode( TCC, OUTPUT );                 //TCC set as output

    digitalWrite( solA, LOW );             //set intital state as off
    digitalWrite( solB, LOW );
    digitalWrite( TCC, LOW );

    //internal flag for TCC status
    bTCCStatus = false;
    gearSelection = 0;          //start in "1st" gear for this test
    lastGearSelection = 0xff;   //ensure we change into correct gear first pass by making last != current
    
}//setup

void loop()  
{
    Gear_Selection_Control();
    Gear_Solenoid_Control();
    TCC_Control();
    
}//loop

void Gear_Selection_Control( void )
{
    byte
        btnState;
        
    btnState = ReadButtons();
    switch( btnState )
    {
        case    NO_PRESS:
            //nothing pressed or not read (interval not elapsed); no action
        break;

        case    BUTTON_UP_PRESSED:
            if( gearSelection < (NUM_FWD_GEARS-1) )
                gearSelection++;
            
        break;

        case    BUTTON_DOWN_PRESSED:
            if( gearSelection > 0 )
                gearSelection--;
                
        break;

        default:
            //only remaining possibility is both pressed; ignore with no action
        break;
        
    }//switch
    
}//void
    
void Gear_Solenoid_Control( void )
{
    if( gearSelection != lastGearSelection )
    {
        lastGearSelection = gearSelection;
        digitalWrite( solA, GearSolenoidProfiles[gearSelection].solenoid_A );
        digitalWrite( solB, GearSolenoidProfiles[gearSelection].solenoid_B );

        //if the gear just selected enables the TCC, start the hold-off timer
        if( GearSolenoidProfiles[gearSelection].bEnableTCC == true )
        {
            timeTCCSolenoid = millis();
            
        }//if
        
    }//if
    
}//Gear_Control

void TCC_Control( void )
{
    //is TCC now off?
    if( bTCCStatus == false  )
    {
        //is TCC enabled?
        if( GearSolenoidProfiles[gearSelection].bEnableTCC == true )
        {
            //has hold-off time passed?
            if( millis() - timeTCCSolenoid >= TCC_DELAY )
            {
                //turn on TCC
                digitalWrite( TCC, HIGH );
                bTCCStatus = true;
            
            }//if
            
        }//if
        
    }//if
    else
    {
        //TCC is on now; is TCC disabled now?
        if( GearSolenoidProfiles[gearSelection].bEnableTCC == false )
        {
            //turn off TCC
            digitalWrite( TCC, LOW );
            bTCCStatus = false;
            
        }//if
        
    }//else
    
}//TCC_Control

//returns a mask:
//0b00000000 - no buttons pressed
//0b00000001 - up pressed
//0b00000010 - down pressed
//0b00000011 - both pressed
//
byte ReadButtons( void )
{
    static unsigned long
        timeButton = 0;
    unsigned long
        tNow;
    byte
        retval,
        nowButton;

    retval = NO_PRESS;
    
    tNow = millis();
    if( (tNow - timeButton) >= BUTTON_READ_INTERVAL )
    {
        //set up for next read interval
        timeButton = tNow;

        //read the button and set the flags
        nowButton = digitalRead( buttonUP );
        if( nowButton != lastUp )
        {
            lastUp = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_UP_PRESSED;
                
        }//if
        
        nowButton = digitalRead( buttonDOWN );
        if( nowButton != lastDn )
        {
            lastDn = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_DOWN_PRESSED;
                
        }//if
        
    }//if
    
    return retval;
    
}//ReadButtons

Thanks for the code, it does compile and uploads. But when I tried it, it doesn't respond to any buttons and is locked in 1st gear.

patracy:
Reverse and park must have the selector moved to those positions. NOT done via solenoids. Thanks for your concern.

Yup. It was meant as a bit of a joke.

patracy:
Thanks for the code, it does compile and uploads. But when I tried it, it doesn't respond to any buttons and is locked in 1st gear.

Interesting. I tried it here, piping each of the solenoid and TCC outputs to the built-in LED and it seems to respond to up and down requests.

Can you show a diagram of your wiring?

This one assumes normally-open switches that ground a pin when pressed. Is that what you have?

Ahh I should have read your code. I was using +5v for buttons. But looking for ground should cancel out any ringing. That's a great idea. Just reloaded it and reconfigured the buttons to see ground when depressed, works great! Thank you so much.

So looking at the mode switch, I have a switch. But maybe it should just be a momentary button and use the same logic (look for ground). I'd like when that button is depressed the controller lock up the TCC in 3rd as well with the delay.

Should I add another switch to switch between manual/automatic?

I see the comment about how does the Arduino know if it's in P/N/D. I was planning on later on just having it look at the VSS. But I think the 4L80e has a gear indicator switch, perhaps that could be used. (I'll have to research how that works)

I've started adding a few things to your code for the tow/haul mode. Not sure where/how to define that, I thought about adding another item to the gear profiles (specifically 3rd gear), but got errors for that. I'm supposed to get a I2C screen monday, so I'm going to try adding that to this as well and report in the gear to the screen. I've also ordered a few more arduinos as well. I'm going to use another one to take two pots and output a square wave for RPM and another one simply for TPS voltage and a 3rd for mph. That would provide a means to simulate the vehicle's info to build out the automatic side of this. And test some safeties that need to be built into the manual mode to lockout downshifts if RPM or MPH > X.

#define NUM_FWD_GEARS               4       //#     number of forward speeds

#define BUTTON_READ_INTERVAL        50ul    //mS    time between up/down button reads

#define NO_PRESS                    0x00    //mask  bit mask for no buttons pressed
#define BUTTON_UP_PRESSED           0x01    //mask  bit mask for up button pressed
#define BUTTON_DOWN_PRESSED         0x02    //mask  bit mask for down button pressed
#define towmode_PRESSED             0x03    //mask  bit mask for mode button pressed

#define TCC_DELAY                   1000ul  //mS    after TCC is enabled, time delay before activation

const byte buttonUP = 2;                    //pin   Push Button for UP shift
const byte buttonDOWN = 4;                  //pin   Push Button for Down shift
const byte solA = 3;                        //pin   Solenoid A output
const byte solB = 5;                        //pin   Solenoid B output
const byte TCC  = 6;                        //pin   TCC output
const byte towmode = 7;                     //pin   button for tow/haul mode

byte
    gearSelection,
    lastGearSelection,
    lastUp,
    lastDn;
bool
    bTCCStatus;
//    btowmode;
unsigned long
    timeTCCSolenoid;

typedef struct structGearSolenoidProfiles
{
    byte    solenoid_A;
    byte    solenoid_B;
    bool    bEnableTCC;
//    bool    btowmode;
   
}sGearSolenoidProfiles;

//
// How does Arduino know reverse, park or drive?
//
const sGearSolenoidProfiles GearSolenoidProfiles[NUM_FWD_GEARS] =
{
    {
        //1st
        .solenoid_A = HIGH,
        .solenoid_B = LOW,
        .bEnableTCC = false
    },
    {
        //2nd
        .solenoid_A = LOW,
        .solenoid_B = LOW,
        .bEnableTCC = false
    },
    {
        //3rd
        .solenoid_A = LOW,
        .solenoid_B = HIGH,
        .bEnableTCC = false
//        .btowmode = true
    },
    {
        //4th
        .solenoid_A = HIGH,
        .solenoid_B = HIGH,
        .bEnableTCC = true
    }
   
};//GearSolenoidProfiles[]

void setup()
{
    pinMode( buttonUP, INPUT_PULLUP );
    lastUp = digitalRead( buttonUP );       //set initial button state
    pinMode( buttonDOWN, INPUT_PULLUP );
    lastDn = digitalRead( buttonDOWN );     //set initial button state
   
    pinMode( towmode, INPUT_PULLUP );           //towmode set as input

    
    pinMode( solA, OUTPUT );                //Solenoid A set as output
    pinMode( solB, OUTPUT );                //Solenoid B set as output
    pinMode( TCC, OUTPUT );                 //TCC set as output

    digitalWrite( solA, LOW );             //set intital state as off
    digitalWrite( solB, LOW );
    digitalWrite( TCC, LOW );

    //internal flag for TCC status
    bTCCStatus = false;
    gearSelection = 0;          //start in "1st" gear for this test
    lastGearSelection = 0xff;   //ensure we change into correct gear first pass by making last != current
   
}//setup

void loop() 
{
    Gear_Selection_Control();
    Gear_Solenoid_Control();
    TCC_Control();
   
}//loop

void Gear_Selection_Control( void )
{
    byte
        btnState;
       
    btnState = ReadButtons();
    switch( btnState )
    {
        case    NO_PRESS:
            //nothing pressed or not read (interval not elapsed); no action
        break;

        case    BUTTON_UP_PRESSED:
            if( gearSelection < (NUM_FWD_GEARS-1) )
                gearSelection++;
           
        break;

        case    BUTTON_DOWN_PRESSED:
            if( gearSelection > 0 )
                gearSelection--;
               
        break;

        case    towmode_PRESSED:
            if( gearSelection > 0 )
                gearSelection--;
               
        break;


        default:
            //only remaining possibility is both pressed; ignore with no action
        break;
       
    }//switch
   
}//void
   
void Gear_Solenoid_Control( void )
{
    if( gearSelection != lastGearSelection )
    {
        lastGearSelection = gearSelection;
        digitalWrite( solA, GearSolenoidProfiles[gearSelection].solenoid_A );
        digitalWrite( solB, GearSolenoidProfiles[gearSelection].solenoid_B );

        //if the gear just selected enables the TCC, start the hold-off timer
        if( GearSolenoidProfiles[gearSelection].bEnableTCC == true )
        {
            timeTCCSolenoid = millis();
           
        }//if
       
    }//if
   
}//Gear_Control

void TCC_Control( void )
{
    //is TCC now off?
    if( bTCCStatus == false  )
    {
        //is TCC enabled?
        if( GearSolenoidProfiles[gearSelection].bEnableTCC == true )
        {
            //has hold-off time passed?
            if( millis() - timeTCCSolenoid >= TCC_DELAY )
            {
                //turn on TCC
                digitalWrite( TCC, HIGH );
                bTCCStatus = true;
           
            }//if
           
        }//if
       
    }//if
    else
    {
        //TCC is on now; is TCC disabled now?
        if( GearSolenoidProfiles[gearSelection].bEnableTCC == false )
        {
            //turn off TCC
            digitalWrite( TCC, LOW );
            bTCCStatus = false;
           
        }//if
       
    }//else
   
}//TCC_Control

//returns a mask:
//0b00000000 - no buttons pressed
//0b00000001 - up pressed
//0b00000010 - down pressed
//0b00000011 - both pressed
//
byte ReadButtons( void )
{
    static unsigned long
        timeButton = 0;
    unsigned long
        tNow;
    byte
        retval,
        nowButton;

    retval = NO_PRESS;
   
    tNow = millis();
    if( (tNow - timeButton) >= BUTTON_READ_INTERVAL )
    {
        //set up for next read interval
        timeButton = tNow;

        //read the button and set the flags
        nowButton = digitalRead( buttonUP );
        if( nowButton != lastUp )
        {
            lastUp = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_UP_PRESSED;
               
        }//if
       
        nowButton = digitalRead( buttonDOWN );
        if( nowButton != lastDn )
        {
            lastDn = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_DOWN_PRESSED;
               
        }//if

        nowButton = digitalRead( towmode );
        if( nowButton != lastDn )
        {
            lastDn = nowButton;
            if( nowButton == LOW )
                retval |= towmode_PRESSED;
               
        }//if

                
    }//if
   
    return retval;
   
}//ReadButtons

An attempt at adding a tow-mode input.

#define NUM_FWD_GEARS               4       //#     number of forward speeds

#define BUTTON_READ_INTERVAL        50ul    //mS    time between up/down button reads

#define NO_PRESS                    0x00    //mask  bit mask for no buttons pressed
#define BUTTON_UP_PRESSED           0x01    //mask  bit mask for up button pressed
#define BUTTON_DOWN_PRESSED         0x02    //mask  bit mask for down button pressed

#define TCC_DELAY                   1000ul  //mS    after TCC is enabled, time delay before activation

const byte buttonUP = 2;                    //pin   Push Button for UP shift
const byte buttonDOWN = 4;                  //pin   Push Button for Down shift
const byte switchTOWMODE = 7;               //pin   Switch for tow/haul mode
const byte solA = 3;                        //pin   Solenoid A output
const byte solB = 5;                        //pin   Solenoid B output
const byte TCC  = 6;                        //pin   TCC output

byte
    gearSelection,
    lastGearSelection,
    lastUp,
    lastDn,
    lastTM;
bool
    bTCCStatus;
unsigned long
    timeTCCSolenoid;

typedef struct structGearSolenoidProfiles
{
    byte    solenoid_A;
    byte    solenoid_B;
    bool    bTCCGearEnable;
    
}sGearSolenoidProfiles;

//
// How does Arduino know reverse, park or drive?
//
const sGearSolenoidProfiles GearSolenoidProfiles[NUM_FWD_GEARS] =
{
    {
        //1st
        .solenoid_A = HIGH,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //2nd
        .solenoid_A = LOW,
        .solenoid_B = LOW,
        .bTCCGearEnable = false
    },
    {
        //3rd
        .solenoid_A = LOW,
        .solenoid_B = HIGH,
        .bTCCGearEnable = true
    },
    {
        //4th
        .solenoid_A = HIGH,
        .solenoid_B = HIGH,
        .bTCCGearEnable = true
    }
    
};//GearSolenoidProfiles[]

void setup() 
{
    pinMode( buttonUP, INPUT_PULLUP );
    lastUp = digitalRead( buttonUP );       //set initial button state
    pinMode( buttonDOWN, INPUT_PULLUP );
    lastDn = digitalRead( buttonDOWN );     //set initial button state
    pinMode( switchTOWMODE, INPUT_PULLUP );
        
    pinMode( solA, OUTPUT );                //Solenoid A set as output
    pinMode( solB, OUTPUT );                //Solenoid B set as output
    pinMode( TCC, OUTPUT );                 //TCC set as output

    digitalWrite( solA, LOW );             //set intital state as off
    digitalWrite( solB, LOW );
    digitalWrite( TCC, LOW );

    //internal flag for TCC status
    bTCCStatus = false;
    gearSelection = 0;          //start in "1st" gear for this test
    lastGearSelection = 0xff;   //ensure we change into correct gear first pass by making last != current
    
}//setup

void loop()  
{
    Gear_Selection_Control();
    Gear_Solenoid_Control();
    TCC_Control();
    
}//loop

void Gear_Selection_Control( void )
{
    byte
        btnState;
        
    btnState = ReadButtons();
    switch( btnState )
    {
        case    NO_PRESS:
            //nothing pressed or not read (interval not elapsed); no action
        break;

        case    BUTTON_UP_PRESSED:
            if( gearSelection < (NUM_FWD_GEARS-1) )
                gearSelection++;
            
        break;

        case    BUTTON_DOWN_PRESSED:
            if( gearSelection > 0 )
                gearSelection--;
                
        break;

        default:
            //only remaining possibility is both pressed; ignore with no action
        break;
        
    }//switch
    
}//void
    
void Gear_Solenoid_Control( void )
{
    if( gearSelection != lastGearSelection )
    {
        lastGearSelection = gearSelection;
        digitalWrite( solA, GearSolenoidProfiles[gearSelection].solenoid_A );
        digitalWrite( solB, GearSolenoidProfiles[gearSelection].solenoid_B );

        //if 
        // - the gear just selected enables the TCC, and
        // - the last gear did not enable it, and
        // - the TCC is not now enaged
        //      start the TCC delay timer
        if( bTCCStatus == false )
        {
            if( GearSolenoidProfiles[gearSelection].bTCCGearEnable == true && 
                    GearSolenoidProfiles[lastGearSelection].bTCCGearEnable == false )
            {
                timeTCCSolenoid = millis();
            
            }//if
            
        }//if
        
    }//if
    
}//Gear_Control

void TCC_Control( void )
{
    unsigned long
        tNow;
    bool
        bTCCEnabled;

    tNow = millis();
    
    //TCC enabled if:
    //  - 4th gear is engaged, OR
    //  - 3rd gear is engaged and tow-mode not selected, AND
    //  - TCC delay timer has expired
    bTCCEnabled =   ( (gearSelection == 3) || 
                    ( (gearSelection == 2 && digitalRead( switchTOWMODE ) == HIGH) ) ) &&
                    ( tNow - timeTCCSolenoid >= TCC_DELAY );  
    
    //if conditions passed and TCC is now off, turn on its solenoid
    if( bTCCEnabled )
    {
        if( bTCCStatus == false )
        {
            //turn on TCC
            digitalWrite( TCC, HIGH );
            bTCCStatus = true;
            
        }//if
        
    }//if
    else 
    {
        if( bTCCStatus == true )
        {
            //turn off TCC
            digitalWrite( TCC, LOW );
            bTCCStatus = false;
            
        }//if
        
    }//else
    
}//TCC_Control

//returns a mask:
//0b00000000 - no buttons pressed
//0b00000001 - up pressed
//0b00000010 - down pressed
//0b00000011 - both pressed
//
byte ReadButtons( void )
{
    static unsigned long
        timeButton = 0;
    unsigned long
        tNow;
    byte
        retval,
        nowButton;

    retval = NO_PRESS;
    
    tNow = millis();
    if( (tNow - timeButton) >= BUTTON_READ_INTERVAL )
    {
        //set up for next read interval
        timeButton = tNow;

        //read the button and set the flags
        nowButton = digitalRead( buttonUP );
        if( nowButton != lastUp )
        {
            lastUp = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_UP_PRESSED;
                
        }//if
        
        nowButton = digitalRead( buttonDOWN );
        if( nowButton != lastDn )
        {
            lastDn = nowButton;
            if( nowButton == LOW )
                retval |= BUTTON_DOWN_PRESSED;
                
        }//if
        
    }//if
    
    return retval;
    
}//ReadButtons

working on a 4l60e version of a arduino based tcm . just wondered how it worked?