Volume knob on custom keyboard?
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Does anyone have any experience adding a volume knob to a Teensy-powered keyboard?
I've done a little reading, and on the hardware side, it seems you could use a rotary encoder or a potentiometer. I'm a bit of an electronics noob, so...what are those and which would be better?
Secondly, on the software side, do any of the pre-built Teensy-compatible keyboard firmware projects have support for a volume knob built in? Or in this case (see below for specifics) would it be better just to write code from scratch?
Essentially, I'm thinking of making a little media controller with the leftover aluminium, switches, LEDs, spare Teensy, etc I will have from my home-made keyboard project!
If I can get it all figured out, it will hopefully include ~4-6 media keys, a volume knob, an audio switch (literally just a DPDT switch so I can switch between headphones and speakers without unplugging and re-plugging - not connected to the Teensy at all) and a USB hub (re-use the innards of a commercial one). The volume knob is the only bit yet I don't have figured out...
I've done a little reading, and on the hardware side, it seems you could use a rotary encoder or a potentiometer. I'm a bit of an electronics noob, so...what are those and which would be better?
Secondly, on the software side, do any of the pre-built Teensy-compatible keyboard firmware projects have support for a volume knob built in? Or in this case (see below for specifics) would it be better just to write code from scratch?
Essentially, I'm thinking of making a little media controller with the leftover aluminium, switches, LEDs, spare Teensy, etc I will have from my home-made keyboard project!
If I can get it all figured out, it will hopefully include ~4-6 media keys, a volume knob, an audio switch (literally just a DPDT switch so I can switch between headphones and speakers without unplugging and re-plugging - not connected to the Teensy at all) and a USB hub (re-use the innards of a commercial one). The volume knob is the only bit yet I don't have figured out...
- Muirium
- µ
- Location: Edinburgh, Scotland
- Main keyboard: HHKB Type-S with Bluetooth by Hasu
- Main mouse: Apple Magic Mouse
- Favorite switch: Gotta Try 'Em All
- DT Pro Member: µ
Definitely doable.
The Teensy firmware I use all the time — Soarer's Controller — can take input from direct pins on the Teensy. You could use a volume knob that sends pulses (one pin for up and one pin for down I assume), and map them to volume up and volume down media keys, without any actual coding. Ditto for whatever functions you'd like your other switches to do. So long as a standard USB keyboard has keys for the functions you want.
If you like C, you can try Hasu's TMK. I literally do not understand it (you must edit source code) but those who do think it's great.
The Teensy firmware I use all the time — Soarer's Controller — can take input from direct pins on the Teensy. You could use a volume knob that sends pulses (one pin for up and one pin for down I assume), and map them to volume up and volume down media keys, without any actual coding. Ditto for whatever functions you'd like your other switches to do. So long as a standard USB keyboard has keys for the functions you want.
If you like C, you can try Hasu's TMK. I literally do not understand it (you must edit source code) but those who do think it's great.
-
- Location: Stockholm, Sweden
- DT Pro Member: 0011
I have only thought about the problem and not built anything yet, but....
Do select a rotary encoder. Potentiometers give absolute readings and the USB HID standard supports only relative controls. I don't know of any firmware that does it, though. I have done some USB HID programming so maybe I could help you with modifying the source code of a firmware of your choosing.
It seems to me as if polling the encoder once every ms or so would be more than sufficient. You could poll the encoder in the same loop that you would use for scanning the keyboard matrix.
There is a lot of info on the web for using rotary encoders and Arduino - but the majority of that is for the purpose of controlling electric motors used in robotics, and they have other requirements than an input device. With an input device, the user is also in the loop, and the user gets some kind of feedback that he/she can use to adjust his speed.
Rotary encoders do not give a pulse for up and a pulse for down: they give off two pulse trains that are out of phase with one-another. However, thinking of pulses out of phases just gives me a headache. I find it easier to think of them as producing 2-bit Gray codes - which is actually the exact same thing.
In case you would find a 3-signal or 4-signal rotary encoder then that should also produce Gray code - If not, then it is not a rotary encoder but a rotary switch.
Do select a rotary encoder. Potentiometers give absolute readings and the USB HID standard supports only relative controls. I don't know of any firmware that does it, though. I have done some USB HID programming so maybe I could help you with modifying the source code of a firmware of your choosing.
It seems to me as if polling the encoder once every ms or so would be more than sufficient. You could poll the encoder in the same loop that you would use for scanning the keyboard matrix.
There is a lot of info on the web for using rotary encoders and Arduino - but the majority of that is for the purpose of controlling electric motors used in robotics, and they have other requirements than an input device. With an input device, the user is also in the loop, and the user gets some kind of feedback that he/she can use to adjust his speed.
Rotary encoders do not give a pulse for up and a pulse for down: they give off two pulse trains that are out of phase with one-another. However, thinking of pulses out of phases just gives me a headache. I find it easier to think of them as producing 2-bit Gray codes - which is actually the exact same thing.
In case you would find a 3-signal or 4-signal rotary encoder then that should also produce Gray code - If not, then it is not a rotary encoder but a rotary switch.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Muirium:
That's great - so you'd recommend Soarer's Controller for a full board as well? I had been planning to use the one in Matt3o's guide (Hasu's, I think?), but I'll have a look at Soarer's if you think it's more convenient.
Do you know if you can control the increments in which the volume goes up? Because the built in hotkeys on my laptop keyboard do 8% at a time (well, specifically, it goes from 0%-12% with the first press and 8% on subsequent presses) which is too much, whereas my current mech does 2% at a time via the hotkey (about right, really).
Also, how OS-specific are the media key functions with this software? do they send a universally 'understood' signal? It's just I use Linux and Windows, so it'd be nice for it to be consistent on both!
Findecanor:
Thanks for the detailed explanation and offer of help! I probably won't be tackling this for a month or so (after I'm done with my main keyboard project), but I may take you up on the offer then!
I was looking at something like this: (just what I found when I searched eBay for rotary encoder earlier) Would that work? If not, what sort of thing should I be looking at?
That's great - so you'd recommend Soarer's Controller for a full board as well? I had been planning to use the one in Matt3o's guide (Hasu's, I think?), but I'll have a look at Soarer's if you think it's more convenient.
Do you know if you can control the increments in which the volume goes up? Because the built in hotkeys on my laptop keyboard do 8% at a time (well, specifically, it goes from 0%-12% with the first press and 8% on subsequent presses) which is too much, whereas my current mech does 2% at a time via the hotkey (about right, really).
Also, how OS-specific are the media key functions with this software? do they send a universally 'understood' signal? It's just I use Linux and Windows, so it'd be nice for it to be consistent on both!
Findecanor:
Thanks for the detailed explanation and offer of help! I probably won't be tackling this for a month or so (after I'm done with my main keyboard project), but I may take you up on the offer then!
I was looking at something like this: (just what I found when I searched eBay for rotary encoder earlier) Would that work? If not, what sort of thing should I be looking at?
-
- Location: Stockholm, Sweden
- DT Pro Member: 0011
Soarer's code is closed-source and Soarer himself hasn't been active on the board for months from what I have heard.
The key codes for media keys are in the USB spec, but how much a volume step is is defined in the software on the host.
The firmware does need specific support for media keys because they are most often sent separate from regular keys. Hasu's TMK firmware does have support.
I'm sorry I can't tell anything about that encoder from just that image. I would need more info.
The key codes for media keys are in the USB spec, but how much a volume step is is defined in the software on the host.
The firmware does need specific support for media keys because they are most often sent separate from regular keys. Hasu's TMK firmware does have support.
I'm sorry I can't tell anything about that encoder from just that image. I would need more info.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Fair enough - this is the listing: http://www.ebay.co.uk/itm/1Pc-KY-040-Ro ... 5d4b76706cFindecanor wrote: ↑ I'm sorry I can't tell anything about that encoder from just that image. I would need more info.
There are plenty of similar-looking ones on ebay, this one just caught my eye because of the PCB mount.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
From what I've read, Soarer's code has the benefit of easy config, but the cons of being abandonware and lacking in certain advanced config options. Hasu's is more complex to set up (but has a fairly comprehensive guide, right?) and has more advanced features. Is this an accurate assessment? Are there any other firmware options?Findecanor wrote: ↑Soarer's code is closed-source and Soarer himself hasn't been active on the board for months from what I have heard.
The key codes for media keys are in the USB spec, but how much a volume step is is defined in the software on the host.
The firmware does need specific support for media keys because they are most often sent separate from regular keys. Hasu's TMK firmware does have support.
Two of my housemates are engineers with a decent level of proficiency in C, so I may go with Hasu's for my main board and get help from them/the forum with that.
Does Hasu's support input straight from the pins like Muirium was saying about Soarer's? If not, it may be easier to use Soarer's for my little media control box, as it won't need any of the advanced features really.
-
- Location: Haarlem, The Netherlands
- Main keyboard: IBM
- Main mouse: Microsoft IntelliMouse
- Favorite switch: Bucklingspring
- DT Pro Member: -
Interesting thread, I will keep an eye on this because this is a project what is in my head for some time but I lack the overall knowledge to make it happen. I was looking at a Griffin Powermate but missed the hardware options you describe here. Headphone jack - Speaker output switch. USB hub and dedicated mediakeys.
- Muirium
- µ
- Location: Edinburgh, Scotland
- Main keyboard: HHKB Type-S with Bluetooth by Hasu
- Main mouse: Apple Magic Mouse
- Favorite switch: Gotta Try 'Em All
- DT Pro Member: µ
Soarer's Controller does volume control keys. I use Fn and +/- for those on all my old mechs thanks to this!
Soarer himself has been gone for about a year now I think. We've no idea what happened to him. Fortunately, his software is pretty much feature complete and rock solid. Hasu's can certainly be extended and modified in ways that Soarer's cannot, but I push it quite hard and never have a problem. It's certainly the one I feel more comfortable with, myself.
Bad news however that volume twiddlers don't work the way I thought. You might be stuck writing something yourself, built on top of Hasu's TMK because of that.
Soarer himself has been gone for about a year now I think. We've no idea what happened to him. Fortunately, his software is pretty much feature complete and rock solid. Hasu's can certainly be extended and modified in ways that Soarer's cannot, but I push it quite hard and never have a problem. It's certainly the one I feel more comfortable with, myself.
Bad news however that volume twiddlers don't work the way I thought. You might be stuck writing something yourself, built on top of Hasu's TMK because of that.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Thanks! Like I said, it might be a month or so before I make any real visible progress on this, but I'll try to remember to update it when I do!malcomkern wrote: ↑Interesting thread, I will keep an eye on this because this is a project what is in my head for some time but I lack the overall knowledge to make it happen. I was looking at a Griffin Powermate but missed the hardware options you describe here. Headphone jack - Speaker output switch. USB hub and dedicated mediakeys.
I found this about doing basically what I want to do but with a Pro Trinket (some sort of Arduino, I think). Does anyone know how hard would that code be to convert to run on a Teensy?
-
- Main keyboard: QWERTY
- Favorite switch: MxBlue
- DT Pro Member: -
http://hackaday.com/2015/01/17/dial-is- ... ontroller/
This guy made a wireless volume up/down song skip, play and pause arduino powered knob
This guy made a wireless volume up/down song skip, play and pause arduino powered knob
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
I'm going to finally bring this back up again, as I'm finally in a position to start looking at this again.
First of all, how easy would it be to 'port' this to a Teensy: https://learn.adafruit.com/pro-trinket- ... me-control
It seems to do basically what I want, so no point re-inventing the wheel if I don't have to.
Secondly, how hard would it be to add media keys to that code? It doesn't seem worth having a matrix, as all I'd need is about 4 switches (play/pause, skip forward, skip back, maybe lock PC/sleep), thus I wouldn't need TMK or Soarer's etc.
Thanks in advance.
First of all, how easy would it be to 'port' this to a Teensy: https://learn.adafruit.com/pro-trinket- ... me-control
It seems to do basically what I want, so no point re-inventing the wheel if I don't have to.
Secondly, how hard would it be to add media keys to that code? It doesn't seem worth having a matrix, as all I'd need is about 4 switches (play/pause, skip forward, skip back, maybe lock PC/sleep), thus I wouldn't need TMK or Soarer's etc.
Thanks in advance.
- Ray
- Location: Germany
- Main mouse: touchpad
- DT Pro Member: -
About runnig that code on a teensy:
You could also use a pro trinket, it is cheaper than the teensy and should do that job.
About more multimedia keys: that's a non-issue really as well. If you go through the code on your link, you will find a line that readsExchange MMKEY_MUTE for what you are looking for.
That function does the whole button press and release thing, so if you want it like with better keyboard firmware, a keydown event when pressed and a keyup when released you would have to change that. The example code on adafruit is really the quick'n'dirty solution here. But it should do the job for you unless you want to hold the skip buttons pressed.
So I guess it is not a problem at all.
You could also use a pro trinket, it is cheaper than the teensy and should do that job.
About more multimedia keys: that's a non-issue really as well. If you go through the code on your link, you will find a line that reads
Code: Select all
TrinketHidCombo.pressMultimediaKey(MMKEY_MUTE);
That function does the whole button press and release thing, so if you want it like with better keyboard firmware, a keydown event when pressed and a keyup when released you would have to change that. The example code on adafruit is really the quick'n'dirty solution here. But it should do the job for you unless you want to hold the skip buttons pressed.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Thanks for the reply, Ray. I said Teensy simply because I happen to have a couple lying around, otherwise I would use a cheaper board.
So I guess I would copy that code and just change the names of the pins to the relevant ones on the teensy. To add extra media keys in, presumably I would copy & paste the whole IF statement section that handles the mute button, but changing the pins and keycodes?
Last time I properly did any coding was 4 years ago in high school! So I sort of know what I'm doing generally, but still need a bit of help with the ins and outs!
So I guess I would copy that code and just change the names of the pins to the relevant ones on the teensy. To add extra media keys in, presumably I would copy & paste the whole IF statement section that handles the mute button, but changing the pins and keycodes?
Last time I properly did any coding was 4 years ago in high school! So I sort of know what I'm doing generally, but still need a bit of help with the ins and outs!
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Right. I got the easy half of this done last week - the easy half being the audio in/out switch. It was subject to a wee bit of feature creep, as it now can not only select one of two outputs, but also one of four inputs. So, I could play music at my desk without having to turn my PC on or unplug and replug the cable into my iPod. Or, for example, when I move next year I might need to put my Wii on my desk instead of in my shared lounge. I will be able to switch between audio sources easily.
Here's a crappy photo: the rotary switch does the four inputs and the toggle switch does the two outputs. The harder bit comes this afternoon. I've got a cup of tea made and a soldering iron warming up, so I'll be trying out the rotary encoder with the Teensy. I won't be putting the media keys in until I have the box I'm going to put it in (I have a few ideas about that) because you need to push MX switches in from the front of the plate, meaning you have to solder them up after they're mounted. But you all knew that...
Here's a crappy photo: the rotary switch does the four inputs and the toggle switch does the two outputs. The harder bit comes this afternoon. I've got a cup of tea made and a soldering iron warming up, so I'll be trying out the rotary encoder with the Teensy. I won't be putting the media keys in until I have the box I'm going to put it in (I have a few ideas about that) because you need to push MX switches in from the front of the plate, meaning you have to solder them up after they're mounted. But you all knew that...
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Right. Ordered a Pro Trinket and re-wired it and it's all recognised. However, turning the knob makes it jump quite randomly. Turn it clockwise and it will more or less consistently go down, turn it anticlockwise and it will hop up and down. But only every 4 or so 'clicks'. Weird...
-
- Location: Stockholm, Sweden
- DT Pro Member: 0011
Hmm.. If that is an electromechanical rotary encoder, then it might debouncing on each signal pin.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Right...and how would I do that? Software or hardware change? As it stands, it's all identical to the Adafruit project linked above.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Well. After a wee bit of googling, trial and error, fiddling, ordering bits and bobs off eBay, we have a working volume knob. Using the code from the tutorial linked to above, but a different circuit design, due to my encoder having debouncing circuits built in. Works well enough - next step: integrate those six Gaterons you can see there! Any suggestions for features? I want to use 6, but can only think of four functions as of yet: play/pause, skip track forward/back, and lock screen.
Just noticed that tea-stain under the encoder! Remind me to clean my desk soon...
Just noticed that tea-stain under the encoder! Remind me to clean my desk soon...
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
It does have a pushbutton! Might make one Gateron a discrete mute key, though, if the action of pushing on the volume knob is awkward.
[Edit]: By awkward, I mean that in pushing down on the knob, it's easy to accidentally twist it one notch, thus unmuting it.
[Edit]: By awkward, I mean that in pushing down on the knob, it's easy to accidentally twist it one notch, thus unmuting it.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Right. This project is 95% complete now! Hooray! It's now drifted a little away from its keyboard roots, but it's still an input device, and it still has some MX clone switches in it, so I thought I'd post a sort of buildlog (thanks @Phenix for reminding me!).
All that's left to do now is:
1) drill one more hole in faceplate for USB cable to exit
2) screw faceplate into main box
3) Make some nice sleeved jack to jack cables for the audio switching part!
As you can see above, my original plan was to have an audio output switcher so I could switch between headphones and speakers with the flip of a switch. I planned to include a USB volume knob and some media controls just for the heck of it. I eventually decided to add an input switcher, so I could plug my PC, iPod, phone, tablet, Wii, etc in and switch between which was outputting sound through my speakers with the twist of a dial (though my dial only has 4 positions - I'm thinking PC, Wii and two spare aux-in's depending on what portable device(s) I might have on me).
So. Here's the front of the faceplate: The four jacks at the left are the inputs, the dial next to them is a rotary switch with 4 positions. The wires then run to the switch in the middle, which selects between either of the jacks below (outputs).
The right dial is volume, and is connected to a rotary encoder which in turn is connected to an Arduino Pro Trinket, as are 4 of the switches to the right (I only wired up 4 because I couldn't think of uses for the other two and I'd run out of those little jumper cables. But I can always wire them up as and when I get ideas for them!). The switches (top left to bottom right) do the following:
1) Lock - this sends the Windows 'lock screen' key combo (Win+L). I set up a custom keyboard shortcut in Linux so it also works on my dualboot setup.
2) Play/pause media
3) Skip to previous track
4) Skip forwards
That's it on the hardware side really. Here's a picture of the wiring, though, spaghetti-ish though it may be: The faceplate is made of 1.5mm plywood stuff (laser cut-able, though I just used a hand drill) and the box...wait for it...is an old military surplus ammo crate. It's the perfect size to use as a monitor stand! I did consider repainting it so it didn't look so 'military', but I quite like the vintage look it has with the big dials and toggle switch etc. The blocks of wood are glued in with Gorilla Glue (my brother swears by the stuff, but we'll see how that holds up) and the faceplate will screw directly into them. It's slightly recessed (by about 30mm) so the lid can still be attached if I want. (The box is actually waterproof, which is kind of cool. Not that I need that feature, but still kind of cool).
I'll post pictures once the thing is finally assembled and I have my nice matching cables.
(Oh yeah, the code. That's on my Windows partition, so I'll go dig it out, tidy it up and post it)
All that's left to do now is:
1) drill one more hole in faceplate for USB cable to exit
2) screw faceplate into main box
3) Make some nice sleeved jack to jack cables for the audio switching part!
As you can see above, my original plan was to have an audio output switcher so I could switch between headphones and speakers with the flip of a switch. I planned to include a USB volume knob and some media controls just for the heck of it. I eventually decided to add an input switcher, so I could plug my PC, iPod, phone, tablet, Wii, etc in and switch between which was outputting sound through my speakers with the twist of a dial (though my dial only has 4 positions - I'm thinking PC, Wii and two spare aux-in's depending on what portable device(s) I might have on me).
So. Here's the front of the faceplate: The four jacks at the left are the inputs, the dial next to them is a rotary switch with 4 positions. The wires then run to the switch in the middle, which selects between either of the jacks below (outputs).
The right dial is volume, and is connected to a rotary encoder which in turn is connected to an Arduino Pro Trinket, as are 4 of the switches to the right (I only wired up 4 because I couldn't think of uses for the other two and I'd run out of those little jumper cables. But I can always wire them up as and when I get ideas for them!). The switches (top left to bottom right) do the following:
1) Lock - this sends the Windows 'lock screen' key combo (Win+L). I set up a custom keyboard shortcut in Linux so it also works on my dualboot setup.
2) Play/pause media
3) Skip to previous track
4) Skip forwards
That's it on the hardware side really. Here's a picture of the wiring, though, spaghetti-ish though it may be: The faceplate is made of 1.5mm plywood stuff (laser cut-able, though I just used a hand drill) and the box...wait for it...is an old military surplus ammo crate. It's the perfect size to use as a monitor stand! I did consider repainting it so it didn't look so 'military', but I quite like the vintage look it has with the big dials and toggle switch etc. The blocks of wood are glued in with Gorilla Glue (my brother swears by the stuff, but we'll see how that holds up) and the faceplate will screw directly into them. It's slightly recessed (by about 30mm) so the lid can still be attached if I want. (The box is actually waterproof, which is kind of cool. Not that I need that feature, but still kind of cool).
I'll post pictures once the thing is finally assembled and I have my nice matching cables.
(Oh yeah, the code. That's on my Windows partition, so I'll go dig it out, tidy it up and post it)
Last edited by Plasmodium on 27 Aug 2016, 15:14, edited 1 time in total.
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Most of my code I took from here: https://learn.adafruit.com/pro-trinket- ... r/overview
I added 4 more buttons by duplicating the code where pushing on the encoder mutes/unmutes. I could possibly have done it more efficiently, but I had struggled for ages with annoying debouncing issues and phantom keypresses (which turned out to be a hardware issue) and this way just worked.
Also note that I had to wire it up a wee bit differently to the tutorial, because my encoder had built-in debouncing circuits. Just had to connect the "+" pin to the 3.3v on the Arduino. (Whereas the tutorial uses no input current, just the pullup resistors. You can probably tell I'm a bit of a noob at this, this took me forever to figure out...)
I added 4 more buttons by duplicating the code where pushing on the encoder mutes/unmutes. I could possibly have done it more efficiently, but I had struggled for ages with annoying debouncing issues and phantom keypresses (which turned out to be a hardware issue) and this way just worked.
Code: Select all
/**************************************************************************/
/*!
* Original Intro:
*
@file ProTrinketVolumeKnobPlus.ino
@author Mike Barela for Adafruit Industries
@license MIT
This is an example of using the Adafruit Pro Trinket with a rotary
encoder as a USB HID Device. Turning the knob controls the sound on
a multimedia computer, pressing the knob mutes/unmutes the sound
Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!
@section HISTORY
v1.0 - First release 1/26/2015 Mike Barela based on code by Frank Zhou
*/
/*My code is mostly copied from the above project with the addition of four more pushbuttons
/**************************************************************************/
#include <ProTrinketHidCombo.h>
#define PIN_ENCODER_A 4
#define PIN_ENCODER_B 5
#define TRINKET_PINx PIND
#define PIN_ENCODER_SWITCH 3
#define PIN_SWITCH_A 9
#define PIN_SWITCH_B 13 //Pin 10 was a bit dodgy and firing off inputs whenever the nearby pins were used (some kind of short?) so I had to move this one up a bit. Forgot pin 13 was the LED pin. Oh well, still works...
#define PIN_SWITCH_C 11
#define PIN_SWITCH_D 12
static uint8_t enc_prev_pos = 0;
static uint8_t enc_flags = 0;
static char sw_was_pressed = 0;
static char swa_was_pressed = 0;
static char swb_was_pressed = 0;
static char swc_was_pressed = 0;
static char swd_was_pressed = 0;
void setup()
{
// set pins as input with internal pull-up resistors enabled
pinMode(PIN_ENCODER_A, INPUT_PULLUP);
pinMode(PIN_ENCODER_B, INPUT_PULLUP);
pinMode(PIN_ENCODER_SWITCH, INPUT_PULLUP);
pinMode(PIN_SWITCH_A, INPUT_PULLUP);
pinMode(PIN_SWITCH_B, INPUT_PULLUP);
pinMode(PIN_SWITCH_C, INPUT_PULLUP);
pinMode(PIN_SWITCH_D, INPUT_PULLUP);
TrinketHidCombo.begin(); // start the USB device engine and enumerate
// get an initial reading on the encoder pins
if (digitalRead(PIN_ENCODER_A) == LOW) {
enc_prev_pos |= (1 << 0);
}
if (digitalRead(PIN_ENCODER_B) == LOW) {
enc_prev_pos |= (1 << 1);
}
}
void loop()
{
int8_t enc_action = 0; // 1 or -1 if moved, sign is direction
// note: for better performance, the code will use
// direct port access techniques
// http://www.arduino.cc/en/Reference/PortManipulation
uint8_t enc_cur_pos = 0;
// read in the encoder state first
if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_A)) {
enc_cur_pos |= (1 << 0);
}
if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_B)) {
enc_cur_pos |= (1 << 1);
}
// if any rotation at all
if (enc_cur_pos != enc_prev_pos)
{
if (enc_prev_pos == 0x00)
{
// this is the first edge
if (enc_cur_pos == 0x01) {
enc_flags |= (1 << 0);
}
else if (enc_cur_pos == 0x02) {
enc_flags |= (1 << 1);
}
}
if (enc_cur_pos == 0x03)
{
// this is when the encoder is in the middle of a "step"
enc_flags |= (1 << 4);
}
else if (enc_cur_pos == 0x00)
{
// this is the final edge
if (enc_prev_pos == 0x02) {
enc_flags |= (1 << 2);
}
else if (enc_prev_pos == 0x01) {
enc_flags |= (1 << 3);
}
// check the first and last edge
// or maybe one edge is missing, if missing then require the middle state
// this will reject bounces and false movements
if (bit_is_set(enc_flags, 0) && (bit_is_set(enc_flags, 2) || bit_is_set(enc_flags, 4))) {
enc_action = 1;
}
else if (bit_is_set(enc_flags, 2) && (bit_is_set(enc_flags, 0) || bit_is_set(enc_flags, 4))) {
enc_action = 1;
}
else if (bit_is_set(enc_flags, 1) && (bit_is_set(enc_flags, 3) || bit_is_set(enc_flags, 4))) {
enc_action = -1;
}
else if (bit_is_set(enc_flags, 3) && (bit_is_set(enc_flags, 1) || bit_is_set(enc_flags, 4))) {
enc_action = -1;
}
enc_flags = 0; // reset for next time
}
}
enc_prev_pos = enc_cur_pos;
if (enc_action > 0) {
TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_UP); // Clockwise, send multimedia volume up
}
else if (enc_action < 0) {
TrinketHidCombo.pressMultimediaKey(MMKEY_VOL_DOWN); // Counterclockwise, is multimedia volume down
}
// remember that the switch is active low
if (bit_is_clear(TRINKET_PINx, PIN_ENCODER_SWITCH))
{
if (sw_was_pressed == 0) // only on initial press, so the keystroke is not repeated while the button is held down
{
TrinketHidCombo.pressMultimediaKey(MMKEY_MUTE); // Encoder pushed down, toggle mute or not
delay(5); // debounce delay
}
sw_was_pressed = 1;
}
else
{
if (sw_was_pressed != 0) {
delay(5); // debounce delay
}
sw_was_pressed = 0;
}
if (digitalRead(PIN_SWITCH_A) == LOW)
{
if (swa_was_pressed == 0) // only on initial press, so the keystroke is not repeated while the button is held down
{
TrinketHidCombo.pressMultimediaKey(MMKEY_PLAYPAUSE ); // Play/pause
delay(5); // debounce delay
}
swa_was_pressed = 1;
}
else
{
if (swa_was_pressed != 0) {
delay(5); // debounce delay
}
swa_was_pressed = 0;
}
if (digitalRead(PIN_SWITCH_B) == LOW)
{
if (swb_was_pressed == 0) // only on initial press, so the keystroke is not repeated while the button is held down
{
TrinketHidCombo.pressKey(KEYCODE_MOD_LEFT_GUI, KEYCODE_L); // Lock screen combo for Windows - set up custom keyboard actions for other OSes
TrinketHidCombo.pressKey(0, 0); // This is important - otherwise the device will keep Win+L held down and weird stuff happens (like accessibility options randomly opening on the lock screen)
delay(5); // debounce delay
}
swb_was_pressed = 1;
}
else
{
if (swb_was_pressed != 0) {
delay(5); // debounce delay
}
swb_was_pressed = 0;
}
if (digitalRead(PIN_SWITCH_C) == LOW)
{
if (swc_was_pressed == 0) // only on initial press, so the keystroke is not repeated while the button is held down
{
TrinketHidCombo.pressMultimediaKey(MMKEY_SCAN_PREV_TRACK); // Previous track
delay(5); // debounce delay
}
swc_was_pressed = 1;
}
else
{
if (swc_was_pressed != 0) {
delay(5); // debounce delay
}
swc_was_pressed = 0;
}
if (digitalRead(PIN_SWITCH_D) == LOW)
{
if (swd_was_pressed == 0) // only on initial press, so the keystroke is not repeated while the button is held down
{
TrinketHidCombo.pressMultimediaKey(MMKEY_SCAN_NEXT_TRACK); // Skip track
delay(5); // debounce delay
}
swd_was_pressed = 1;
}
else
{
if (swd_was_pressed != 0) {
delay(5); // debounce delay
}
swd_was_pressed = 0;
}
TrinketHidCombo.poll(); // check if USB needs anything done, do every 10 ms or so
}
- Phenix
- -p
- Location: Germany, Cologne
- Main keyboard: F122, soarer´d|Novatouch-s
- Main mouse: Roccat Kone Pure|Rollermouse
- Favorite switch: BS F|Topre-s
- DT Pro Member: -
this looks really good, congrats!
Badly I don't feel like I could do that, eventough I would really like to build some rotary dials in an Model F122..
Badly I don't feel like I could do that, eventough I would really like to build some rotary dials in an Model F122..
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Thanks for the kind words! Not quite finished yet, though. Maybe tomorrow afternoon I'll find the time to do the last few little tasks!Ray wrote: ↑Nice to see a finished project. And not too shabby at that. I always like ammo-boxes as project boxes and the fact that you didn't need to drill into it and keep it waterproof is also nice. Totally unnecessary, but indeed kinda cool
It's not too bad! Especially if you use the jumper/breadboard wires, you don't have to solder anything permanently (so you don't have to worry about making mistakes!).Phenix wrote: ↑this looks really good, congrats!
Badly I don't feel like I could do that, eventough I would really like to build some rotary dials in an Model F122..
- Plasmodium
- Location: UK
- Main keyboard: QPAD MK80
- Main mouse: Logitech LX3
- Favorite switch: Cherry brown
- DT Pro Member: -
Well, you don't really need to understand the code as long as it works, right?Phenix wrote: ↑I will look into the code more closely, the soldering is not the hardest part imo