loading
Picture of Homemade MPC style MIDI controller
fig2.png
fig3.png
fig4.png
fig5.png


1.0 INTRODUCTION
 I decided to build and design a midi controller which is used to send commands to a computer running a DAW(digital audio workstation)  to control different parameters within it. The DAW I used is called Ableton Live. There are 16 button pads and 6 potentiometers on the front of the unit. Depending on which DAW is used, you can assign the potentiometers to control parameters like track volume, track reverb, and any other effects applied to a track. There is also a dock on the side which has 10 more analog channels to connect more potentiometers and allow for future expansion of other projects and ideas.  The buttons can be used to launch loops, or you can play it just as you would play a regular piano or keyboard.  You will be able to change the bank of notes that the buttons send to the computer using bank up and bank down button on the front panel. There is a total of 128 notes (or 128 values)  you can play on the buttons and you can bank up 16 notes at a time meaning 8 banks. There are also RGB LEDs’ under the buttons to indicate what bank you are currently on. There is also an LCD display displays what value you are sending to the computer and indicates the bank number.

1.1 Midi Overview
Midi allows you to control virtual instruments within a audio recording program. For example you can assign a piano to a track and control the notes of the virtual piano using a midi controller.  A midi command is consists of 3 bytes. The first byte is a status byte. It tells the computer what type of action it will be performing. For example a common status byte would be  the decimal value 144 which means note on. This is then followed by two data bytes; the next one being which note to turn on.  0 is the lowest note and 128 is the highest.  The last byte would be how loud you want that note to sound.  This is called velocity. 0 would be the quietest and 128 would be the loudest.   If you want to control things like volume or any other parameters you can send what is called a control change command. This is only two bytes. The first byte would tell the computer which control change you are wanting to control. For example sending the decimal value 16 would be initiated a control change on channel 1.   The next byte is the value between 0 and 128  which is sent to the computer. You assign which parameter is controls within the program.


2.0 PCB AND HARDWARE SETUP
There are 3 PCBs’ which I have designed which make the operation of this midi controller possible; the main PCB(Figure 2.0), the RGB driver(Figure 3.0-yellow), and  the analog channel expansion port(4.0-yellow). There are 3 units I have used that are bought online; the MIDI to USB converter(Figure 4.0-purple), the LCD screen(Figure 3.0-purple), and the button pad PCB(Figure 3.0-purple).

The main PCB holds the microcontroller I used, and two ADC chips. The microcontroller I used is a PIC18F2550, and the two ADCs’ I used are LTC2309s’.  If you refer to figure 2.0, you can see the PIC placed in the center and I have placed the two ADC’s on either end of the PCB. The reason I did this was because of the location I have mounted the PCB within the enclosure. The 6 onboard potentiometers are to the left of the PCB and the ADC extension port is to the right of the main PCB.  Since each ADC has 8 channels, I have set it up so  IC2 uses 6 of its channels for the onboard potentiometers, and then the extra two  ADC channels  are added to the ADC extension port. 
If you refer to the main PCB schematic in step 5, you will note that I have used two voltage regulators for this design. IC3 is set to regulate the voltage at 5 volts. This voltage is used to power the chips, LCD, and button pad LEDs’. The other voltage regulator, IC5, is an adjustable reference voltage for the potentiometers and ADC channels.  This is adjusted using a small surface mount potentiometer located directly beside it. There is also a diode in series at the input of these voltage regulators to keep anything from being damaged if the input voltage was accidently reversed. I made sure the diode was rated high enough to handle the current.  Located around the PIC are various connectors used for connecting to the button pad and LEDs’. The function of each pin will be discussed in a later section. To the right of the PIC are the connectors used for connecting to the analog channel expansion port and the programming port. The reason I have the programming port on the same PCB as the ADC extension port is I want to be able to reprogram the PIC without having to remove the lid of the unit. To get access to it, the side panel simply needs to be removed as shown in figure 5.0.
 
The LED driver PCB I designed is mounted directly beneath the button pad PCB(Figure 3.0).  If you refer to the schematic in step 4 this PCB enables me to control all the LEDs at the same time.  The connection from this board to the main PCB has 5 pins; VDD, GND,  and 3 LED control pins. Each of these control pins is connected directly to the input of the mosfet on the driver board which controls all the LEDs of that color. One mosfet controls all the red LEDs, one for all the green LEDs, and one for all the blue LEDs.

 
 
Remove these adsRemove these ads by Signing Up

Step 1: Program operation.

Picture of Program operation.
fig7.png
fig8.png
fig9.png
3.0 PROGRAM OPERATION
The following section will discuss how the program works.  Section 3.1 will go over the initialization part of the code which happens before the main loop. Once the program enters the main loop is calls out to 4 different functions: potread, keypress,  bankchange, and RGB. Sections 3.2, 3.3, 3.4, and 3.5 will discuss these functions separately.  Please refer to the code in step 6.

3.1 Initialization
Any microcontroller needs to be configured first before it enters a main program loop.  This includes setting up the direction of the pins, putting the correct values in any of the control registers, and defining the main clock that the microcontroller is going to be using.  The first step of my program was to set up the config registers.   These registers typically control things like the watchdog timer, any master clear reset pins, brown out detect, and oscillator configurations. In this particular example I set it up so that a 20Mhz external oscillator crystal is used as the main clock for the PIC.  The PIC has internal oscillators and can run up to 8Mhz, but due to the speed of the midi data, I needed to run the microcontroller at a higher speed in order to avoid any data errors.  Note the location of the oscillator on the main PCB board layout in section 7.1. I soldered the crystal directly beneath the board so it is not visible in figure 2.0.
The next register I configured was the RCSTA and TXSTA registers. These registers are responsible for controlling hardware serial commands. The reason I used hardware serial commands, as opposed to software serial for sending the midi commands, is because I am sending the data to the midi converter board at 31250 baud.  I tried sending the data first using software commands only, and I was getting errors and the computer was receiving data that had missing bits and missing pieces of information.  The hardware serial port has an internal buffer used for directing the flow of data and is therefore more reliable.  The only limitation of using the hardware serial commands is you are restricted to using only certain pins on the microcontroller where as if you send software commands, you can use any available pin you want.   The LCD I used only required the data to be sent at 9600 baud, so I any command I sent to the LCD was software serial commands.
I then set up the pins that were going to be used to control the LTC2309 chips.  These chips are controlled using I2C commands so only two pins are needed to control the two chips.
After this I defined all the global variables used in the program. I then configured the direction of the pins but loading the correct bytes into the TRISA, TRISB, and TRISC registers on the PIC.  Loading a zero defines the pin of that port to an output. Loading a one, defines it as an input. For example: if I load the value 00000001 in into the TRISB register,  Pin zero on PORTB would be an input while pins one through seven are defined as outputs.
Since the PIC also has onboard ADCs’ I needed to disable those so that’s the next thing I did.  The LCD display then is turned on and an intro screen is displayed.  The software serial command is a function built into Picbasic Pro which is the compiler I used.   Anytime I want to issue a software serial command, I need to specify the pin I want to send the command on, the baud rate, and the data that I want to send.  I found out how to control the LCD through its data sheet. 
The buttons then cycle through the different colors.  The purpose of this is to make sure everything is connected properly.  If all the colors are displayed I know the RGB LEDs are connected correctly. The program then enters the main loop.

3.2 Potread
Since there are 8 channels on each LTC2309, I set up the program so all 8 channels of IC2 are read in one for loop, and all 8 channels of IC4 are read in another for loop.  Since these chips are controlled using I2C commands only two pins are used.  One is a clock pin, which runs a 100Khz, and the other pin is a bi-directional pin, which is used to send and receive data.

