Advertisement
retrokits

RK005 CH340 MIDI Key Commander

Apr 8th, 2019
294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <Keypad.h>
  2. #include <U8g2lib.h>
  3. #include <SPI.h>
  4. #include <Wire.h>
  5.  
  6. U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0);
  7.  
  8. // Accompanying code for Retrokits RK005 MIDI command keypad
  9. // more info on the 4x4 keypad an it's workings:
  10. // https://iamzxlee.wordpress.com/2013/07/24/4x4-matrix-keypad/
  11. // example seller on aliexpress:
  12. // https://www.aliexpress.com/item/4x4-Matrix-Keyboard-Keypad-Module-Use-Key-PIC-AVR-Stamp-Sml-4-4-Plastic-Keys-Switch/32828049888.html
  13.  
  14. // Arduino Nano with CH340 search results:
  15. // The CH340 is the onboard serial driver which the RK005 supports
  16. // https://www.aliexpress.com/wholesale?catId=0&SearchText=ch340+arduino+nano
  17.  
  18. // OLED for some fancy display shizzle, connect to GND, 5V, port A5(SCL) and A6(SDA):
  19. // https://www.aliexpress.com/item/1pcs-0-91-inch-OLED-module-0-91-white-OLED-128X32-OLED-LCD-LED-Display-Module/32803096466.html
  20.  
  21. const byte ROWS = 4; // Pad with four rows
  22. const byte COLS = 4; // and four columns
  23.  
  24. // Define the Keymap
  25. char keys[ROWS][COLS] = {
  26.   {'1','4','7','*'},
  27.   {'2','5','8','0'},
  28.   {'3','6','9','#'},
  29.   {'A','B','C','D'}
  30. };
  31.  
  32. // arduino connection pins
  33. // pins 9 and 8 were not defined as PBx pins hence the inconsistent numbering ( * sigh * )
  34. // pins marking on board are D9,D8,D7,D6, D5,D4,D3,D2
  35. byte rowPins[ROWS] = { 9,8,PD7,PD6};
  36. byte colPins[COLS] = {PD5,PD4,PD3,PD2};
  37.  
  38. // var definitions for keypad
  39. // holds typed number
  40. int keyval=0;
  41.  
  42. // holds global midi channel
  43. byte midichannel=0;
  44.  
  45. byte keymode=0;
  46. // holds pad keymode
  47. // just 2 defined in this example:
  48. //    A = programchange
  49. //    C = midi channel change
  50. //  # concludes the number pressing and sends a command
  51.  
  52. bool dispUpdate=false;
  53. bool clock_running=false;
  54. long currentTime=0;
  55. byte pc=0;
  56. byte nt=0;
  57.  
  58.  
  59. // Create the Keypad
  60. Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
  61.  
  62. #define ledpin 13
  63. // LED goes on when in 'number enter' mode and goes off when # is pressed
  64.  
  65. void setup()
  66. {
  67.  pinMode(ledpin,OUTPUT);
  68.  // RK005 can connect with the CH340 serial chip on 38400KBps
  69.  // easier then the 31250 midi speed for debugging your sketch
  70.  // on a standard serial monitor
  71.   Serial.begin(38400);
  72.  
  73.   while (!Serial) {
  74.   // wait for serial to become available
  75.   }
  76.   u8g2.begin();
  77.   u8g2.clearBuffer();  // clear the internal memory
  78.   // u8g2.setFont(u8g2_font_6x12_t_cyrillic);
  79.   // choose a suitable font at https://github.com/olikraus/u8g2/wiki/fntlistall
  80.   u8g2.setFont(u8g2_font_fub20_tf);
  81.   u8g2.drawStr(0,31,"READY");
  82.   dispOver();
  83. }
  84.  
  85.  
  86. // main loop for checking keypad
  87. void loop(){
  88.   if(dispUpdate){
  89.     if((millis()-currentTime)>1500){
  90.       dispUpdate=false;
  91.       u8g2.clearBuffer();
  92.       u8g2.setFont(u8g2_font_6x12_t_cyrillic);
  93.       u8g2.drawStr(0,19,"MIDI KEYPAD");
  94.       if(!clock_running){
  95.         u8g2.drawStr(90,19,"STOP");
  96.       }else{
  97.         u8g2.drawStr(90,19,"PLAY");
  98.       }
  99.       u8g2.setCursor(0,30);
  100.       u8g2.print("Patch:"+String(pc+1)+" MIDI CH:"+String(midichannel+1));
  101.       u8g2.sendBuffer();
  102.       if(nt>0){ // there is a note on, off it
  103.         byte buf[3]={0x80+midichannel,nt,100};
  104.         Serial.write(buf,3);
  105.         nt=0; // notes are off
  106.       }
  107.     }
  108.   }
  109.   char key = kpd.getKey();
  110.   if (key != NO_KEY)
  111.   {
  112.     // is it numeric:
  113.     if ( (key >= '0') && (key<= '9') ){
  114.       dispUpdate=false; // prevent timeout on big display
  115.       currentTime = millis(); // reset key timeout
  116.        digitalWrite(ledpin, HIGH);
  117.        // add the numeric keys and multiply a possible former key by ten
  118.        keyval= keyval *10;
  119.        // key is a ASCII keycode 0 so deduct '0' means: '0'is actually 0
  120.        keyval+= (key-'0'); // add it to the existing value
  121.        if(keyval>128){
  122.          setSubScreen("INVALID",true);
  123.          keyval=0;
  124.          return;
  125.        }
  126.        if(keymode==2){
  127.          setSubScreen("CH:"+String(keyval),false);
  128.        }
  129.        if(keymode==0){
  130.          setSubScreen("PC:"+String(keyval),false);
  131.        }
  132.        if(keymode==1){
  133.          setSubScreen("NT:"+String(keyval),false);
  134.        }
  135.       }
  136.     if ( key == '#') // command close, end our key group
  137.      {
  138.       digitalWrite(ledpin, LOW);
  139.       if(keymode==0){ // A = keymode 0 (Program Change)
  140.         // set patch (deduct 1: 1-128 -> 0-127 internally )
  141.         // clamp the values in midi spec 0-127
  142.         pc=(byte)max(0,min(127,keyval-1));
  143.         byte buf[2]={0xC0+midichannel,pc};
  144.         Serial.write(buf,2);
  145.         setSubScreen( "P"+String(pc+1)+"/C"+String(midichannel+1),true);
  146.       }
  147.       if(keymode==1){ // B = keymode 1 (Note Send)
  148.         // set note (deduct 1: 1-128 -> 0-127 internally )
  149.         // clamp the values in midi spec 0-127
  150.         if(nt>0){ // there is a note on, off it first
  151.           byte obuf[3]={0x80+midichannel,nt,100};
  152.           Serial.write(obuf,3);
  153.         }
  154.         nt=(byte)max(0,min(127,keyval-1));
  155.         byte buf[3]={0x90+midichannel,nt,100};
  156.         Serial.write(buf,3);
  157.         setSubScreen("N"+String(nt+1)+"/C"+String(midichannel+1),true);
  158.       }
  159.       if(keymode==2){ // C = keymode 2 (MIDI Channel)
  160.         // set channel, (deduct 1: 1-16 -> 0-15 internally )
  161.         midichannel=(byte)max(0,min(15,keyval-1));
  162.         setSubScreen("CH:"+String(midichannel+1)+" OK",true);
  163.         //keymode = 0; // after midi channel change, reset to program change input mode
  164.       }
  165.       keyval=0;//reset for next input
  166.       return;
  167.      }
  168.      
  169.     // ------------------------------------
  170.     if ( key == '*'){
  171.       // cancel input
  172.       if(keyval>0){
  173.         setSubScreen("CANCEL",true);
  174.         keyval=0;
  175.       }else{
  176.         if(keymode==1){
  177.         // all notes off
  178.           setSubScreen("NT PANIC",true);
  179.           byte offbuf[48];
  180.           for(byte i=0;i<48;i+=3){
  181.             offbuf[i]=0xB0+(i/3);
  182.             offbuf[i+1]=123;
  183.             offbuf[i+2]=0;
  184.           }
  185.           Serial.write(offbuf,48);
  186.  
  187.         }
  188.       }
  189.     }
  190.     // ------------------------------------
  191.     if ( key == 'A'){
  192.       // set to 'MIDI Patch change' mode
  193.       keymode=0;
  194.       keyval=0;
  195.         setSubScreen("PCHANGE",true);
  196.     }
  197.    
  198.     // ------------------------------------
  199.     if ( key == 'B'){
  200.       // quick note send
  201.       keymode=1;
  202.       keyval=0;
  203.       setSubScreen("NOTE ON",true);
  204.     }
  205.    
  206.     // ------------------------------------
  207.     if ( key == 'C'){
  208.        // set to 'MIDI Channel change' mode
  209.        keymode = 2;
  210.        keyval=0;
  211.        setSubScreen("CHANNEL",true);
  212.     }
  213.    
  214.     // ------------------------------------
  215.     if ( key == 'D'){
  216.       // send clock start/stop
  217.       if(!clock_running){
  218.         //  send clock start
  219.         Serial.write(0xFA);
  220.         setSubScreen("START",true);
  221.  
  222.       }else{
  223.         //  send clock stop
  224.         Serial.write(0xFC);
  225.         setSubScreen("STOP",true);
  226.       }
  227.       clock_running=!clock_running;
  228.     }
  229.    
  230.   }
  231. }
  232.  
  233. void setSubScreen(String message,bool tmout){
  234.    u8g2.clearBuffer();
  235.    u8g2.setFont(u8g2_font_fub20_tf);
  236.    u8g2.setCursor(0,31);
  237.    u8g2.print(message);
  238.    u8g2.sendBuffer();
  239.    if(tmout){
  240.     dispOver();
  241.    }else{
  242.     u8g2.sendBuffer();
  243.    }
  244. }
  245. // this function sends the screen of a key status update and
  246. // sets the timeout function to revert to the overview screen
  247. void dispOver(){
  248.   u8g2.sendBuffer();
  249.   dispUpdate=true;
  250.   currentTime = millis();
  251. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement