Archived
1
0

add sr0_LED_shiftRegs.ino, LED_shiftRegs, LED_shiftRegs

This commit is contained in:
wolfv6 2016-10-30 02:30:13 -06:00
parent 6e3640d95f
commit 0c4b54db13
39 changed files with 731 additions and 96 deletions

View File

@ -4,8 +4,8 @@ We'd love for you to contribute to the keybrd project.
Improvement suggestions
-----------------------
We need to know what improvements to the keybrd library would help you create your keyboard design.
Before requesting an improvement, please check [planned_features list](doc/planned_features.md)
We need to know what keybrd library improvements would help you create keyboard designs.
Before requesting an improvement, please check the [planned_features list](doc/planned_features.md).
Submit improvement suggestions to [GitHub issues](https://github.com/wolfv6/Keybrd/issues)
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
@ -16,8 +16,8 @@ or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
Bug reports
-----------
A bug report is the first step in finding a bug.
Once it is found, correcting it is usually relatively easy.
Submitting a bug report is the first step in fixing a bug.
Once it is found, correcting a bug is usually relatively easy.
Please submit bug reports to [GitHub issues](https://github.com/wolfv6/Keybrd/issues)
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
@ -33,7 +33,7 @@ Provide enough information so we can reproduce the buggy behaviour!
Code contributions
------------------
Unsure where to begin contributing to keybrd code?
Unsure of where to begin contributing to keybrd code?
You can start by looking through the improvement suggestions, bug reports, and [planned_features](doc/planned_features.md).
Git commit message style guide:
@ -49,18 +49,57 @@ Any project requires various kinds of contributions to succeed.
A thriving project is more than a pile of code.
It's the packaging, explanation, outreach, and empathy of maintainers that make a good project great.
### Beta testing
keybrd library has been Alpha tested on the DodoHand keyboard, tutorial sketches, Teensy 2.0, and Teensy LC. What we need now are Beta testers:
* use the tutorials (feedback from noobs is especially valuable)
* use the keybrd library to implement your own keyboard design
### keybrd tutorials usability survey
We want feedback on keybrd tutorial usability from real users (feedback from noobs is especially valuable).
Please take the survey after completing a tutorial.
Answer the questions you feel like answering, or make up your own questions.
Feedback from Beta testers will be used to make improvements to the keybrd library.
* How easy was it to find the relevant tutorial?
* Which tutorial did you read?
* Did the tutorial provide complete information?
* What other tutorial topics would be useful?
* Are you satisfied with the tutorial?
* Other comments or suggestions.
Post the completed Q & A on [geekhack thread](https://geekhack.org/index.php?topic=83599.0) with a heading "Tutorial usability survey".
If you prefer your answers remain confidential, pm the completed Q & A to [wolfv](https://geekhack.org/index.php?action=pm;sa=send;u=25471).
Usability survey results will be used to make improvements to the tutorials.
### keybrd library usability survey
We want feedback on keybrd library usability from real users.
Please fill the survey after using the keybrd library to implement a keyboard design.
Answer the questions you feel like answering, or make up your own questions.
* How easy was it to find relevant information?
* Did the User guide provide complete information?
* What other keyboard firmware have you used?
* What pros and cons did you find compared to other keyboard firmware?
* Did you publish your keyboard firmware? If so, please provide a link.
* Are you satisfied with the keybrd library?
* Other comments or suggestions.
Post the completed Q & A on [geekhack thread](https://geekhack.org/index.php?topic=83599.0) with a heading "keybrd library usability survey".
If you prefer your answers remain confidential, pm the completed Q & A to [wolfv](https://geekhack.org/index.php?action=pm;sa=send;u=25471).
Usability survey results will be used to make improvements to the keybrd library.
### Schematics
The most glaring deficiency is the tutorials' lack of schematics.
Schematics would be an improvement over the current photos.
Schematics would be easier to read than the current photos.
Schematics are not my area of expertise. Use what ever you think would be the best solution for the tutorials:
Schematics are not my area of expertise. Use what ever would be the best solution for the tutorials:
* schematics
* breadboard drawings
* Arduino simulation software
@ -71,12 +110,29 @@ Contributions of tutorial schematics would benefit users new to the keybrd libra
Suggest a clarification, simplification, correction, or other improvement.
We need the perspective of people new to the project to see these things.
Sometimes just changing a word or two makes a big difference.
Please submit improvement and errata to [GitHub issues](https://github.com/wolfv6/Keybrd/issues)
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).
Text file documentation style guide:
* Use Markdown with a .md suffix.
* "Underline" first-level (=) and second-level (-) headings (because easier to read in plain text).
* Capitalize first letter of headings (no extra capitalization in headings).
### Write a sketch for a keyboard that is popular with Arduino-compatible controllers
Write a keybrd sketch for a keyboard that is popular with Arduino-compatible controllers.
* You should own the keyboard so you can test the firmware
* The keyboard should have an Arduino compatible controller (e.g. ErgoDox and Phantom use Teensy 2.0)
* The layout should be a plain baseline layout (QWERTY)
Other owners of that model keyboard can then easily modify and compile the sketch on Arduino IDE.
The README should have:
* brief description of the electronics
* link to a hardware page
* list any firmware deficiencies
Follow the "Publish" instructions in tutorial_8c_sharing_your_keybrd_sketch.md
### Blog
You have a fresh perspective of how the keybrd library works.
This makes you the perfect person to write an introductory blog explaining the project.
@ -85,5 +141,7 @@ A healthy project needs the perspective of many people.
Submitting a pull request
-------------------------
Pull request is the preferred way to contribute code and documentation.
If you want to contribute some other way, please make a request in the [GitHub issues](https://github.com/wolfv6/Keybrd/issues).
If you want to contribute some other way, please make a request in
[GitHub issues](https://github.com/wolfv6/Keybrd/issues)
or [geekhack thread](https://geekhack.org/index.php?topic=83599.0).

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 334 KiB

View File

@ -0,0 +1,69 @@
/* simulate one scan of a key martix, on open-drain active-low I/O expander
BREADBOARD SETUP *******************************
Teensy LC connected to MCP23018 I/O expander via I2C
4.7k Ohm pullup resistors on SDA and SCL
use volt meter to measure pin voltages
MCP23018 has open-drain outputs (open-drain can only sink current)
MCP23018 PIN DIAGRAM ***************************
write port B read port A
GND VSS 1 28 NC
NC 2 27 GPA7
jumper0 GPB0 3 26 GPA6
GPB1 4 25 GPA5
GPB2 5 24 GPA4 jumper4
GPB3 6 23 GPA3
jumper4 GPB4 7 22 GPA2
GPB5 8 21 GPA1
GPB6 9 20 GPA0 jumper0
GPB7 10 19 INTA
power VDD 11 18 INTB
SCL SCL 12 17 NC
SDA SDA 13 16 RESET power
NC 14 15 ADDR GND
*/
#include "Wire.h"
const uint8_t ADDR = 0x20; //MCP23018 I2C address with ADDR pin grounded
void setup()
{
delay(1000); //time for Serial print to work
// ================= configure ================
Serial.print("config ");
Wire.begin();
Wire.beginTransmission(ADDR);
Wire.write(0x01); //IODIRB Configure
Wire.write(0); //as output
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x00); //IODIRA Configuration
Wire.write(~0); //as input
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x0C); //GPPUA pull-up
Wire.write(~0); //pull-up enabled
Wire.endTransmission();
// =================== scan ===================
Serial.println("scan");
Wire.beginTransmission(ADDR);
Wire.write(0x13); //GPIOB output
Wire.write(B00001111); //pins 0-3 off, pins 4-7 sink on (strobe, LED on)
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x12); //GPIOA (immediately before requestFrom)
Wire.endTransmission();
Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one byte from GPIOA read
Serial.print("portA=");
Serial.println(Wire.read(), BIN); //prints portA=11101111
}
void loop() { }

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

View File

@ -0,0 +1,69 @@
/* simulate one scan of a key martix, on source active-high I/O expander
BREADBOARD SETUP *******************************
Teensy LC connected to MCP23017 I/O expander via I2C
10k Ohm external pulldown resistors on port A
4.7k Ohm pullup resistors on SDA and SCL
use volt meter to measure pin voltages
MCP23017 PIN DIAGRAM ***************************
write port B read port A
jumper0 GPB0 1 26 GPA7 pulldown
GPB1 2 25 GPA6 pulldown
GPB2 3 24 GPA5 pulldown
GPB3 4 23 GPA4 pulldown jumper4
jumper4 GPB4 5 22 GPA3 pulldown
GPB5 6 21 GPA2 pulldown
GPB6 7 20 GPA1 pulldown
GPB7 8 19 GPA0 pulldown jumper0
power VDD 9 18 INTA
GND VSS 10 28 INTB
NC 11 27 RESET power
SCL SCL 12 17 A2 gnd
SDA SDA 13 16 A1 gnd
NC 14 15 A0 gnd
*/
#include "Wire.h"
const uint8_t ADDR = 0x20; //MCP23017 I2C address with all ADDR pins grounded
void setup()
{
delay(1000); //time for Serial print to work
// ================= configure ================
Serial.print("config ");
Wire.begin();
Wire.beginTransmission(ADDR);
Wire.write(0x01); //IODIRB Configure
Wire.write(0); //as output
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x00); //IODIRA Configuration
Wire.write(~0); //as input
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x0C); //GPPUA pull-up
Wire.write(0); //pull-up disabled
Wire.endTransmission();
// =================== scan ===================
Serial.println("scan");
Wire.beginTransmission(ADDR);
Wire.write(0x13); //GPIOB output
Wire.write(B11110000); //pins 0-3 ground, pins 4-7 power (strobe, LED on)
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x12); //GPIOA (immediately before requestFrom)
Wire.endTransmission();
Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one byte from GPIOA read
Serial.print("portA=");
Serial.println(Wire.read(), BIN); //prints portA=00010000
}
void loop() { }

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

View File

@ -0,0 +1,68 @@
/* simulate one scan of a key martix, on source active-low I/O expander
BREADBOARD SETUP *******************************
Teensy LC connected to MCP23017 I/O expander via I2C
4.7k Ohm pullup resistors on SDA and SCL
use volt meter to measure pin voltages
MCP23017 PIN DIAGRAM ***************************
write port B read port A
jumper0 GPB0 1 26 GPA7
GPB1 2 25 GPA6
GPB2 3 24 GPA5
GPB3 4 23 GPA4 jumper4
jumper4 GPB4 5 22 GPA3
GPB5 6 21 GPA2
GPB6 7 20 GPA1
GPB7 8 19 GPA0 jumper0
power VDD 9 18 INTA
GND VSS 10 28 INTB
NC 11 27 RESET power
SCL SCL 12 17 A2 gnd
SDA SDA 13 16 A1 gnd
NC 14 15 A0 gnd
*/
#include "Wire.h"
const uint8_t ADDR = 0x20; //MCP23017 I2C address with all ADDR pins grounded
void setup()
{
delay(1000); //time for Serial print to work
// ================= configure ================
Serial.print("config ");
Wire.begin();
Wire.beginTransmission(ADDR);
Wire.write(0x01); //IODIRB Configure
Wire.write(0); //as output
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x00); //IODIRA Configuration
Wire.write(~0); //as input
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x0C); //GPPUA pull-up
Wire.write(~0); //pull-up enabled
Wire.endTransmission();
// =================== scan ===================
Serial.println("scan");
Wire.beginTransmission(ADDR);
Wire.write(0x13); //GPIOB output
Wire.write(B00001111); //pins 0-3 power (strobe, LED on), pins 4-7 ground
Wire.endTransmission();
Wire.beginTransmission(ADDR);
Wire.write(0x12); //GPIOA (immediately before requestFrom)
Wire.endTransmission();
Wire.requestFrom(ADDR, static_cast<uint8_t>(1)); //request one byte from GPIOA read
Serial.print("portA=");
Serial.println(Wire.read(), BIN); //prints portA=11101111
}
void loop() { }

View File

@ -6,11 +6,6 @@ This project adheres to [Semantic Versioning 2.0.0](http://semver.org/).
keybrd version 0.x.x is for initial development.
keybrd version 1.0.0 will be released when the public API is stable.
< !--
Unreleased
----------
-->
0.6.0 (2016-09-28)
------------------
* Enhancements

View File

@ -2,14 +2,12 @@ planned_features is a view of where the keybrd project is headed.
Top priority
------------
* Beta testing
* Add breadboard keyboard schematics to tutorials
* User testing
Medium priority
---------------
* Add matrix-to-layout mapping array (to decouple key matrix from layout)
* Add tutorial_4b_split_keyboard_with_shift_registers
* Add matrix-to-layout mapping (to decouple key matrix from layout)
* Add breadboard keyboard schematics to tutorials
Low priority
------------
* Add MCP23S18 I/O expander with Serial Peripheral Interface (SPI)

View File

@ -0,0 +1,131 @@
/* keybrd_MCP23018.ino
This sketch:
is a simple 1-layer keyboard
runs on two matrices of a breadboard keyboard
Controller I/O expander
| Left | **0** | **1** | | Right | **0** | **1** |
|-------|-------|-------| |-------|-------|-------|
| **1** | 1 | 2 | | **1** | 3 | 4 |
| **0** | a | b | | **0** | c | d |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
#include <ScanDelay.h>
#include <Code_Sc.h>
#include <Code_LEDLock.h>
#include <Row.h>
//left matrix
#include <Scanner_uC.h>
//right matrix
#include <Port_MCP23018.h>
#include <Scanner_IOE.h>
#include <LED_Port.h>
// ============ SPEED CONFIGURATION ============
ScanDelay scanDelay(9000);
/* ================ LEFT SCANNER ===============
Left matrix rows work the same as the ones in keybrd_2_single-layer.ino
*/
uint8_t readPins[] = {14, 15};
const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
Scanner_uC scanner_L(LOW, readPins, readPinCount);
/* =============== RIGHT SCANNER ===============
The right matrix is scanned by an I/O expander.
The MCP23018 address is set by grounding or powering pins.
*/
const uint8_t IOE_ADDR = 0x20; //MCP23018 address pin grounded
/*
Normally all strobe pins are on one port, and all the read pins are on the other port.
In this example, portB stobes the row while portA reads the colums.
Port_MCP23018 constructor parameters are: deviceAddr, portNum, readPins.
readPins is a bit pattern, where 0=output, 1=input.
In portA, the first two pins are set to input for reading.
"<<" (bit shift left) and "|" (OR) are bitwise operators.
Pin numbers to be read are delimited by "|" and to the right of "1<<".
*/
Port_MCP23018 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //read pins 0, 1
Port_MCP23018 portB(IOE_ADDR, 1, 0);
Scanner_IOE scanner_R(LOW, portB, portA);
/* ================= RIGHT LED =================
The LED_Port constructor parameters are a port and pin number that is connected to an LED.
*/
LED_Port LED_capsLck(portA, 1<<7);
// =================== CODES ===================
Code_Sc s_a(KEY_A);
Code_Sc s_b(KEY_B);
Code_Sc s_c(KEY_C);
Code_Sc s_d(KEY_D);
Code_Sc s_1(KEY_1);
Code_Sc s_2(KEY_2);
Code_Sc s_3(KEY_3);
Code_Sc s_4(KEY_4);
Code_LEDLock o_capsLock(KEY_CAPS_LOCK, LED_capsLck);//todo was testing LED, restore s_4 when done
/* =================== ROWS ====================
Left row names contain the letter 'L', while right row names conatain the letter 'R'.
Row constructor parameters are: scanner, strobePin, ptrsKeys[], keyCount.
strobePin has one of two formats:
* if refScanner a Scanner_uC, then strobePin is an Arduino pin number connected to this row
* otherwise strobePin is a bit pattern, 1 indicating an IC pin connected to the row
*/
/* ---------------- LEFT ROWS ------------------
The left rows have a Scanner_uC and Arduino pin numbers to strobe.
*/
Key* ptrsKeys_L0[] = { &s_1, &s_2 };
const uint8_t KEY_COUNT_L0 = sizeof(ptrsKeys_L0)/sizeof(*ptrsKeys_L0);
Row row_L0(scanner_L, 0, ptrsKeys_L0, KEY_COUNT_L0);
Key* ptrsKeys_L1[] = { &s_a, &s_b };
const uint8_t KEY_COUNT_L1 = sizeof(ptrsKeys_L1)/sizeof(*ptrsKeys_L1);
Row row_L1(scanner_L, 1, ptrsKeys_L1, KEY_COUNT_L1);
/* ---------------- RIGHT ROWS -----------------
The right rows have a Scanner_IOE and pin bits to strobe.
*/
Key* ptrsKeys_R0[] = { &s_3, &o_capsLock };
const uint8_t KEY_COUNT_R0 = sizeof(ptrsKeys_R0)/sizeof(*ptrsKeys_R0);
Row row_R0(scanner_R, 1<<0, ptrsKeys_R0, KEY_COUNT_R0);
Key* ptrsKeys_R1[] = { &s_c, &s_d };
const uint8_t KEY_COUNT_R1 = sizeof(ptrsKeys_R1)/sizeof(*ptrsKeys_R1);
Row row_R1(scanner_R, 1<<1, ptrsKeys_R1, KEY_COUNT_R1);
// ################### MAIN ####################
void setup()
{
Keyboard.begin();
scanner_R.begin();
}
void loop()
{
//left matrix
row_L0.process();
row_L1.process();
//right matrix
row_R0.process();
//Keyboard.println(" 0");
//delay(2000);
row_R1.process();
//Keyboard.println(" 1");
//delay(2000);
scanDelay.delay();
//Keyboard.println(" end loop");//todo
//debug.print_scans_per_second();
//debug.print_microseconds_per_scan();
}

33
src/LED_shiftRegs.cpp Normal file
View File

@ -0,0 +1,33 @@
#include "LED_shiftRegs.h"
/* constructor
*/
LED_shiftRegs::LED_shiftRegs(const uint8_t slaveSelect, const uint8_t pin)
:slaveSelect(slaveSelect), pin(pin)
{
pinMode(slaveSelect, OUTPUT);
}
/* begin() should be called once from sketch setup().
Initializes shift register's shift/load pin.
*/
void LED_shiftRegs::begin()
{
SPI.begin();
digitalWrite(slaveSelect, HIGH);
}
//todo preserve other LED values, similar to Port_PCA9655E outputVal
void LED_shiftRegs::on()
{
digitalWrite(slaveSelect, LOW);
SPI.transfer(pin);
digitalWrite (slaveSelect, HIGH);
}
void LED_shiftRegs::off()
{
digitalWrite(slaveSelect, LOW);
SPI.transfer(0);
digitalWrite (slaveSelect, HIGH);
}

22
src/LED_shiftRegs.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef LED_SHIFTREGS_H
#define LED_SHIFTREGS_H
#include <Arduino.h>
#include <inttypes.h>
#include <SPI.h>
#include <LEDInterface.h>
/* A LED_shiftRegs turns LED on and off.
shift register RCLK pin a.k.a. SS or ST
*/
class LED_shiftRegs: public LEDInterface
{
private:
const uint8_t slaveSelect;//controller pin number connected to shift register RCLK
const uint8_t pin; //bit pattern, shift register pin that is connected to an LED
public:
LED_shiftRegs(const uint8_t slaveSelect, const uint8_t pin);
void begin();
virtual void on();
virtual void off();
};
#endif

View File

@ -14,7 +14,7 @@ class LED_uC: public LEDInterface
public:
LED_uC(const uint8_t pin): pin(pin)
{
pinMode(pin, OUTPUT);
pinMode(pin, OUTPUT);//todo move to .cpp file
}
virtual void on();
virtual void off();

83
src/Port_MCP23018.cpp Normal file
View File

@ -0,0 +1,83 @@
#include "Port_MCP23018.h"
//todo add Port_MCP23018::write() like Port_MCP23S17::transer() ??
/* beginProtocol() is called from Scanner_IOE::begin(). Initiates I2C bus.
MCP23018 supports I2C SCL Clock Frequencies: 100 kHz, 400 kHz, 1000 kHz (Datasheet page 1 & 6)
The electrical limitation to bus speed is bus capacitance and the length of the wires involved.
Longer wires require lower clock speeds.
http://playground.arduino.cc/Main/WireLibraryDetailedReference > Wire.setclock()
*/
void Port_MCP23018::beginProtocol()
{
Wire.begin(); //initiate I2C bus to 100 kHz
//Wire.setClock(400000L); //set I2C bus to 400 kHz (have not tested 400 kHz)
}
/* begin() is called from Scanner_IOE::begin().
Configures port's IODIR and GPPU.
*/
void Port_MCP23018::begin(const uint8_t strobeOn)
{
uint8_t pullUp; //bits, GPPU 0=pull-up disabled, 1=pull-up enabled
if (strobeOn == LOW) //if active low
{
pullUp = readPins; //0=pull-up disabled (for LED), 1=pull-up enabled (for read)
}
else //if active high
{
pullUp = 0; //0=pull-up disabled (for external pull-down resistors)
}
Wire.beginTransmission(deviceAddr);
Wire.write(portNum); //IODIR
Wire.write(readPins); //0=output (for strobe and LED), 1=input (for read)
Wire.endTransmission();
Wire.beginTransmission(deviceAddr);
Wire.write(portNum + 0x0C); //GPPU
Wire.write(pullUp);
Wire.endTransmission();
}
/* write() sets pin output to logicLevel.
pin is bit pattern, where pin being strobed is 1.
logicLevel is HIGH or LOW.
write() does not overwrite the other pins.
*/
void Port_MCP23018::write(const uint8_t pin, const bool logicLevel)
{
if (logicLevel == LOW)
{
outputVal &= ~pin; //set pin output to low
//Keyboard.print(" low");
}
else
{
outputVal |= pin; //set pin output to high
//Keyboard.print(" high");
}
//Keyboard.print(" outputVal=");//todo
//Keyboard.println(outputVal);
Wire.beginTransmission(deviceAddr);
Wire.write(portNum + 0x12); //GPIO
Wire.write(outputVal);
Wire.endTransmission();
//delay(4000);
}
/* read() returns portState.
Only portState bits of readPins are valid.
*/
uint8_t Port_MCP23018::read()
{
Wire.beginTransmission(deviceAddr);
Wire.write(portNum + 0x12); //GPIO
Wire.endTransmission(false); //MCP23018 needs false to send a restart ??really?
Wire.requestFrom(deviceAddr, 1u); //request one byte from input port
return Wire.read();
}

48
src/Port_MCP23018.h Normal file
View File

@ -0,0 +1,48 @@
#ifndef PORT_MCP23018_H
#define PORT_MCP23018_H
#include <Arduino.h>
#include <inttypes.h>
#include <Wire.h>
#include <PortInterface.h>
/*
write pins are connected to matrix Row (strobe pin) or LED.
readPins are connected to matrix column to read which keys are pressed.
MCP23018 has open-drain outputs (open-drain can only sink current). If LEDs are used, connect:
LED anodes (the longer lead) to power
LED cathodes (the shorter lead) to GPIO pin
Instantiation
------------
Example instantiation:
const uint8_t IOE_ADDR = 0x20; //MCP23018 address pin grounded
Port_MCP23018 portB(IOE_ADDR, 1, 0); //all pins are set to output for strobes and LEDs
Port_MCP23018 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //pin 0 and pin 1 are set to input for reading,
//remaining pins can be used for LEDs
Diode orientation
----------------
Diode orientation is explained in keybrd_library_user_guide.md > Diode orientation
MCP23018 data sheet
----------------
http://ww1.microchip.com/downloads/en/DeviceDoc/22103a.pdf
*/
class Port_MCP23018 : public PortInterface
{
private:
const uint8_t deviceAddr;
const uint8_t portNum; //port identification number, 0=A, 1=B
uint8_t outputVal; //bit pattern for strobe and LEDs
const uint8_t readPins; //bit pattern, IODIR 0=output, 1=input
public:
Port_MCP23018(const uint8_t deviceAddr, const uint8_t portNum, const uint8_t readPins)
: deviceAddr(deviceAddr), portNum(portNum), outputVal(0), readPins(readPins) {}
void beginProtocol();
void begin(const uint8_t strobeOn);
virtual void write(const uint8_t pin, const bool logicLevel);
virtual uint8_t read();
};
#endif

View File

@ -22,7 +22,7 @@ uint8_t Port_MCP23S17::transfer(const uint8_t command, const uint8_t registerAdd
return portState;
}
/* begin() is called from Scanner_IOE::begin(). Initiates SPI bus.
/* beginProtocol() is called from Scanner_IOE::begin(). Initiates SPI bus.
*/
void Port_MCP23S17::beginProtocol()
{
@ -39,13 +39,13 @@ void Port_MCP23S17::begin(const uint8_t strobeOn)
{
uint8_t pullUp; //bits, GPPU 0=pull-up disabled, 1=pull-up enabled
if (strobeOn == LOW) //if active low, use internal pull-up resistors
if (strobeOn == LOW) //if active low
{
pullUp = readPins;
pullUp = readPins; //0=pull-up disabled (for LED), 1=pull-up enabled (for read)
}
else //active high requires external pull-down resistors
else //if active high
{
pullUp = 0;
pullUp = 0; //0=pull-up disabled (for external pull-down resistors)
}
transfer(deviceAddr << 1, portNum, readPins); //configure IODIR

View File

@ -1,6 +1,6 @@
#include "Port_PCA9655E.h"
/* begin() is called from Scanner_IOE::begin(). Initiates I2C bus.
/* beginProtocol() is called from Scanner_IOE::begin(). Initiates I2C bus.
PCA9655E supports I2C SCL Clock Frequencies: 100 kHz, 400 kHz, 1000 kHz (Datasheet page 1 & 6)
The electrical limitation to bus speed is bus capacitance and the length of the wires involved.

View File

@ -16,6 +16,7 @@ Configures controller to communicate with shift register matrix.
void Scanner_ShiftRegsPISOMultiRow::init(const uint8_t strobePin)
{
pinMode(strobePin, OUTPUT);
//digitalWrite(strobePin, strobeOff);//todo is this needed?
}
/* begin() should be called once from sketch setup().
@ -23,7 +24,7 @@ Initializes shift register's shift/load pin.
*/
void Scanner_ShiftRegsPISOMultiRow::begin()
{
digitalWrite(slaveSelect, HIGH);
SPI.begin();
}
/* scan() strobes the row's strobePin and returns state of the shift register's input pins.
@ -34,16 +35,25 @@ read_pins_t Scanner_ShiftRegsPISOMultiRow::scan(const uint8_t strobePin)
{
read_pins_t readState = 0; //bits, 1 means key is pressed, 0 means released
//strobe row on
//strobe on
digitalWrite(strobePin, strobeOn);
delayMicroseconds(3); //time to stablize voltage
//SPI.beginTransaction( SPISettings(5000000, MSBFIRST, SPI_MODE0) ); //control SPI bus, 5 MHz
//digitalWrite(slaveSelect, LOW); //assert slave
delayMicroseconds(3); //time to stabilize photo-transistor todo needed?
delayMicroseconds(50); //todo for sr2_LEDs_strobe.ino
//read all the column pins
digitalWrite(slaveSelect, LOW); //load parallel inputs to the register
digitalWrite(slaveSelect, HIGH); //shift the data toward a serial output
SPI.transfer(&readState, byte_count);
//strobe row off
SPI.transfer(&readState, byte_count);
digitalWrite(slaveSelect, LOW); //load parallel inputs to registers
//digitalWrite(slaveSelect, HIGH); //de-assert slave
//SPI.endTransaction();
//strobe off
digitalWrite(strobePin, strobeOff);
return readState;

View File

@ -9,7 +9,7 @@
/* Scanner_ShiftRegsPISOMultiRow reads shift registers.
This was tested on 74HC165 shift registers, which are Parallel-In-Serial-Out (PISO).
Upto 4 shift registers can be in a daisy chained for a total of 32 read pins.
Shift registers can be daisy chained for a total of 32 read pins.
Example instantiation:
Scanner_ShiftRegsPISOMultiRow scanner_R(HIGH, SS, 4);
@ -18,7 +18,6 @@ There are three Scanner_ShiftRegsPISOMultiRow parameters.
"strobeOn" paramter is active state HIGH or LOW.
"slaveSelect" paramter can be any controller pin connected to shift register's SHIFT-LOAD pin.
slaveSelect pin SS (Arduino pin 10) has the fastest scan.
"byte_count" is the number of bytes to read from shift registers (1 to 4).
byte_count should cover all the row's keys:
@ -26,7 +25,7 @@ byte_count should cover all the row's keys:
Hardware setup:
Each row needs to be connected to a strobe pin from the controller.
Switche and diode in series are connected to shift-register parallel-input pins and strobed row.
Switch and diode in series, connect shift-register parallel-input pins to strobed row.
For active low:
Shift-register parallel-input pins need 10k Ohm pull-up resistors powered.

View File

@ -1,6 +1,7 @@
#include "Scanner_ShiftRegsPISOSingleRow.h"
/* constructor
Parameter strobeOn is not used.
*/
Scanner_ShiftRegsPISOSingleRow::Scanner_ShiftRegsPISOSingleRow(const bool strobeOn,
const uint8_t slaveSelect, const uint8_t byte_count)
@ -26,6 +27,7 @@ void Scanner_ShiftRegsPISOSingleRow::begin()
}
/* scan() returns state of the shift register's input pins.
Parameter strobePin is not used.
No strobe pin is needed, the shift register is wired so the strobe is effectivley always "on".
Bit patterns are 1 bit per key.
*/

View File

@ -22,7 +22,6 @@ There are three Scanner_ShiftRegsPISOSingleRow parameters.
"strobeOn" paramter is ignored, but should be active state HIGH or LOW required by ScannerInterface.
"slaveSelect" paramter can be any controller pin connected to shift register's SHIFT-LOAD pin.
slaveSelect pin SS (Arduino pin 10) has the fastest scan.
"byte_count" is the number of bytes to read from shift registers (1 to 4).
byte_count should cover all the row's keys:
@ -30,7 +29,8 @@ byte_count should cover all the row's keys:
Hardware setup:
There is only one row, and it is permanently active.
Switches are connected to shift-register parallel-input pins (diodes are not needed) and row.
Switches are connected to shift-register parallel-input pins and row.
Diodes are not needed because there is only one row.
For active low:
Shift-register parallel-input pins need 10k Ohm pull-up resistors powered.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 322 KiB

View File

@ -3,7 +3,7 @@ Tested on Teensy LC and two 74HC165 shift registers.
Controller Two shift registers daisy chained
| Left |**0**| | Right |**0**|**1**|**2**|**3**|**4**|**5**|**6**|
|:-----:|-----| |:-----:|-----|-----|-----|-----|-----|-----|-----|
|-------|-----| |-------|-----|-----|-----|-----|-----|-----|-----|
| **0** | x | | **0** | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| **1** | y | | **1** | a | b | c | d | e | f | g |
*/
@ -49,10 +49,8 @@ uint8_t readPinCount_L = sizeof(readPins_L)/sizeof(*readPins_L);
Scanner_uC scanner_L(LOW, readPins_L, readPinCount_L); //active LOW
/* --------------- RIGHT SCANNER ---------------
use slaveSelect pin SS (Arduino pin 10) for fastest scan
*/
Scanner_ShiftRegsPISOSingleRow scanner_R(HIGH, SS, 2); //active HIGH
// --------------- RIGHT SCANNER ---------------
Scanner_ShiftRegsPISOSingleRow scanner_R(HIGH, 10, 2); //active HIGH
// =================== ROWS ====================
// ----------------- LEFT ROWS -----------------

View File

@ -6,7 +6,7 @@ This sketch:
Controller I/O expander
| Left | **0** | **1** | | Right | **0** | **1** |
|:-----:|-------|-------|-|:-----:|-------|-------|
|-------|-------|-------| |-------|-------|-------|
| **1** | 1 | 2 | | **1** | 3 | 4 |
| **0** | a | b | | **0** | c | d |
*/

View File

@ -1,7 +1,7 @@
/* keybrd_5b_LED_on_IOE.ino
This sketch:
is a simple 1-layer keyboard with CapsLck indicator LED on I/O expander
is a simple 1-layer keyboard with indicator LED on controller and 2 LEDs on I/O expander
runs on a two-matrix breadboard keyboard
modified keybrd_4c_split_keyboard_with_IOE.ino by adding LED_capsLck
@ -10,8 +10,8 @@ This layout table shows left and right matrices:
Controller I/O expander
| Left | **0** | **1** | | Right | **0** | **1** |
|:-----:|-------|-------|-|:-----:|-------|-------|
| **1** |CapsLck| a 1 | | **1** | b 2 | c 3 |
| **0** | fn | x = | | **0** | y - | z / |
| **0** |CapsLck| a 1 | | **1** | b 2 | c 3 |
| **1** | fn | x = | | **0** | y - | z / |
*/
// ################## GLOBAL ###################
// ================= INCLUDES ==================
@ -35,7 +35,7 @@ This layout table shows left and right matrices:
// ============ SPEED CONFIGURATION ============
ScanDelay scanDelay(9000);
// ==================== IC =====================
// ==================== ICs ====================
// ---------------- LEFT SCANNER ---------------
uint8_t readPins[] = {14, 15};
const uint8_t readPinCount = sizeof(readPins)/sizeof(*readPins);
@ -47,8 +47,8 @@ LED_uC LED_capsLck(21);
// --------------- RIGHT SCANNER ---------------
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read and LED
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //for strobe and LED
Port_MCP23S17 portA(IOE_ADDR, 0, 1<<0 | 1<<1 ); //for read
Port_MCP23S17 portB(IOE_ADDR, 1, 0); //for strobe
Scanner_IOE scanner_R(LOW, portB, portA);

View File

@ -43,21 +43,21 @@ These are explained in [How to Use a Breadboard](https://learn.sparkfun.com/tuto
Electrostatic discharge (ESD) safety
------------------------------------
Static electricity can damage a microcontroller in ways that are hard to trouble shoot.
Static electricity can damage a ICs in ways that are hard to trouble shoot.
I live in a desert on a carpeted floor and get zapped by door knobs regularly.
Here is the ESD precaution I take whenever I handle a microcontroller:
Here is a ESD precaution for handling ICs:
1. Touch the bare metal on the back of my desktop computer (its grounded).
2. Then touch the metal USB connector case on the microcontroller.
Anti-static mat or anti-static wristband are also effective.
Being tethered by an anti-static wristband can be inconvenient (wireless antistatic wrist straps are a scam).
2. Then touch the IC or circuit (if its a micro-controller, touch the metal USB connector case).
I take these ESD precaution because I live in a dry environment on a carpeted floor.
Not everyone needs to take ESD precautions:
* http://forum.arduino.cc/index.php?topic=4643.0
* https://forums.adafruit.com/viewtopic.php?f=8&t=12128
Anti-static mat or anti-static wristband are also effective.
But being tethered by an anti-static wristband can be inconvenient (wireless antistatic wrist straps are a scam).
Building a basic breadboard keyboard
------------------------------------
The basic breadboard keyboard has 4 switches.

View File

@ -20,7 +20,9 @@ The scanner should have enough readPins to cover all the keys of the longest row
| Layout |**0**|**1**|**2**|
|:------:|:---:|:---:|:---:|
| **0** | 1 | 2 | 3 |
| **1** | a | b |
| **1** | a | b | |
[keybrd tutorials usability survey](../CONTRIBUTING.md##keybrd-tutorials-usability-survey)
<br>
<a rel="license" href="https://creativecommons.org/licenses/by/4.0/"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by/4.0/88x31.png" /></a><br /><span xmlns:dct="http://purl.org/dc/terms/" property="dct:title">keybrd tutorial</span> by <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd" property="cc:attributionName" rel="cc:attributionURL">Wolfram Volpi</a> is licensed under a <a rel="license" href="https://creativecommons.org/licenses/by/4.0/">Creative Commons Attribution 4.0 International License</a>.<br />Permissions beyond the scope of this license may be available at <a xmlns:cc="https://creativecommons.org/ns" href="https://github.com/wolfv6/keybrd/issues/new" rel="cc:morePermissions">https://github.com/wolfv6/keybrd/issues/new</a>.

View File

@ -28,9 +28,10 @@ But if there are enough pins on the controller, using just a cable with more wir
I/O Expanders can power LEDs, while PISO shift registers can not.
I2C is a little slow if the I/O expander is scanning more than 4 rows.
The keybrd_DH (DodoHand) sketch polls 5 rows over I2C at 7.5ms per keyboard scan.
Which is acceptable, but faster would be nicer.
I2C is fast enough for scanning up to 5 rows.
SPI is much faster, but requires 2 additional wires.
More scanning options are reviewed at http://www.openmusiclabs.com/learning/digital/input-matrix-scanning/
## Cables table
@ -52,7 +53,7 @@ There are also wireless options if you don't mind adding complexity and maintain
The 8-wire "GearIT Cat 6 Ethernet Flat Patch Cable 7 Feet" is very flexible.
It's available at Walmart (9/19/16) if you want to feel the merchandise before you buy.
All the modular connectors are flat.
All the modular connector cables are available in the flat form factor.
For prototyping on perfboards, consider a 0.1" header.

View File

@ -36,7 +36,7 @@ This table lists what gets connected to the 74HC165 pins:
**74HC165 left (lower half of breadboard)**
|NAME |PIN#|DESCRIPTION |TO TEENSY LC PIN#|CHAIN |
|--------|:--:|--------------------|-----------------|-----------|
|:-------|:--:|:-------------------|:----------------|:----------|
|SH/LD |1 |shift or load input |CS0 10 |green wire |
|CLK |2 |clock input |SCK0 13 |yellow wire|
| D4 |3 |parallel input | | |
@ -49,7 +49,7 @@ This table lists what gets connected to the 74HC165 pins:
**74HC165 right (upper half of breadboard)**
|NAME |PIN#|DESCRIPTION |TO TEENSY LC PIN#|CHAIN |
|--------|:--:|--------------------|-----------------|-------------------------|
|:-------|:--:|:-------------------|:----------------|:------------------------|
|VCC |16 |power pin |3.3V |red wire |
|CLK INH |15 |clock inhibit | |blue bus |
| D3 |14 |parallel input | | |

View File

@ -17,6 +17,31 @@ Two rows (red buses) are connected to the I/O expander.
![breadboard keyboard with IOE](keybrd_4c_split_keyboard_with_IOE/front.JPG "breadboard keyboard with IOE")
I/O expanders
-------------
The MCP23S17 I/O expander has two ports with 8 I/O pins each.
I/O expander input/output pins are connected to a switch matrix.
Port B strobes one row at a time.
Port A reads the columns.
SPI and I2C communication protocols
-----------------------------------
SPI and I2C are popular communication protocols.
Either one can be used to connect split keyboards.
I2C is fast enough for scanning up to 5 rows.
The keybrd_DH (DodoHand) sketch polls 5 rows over I2C at 7.5ms per keyboard scan.
SPI is much faster, but requires 2 additional wires.
Use SPI if your key matrix has more then 5 rows.
| connection type | controller pins | wire count |
|------------------------|:---------------:|:----------:|
| I/O expander SPI | 4 | 6 |
| I/O expander I2C | 2 | 4 |
The example in this tutorial uses the SPI protocol.
Building a split keyboard with I/O Expander
-------------------------------------------
Starting with the basic breadboard keyboard described in [tutorial_1_breadboard_keyboard.md](tutorial_1_breadboard_keyboard.md), add parts as described above.

View File

@ -39,7 +39,7 @@ Less resistance makes the LED brighter.
Too little resistance will burn out the LED.
The current supplied to an LED should always be limited by a resistor or some other device.
LED current limiting resistor values
LED current-limiting resistor values
------------------------------------
In the section we will compute the minimum resistor value for maximum LED brightness.

View File

@ -26,7 +26,7 @@ keybrd sketch with LEDs on IOE
------------------------------
The [keybrd_5b_LED_on_IOE.ino](keybrd_5b_LED_on_IOE/keybrd_5b_LED_on_IOE.ino) sketch will run on the above breadboard keyboard.
The sketch features:
The sketch demonstrates:
* multiple layers
* split keyboard
* LED on controller

View File

@ -0,0 +1,33 @@
/* unit test for Port_MCP23018
Picture of hardware is in unit_tests/PortMCP23018_read/PortMCP23018_bb.JPG todo
The setup is an MCP23018 I/O expander on a Teensy LC controller.
MCP23018 port-A GPIO pins are not connected to anything.
Port-A GPIO-pin ouputs alternate between 0 and 3.3 volts.
volt meter between pin A1 and power because
MCP23018 has open-drain outputs (open-drain can only sink current)
Use a volt meter to measure port-A GPIO-pin outputs or red LED.
*/
#include "Port_MCP23018.h"
const uint8_t IOE_ADDR = 0x20; //MCP23018 address ADDR pin grounded
Port_MCP23018 portA(IOE_ADDR, 0, 0);
void setup()
{
delay(6000);
Keyboard.println("PortMCP23018_write.ino");
portA.beginProtocol();
portA.begin(LOW); //HIGH or LOW, not matter if readPins=0
}
void loop()
{
portA.write(~0, HIGH); //set all GPIOA pins HIGH
Keyboard.print("+");
delay(2000);
portA.write(~0, LOW); //set all GPIOA pins LOW
Keyboard.print("0");
delay(2000);
}

View File

@ -2,28 +2,24 @@
Picture of hardware is in unit_tests/PortMCP23S17_read/PortMCP23S17_bb.JPG
The setup is an MCP23S17 I/O expander on a Teensy LC controller.
MCP23S17 port-B pins are alternately grounded and energized.
portBState is a bitwise reading of port B.
output is: 10101010
*/
#include "PortIOE.h"
#include "PortMCP23S17.h"
#include "Port_MCP23S17.h"
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
PortIOE portB(1);
PortMCP23S17 portBRead(portB, ~0);
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins grounded
Port_MCP23S17 portB(IOE_ADDR, 1, ~0); //read all pins
void setup()
{
uint8_t portBState; //bit pattern
uint8_t BitPattern; //reading of port B
delay(6000);
portBRead.begin(HIGH); //HIGH or LOW, not matter
portB.begin(HIGH); //HIGH or LOW, does not matter
portBState = portBRead.read();
Keyboard.print("portBState = ");
Keyboard.println(portBState, BIN); //prints 10101010
BitPattern = portB.read();
Keyboard.print("BitPattern = ");
Keyboard.println(BitPattern, BIN); //prints 10101010
}
void loop() { }

View File

@ -1,34 +1,29 @@
/* unit test for PortMCP23S17
/* unit test for Port_MCP23S17
Picture of hardware is in unit_tests/PortMCP23S17_read/PortMCP23S17_bb.JPG
The setup is an MCP23S17 I/O expander on a Teensy LC controller.
MCP23S17 port-A GPIO pins are not connected to anything.
Port-A GPIO-pin ouputs alternate between 0 and 3.3 volts.
Use a volt meter to measure port-A GPIO-pin outputs.
OR low-voltage LED, with forward voltage less than 2 volts.
Use a volt meter to measure port-A GPIO-pin outputs or red LED.
*/
#include "PortIOE.h"
#include "PortMCP23S17.h"
#include "Port_MCP23S17.h"
const uint8_t PortIOE::DEVICE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins are grounded
PortIOE portA(0);
PortMCP23S17 portAWrite(portA, 0); //PortAWrite needed for begin()
//const uint8_t GPIOA = 0x12; //LEDs are on port A
const uint8_t IOE_ADDR = 0x20; //MCP23S17 address, all 3 ADDR pins grounded
Port_MCP23S17 portA(IOE_ADDR , 0, 0); //PortAWrite needed for begin()
void setup()
{
delay(6000);
portAWrite.begin(LOW); //HIGH or LOW, not matter if readPins=0
Keyboard.print("start writing");
Keyboard.println("start setup");
portA.begin(LOW); //HIGH or LOW, not matter if readPins=0
Keyboard.println("start loop");
}
void loop()
{
portAWrite.write(~0, HIGH); //set all GPIOA pins HIGH
portA.write(~0, HIGH); //set all GPIOA pins HIGH
delay(2000);
portAWrite.write(~0, LOW); //set all GPIOA pins LOW
portA.write(~0, LOW); //set all GPIOA pins LOW
delay(2000);
}