In this tutorial we are going to make a Touch Capacitive PCB using an ATMega328P IC to control neo pixel led strip. We will include some features such as music reactive mode, random animation mode, and RGB controlling mode on our PCB. So far, we've made a touch capacitive piano where you can find the basics of touch capacitive technology. And now in this tutorial, we are going to design a Touch Capacitive-based light panel PCB that will have three different modes for controlling the Neo-Pixel strip. These modes are ‘Ring Mode’ in which we can change the LED color using the sliders presented on the board. The second mode is the ‘RGB mode’ where we can change the LED strip color and intensity in between RGB color and the last mode is the ‘Music mode’ where the color and intensity of the LEDs change according to the music playing. This elegant project design was made possible by the PCB boards fabricated by PCBWay, we will also show you how the board was designed and ordered from PCBway
Components Required to build the Front Panel PCB
The following components are required to build a PCB Piano using Arduino Nano.
- ATMega328P IC (DIP Package)
- SMD Resistors (1Mega Ohm, 0805) X 9
- SMD Resistors (1K, 0805)x1
- Piezoelectric Buzzer
- SMD 78M05 IC
- SMD Electrolytic Capacitor (10uF,16V,4x45mm) x 2
- SMD Capacitor ( 22pF 0805) x 11
- Crystal Oscillator (16 MHz)
Circuit Diagram for the PCB Light Panel
The 9pcs 1Mega Ohm Resistors are connected to the ATMega328P IC’s Pin number PB1 as a common pin in the following circuit diagram. The digital pins PD2 to PD7 and PB0 were further connected to the other connecting points of each resistor. On the diagram below, the remaining digital pins are connected to the 1x5 pin header and named “REMAINING DIGITAL PINS”.
We've connected eight 22uF capacitors to each of the resistors. And the negative pin of each capacitor is connected to the Atmega328p IC’s ground pin. Then we have a Power section that provides a proper 5V to the ATMega328P IC and the Neo Pixel.
Note: If necessary, we can add capacitors. Small capacitors (20pF - 400pF) are highly recommended for stabilizing detected data. However, ensure that the capacitors are grounded, as this reduces the parallel to the body resistance. In my case, I did not use the capacitors because it works fine for me without them. I mentioned the capacitors in the schematic above so you could easily add them during the practical implementation. The following capacitors' values must be between 20pF and 400pF, as specified in the “CapacitveSensor” library's documentation.
How the Capacitive Sensor Library Works?
This is where the Arduino libraries come in handy. Thanks to Paul Bagder and Paul Stoffregen, the authors of the “CapacitiveSensor” library. When we touch that conductive plate, we can detect a change in capacitance using this library. One of the digital pins is used as a send pin (as OUTPUT), while the other is used as a receive pin (as INPUT) in this library. The duration between when the send pin goes high and when the receive pin goes high is the sole way to detect a change in capacitance. When you set the send pin to high (or 5 volts), the resistor-capacitor pair produces a delay between when the send pin becomes high and when the receive pin reads the high value from the send pin. The CapacitiveSensor library provides a function that sets the send pin to HIGH, then waits and counts until the receive pin is read as HIGH. This function returns a time value that can be used to detect capacitance changes. When the time value increases or decreases, it indicates that the capacitance value has changed. The receive pin will take longer to reach high when there is more capacitance, and it will take less time to go high when there is less capacitance. As a result, we can determine what the normal state is and then check for changes each time the send pin toggles.
Fabricating PCB for PCB Light Panel
Now that we have the schematic, and we can proceed with laying out the PCB for Touch Capacitive Based PCB Light Panel. You can design the PCB using any PCB software of your choice. Here we are using the EasyEDA platform to create the Schematic and the PCB for our project. Below are the 3D model views of the top layer and bottom layer of the PCB Light Panel:
The PCB layout for the above circuit is also available for download as Gerber from the link given below:
Ordering PCB from PCBWay
Now after finalizing the design, you can proceed with ordering the PCB:
Step 1: Get into https://www.pcbway.com/, sign up if this is your first time. Then, in the PCB Prototype tab, enter the dimensions of your PCB, the number of layers, and the number of PCBs you require.
Step 2: Proceed by clicking on the ‘Quote Now’ button. You will be taken to a page where to set a few additional parameters like the Board type, Layers, Material for PCB, Thickness, and More, most of them are selected by default, if you are opting for any specific parameters, you can select it in here.
Step 3: The final step is to upload the Gerber file and proceed with the payment. To make sure the process is smooth, PCBWAY verifies if your Gerber file is valid before proceeding with the payment. This way, you can be sure that your PCB is fabrication friendly and will reach you as committed.
Assembling the Touch Capacitive Light Panel PCB
After the board was ordered, it reached me after some days through courier in a neatly labeled well-packed box. The PCB quality was good as always. The top layer and the bottom layer of the board are shown below:
After making sure the tracks and footprints were correct. I proceeded with the assembling of the PCB. The completely soldered board looks like the below:
PCB Light Panel Programming
The complete code for Touch Capacitive Based PCB Light Panel can be downloaded from the github repository of this project. The “CapacitiveSensor” library is really easy to use and they have provided such good documentation on how to use the library. Before getting into the program let's install the “CapacitiveSensor” library on the Arduino IDE. You need to download the zip file of the library. Then go to the “Sketch -> Include Library” section under the toolbar of the Arduino IDE. Add the zip file by using the “Add .Zip Library…” option as shown in the image below. Then restart the Arduino IDE. Similar way you can also install the ADCTouch.h library.
Now after installing the required library files, start the code by including all the library files. Adafruit_NeoPixel.h is used for controlling single-wire-based LED pixels and strips. Here we are using it to control the Neo-Pixel led strip. CapacitiveSensor library is used to sense the touch on the PCB pads.
#include <Adafruit_NeoPixel.h> #include <CapacitiveSensor.h> #include <ADCTouch.h>
Then in next lines we have created nine instances using the CapacitiveSensor() function. These instances define the pins where touchpads are connected. The syntax for this function is CapacitiveSensor(byte sendPin, byte receivePin) where one of the digital pins is used as a send pin (as OUTPUT), while the other is used as a receive pin (as INPUT) in this library.
CapacitiveSensor Mode_Pad = CapacitiveSensor(9,8); CapacitiveSensor RGB_Pad = CapacitiveSensor(9,7); CapacitiveSensor Music_Pad = CapacitiveSensor(9,6); CapacitiveSensor Ring_L_Pad = CapacitiveSensor(9,5); CapacitiveSensor Ring_LT_Pad = CapacitiveSensor(9,4); CapacitiveSensor Ring_T_Pad = CapacitiveSensor(9,3); CapacitiveSensor Ring_TR_Pad = CapacitiveSensor(9,2);
After that, declare the Neo Pixel strip object where Argument 1 is the number of pixels in the Neo Pixel strip and Argument 2 is the pin where the LED strip is connected.
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, PIN, NEO_GRB + NEO_KHZ800);
Then we have defined some functions to detect the touch on the pads and rings. The first three functions namely ModeMode(), RGBMode() and MusicMode() are used to detect the touch on the pads that are used to change between different modes of PCB. In the first function, we will read the values of the first pad that is ‘MODE’ and if the detected values are more than 500 then it will return 1 otherwise zero. Similarly, we have defined two more functions for the RGB pad and MUSIC pad.
boolean ModeMode(){ long Mode_Pad_Value = Mode_Pad.capacitiveSensor(30; if (Mode_Pad_Value>500) return 1; else return 0; } boolean RGBMode(){ long RGB_Pad_Value = RGB_Pad.capacitiveSensor(30); if (RGB_Pad_Value>500) return 1; else return 0; } boolean MusicMode(){ long Music_Pad_Value = Music_Pad.capacitiveSensor(30); if (Music_Pad_Value>500) return 1; else return 0; }
Check_Ring_Pos() function is used to detect the touch on the rings. Apart from that it also stores the ring position. These ring positions are used to detect the clockwise or counter-clockwise rotations on the rings. Similarly, we have defined another function to check the slider positions and we are also checking the swipe direction using the positions of the pads on the slider.
char Check_Ring_Pos() { char ring_pos = 0; char result = 0; long Ring_L_Pad_Value = Ring_L_Pad.capacitiveSensor(30); long Ring_LT_Pad_Value = Ring_LT_Pad.capacitiveSensor(30); long Ring_T_Pad_Value = Ring_T_Pad.capacitiveSensor(30); long Ring_TR_Pad_Value = Ring_TR_Pad.capacitiveSensor(30); if (Ring_L_Pad_Value>500) ring_pos = 1; if (Ring_LT_Pad_Value>500) ring_pos = 2; if (Ring_T_Pad_Value>500) ring_pos = 3; if (Ring_TR_Pad_Value>500) ring_pos = 4; char current_ring_pos = ring_pos; Serial.println(current_ring_pos - pvs_ring_pos); if ((current_ring_pos - pvs_ring_pos) == 1) result = 1; if ((current_ring_pos - pvs_ring_pos) == -1) result =2; if (current_ring_pos != pvs_ring_pos); pvs_ring_pos = current_ring_pos; return result; }
Now that we know whether a particular pad was touched or not and if yes then in which direction, we are going to use these readings to switch between the three modes. In RGB mode we can use slider pads to increase or decrease the intensity of the lights. If we swipe from left to right intensity will increase and if we swipe from right to left then intensity will decrease. Similarly, we can use Ring pads in the clockwise or counter-clockwise directions to change the colors. In Mode mode ring pads will be used to rotate the lights in clockwise and counter-clockwise directions.
void RGB_Mode(){ Serial.print("We have entered RGB Mode"); beep(); uint16_t i, j, k; Brightness = 255; while(1){ char Sider_Status = Check_Slider_Pos(); char Ring_Status = Check_Ring_Pos(); if (Sider_Status ==1){ //return 0 for no movement and 2 for right to left Serial.println ("Moved Left to Right"); beep(); Brightness = Brightness+50; Serial.print(Brightness); } ……………………………………..
Now if the Music Mode pad is touched Arduino will start reading the microphone readings and will change the intensity and color of lights randomly according to the music.
void Music_Mode(){ Serial.print("We have entered MUSIC Mode"); beep(); while(1){ if (digitalRead(A5)==LOW) { Serial.print("TAP"); for(int i=0; i< 48; i++) { strip.setBrightness(random (100,255)); strip.setPixelColor(i, strip.Color(random (0,255), random (0,255), random (0,255))); strip.show(); }
3-D Printing the Casing for Touch Capacitive PCB Light Panel
Now the idea is to hang this PCB light panel on a wall and for that, I printed a PCB holder. I measured the dimensions of the setup using my vernier to design a casing. My design looked something like this below once it was done. The STL file is also available for download from Thingiverse and you can print your casing using it.
Testing the Touch Capacitive PCB Light Panel
After assembling the PCB and programming ATMega328, we can now test the setup. For that, mount the 3-D printed holder on PCB and wrap the Neo-pixel strip as shown below:
Now power the board using a 12V adapter. You can use the Three touchpads that are MODE, RGB, and MUSIC to switch between the different modes and the sliders to change the intensity and color of the light.
#include <Adafruit_NeoPixel.h>
#include <CapacitiveSensor.h>
#include <ADCTouch.h>
#define PIN 10 //Neo pixel connected to pin 10
#define BUZZER 13 //BUZZER is connected to pin D13
#define N_PIXELS 23 //48 neopixel in led strip
#define MIC A5 // Microphone is connected at pin A5
#define N 10 // Number of samples
#define fadeDelay 25 // fade amount
#define noiseLevel 25 // Amount of noice we want to chop off
int ref1,ref2,ref3, ref4,ref5; //reference values to remove offset fro using analog pins are capacitive touch
char pvs_slider_pos = 0;
char pvs_ring_pos = 0;
int samples[N]; // storage for a sample
int periodFactor = 0; // For period calculation
int t1 = -1;
int T;
int slope;
byte periodChanged = 0;
int Brightness=0;
int led_position=0;
CapacitiveSensor Mode_Pad = CapacitiveSensor(9,8);
CapacitiveSensor RGB_Pad = CapacitiveSensor(9,7);
CapacitiveSensor Music_Pad = CapacitiveSensor(9,6);
CapacitiveSensor Ring_L_Pad = CapacitiveSensor(9,5);
CapacitiveSensor Ring_LT_Pad = CapacitiveSensor(9,4);
CapacitiveSensor Ring_T_Pad = CapacitiveSensor(9,3);
CapacitiveSensor Ring_TR_Pad = CapacitiveSensor(9,2);
//create a NeoPixel strip
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, PIN, NEO_GRB + NEO_KHZ800);
boolean ModeMode(){
long Mode_Pad_Value = Mode_Pad.capacitiveSensor(30);
if (Mode_Pad_Value>500)
return 1;
else
return 0;
}
boolean RGBMode(){
long RGB_Pad_Value = RGB_Pad.capacitiveSensor(30);
if (RGB_Pad_Value>500)
return 1;
else
return 0;
}
boolean MusicMode(){
long Music_Pad_Value = Music_Pad.capacitiveSensor(30);
if (Music_Pad_Value>500)
return 1;
else
return 0;
}
char Check_Ring_Pos()
{
char ring_pos = 0;
char result = 0;
long Ring_L_Pad_Value = Ring_L_Pad.capacitiveSensor(30);
long Ring_LT_Pad_Value = Ring_LT_Pad.capacitiveSensor(30);
long Ring_T_Pad_Value = Ring_T_Pad.capacitiveSensor(30);
long Ring_TR_Pad_Value = Ring_TR_Pad.capacitiveSensor(30);
if (Ring_L_Pad_Value>500)
ring_pos = 1;
if (Ring_LT_Pad_Value>500)
ring_pos = 2;
if (Ring_T_Pad_Value>500)
ring_pos = 3;
if (Ring_TR_Pad_Value>500)
ring_pos = 4;
char current_ring_pos = ring_pos;
Serial.println(current_ring_pos - pvs_ring_pos);
if ((current_ring_pos - pvs_ring_pos) == 1)
result = 1; //Serial.print("Ring touched clockwise");
if ((current_ring_pos - pvs_ring_pos) == -1)
result =2; //Serial.print("Ring touched counter clockwise");
if (current_ring_pos != pvs_ring_pos);
pvs_ring_pos = current_ring_pos;
return result;
}
char Check_Slider_Pos()
{
char slider_pos = 0;
char result = 0;
int sensorValue1 = ADCTouch.read(A0);
int sensorValue2 = ADCTouch.read(A1);
int sensorValue3 = ADCTouch.read(A2);
int sensorValue4 = ADCTouch.read(A3);
int sensorValue5 = ADCTouch.read(A4);
sensorValue1 -= ref1;
sensorValue2 -= ref2;
sensorValue3 -= ref3;
sensorValue4 -= ref4;
sensorValue5 -= ref5;
if (sensorValue1>50)
slider_pos = '1';
if (sensorValue2>50)
slider_pos = '2';
if (sensorValue3>50)
slider_pos = '3';
if (sensorValue4>50)
slider_pos = '4';
if (sensorValue5>50)
slider_pos = '5';
char current_slider_pos = slider_pos;
if ((current_slider_pos - pvs_slider_pos) == 1)
result = 1; //Serial.print("Slider Left to Right");
if ((current_slider_pos - pvs_slider_pos) == -1)
result =2; //Serial.print("Slider Right to Left");
if (current_slider_pos != pvs_slider_pos);
pvs_slider_pos = current_slider_pos;
return result;
}
void RGB_Mode(){
Serial.print("We have entered RGB Mode");
beep();
uint16_t i, j, k;
Brightness = 255;
while(1){ //Stay in RGB mode
char Sider_Status = Check_Slider_Pos();
char Ring_Status = Check_Ring_Pos();
if (Sider_Status ==1){ //return 0 for no movement and 2 for right to left
Serial.println ("Moved Left to Right");
beep();
Brightness = Brightness+50;
Serial.print(Brightness);
}
if (Sider_Status==2){ //return 0 for no movement and 2 for right to left
Serial.println ("Moved Right to Left");
beep();
Brightness = Brightness-50;
Serial.print(Brightness);
}
if (Ring_Status==1) {//return 0 for no movement and 2 for counter clockwise
Serial.println ("Ring in Clockwise");
beep();
i = random (0,255);
j = random (0,255);
k= random (0,255);
}
if (Ring_Status==2) {//return 0 for no movement and 2 for counter clockwise
Serial.println ("Ring in Counter-Clockwise");
beep();
i = random (0,255);
j = random (0,255);
k= random (0,255);
}
for(int x=0; x<N_PIXELS; x++) {
strip.setBrightness(Brightness);
strip.setPixelColor(x, strip.Color(i,j,k));
strip.show();
}
if ( RGBMode() || ModeMode() || MusicMode())
break;
}
}
void Mode_Mode(){
Serial.print("We have entered MODE Mode");
beep();
while(1){ //Stay in RGB mode
char Ring_Status = Check_Ring_Pos();
if (Ring_Status==1) {//return 0 for no movement and 2 for counter clockwise
Serial.println ("Ring in Clockwise");
beep();
}
for(int i=0; i< 48; i++) {
strip.setBrightness(255);
strip.fill(255,(i+0),(1+i));
strip.fill(0,0,i);
strip.show();
delay(20);
}
if (Ring_Status==2){ //return 0 for no movement and 2 for counter clockwise
Serial.println ("Ring in Anti- Clockwise");
beep();
for(int i=48; i>0; i--) {
strip.setBrightness(255);
strip.fill(255,(i+0),(1+i));
strip.fill(0,0,i);
strip.show();
delay(20);
}
}
if ( RGBMode() || ModeMode() || MusicMode())
break;
}
}
void Music_Mode(){
Serial.print("We have entered MUSIC Mode");
beep();
while(1){ //Stay in RGB mode
if (digitalRead(A5)==LOW)
{
Serial.print("TAP");
for(int i=0; i< 48; i++)
{
strip.setBrightness(random (100,255));
strip.setPixelColor(i, strip.Color(random (0,255), random (0,255), random (0,255)));
strip.show();
}
delay(100);
}
else
{
for(int i=0; i< 48; i++)
{
strip.setBrightness(0);
strip.setPixelColor(i, strip.Color(random (0,255), random (0,255), random (0,255)));
strip.show();
}
}
if ( RGBMode() || ModeMode() || MusicMode() )
break;
}
}
void setup() {
// start the strip and blank it out
strip.begin();
//strip.show();
//cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF); // turn off autocalibrate on channel 1 - just as an example
Serial.begin(9600);
ref1 = ADCTouch.read(A0, 500);
ref2 = ADCTouch.read(A1, 500);
ref3 = ADCTouch.read(A2, 500);
ref4 = ADCTouch.read(A3, 500);
ref5 = ADCTouch.read(A4, 500);
pinMode(BUZZER, OUTPUT);
}
void loop() {
//strip.clear();
strip.show();
if (ModeMode()==1)
Mode_Mode();
if (RGBMode()==1)
RGB_Mode();
if (MusicMode()==1)
Music_Mode();
}
void beep(){
tone(BUZZER,400);
delay(50);
noTone(BUZZER);
}