In order to read the analog value from any given channel, you need to tell the ADC what channel you want to read therefore before you read any channel you must first send two bytes of information to the chip. The first byte the microcontroller sends to the ADC is the address frame. There are two pins on the LTC2309, which you can configure to set the address.  By setting the AD1 pin, and AD0 pin to either high, low, or floating, you can get up to 8 different addresses, meaning you can connect up to 8 different LTC2309s’ on one I2C bus.  If you refer to Figure 6.0 you can view the different configurations.  I’ve indicated which address’ I am using. 7 bits are used as the address, and  the LSB(Bit 0) is used to indicate weather it is a read command or write command.  Setting this bit to one prepares the ADC for a read command and setting it to zero sets it to a write command.

The following byte sent to the ADC is a 6 bit “Din” word.  This is responsible for channel configuration.  See Figure 8.0 for Din configurations. I’ve highlighted the different words I have used.  In my program, the S/D bit is always set because I am doing single ended measurements.  The UNI bit is also always set because I am only using the chip in unipolar mode.  Figure 7.0 is the timing diagram for a write command included in the data sheet.

Next the ADC sends the analog value to the microcontroller. However, any time any information exchanged from the ADC to the microcontroller, you must still send the address frame, except the LSB in the address frame is changed to one, meaning it is a read command.   The 12 bit analog value is sent in two bytes.  Figure 9.0 is the format of the data comes in. I read the analog value into two different variables. One variable holds the 8 most significant bits, and the other byte holds the 4 least significant bits of the variable.  However the least significant bits are siting 4 places to the left in that variable, and the 4 bits to the right are just zeroes. In order to get this value into a useable form, I shift the 8 most significant bits 4 places to the left. I am able to do this since the variable I am using is a 16 bit word.  I then shift the variable with the 4 least significant bits 4 spots to the right.  These two values are then or’ed together and the result is a 16 bit variable with a 12 bit analog value.  However I still have to scale the value down since a midi control signal value is only one byte. The max ADC value is 4095 in decimal, and therefore needs to be scaled down to 128. To do this I multiply the ADC value by 4095 then divide is by 128.  I have another variable, which I use to save the previous ADC value. When the loop comes around again it checks if the new ADC value has changed. If it changed more than a certain threshold value, then it sends a midi signal with the new ADC value.  If it is below this value, it skips it all together and continues to read the next channel.  I save the un-scaled value, so this threshold is 50.  I had to choose a value that was large enough to be above the noise, but not be so large that the analog values sent to the midi controller are really far away from each other, thus giving a choppy sound. A midi control command is a series of 3 bytes. The first byte specifies that it is a control command that is being sent. The second byte is which channel the control command is being sent.  The last byte is the analog value.    So for example, lets say within my music software I assign a volume on a certain channel to accept incoming midi signals from channel 16.  As I turn the potentiometer, the midi controller is continuously sending these 3 bytes at a very fast rate.  First two bytes stay the same every time these bytes are sent but the last value will be changing. The idea is you want this value to move up or down in small increments. The increments that it changes by is the threshold value  was discussed earlier. I increment the channel by 1, after each loop, so all the potentiometers are writing to their own midi channel. This loop is then continued 7 more times for that ADC chip. I continue a different loop another 8 times to read the values from the other ADC chip. The only difference between the two loops is the address I use to communicate with the chip, and the channel numbers that are being updated.

Step 2:

