Advertisement
cz3dtc

Keyboard-stream

Mar 26th, 2022
17
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.56 KB | None | 0 0
  1. #include "Keyboard.h"
  2.  
  3. //#define DEBUG
  4.  
  5. #ifdef DEBUG
  6. #define BASE_SCANCODE 'a'
  7. #define TOGGLEMOD KEY_LEFT_SHIFT
  8. #else
  9. #define BASE_SCANCODE KEY_F13
  10. #define TOGGLEMOD KEY_LEFT_CTRL
  11. #endif
  12.  
  13. // This is the time in ms between for a toggle key between 'pressing' and 'releasing' the relevant keycode. Should be enough to register the key, but not enough to trigger autorepeat or such
  14. #define REG_DELAY 200
  15.  
  16. // Leds are multiplexed. This is how many columns and rows are there. Anodes (+) go to rows, cathodes (-) to columns.
  17. #define LED_COL_N 3
  18. #define LED_ROW_N 4
  19.  
  20. // This many buttons are connected
  21. #define NBUTTONS 10
  22.  
  23. // The buttons numbered 0..NBUTTONS-1 are connected between these pins and GND (use only pins that have internal pullups or connect external pullups yourself!):
  24. const uint8_t button_pin[NBUTTONS] = {9, 2, 10, 8, 4, 14, 7, 3, 5, 6};
  25.  
  26. // These are the pins that LED cathodes are connected to:
  27. const uint8_t led_cols[LED_COL_N] = {A3, A1, A2};
  28.  
  29. // These are the pins that LED anodes are connected to:
  30. const uint8_t led_rows[LED_ROW_N] = {16, 15, A0, 0};
  31.  
  32. // LEDS are counted 0..(rows x cols - 1) column by column then row by row. How they are physically aranged is a different story, so here's mapping from button number to LED number
  33. const uint8_t led_map[NBUTTONS] = {2,3,4,5,6,7,8,9,10,11};
  34.  
  35. // There are two more LEDs in my design than I have keys, so for future use I saved their numbers here:
  36. const uint8_t led_red = 0;
  37. const uint8_t led_green = 1;
  38.  
  39. // For each key in sequence:
  40. // 1 means the key is a toggle, so on first press it will send e.g. F13 and its LED will light up, the following keypress will send CTRL-F13 and extinguish the LED:
  41. // 0 means it's an ordinary key behaving like a normal function key on the keyboard, i.e. pressing it each time will send a single keypress, if you hold it, your system will start autorepeating.
  42. const uint8_t toggles[NBUTTONS] = {1, 1, 1, 1, 0, 0, 0, 0, 0, 0};
  43.  
  44.  
  45. // For momentary keys (where toggles[i] is zero) key groups can be defined. If a key has a non-zero group assigned, its LED will stay on after pressing (the key behaves like a normal keyboard key, it's just the LED that will stay on).
  46. // At the same time all LEDs of other keys in the same group will be extinguished. This is useful if you use the keys e.g. to switch scenes in OBS: the last selected scene is the active one, and the LED will tell you which one it was.
  47. // If a key is assigned group 0 it is in no group at all, its LED will light as long as the key is held down and will go out as soon as you release it.
  48. const uint8_t groups[NBUTTONS] = {0, 0, 0, 0, 1, 1, 1, 1, 1, 1};
  49.  
  50.  
  51. //internal tables to save state of the keypad
  52. uint8_t t_state[NBUTTONS]; // toggle states, i. e. whether each toggle key is on or off.
  53. uint8_t key_state[NBUTTONS]; // key states, i.e. which key was pressed the last time we checked.
  54. uint8_t led_state[LED_COL_N*LED_ROW_N]; // LED states, in sequence of LEDs in matrix, 1 is on, 0 is off.
  55.  
  56. void setup() {
  57. for (uint8_t i=0;i<NBUTTONS;i++) // setup pins for keys, keypad is non-multiplexed to make panel wiring easy and prevent any sort of ghosting
  58. {
  59. pinMode(button_pin[i], INPUT_PULLUP);
  60. }
  61. for (uint8_t i=0;i<LED_COL_N;i++) // setup LED matrix control - column outputs
  62. {
  63. pinMode(led_cols[i],OUTPUT);
  64. digitalWrite(led_rows[i],HIGH);
  65. }
  66. for (uint8_t i=0;i<LED_ROW_N;i++)
  67. {
  68. pinMode(led_rows[i],OUTPUT); // setup LED matrix control - row outputs
  69. digitalWrite(led_rows[i],LOW);
  70. }
  71.  
  72. // master clock init sequence:
  73. CLKPR = 0x80;
  74. CLKPR = 0b00000000;
  75.  
  76. //sync timers and reset their prescalers
  77. GTCCR = 0b10000011;
  78.  
  79. // timer mode initialization
  80. TCCR1A = 0b00000001;
  81. TCCR1B = 0b00001011;
  82. // 0101 F-PWM, 8-bit TOP=0x00FF Upd.OCR1x@BOT TOV1@:TOP
  83. // 00 Normal port operation, OC1A disconnected.
  84. // 00 Normal port operation, OC1B disconnected.
  85. // 011 0064 clkIO/64 (From prescaler)
  86. // 0 NC off
  87. // 0 count on falling edge
  88. // Timer 1 clock: 250000 Hz, resulting base frequency: 976.5625 Hz, resulting base period: 1.024 ms
  89.  
  90.  
  91. TIMSK1 = (1 << TOIE1);
  92. sei();
  93.  
  94. //release prescaler reset
  95. GTCCR = 0x00;
  96.  
  97. // initialize control over the keyboard:
  98. Keyboard.begin();
  99. #ifdef DEBUG
  100. Serial.begin(9600);
  101. #endif
  102.  
  103. }
  104.  
  105. void loop() {
  106. for (char i=0;i<NBUTTONS;i++) //scan through all keys
  107. {
  108. if (digitalRead(button_pin[i])!=key_state[i]) // the button has either been pressed, or released, anyway the state changed
  109. {
  110. if (toggles[i])
  111. { // the key is a toggle key, i.e. it should send alternating keycodes on alternating keypresses...
  112. if (key_state[i]==LOW)
  113. { //the key was pressed, but isn't anymore - do nothing except register the fact...
  114. key_state[i] = HIGH;
  115. #ifdef DEBUG
  116. Serial.print("Key release: ");
  117. Serial.println(uint8_t(i));
  118. #endif
  119. }
  120. else
  121. { //the key wasn't pressed, but is now, i.e. we need to toggle the toggle...
  122. key_state[i] = LOW;
  123. #ifdef DEBUG
  124. Serial.print("Key press: ");
  125. Serial.println(uint8_t(i));
  126. #endif
  127. if (t_state[i])
  128. { //the state was on, so now it's off
  129. t_state[i] = 0;
  130. led_state[led_map[i]] = 0; //turn the key LED off
  131. Keyboard.press(TOGGLEMOD);
  132. Keyboard.press(BASE_SCANCODE+i);
  133. delay(REG_DELAY);
  134. Keyboard.release(BASE_SCANCODE+i);
  135. Keyboard.release(TOGGLEMOD);
  136. }
  137. else
  138. { //the state was off, so now it's on
  139. t_state[i] = 1;
  140. led_state[led_map[i]] = 1; //turn the key LED on
  141. Keyboard.press(BASE_SCANCODE+i);
  142. delay(REG_DELAY);
  143. Keyboard.release(BASE_SCANCODE+i);
  144. }
  145. }
  146.  
  147. }
  148. else
  149. { //the key is an ordinary key
  150. if (key_state[i]==LOW)
  151. { //the key was pressed, but isn't anymore
  152. key_state[i] = HIGH;
  153. Keyboard.release(BASE_SCANCODE+i);
  154. if (groups[i]==0) led_state[led_map[i]] = 0; // if the key isn't in any key group, switch its LED off as soon as it's released
  155. #ifdef DEBUG
  156. Serial.print("Key release: ");
  157. Serial.println(uint8_t(i));
  158. #endif
  159. }
  160. else
  161. { //the key wasn't pressed, but is now
  162. key_state[i] = LOW;
  163. Keyboard.press(BASE_SCANCODE+i);
  164. if (groups[i])
  165. { // if the key is in a key group, switch all other group key's LEDs off first
  166. for (uint8_t cancel = 0; cancel<NBUTTONS; cancel++)
  167. if ((groups[cancel] == groups[i]) && (toggles[cancel]==0)) led_state[led_map[cancel]] = 0; //kill all other LEDs in the group, except if they are toggles
  168. }
  169. led_state[led_map[i]] = 1; //then light up the LED of the key that was pressed - this regardless of whether it's in a group or not
  170. #ifdef DEBUG
  171. Serial.print("Key press: ");
  172. Serial.println(uint8_t(i));
  173. #endif
  174. }
  175. }
  176. }
  177. }
  178. }
  179.  
  180. ISR(TIMER1_OVF_vect)
  181. {
  182. //do the LED matrix scanning:
  183. static uint8_t row = 0;
  184. static uint8_t ledcounter = LED_COL_N;
  185. digitalWrite(led_rows[row],LOW); // release last active row
  186. row++;
  187. if (row == LED_ROW_N) //if we scanned all rows already, restart the scan from the beginning
  188. {
  189. row = 0;
  190. ledcounter = 0;
  191. }
  192. for (uint8_t col = 0; col<LED_COL_N; col++) // set up column outputs for the current row
  193. {
  194. if (led_state[ledcounter++])
  195. digitalWrite(led_cols[col],LOW);
  196. else
  197. digitalWrite(led_cols[col],HIGH);
  198. }
  199. digitalWrite(led_rows[row],HIGH); // activate current row
  200. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement