Touch mini switch with glass panel on nRF52832
In today's article I want to share with you a new project. This time it is a touch switch with a glass panel. The device is compact, dimensions 42x42mm (standard glass panel has dimensions 80x80mm). The history of this device began a long time ago, about a year ago.

The first options were on the atmega328 microcontroller, but in the end it all ended with the nRF52832 microcontroller.

The touch part of the device runs on TTP223 chips. Both sensors are serviced by one interrupt. Powered by CR2477 battery, via boost converter on TPS610981 | Datashit .


The device implements a power off circuit for field-effect transistors. After pressing the button, the microcontroller itself intercepts the power management and then the button can be used for service modes (in my case it is pairing with other devices, turning off the power and resetting to factory settings (factory reset)).
There are 2 rgb LEDs to indicate statuses and service modes. A piezo emitter has also been added to simulate a click when you touch the touch buttons and sound indication of service modes. The LEDs and piezo emitter can be turned on and off at the request of the user. This is done through the smart home controller, by sending commands to technical sensors, it is also possible to change the user intervals for sending the battery charge and signal level through the smart home controller. In my case, it is MAJORDOMO .
Consumption in transmission mode is 7 mA (250 kbps, 10 ms), sleep consumption is 40 μA, off-line consumption is less than 1 μA (= consumption of the boost converter in idle mode). Output rx, tx, swd plug for programming. A miniature 2x3p connector is used in increments of 1.27. A special adapter has been made for programming.

As always, the device is based on the MySensors protocol . This touch switch is planned to be used in the control system for roller blinds. But in general, the application is limited only by your imagination. For example, already now a son (7 years old) made 3 orders for the switch version: to turn on and off the light in the toilet with a bathtub (it will be mounted not high from the floor), to turn on the light in a long and dark corridor when traveling to the toilet with a bathtub and one more bedside, to quickly turn on the light in your room so that the monsters scatter.



The case was traditionally printed on an SLA printer, the device is tiny, the case is small, the use of this printing technology is justified.