3.3 Keypress
“Scanning” is the process I used to multiplex the button pad so I wouldn’t have to use 16 pins on the microcontroller for 16 buttons. Instead I only had to use 8 pins. If you refer to step 4 I’ve included the schematic for the button pad I bought from sparkfun electronics and have indicated the signal path of each pin on the button pad PCB. As you can see there are separate pins for controlling the LEDs and controlling the buttons. The LED control pins will be discussed in a later section.
The microcontroller is set it up so all the columns are outputs and all the rows are inputs. If you refer to the button pad schematic, I start by setting the first column (which is RB4 on the pic) to zero. I set the rest of the columns to 1(RB5,RB6,RB7).  The program then checks the state of all the rows at the same time(RC4,RC5,RC7,RC0). The program pauses for 1 millisecond and checks those pins again. Since switches and buttons often bounce, this causes unwanted ripples on the signal, so we eliminate this with a process called de-bouncing. If the values from the two checks are equal then that means it was a valid button press on that column and not a bounce.  The program then enters a for loop, which checks the state of each of the rows. If a button is pressed on that column, it is read as a zero on the corresponding row since the column is set to zero. Since each of the pins on the rows has a 10k pull-up resistor(not shown on button pad schematic),  if a button is not pressed that row pin will be read as a 1. 
Once a button press is detected on that column it sends a 3 byte midi message over the hardware serial port on the PIC.  The first byte is 0x92 which the computer detects as a channel 4 note on message. The second byte is which note is to be turned on, which can be anywhere between 0 and 127. Since I am using a for loop to check each of the rows I am using the for loop variable “i” to indicate which note I want on.  Since I am also using 8 banks of notes(128 notes total)  I add it to the current bank variable which is “c”. The bank switch process will be further discussed in section 3.4. The last byte is the velocity which also can be anywhere between 0 and 127, but for all the buttons I set that value to 100.  The next line of code then sends the same commands in ascii text to an LCD over a microcontroller pin I configured for software serial out.
The microcontroller also needs to detect when a note is released because it needs to send another command to turn that same note off. Within the same for loop this is done by sending the same 3 bytes except the last byte(velocity), is set to zero which turns that note off. If this command not sent, that note would stay on indefinitely, even if that button was released. 
Up until this point we have only checked the status, and sent commands for the 4 buttons on the first column. This whole process is repeated 3 more times, one for each column.  In the next for loop I set the next column to zero and set the rest to 1, and do the same for the remaining columns. 

3.4 Bank Change
Since there are 128 different midi notes that can be sent as  a midi command I wanted to be able to make full use of all of them, so I added the ability to bank between groups of 16 notes at a time. To do this I added two push buttons on the front panel beneath the LCD(see Figure 1.0).  To bank up, I polled the input of the pin on the microcontroller I set up as the input for banking up. Since I set up these microcontroller inputs with a pull-down resistor I checked for a low to high transition when the switch connects to VDD. When that transition was detected, I added one to the variable “j”.  I set it up so once “j” was more than 8 it reset back to zero. I also wanted the ability to save the bank on the non-volatile eeprom so if for what ever reason I have to remove the power to re-arrange cables the midi controller boots up and automatically sets itself back to the bank it was on before it was powered off.  I also found that if I was holding a note and pressed one of the bank buttons at the same time,  the midi controller lost track of which note was being pressed so that note would never turn off. To fix this I made a for loop which turns off all of the notes at the same time anytime I bank up or down.  I used the same code for the bank down button except instead of adding one to “j” I subtracted one from “j” and has it reset to 8 if it went below 1.   I set it up so “j” as a global variable and is used throughout different sections of the program.  
At the end of this function, I check what value j is and set the variable  “c” accordingly. “c” enables the midi controller to bank up 16 notes at a time by adding it to whichever keypad number you are pressing.  For example if I want midi note number 35 on, I need to go to bank 3.   “c” is added to which key number I am pressing. So if I am pressing button number 3 on the keypad, the midi controller adds the value “c”, which is in this case is 32.

3.5 RGB
I set aside 3 pins on the microcontroller to control all the RGB LEDs’.  RA0 controls all the red LEDs’, RA1 controls all the green LEDs’ and RA2 controls all the blue.  Each pin controls all the LEDs’ by connecting to the gate on a MOSFET located on the LED driver board(See step 4). The LEDs’ had to be driven this way because the current required to drive all the LEDs’ exceeded the microctrollers current sourcing abilities.
This RGB function in the program basically checks what bank of notes the midi controller is in by checking the value of the variable “j”.  To get the different colors I simply combined different sets of colors together. For example to get the color purple, I turn on red and blue at the same time by setting RA0 and RA2 to high and setting RA1 to low.

Step 3:

Picture of
fig11.png
fig12.png
fig13.png
4.0 ESTHETICS
4.1 Enclosure

