The Influence

Since cars were invented, people have been customizing them. It’s in our DNA. For the better part of a decade, I’ve worked as a 12v installer integrating all different sorts of electronics into modern cars.

The problem with adding most aftermarket electronics is that typically no ideal way to activate or deactivate them exists. Most people will just add a momentary button somewhere on their dashboard — either with adhesive or by drilling a permanent hole. Others that want to preserve a factory look will purchase OEM buttons specifically designed for their year, make, and model. However, the cost of these can add up fast and soon you’re spending a considerable amount on simply switches alone.

In my experience, customers that purchase high end vehicles often times want little to no aesthetic modification at all. Using an Arduino and CAN receiver, we are able to accomplish exactly this.

If you are brand new to Arduino or CAN, it may be beneficial to skim through my last article before continuing.

How It’s Done

Let’s take a look at the sketch I used to complete this on my first project , along with a breakdown of what’s happening starting from the top and working down.

digitalRead(2) is connected to the interrupt on our mcp2515 module. If this pin is low, new CAN messages have been received by the Ardino so we then call on the function CAN0.readMsgBuf(&rxId, &len, rxBuf) to read the data.

With (rxId == buttonId) && (rxBuf == buttonData) buttonId is the CAN ID that corresponds with the button we want to add functionality to and buttonData is the data we observe when the button is pressed. buttonPress is the variable we’ll use to keep count of how many times the button’s been pressed. At this point all we are saying is if the button in the car is pressed, increase the count by 1.

To understand the next part, you need to be somewhat familiar with the millis() function. Essentially, it’s just keeping a running log of the milliseconds that have passed since the program started running and by calling on it you are able to get a snapshot of that time.

So with if (buttonPress == 1) { startMillis = millis(); what we are saying is if the button has been pressed once, record the current time. The same applies for if (buttonPress == 2) { endMillis = millis(); . If it’s pressed again, record the current time, but in a different variable.

Then we need to compare the time values to eachother. By using the statement if (endMillis — startMillis <= 1000) //Do something! what we are saying is that if the button is double pressed (pressed 2x within 1 second) then do something.

If the interval between presses is longer than 1 second, else {buttonPress — ; decreases the the counter back to 1. And if the second press just never comes, if ((buttonPress == 1) && (millis() — startMillis > 1000)) { buttonPress — ; resets the counter to zero.

DoublePress Demo

As you can see, by utilizing this sketch we can easily add a second function to any button we have bus access to. Also, we can customize by increasing the length of time needed between presses, or make it so a long press and hold is needed instead, or even require more than one button is pressed at a single time in order to activate.

Keep in mind that because we are only listening to the bus, every time the button is pressed whatever the default action of that button is will still occur. For instance, you likely wouldn’t want to program something like this to a volume up button for the radio. In my car, I used the ‘cancel cruise control’ button since majority of the time it’s not being used. Now, if we were to use a pair of Arduino’s and CAN receivers then we could firewall the bus and avoid the default action from taking place entirely, but that is another story…

Lastly, this was developed using the GMLAN bus on a late model Chevrolet and there is always a possibility that your CAN data behaves differently.