John L Errington MSc

Experiments with an Arduino: keypress simulator (1)

PC test equipment using a tiny Arduino

A client recently asked me to check her PC. She told me when she was typing a long email it would often misbehave, ignoring key entries. I wondered if I could use an Arduino to build a device that would simulate keyboard entry. As I has a Nano lying around I started with that. I'll use this example to illustrate a "top down" approach to program development.

Arduino nano
I'll need to wait for my ProMicro boards to be delivered as the Nano does not support USB I/O. Core libraries allow the 32u4 and SAMD based boards (Leonardo, Esplora, Zero, Due and MKR Family) to appear as a native Mouse and/or Keyboard to a connected computer.

So for now I'm going to develop the program structure and leave the actual keystroke routine for later development.

Top Down design

If the "box" just sends characters all the time I would not be able to interact with the PC; so we need at least two "phases" to the program; An "idle" phase in which it indicates its ready to send, and an "active" phase during which characters are sent. There will need to be some way to switch between these two states.

void loop(){

if (command==HIGH) then { idle(); } else { active(); }

}

Notice the important aspects of top down design;

We have not concerned ourselves with how the idle and active phases will work, just the simple idea that there will be two phases and a command to switch between them. This mirrors the simple State Machine Diagram we already developed.

First implementation

I started by connecting an LED to pin D5 on the Nano, and the negative end through a resistor to ground; pin D5 supports PWM and digital I/O. During development the "active" phase was to be indicated by flashing the LED, while the "idle" phase faded it slowly between full brightness and zero, then back to full repeatedly. These used the traditional "delay" for timing. There will be a toggle value to switch between them, controlled by a push button switch connected between pin D2 and ground.

void loop(){

if (toggleValue) then { fadeLed(); } else { flashLed(); }

}

First tests, debouncing and the decision to use an interrupt.

On test the program did not work very well for two reasons. Firstly, the fadeLed() routine had a duration of about 2 sec, during which time the switch was not polled. Secondly, like most switches it is subject to contact bounce, so the condition of the toggle might change several times for a single press.

I decided to use the switch on D2 to generate an interrupt on a falling edge. (Note - on the NANO only pins D2 and D3 support interrupts directly.)

This has two immediate advantages:

Here is the part of the code to set up the interrupt action:

void setup() {

pinMode(ledPin, OUTPUT);  digitalWrite(ledPin, LOW); //start with LED off to save power

pinMode(button,INPUT_PULLUP);  // this is the pin connected to the button switch

attachInterrupt(digitalPinToInterrupt(button), isr, FALLING);

//isr is the Interrupt Service Routine that will be called when the button is pressed

..

}

 

.. and the interrupt routine. We still need to make sure that switch bounce does not cause problems, which we can achieve by ensuring that sufficient time has elapsed since the previous interrupt.

void isr(){ //this is the interrupt service routine

if(millis() - lastIntMillis > debounceMillis){

toggleVal = !toggleVal;

intFlag = 0;

lastIntMillis = millis(); //record time of interrupt

}

}

 

sketch for this stage of the development

next page: further development