I purchased the enclosure from OKW(www.okw.com), a  company in the states which manufactures various types of enslosures and project boxes. I first downloaded the autoCAD drawing of the enclosure I wanted to purchase so I could check the dimensions to make sure it would fit a project of this scale.  I also used this autoCAD drawing to find the dimensions and spacing of the plastic mounting stand-offs built into it so it would match with the PCBs’. Figure 10.0 is a picture of what it looked like before I did any modification to it. I then painted it and used a dremel to cut a hole big enough to fit the face plate I was going to design(Figure 11.0).


4.2 Front Panel
To design the front panel I used AutoCAD. I found the drawing of the button pad I purchased and used that to make sure the holes and mounting screws were properly spaced apart so buttons could be pressed without having them stick. I also found a drawing of the LCD and did the same thing.  When my panel design was done, I purchased some diamond plate aluminum from a hardware store(Figure 12.0) and had it machined using a CNC mill I had access to(Figure 13.0)

Step 4: Schematics and Board layouts

Picture of Schematics and Board layouts
analogexpantion.png
button pad pinout.png
led driver schematic.png
Images are in the following order:

-Main PCB schematic
- Analog Channel Expansion Port Schematic
-Button Pad Schematic
- RGB Driver Schematic

Step 5: Board Layouts

Picture of Board Layouts
pot interface boardd.png
button pad layout.png
led driver board.png
Images are in the following order:

-Main PCB Layout
-Analog Channel Expansion Port Board Layout
-Button Pad Board Layout
-RGB Driver Board Layout

Step 6: The Code.

'****************************************************************
'*  Name    : UNTITLED.BAS                                      *
'*  Author  : Matthew Reid                                      *
'*  Notice  : Copyright (c) 2012 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 9/5/2012                                          *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
pause 300
include "modedefs.bas"

#CONFIG
__CONFIG _CONFIG1L, _PLLDIV_5_1L   & _CPUDIV_OSC1_PLL2_1L & _USBDIV_2_1L
__CONFIG _CONFIG1H, _FOSC_HS_1H & _FCMEN_ON_1H  & _IESO_ON_1H
__CONFIG _CONFIG2L, _PWRT_ON_2L & _BOR_ON_2L & _BORV_3_2L & _VREGEN_OFF_2L
__CONFIG _CONFIG2H, _WDT_ON_2H & _WDTPS_256_2H
__CONFIG _CONFIG3H, _MCLRE_OFF_3H & _PBADEN_OFF_3H
__CONFIG _CONFIG4L, _STVREN_ON_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_OFF_4L
#endconfig
define OSC 20



OSCCON = %00001000

'set up hardware serial port
define HSER_RCSTA 90H
define HSER_TXSTA 24H
define HSER_BAUD 31250


'i2c ports
SDA var PORTB.2
SCL var PORTB.1

'button variables

'column 1 variables
buttonval1 var byte
bouncecheck1 var byte
buttonstate1 var bit[4]
i var byte
value1 var byte

'column 2 variables
buttonval2 var byte
bouncecheck2 var byte
buttonstate2 var bit[4]
value2 var byte

'column 3 variables
buttonval3 var byte
bouncecheck3 var byte
buttonstate3 var bit[4]
value3 var byte

'column 4variables
buttonval4 var byte
bouncecheck4 var byte
buttonstate4 var bit[4]
value4 var byte

'bankchange variable
upstate var bit
downstate var bit
j var byte: j = 1
c var byte







'variables for a to d  (IC2)
one var byte[8]
two var byte[8]
three var word[8] :three = 0
threshold var word: threshold = 50
prevpotval var byte[8]

prevadval var word[8]
currentadval var word [8]

'variables for a to d  (IC1)
one1 var byte[8]
two1 var byte[8]
three1 var word[8] :three = 0

prevpotval1 var byte[8]

prevadval1 var word[8]
currentadval1 var word [8]




'port direction
trisa = %00000000
trisb = %00000001
trisc = %10110110

'enable RC4 and RC5
ucon.3 = 0
ucfg.3 = 1

'disable internal A to D
adcon0 = %00111100
adcon1 = %00001111


'turn on lcd and set brightness to max
pause 1000
serout PORTB.3, N9600, [$1b,$2a,$FF]


