#include //sketch to read 6 way switch code on Micro Pro & display switch position /* http://www.geeetech.com/wiki/index.php/Serial_I2C_1602_16%C3%972_Character_LCD_Module connections: Vcc - +5V GND - 0V SDA - A4 SCL - A5 the blue box is a potentiometer Spinning the potentimeter clockwise is to increase contrast ,spinning unclockwise is to decrease it */ #include "Keyboard.h" #include LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display // pin assignments const byte ledPin = 9; //LED on pin D9 with resistor to GROUND const byte button = 7; //Button switch is connected between pin 2 and ground. Hardware interrupt. const byte tswitch = 4; //toggle switch on pin4 for on/off const int analogPin = A10; //wiper connects to Analog pin 10; compiler assigns correct number value automatically byte switchval, oldval = 16; //ensure at start oldval != switchval read from switch - which cannot exceed 8; enum rotaryswitch { ZERO, ONE, TWO, THREE = 4, FOUR, FIVE }; //rotary switch positions THREE=100, FOUR=101, FIVE=110 bool ledValue = 0; //led Off int flashRate = 100; //speed for delays - set later bool tswitchState; //is toggle switch tswitch on or off? char letter; // to be sent to PC bool firstLine = 1; //only print header if its the first line of a sequence //variables shared between ISR and code must be type volatile. volatile bool toggleVal = 0; // 0=resting, 1=active; do not send chars unless go button pressed volatile bool intFlag = 0; //if ==1 flags that an interrupt has occurred to allow routine to be suspended volatile int timerCount = 0; //count how many times the timer interrupt has occurred. //For interrupt button debounce: volatile unsigned long lastIntMillis = 0; //this is the time of the last interrupt volatile unsigned long debounceMillis = 500; //dont allow another in less than 0.5 sec #define DDRFmask 0b00001111 //AND mask, sets MSByte as inputs (=0) #define PORTFmask 0b11110000 //OR mask, sets MSByte "outputs" high for input-pullup int readA2() { //read analog input from potentiometer and process it for rate control unsigned long analogVal = analogRead(analogPin) + 75; //max value is approx 1020, minimum zero so add 75 //Serial.print(analogVal); analogVal *= analogVal; //square it so high end value has more effect analogVal = analogVal >> 11; //right shift to bring value back to max 600 min 2 int speed = analogVal; //to set a max flash rate of 5msec and slowest about 1 per sec //Serial.print(": speed "); //Serial.println(speed); return speed; } void waitFor(int msec) { do { int i = 0; } while (timerCount <= msec); timerCount = 0; } void blinkLed() { flashRate = readA2(); //read the speed from the potentiometer if (flashRate <= 25)flashRate = 25; //set a maximum rate to allow PC to respond. waitFor(flashRate); ledValue = 1; digitalWrite(ledPin, ledValue); waitFor(flashRate ); ledValue = 0; digitalWrite(ledPin, ledValue); } void flashLed(int s) { flashRate = s; waitFor(flashRate); ledValue = 1; digitalWrite(ledPin, ledValue); waitFor(flashRate); ledValue = 0; digitalWrite(ledPin, ledValue); } void notepad() { blinkLed(); Keyboard.press(KEY_LEFT_GUI); Keyboard.press('r'); blinkLed(); Keyboard.releaseAll(); blinkLed(); Keyboard.print("notepad.exe"); Keyboard.press(KEY_RETURN); flashLed(40);//timing is significant - too long and get too many returns Keyboard.releaseAll(); blinkLed(); Keyboard.print("Test launch and send characters to Notepad"); toggleVal = 0; //reset so we know its all done - dont repeat unless another interrupt blinkLed(); } void sendLetters() { blinkLed(); if (firstLine) { Keyboard.println("skillbank.co.uk testing keyboard entry"); firstLine = 0; } //send caps for (letter = 65; letter <= 95; letter++) { blinkLed(); Keyboard.print(letter); flashLed(20); Keyboard.print(" "); //space flashLed(20); //if(toggleVal==0)break; } //end of sending Caps Keyboard.println(" "); //new line blinkLed(); //send lower case for (letter = 97; letter <= 126; letter++) { blinkLed(); Keyboard.print(letter); flashLed(20); Keyboard.print(" "); //space flashLed(20); //if(toggleVal==0)break; } //end of sending lower case Keyboard.println(" "); //new line blinkLed(); //send symbols & numbers for (letter = 33; letter <= 64; letter++) { blinkLed(); Keyboard.print(letter); flashLed(20); Keyboard.print(" "); //space flashLed(20); //if(toggleVal==0)break; } Keyboard.println(" "); //new line //all done toggleVal = 0; //reset so we know its all done - dont repeat unless another interrupt blinkLed(); } void showswitchpos(int value) { if (value != oldval) { //only update display if setting has changed lcd.clear(); lcd.backlight(); //turn backlight on - in case its off lcd.setCursor ( 0, 0 ); // set to col:row - eg 1,8 is 8 chars in on of lower line switch (value) { case ZERO: { lcd.print(" LED Off"); break; } case ONE: { lcd.print(" LED On"); break; } case TWO: { lcd.print("Launch Notepad"); break; } case THREE: { lcd.print("Send Characters"); break; } case FOUR: { lcd.print("Flash LED fast"); break; } case FIVE: { lcd.print("Blink LED speed"); break; } default: { //default is optional - only happens if theres a fault on the switch } } lcd.setCursor ( 0, 1 ); // set to centre of lower line lcd.print("Position "); lcd.print(value); lcd.print(";"); oldval = value; //only change display if value has changed } } void setup() { Serial.begin(9600); Keyboard.begin(); lcd.init(); // initialize the lcd //set up button press to generate hardware interrupt pinMode (button, INPUT_PULLUP); //this is our interrupt button pinMode (tswitch, INPUT_PULLUP); //go - stop switch //Direct access to registers for port F follows DDRF &= DDRFmask; //to set pins 18-21 as inputs PORTF |= PORTFmask; //with input-pullup pinMode(ledPin, OUTPUT); //to show activity attachInterrupt(digitalPinToInterrupt(button), isr, FALLING); //Timer tick interrupt for waitfor() routine OCR0A = 0xAF; // set compare register to #175, interrupt on match TIMSK0 |= _BV(OCIE0A); } // Timer tick interrupt is called once a millisecond, ISR(TIMER0_COMPA_vect) { timerCount += 1; } void isr() { //this is the hardware interrupt service routine //if there has been enough time since the last interrupt then the switch value has been stable, so this isnt a bounce if (millis() - lastIntMillis > debounceMillis) { toggleVal = 1; intFlag = 1; lastIntMillis = millis(); //record time of interrupt } } void loop() { //Direct access to registers for port F follows switchval = PINF >> 4; //read data from PORT F pins 18-21 switchval = ~switchval; // invert it switchval &= 0b00000111; //mask off except lowest three bits switch (switchval) { case ZERO: { //Serial.println("skillbank: switch position zero"); showswitchpos(switchval); digitalWrite(ledPin, 0); // LED OFF break; } case ONE: { //Serial.println("skillbank: switch position one "); showswitchpos(switchval); digitalWrite(ledPin, 1); //LED ON break; } case TWO: { //Serial.println("skillbank: switch position two"); //only do this once showswitchpos(switchval); if (toggleVal) { notepad(); //Open Notepad & send chars flashLed(200); } break; } case THREE: { //Serial.println("skillbank: switch position three"); //only do this once showswitchpos(switchval); if (toggleVal) { sendLetters(); // Send all chars to PC flashLed(20); } break; } case FOUR: { //Serial.println("skillbank: switch position four"); showswitchpos(switchval); flashLed(40); break; } //Serial.println("skillbank: switch position five"); case FIVE: { showswitchpos(switchval); blinkLed(); break; } default: { //default is optional - only happens if theres a fault on the switch } }//switch }