Magnets are glued into the housing and battery cover.
Vidosiki with tests of this device:
For those wishing to repeat:
Circuit breaker test program code for the roller blind control system for Arduino IDE
int8_t timer_status = 0;
boolean sens_flag1 = 0;
boolean sens_flag2 = 0;
boolean switch_a = 0;
boolean switch_b = 0;
uint16_t temp;
float vcc;
int battery;
int old_battery;
uint32_t oldmillis;
uint32_t newmillis;
uint32_t interrupt_time;
uint32_t SLEEP_TIME = 7000;
uint32_t SLEEP_TIME_W;
uint32_t SLEEP_TIME_W2;
int NrfRSSI;
uint16_t NrfRSSI2;
boolean wait_off;
#define MY_DEBUG
#define MY_RADIO_NRF5_ESB
#define MY_PASSIVE_NODE
#define MY_NODE_ID 120
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC
#define MY_TRANSPORT_UPLINK_CHECK_DISABLED
#define POWER_CHILD_ID 110
#define UP_POWER_SWITCH_ID 1
#define DOWN_POWER_SWITCH_ID 2
#define CHILD_ID_nRF52_RSSI_RX 3
#define BAT_COOF 0.0092957746478873
#define BAT_MIN 200
#define BAT_MAX 290
#include
MyMessage upMsg(UP_POWER_SWITCH_ID, V_STATUS);
MyMessage downMsg(DOWN_POWER_SWITCH_ID, V_STATUS);
MyMessage powerMsg(POWER_CHILD_ID, V_VAR1);
MyMessage msgRF52RssiReceiv(CHILD_ID_nRF52_RSSI_RX, V_VAR1);
void preHwInit() {
//delay(1000);
pinMode(31, OUTPUT);
digitalWrite(31, HIGH);
delay(3000);
pinMode(3, INPUT);
pinMode(25, OUTPUT);
pinMode(26, OUTPUT);
pinMode(27, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(28, OUTPUT); // bizzer
pinMode(2, INPUT);
pinMode(9, INPUT);
pinMode(10, INPUT);
pinMode(29, INPUT);
digitalWrite(28, LOW); // off bizzer
digitalWrite(27, HIGH);
digitalWrite(26, HIGH);
digitalWrite(25, HIGH);
digitalWrite(6, HIGH);
digitalWrite(7, HIGH);
digitalWrite(8, HIGH);
}
void before()
{
//digitalWrite(31, HIGH);
NRF_POWER->DCDCEN = 1;
//NRF_UART0->ENABLE = 0;
analogReadResolution(12);
disableNfc();
turnOffAdc();
//wait(2000);
digitalWrite(25, LOW);
digitalWrite(6, LOW);
wait(200);
digitalWrite(25, HIGH);
digitalWrite(6, HIGH);
wait(100);
playSound0();
wait(100);
digitalWrite(25, LOW);
digitalWrite(6, LOW);
wait(200);
digitalWrite(25, HIGH);
digitalWrite(6, HIGH);
wait(3000);
digitalWrite(27, LOW);
digitalWrite(8, LOW);
wait(200);
digitalWrite(27, HIGH);
digitalWrite(8, HIGH);
wait(400);
digitalWrite(6, LOW);
digitalWrite(25, LOW);
wait(200);
digitalWrite(6, HIGH);
digitalWrite(25, HIGH);
wait(400);
digitalWrite(26, LOW);
digitalWrite(7, LOW);
wait(200);
digitalWrite(26, HIGH);
digitalWrite(7, HIGH);
wait(1000);
digitalWrite(26, LOW);
digitalWrite(7, LOW);
}
void setup()
{
digitalWrite(26, HIGH);
digitalWrite(7, HIGH);
wait(50);
playSound();
wait(2000);
readBatLev();
wait(200);
SLEEP_TIME_W = SLEEP_TIME;
}
void presentation()
{
sendSketchInfo("Power on|off Node", "1.0");
wait(100);
present(POWER_CHILD_ID, S_CUSTOM, "BATTERY DATA");
wait(100);
present(UP_POWER_SWITCH_ID, S_BINARY, "UP SWITCH");
wait(100);
present(DOWN_POWER_SWITCH_ID, S_BINARY, "DOWN SWITCH");
}
void loop()
{
if (sens_flag1 == 0 && sens_flag2 == 0) {
if (switch_a == 0 && switch_b == 0) {
timer_status = sleep(digitalPinToInterrupt(2), RISING, digitalPinToInterrupt(3), RISING, 3600000, false);
wait_off = 1;
} else {
//oldmillis = millis();
timer_status = sleep(digitalPinToInterrupt(2), RISING, digitalPinToInterrupt(3), RISING, SLEEP_TIME_W, false);
wait_off = 0;
}
}
if (timer_status == 3) {
wait(100);
digitalWrite(27, LOW);
digitalWrite(8, LOW);
wait(2000);
digitalWrite(27, HIGH);
digitalWrite(8, HIGH);
wait(100);
digitalWrite(31, LOW);
}
if (timer_status == 2) {
if (digitalRead(9) == HIGH && sens_flag1 == 0 && switch_b == 0) {
sens_flag1 = 1;
if (switch_a == 0) {
oldmillis = millis();
SLEEP_TIME_W = SLEEP_TIME;
switch_a = 1;
send(upMsg.set(switch_a));
//wait(200);
digitalWrite(6, LOW);
wait(10);
playSound1();
wait(20);
playSound2();
wait(50);
} else {
switch_a = 0;
send(upMsg.set(switch_a));
//wait(200);
digitalWrite(6, HIGH);
wait(10);
playSound2();
wait(20);
playSound1();
wait(50);
}
//sleep_not_pasible = 1;
//digitalWrite(25, HIGH);
//wait(100);
}
if (digitalRead(10) == HIGH && sens_flag2 == 0 && switch_a == 0) {
sens_flag2 = 1;
if (switch_b == 0) {
oldmillis = millis();
SLEEP_TIME_W = SLEEP_TIME;
switch_b = 1;
send(downMsg.set(switch_b));
//wait(200);
digitalWrite(25, LOW);
wait(10);
playSound1();
wait(20);
playSound2();
wait(50);
} else {
switch_b = 0;
send(downMsg.set(switch_b));
//wait(200);
digitalWrite(25, HIGH);
wait(10);
playSound2();
wait(20);
playSound1();
wait(50);
}
//sleep_not_pasible = 1;
//digitalWrite(6, HIGH);
//wait(100);
}
if (digitalRead(9) == LOW && sens_flag1 == 1) {
sens_flag1 = 0;
//digitalWrite(6, HIGH);
//playSound2();
//wait(50);
}
if (digitalRead(10) == LOW && sens_flag2 == 1) {
sens_flag2 = 0;
//digitalWrite(25, HIGH);
//playSound2();
//wait(50);
}
if (switch_a == 1 || switch_b == 1) {
if (wait_off == 0) {
newmillis = millis();
wait(10);
SLEEP_TIME_W2 = SLEEP_TIME_W;
wait(10);
interrupt_time = newmillis - oldmillis;
wait(10);
SLEEP_TIME_W = SLEEP_TIME_W2 - interrupt_time;
wait(10);
Serial.print("WAS IN A SLEEP: ");
Serial.print(newmillis - oldmillis);
Serial.println(" MILLISECONDS");
if (SLEEP_TIME_W < 1000) {
if (switch_a == 1) {
switch_a = 0;
digitalWrite(6, HIGH);
//wait(10);
//playSound2();
//wait(20);
//playSound1();
//wait(50);
//send(upMsg.set(switch_a));
//wait(200);
}
if (switch_b == 1) {
switch_b = 0;
digitalWrite(25, HIGH);
//wait(10);
//playSound2();
//wait(20);
//playSound1();
//wait(50);
//send(downMsg.set(switch_b));
//wait(200);
}
SLEEP_TIME_W = SLEEP_TIME;
wait(50);
}
Serial.println(SLEEP_TIME);
Serial.println(SLEEP_TIME_W);
Serial.println(SLEEP_TIME_W2);
Serial.print("GO TO SLEEP FOR: ");
Serial.print(SLEEP_TIME_W);
Serial.println(" MILLISECONDS");
}
oldmillis = millis();
}
}
if (timer_status == -1) {
if (switch_a == 1 || switch_b == 1) {
if (switch_a == 1) {
switch_a = 0;
digitalWrite(6, HIGH);
wait(10);
playSound2();
wait(20);
playSound1();
wait(50);
send(upMsg.set(switch_a));
wait(200);
}
if (switch_b == 1) {
switch_b = 0;
digitalWrite(25, HIGH);
wait(10);
playSound2();
wait(20);
playSound1();
wait(50);
send(downMsg.set(switch_b));
wait(200);
}
} else {
readBatLev();
}
}
}
void disableNfc() {
NRF_NFCT->TASKS_DISABLE = 1;
NRF_NVMC->CONFIG = 1;
NRF_UICR->NFCPINS = 0;
NRF_NVMC->CONFIG = 0;
}
void turnOffAdc() {
if (NRF_SAADC->ENABLE) {
NRF_SAADC->TASKS_STOP = 1;
while (NRF_SAADC->EVENTS_STOPPED) {}
NRF_SAADC->ENABLE = 0;
while (NRF_SAADC->ENABLE) {}
}
}
void myTone(uint32_t j, uint32_t k) { // Определяем функцию myTone
j = 500000 / j; // Меняем значение переменной j на время одного полупериода в мкс
k += millis(); // Меняем значение переменной к на время завершения вывода сигнала
while (k > millis()) { // Выводим сигнал, пока не истечёт указанное время
digitalWrite(28, HIGH); delayMicroseconds(j); // Устанавливаем на выходе i уровень логической «1» на время j
digitalWrite(28, LOW ); delayMicroseconds(j); // Устанавливаем на выходе i уровень логического «0» на время j
}
}
void playSound0() {
//wait(500);
myTone(1300, 50); // Выводим звуковой сигнал длительностью 0,1 сек с частотой 2048 Гц
wait(20); // Ждём 0,1 сек
myTone(1300, 50);
wait(50);
}
void playSound() {
//wait(500);
myTone(700, 30); // Выводим звуковой сигнал длительностью 0,1 сек с частотой 2048 Гц
wait(10); // Ждём 0,1 сек
myTone(700, 30);
wait(10);
myTone(700, 30);
wait(50); // Ждём 0,1 сек
//myTone(500, 30);
//wait(500);
}
void playSound1() {
//wait(500);
myTone(200, 10); // Выводим звуковой сигнал длительностью 0,1 сек с частотой 2048 Гц
wait(10); // Ждём 0,1 сек
myTone(400, 5);
wait(30); // Ждём 0,1 сек
//myTone(500, 30);
//wait(500);
}
void playSound2() {
//wait(500);
myTone(400, 10); // Выводим звуковой сигнал длительностью 0,1 сек с частотой 2048 Гц
wait(10); // Ждём 0,1 сек
myTone(200, 5);
wait(30); // Ждём 0,1 сек
//myTone(500, 30);
//wait(500);
}
void readBatLev() {
//NRF5_ESB_startListening();
wait(200);
temp = analogRead(29);
vcc = temp * 0.0033 * 100;
battery = map((int)vcc, BAT_MIN, BAT_MAX, 0, 100);
if (battery < 0) {
battery = 0;
}
if (battery > 100) {
battery = 100;
}
sendBatteryLevel(battery);
wait(200);
send(powerMsg.set(temp));
wait(200);
NrfRSSI = transportGetReceivingRSSI();
NrfRSSI2 = map(NrfRSSI, -85, -40, 0, 100);
if (NrfRSSI2 < 0) {
NrfRSSI2 = 0;
}
if (NrfRSSI2 > 100) {
NrfRSSI2 = 100;
}
send(msgRF52RssiReceiv.set(NrfRSSI2));
wait(200);
}
For questions about this development, about the difficulties in your development, the Arduino and Mysensors will always come to the rescue in our telegram chat .