serout PORTB.3,N9600,[$1b,$30]
serout PORTB.3,N9600,[$1b,$2a,200]
serout PORTB.3,N9600,[$1b,$46]

serout PORTB.3,N9600,[$fe,$80]
serout PORTB.3,N9600,["Midi Pad v1_1"]
serout PORTB.3,N9600,[$fe,$c0]
serout PORTB.3,N9600,["Matt Reid  2012"]

'intro flash

'red
porta.0 = 1
porta.1 = 0
porta.2 = 0
pause 400
'green
porta.0 = 0
porta.1 = 1
porta.2 = 0
pause 400
'blue
porta.0 = 0
porta.1 = 0
porta.2 = 1
pause 400
'purple
porta.0 = 1
porta.1 = 0
porta.2 = 1
pause 400
'white
porta.0 = 1
porta.1 = 1
porta.2 = 1
pause 400
'cyan
porta.0 = 0
porta.1 = 1
porta.2 = 1
pause 400

'_________________________



'read bank from eeprom
read 5, j

mainloop:
gosub bankchange  
gosub keypress
gosub potread
gosub RGB

goto mainloop



bankchange:

'bank up
if portc.2 = 1 & upstate = 1 then
j = j + 1
    if j > 8 then
    j = 1
    endif
   
    'clear all notes
    for i = 0 to 128
    hserout[$92, i, 0]
    next i
    'write bank change to eeprom
    write 5,j
upstate = 0 
endif  
if portc.2 = 0 & upstate = 0 then
upstate = 1
endif

'bank down
if portc.1 = 1 & downstate = 1 then
j = j - 1
    if j < 1 then
    j = 8
    endif
    'clear all notes
    for i = 0 to 128
    hserout[$92, i, 0]
    next i
    'write bank change to eeprom
    write 5,j

downstate = 0 
endif  
if portc.1 = 0 & downstate = 0 then
downstate = 1
endif

