keybrd library is an open source library for creating custom-keyboard firmware.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

RowBase.cpp 6.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. #include "RowBase.h"
  2. /*
  3. scans the row and calls any newly pressed or released keys.
  4. */
  5. void RowBase::process(const bool activeHigh)
  6. {
  7. //these variables are all bitwise, one bit per key
  8. uint8_t rowState; //1 means pressed, 0 means released
  9. uint16_t rowEnd; //1 bit marks positioned after last key of row
  10. uint8_t debouncedChanged; //1 means debounced changed
  11. wait();
  12. scan(activeHigh); //save column-port-pin values to portState
  13. rowState = getRowState(rowEnd, activeHigh);
  14. debouncedChanged = debounce(rowState);
  15. pressRelease(rowEnd, debouncedChanged);
  16. }
  17. /* wait() delay's scan to give switches time to debounce.
  18. This version of wait() is very simple. More sophisticated versions can override this one.
  19. For fastest response time, wait() should be placed before scan() or after pressRelease()
  20. (waiting between strobe and send would unnecessarily delay send).
  21. A keyboard with a faster scan rate responds faster.
  22. Follow these step to tune DELAY_MICROSECONDS for maximum scan rate for a given SAMPLE_COUNT:
  23. Initialize DELAY_MICROSECONDS in your sketch:
  24. const unsigned int Row::DELAY_MICROSECONDS = 1000;
  25. Add this to the sketch's loop() function:
  26. debug.print_microseconds_per_scan();
  27. Compile and load the sketch into the microcontroller; microseconds_per_scan is printed every second.
  28. Adjust the value of DELAY_MICROSECONDS and repeat until:
  29. debug.print_microseconds_per_scan() <= DEBOUNCE_TIME / SAMPLE_COUNT
  30. DEBOUNCE_TIME can be obtained from the switch's datasheet. Some switch bounce times are:
  31. Cherry MX specifies 5msec bounce time http://www.cherrycorp.com/english/switches/key/mx.htm
  32. hasu measured Cherry MX bounce times .3ms to 1.4ms http://geekhack.org/index.php?topic=42385.0
  33. Tactile switch MJTP series bounce 10 ms http://www.apem.com/files/apem/brochures/MJTP_6MM.pdf
  34. Avoid sampling the switch input at a rate synchronous to events in the environment
  35. that might create periodic EMI. For instance, 50 and 60 Hz.
  36. Polling I2C may slow the scan rate enough so that no additional delay is needed:
  37. const unsigned int Row::DELAY_MICROSECONDS = 0;
  38. Slow-scan trick for debug messages that print too fast:
  39. change DELAY_MICROSECONDS to a large number like 10000
  40. That way debug messages are printed at a managable rate.
  41. */
  42. void RowBase::wait()
  43. {
  44. delayMicroseconds(DELAY_MICROSECONDS); //delay between Row scans to debounce switches
  45. }
  46. /*
  47. Strobes the row and reads the columns.
  48. Strobe is on for shortest possible time to preserve IR LED on DodoHand's optic switch.
  49. */
  50. void RowBase::scan(const bool activeHigh)
  51. {
  52. //strobe row on
  53. if (activeHigh)
  54. {
  55. refRowPort.setActivePinHigh(rowPin);
  56. }
  57. else //activeLow
  58. {
  59. refRowPort.setActivePinLow(rowPin);
  60. }
  61. //read all the column ports
  62. for (uint8_t i=0; i < colPortCount; i++)
  63. {
  64. ptrsColPorts[i]->read();
  65. }
  66. //strobe row off
  67. if (activeHigh)
  68. {
  69. refRowPort.setActivePinLow(rowPin);
  70. }
  71. else //activeLow
  72. {
  73. refRowPort.setActivePinHigh(rowPin);
  74. }
  75. }
  76. /*
  77. Copies column pins to rowState. Unused column pins are not copied.
  78. Sets rowEnd and returns rowState.
  79. rowEnd is bitwise, where 1 bit corrsiponds to place immediatly after last key of row.
  80. rowEnd and rowMask are larger type than portMask so that they can not overflow.
  81. */
  82. uint8_t RowBase::getRowState(uint16_t& rowEnd, const bool activeHigh)
  83. {
  84. uint16_t rowMask = 1; //bitwise, one col per bit, active col bit is 1
  85. uint8_t rowState = 0; //bitwise, one key per bit, 1 means key is pressed
  86. for (uint8_t i=0; i < colPortCount; i++) //for each col port
  87. {
  88. //bitwise colPins, 1 means pin is connected to column
  89. uint8_t colPins = ptrsColPorts[i]->getColPins();
  90. //bitwise colPortState, pin values where set in ColPort::read(), get them now
  91. uint8_t colPortState = ptrsColPorts[i]->getPortState();
  92. if (activeHigh)
  93. {
  94. colPortState = ~colPortState;
  95. }
  96. for ( uint8_t portMask = 1; portMask > 0; portMask <<= 1 ) //shift portMask until overflow
  97. { //for each pin of col port
  98. if (portMask & colPins) //if pin is connected to column
  99. {
  100. if (portMask & ~colPortState) //if pin detected a key press
  101. {
  102. rowState |= rowMask; //set rowState bit for that key
  103. }
  104. rowMask <<= 1; //shift rowMask to next key
  105. }
  106. }
  107. }
  108. rowEnd = rowMask;
  109. return rowState;
  110. }
  111. /*
  112. pressRelease() calls key's press() or release() function if it was pressed or released.
  113. Both parameters are bitwise.
  114. */
  115. void RowBase::pressRelease(const uint16_t rowEnd, const uint8_t debouncedChanged)
  116. {
  117. uint8_t isFallingEdge; //1 means falling edge
  118. uint8_t isRisingEdge; //1 means rising edge
  119. uint8_t rowMask; //bitwise, active col bit is 1
  120. uint8_t col; //index for ptrsKeys[col] array
  121. //bit=1 if last debounced changed from 1 to 0, else bit=0
  122. isFallingEdge = debouncedChanged & ~debounced;
  123. //bit=1 if last debounced changed from 0 to 1, else bit=0
  124. isRisingEdge = debouncedChanged & debounced;
  125. for (rowMask=1, col=0; rowMask<rowEnd; rowMask<<=1, col++) //for each key in row
  126. {
  127. //release before press avoids impossible key sequence
  128. if (rowMask & isFallingEdge) //if key was released
  129. {
  130. ptrsKeys[col]->release();
  131. }
  132. if (rowMask & isRisingEdge) //if key was pressed
  133. {
  134. ptrsKeys[col]->press();
  135. keyWasPressed();
  136. }
  137. }
  138. }
  139. void RowBase::keyWasPressed()
  140. {
  141. //empty in RowBase class. To unstick sticky keys, override keyWasPressed() in derived class.
  142. }