'display bank
serout PORTB.3, N9600, [$Fe, $c0]
serout PORTB.3, N9600, ["BANK", " ", #j, "         "]

if j = 1 then
c = 0
endif

if j = 2 then
c = 16
endif

if j = 3 then
c = 32
endif

if j = 4 then
c = 48
endif

if j = 5 then
c = 64
endif

if j = 6 then
c = 80
endif

if j = 7 then
c = 96
endif

if j = 8 then
c = 112
endif


return



potread:
'adc potentiometer stuff------------------------------------------------------



'read ic2
for i = 1 to 8
    three[i] = 0
   
        if i = 1 then
        i2cwrite SDA, SCL, %00010000 , [ %10001100]
        endif
        if i = 2 then
        i2cwrite SDA, SCL, %00010000 , [ %11001100]
        endif
        if i = 3 then
        i2cwrite SDA, SCL, %00010000 , [ %10011100]
        endif
        if i = 4 then
        i2cwrite SDA, SCL, %00010000 , [ %11011100]
        endif
        if i = 5 then
        i2cwrite SDA, SCL, %00010000 , [ %10101100]
        endif
        if i = 6 then
        i2cwrite SDA, SCL, %00010000 , [ %11101100]
        endif
        if i = 7 then
        i2cwrite SDA, SCL, %00010000 , [ %10111100]
        endif
        if i = 8 then
        i2cwrite SDA, SCL, %00010000 , [ %11111100]
        endif
    'this pause is important to keep the adc from jumping around
    pause 4
      
    i2cread SDA, SCL, %00010001, [one[i], two[i]]
       
       
       
    three[i] = one[i] | three[i]
   
   
    three[i] = three[i]<<4
    two[i] = two[i]>>4
    three[i] = two[i] | three[i]
    currentadval[i] = three[i]
    'pause 10
   
    three[i] = three[i] * 128
    three[i] = div32 4095   
   
    if abs(currentadval[i] - prevadval[i]) >= threshold then
         hserout[$B2, 13+i, three[i]]
         prevpotval[i] = three[i]
         prevadval[i] =  currentadval[i]
         'display a to d value
    serout PORTB.3, N9600, [$Fe, $80]
        serout PORTB.3, N9600, [#178, " ", #(13+i), " ",#three[i], "           "]
    endif    
next i

'read ic1
for i = 1 to 8
    three1[i] = 0
   
        if i = 1 then
        i2cwrite SDA, SCL, %00010100 , [ %10001100]
        endif
        if i = 2 then
        i2cwrite SDA, SCL, %00010100 , [ %11001100]
        endif
        if i = 3 then
        i2cwrite SDA, SCL, %00010100 , [ %10011100]
        endif
        if i = 4 then
        i2cwrite SDA, SCL, %00010100 , [ %11011100]
        endif
        if i = 5 then
        i2cwrite SDA, SCL, %00010100 , [ %10101100]
        endif
        if i = 6 then
        i2cwrite SDA, SCL, %00010100 , [ %11101100]
        endif
        if i = 7 then
        i2cwrite SDA, SCL, %00010100 , [ %10111100]
        endif
        if i = 8 then
        i2cwrite SDA, SCL, %00010100 , [ %11111100]
        endif
       
    'this pause is important to keep the adc from jumping around
    pause 4
       
    i2cread SDA, SCL, %00010101, [one1[i], two1[i]]
       
       
       
    three1[i] = one1[i] | three1[i]
   
   
    three1[i] = three1[i]<<4
    two1[i] = two1[i]>>4
    three1[i] = two1[i] | three1[i]
    currentadval1[i] = three1[i]
    'pause 10
   
    three1[i] = three1[i] * 128
    three1[i] = div32 4095   
   
    if abs(currentadval1[i] - prevadval1[i]) >= threshold then
         hserout[$B2, 13+i, three1[i]]
         prevpotval1[i] = three1[i]
         prevadval1[i] =  currentadval1[i]
         'display a to d value
    serout PORTB.3, N9600, [$Fe, $80]
        serout PORTB.3, N9600, [#178, " ", #(21+i), " ",#three1[i], "           "]
    endif    
next i




   
   
return


keypress:

'button code
'set column 1--------------------------------------------------------------------
portb.4 = 0
portb.5 = 1
portb.6 = 1
portb.7 = 1

buttonval1 = 0
bouncecheck1 = 0


buttonval1.0 = portc.4
buttonval1.1 = portc.5
buttonval1.2 = portc.7
buttonval1.3 = portb.0

pause 1

bouncecheck1.0 = portc.4
bouncecheck1.1 = portc.5
bouncecheck1.2 = portc.7
bouncecheck1.3 = portb.0



if buttonval1 = bouncecheck1 then

for i = 0 to 3  ' Count from 0 to 3

   value1 = buttonval1 >> i
    if value1.0 = 1 &  buttonstate1[i] = 1 then
    hserout[$92, c + i, 0]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c + i)," ", #0, "           "]
    buttonstate1[i] = 0
    endif
   
    if value1.0 = 0 & buttonstate1[i] = 0 then
    hserout[$92, c + i, 100]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c + i)," ", #100, "           "]
    buttonstate1[i] = 1
    endif

next i

endif


'set column 2--------------------------------------------------------------------
portb.4 = 1
portb.5 = 0
portb.6 = 1
portb.7 = 1

buttonval2 = 0
bouncecheck2 = 0


buttonval2.0 = portc.4
buttonval2.1 = portc.5
buttonval2.2 = portc.7
buttonval2.3 = portb.0

pause 1

bouncecheck2.0 = portc.4
bouncecheck2.1 = portc.5
bouncecheck2.2 = portc.7
bouncecheck2.3 = portb.0



if buttonval2 = bouncecheck2 then

for i = 0 to 3  ' Count from 0 to 3

   value2 = buttonval2 >> i
    if value2.0 = 1 &  buttonstate2[i] = 1 then
    hserout[$92, c+4+i, 0]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c+4+i)," ", #0, "           "]
    buttonstate2[i] = 0
    endif
   
    if value2.0 = 0 & buttonstate2[i] = 0 then
    hserout[$92, c+4+i, 100]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c+4+i)," ", #100, "           "]
    buttonstate2[i] = 1
    endif

next i

endif

'set column 3--------------------------------------------------------------------
portb.4 = 1
portb.5 = 1
portb.6 = 0
portb.7 = 1

buttonval3 = 0
bouncecheck3 = 0


buttonval3.0 = portc.4
buttonval3.1 = portc.5
buttonval3.2 = portc.7
buttonval3.3 = portb.0

pause 1

bouncecheck3.0 = portc.4
bouncecheck3.1 = portc.5
bouncecheck3.2 = portc.7
bouncecheck3.3 = portb.0



if buttonval3 = bouncecheck3 then

for i = 0 to 3  ' Count from 0 to 3

   value3 = buttonval3 >> i
    if value3.0 = 1 &  buttonstate3[i] = 1 then
    hserout[$92, c+8+i, 0]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c+8+i)," ", #0, "           "]
    buttonstate3[i] = 0
    endif
   
    if value3.0 = 0 & buttonstate3[i] = 0 then
    hserout[$92, c+8+i, 100]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c+8+i)," ", #100, "           "]
    buttonstate3[i] = 1
    endif

next i

endif


'set column 4--------------------------------------------------------------------
portb.4 = 1
portb.5 = 1
portb.6 = 1
portb.7 = 0

buttonval4 = 0
bouncecheck4 = 0


buttonval4.0 = portc.4
buttonval4.1 = portc.5
buttonval4.2 = portc.7
buttonval4.3 = portb.0

pause 1

bouncecheck4.0 = portc.4
bouncecheck4.1 = portc.5
bouncecheck4.2 = portc.7
bouncecheck4.3 = portb.0



if buttonval4 = bouncecheck4 then

for i = 0 to 3  ' Count from 0 to 3

   value4 = buttonval4 >> i
    if value4.0 = 1 &  buttonstate4[i] = 1 then
    hserout[$92, c+12+i, 0]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c+12+i)," ", #0, "           "]
    buttonstate4[i] = 0
    endif
   
    if value4.0 = 0 & buttonstate4[i] = 0 then
    hserout[$92, c+12+i, 100]
    serout PORTB.3, N9600, [$Fe, $80]
    serout PORTB.3, N9600, [#146," ", #(c+12+i)," ", #100, "           "]
    buttonstate4[i] = 1
    endif

next i

endif

return


RGB:

if j = 1 then
'yellow
porta.1 = 0
pauseus 200


porta.0 = 1
porta.1 = 1
porta.2 = 0
endif

if j = 2 then
'red
porta.0 = 1
porta.1 = 0
porta.2 = 0
endif

if j = 3 then
'green
porta.0 = 0
porta.1 = 1
porta.2 = 0
endif

if j = 4 then
'blue
porta.0 = 0
porta.1 = 0
porta.2 = 1
endif

if j = 5 then
'purple
porta.0 = 1
porta.1 = 0
porta.2 = 1
endif

if j = 6 then
'white
porta.0 = 1
porta.1 = 1
porta.2 = 1
endif

if j = 7 then
'cyan
porta.0 = 0
porta.1 = 1
porta.2 = 1
endif

if j = 8 then
'blue
porta.0 = 0
porta.1 = 0
porta.2 = 1
endif
return

Great job !! ....but while i was trying to compile the code, i got an ASM Warning,

FOUND DIRECTIVE IN COLUMN 1. (__CONFIG)

but it was compiled successfully anyway...Is it okay to burn this HEX...

Thanks

hi!!
if I type in or copy paste the same code that you gave, then will I be able to play the same sounds as you did in the video?

dieferman1 year ago
Really Nice Job !!!!
Thanks For Sharing !!!!
rabitt2 years ago
hi ! what if a want more button pads.. "encoders" and more rgb leds??

regards
mrcrud5 (author)  rabitt1 year ago
You can buy the button pad from sparkfun. Just search it on the website
About how much did this project cost you?
sonicrz2 years ago
That is very cool I wish I could make one (I don't know much about PCB and electrical but you have inspired me to make one a little different and much easier.