Interrupteur tactile sans fil avec rétro-éclairage fluorescent supplémentaire

Salutations à tous les lecteurs de la section DIY ou Do-it-yourself sur Habr! L'article d'aujourd'hui portera sur l'interrupteur tactile de la puce TTP223 | fiche technique . Le commutateur fonctionne sur le microcontrôleur nRF52832 | fiche technique , le module YJ-17103 avec une antenne imprimée et un connecteur pour une antenne externe MHF4 a été utilisé. L'interrupteur tactile est alimenté par des piles CR2430 ou CR2450. La consommation en mode transmission ne dépasse pas 8mA, en mode veille ne dépasse pas 6mA.



Comme tous les projets précédents, celui-ci est également un projet Arduino, le programme est écrit dans l'IDE Arduino. L'implémentation logicielle de l'appareil est basée sur le protocole Mysensors | Bibliothèques GitHub, prise en charge GitHub pour les cartes nRF5 dans Mysensors. Forum communautaire de langue anglaise - http://forum.mysensors.org , forum communautaire de langue russe - http://mysensors.ru/forum/
(Pour ceux qui souhaitent étudier - Documentation , Protocole série , API , Protocole , Analyseur | pour ceux qui souhaitent aider au développement du projet - Documentation )

La carte à interrupteur tactile a été développée dans le cadre du programme Diptrace, en tenant compte de la fabrication ultérieure selon la méthode de la technologie Laser Iron (LUT). La planche a été développée dans des tailles de 60x60 mm (le panneau de verre standard a des dimensions de 80x80 mm). Le circuit a été imprimé sur les pages du magazine Antenna et transféré par un fer à repasser Bosch avec le réglage «Len» (puissance maximale) sur une plaque de fibre de verre recouverte d'un film double face de 1,5 mm, 35 µm (à défaut d'un autre).


La gravure a été réalisée avec une solution de chlorure ferrique, préalablement préparée dans les proportions de 1,5 partie d'une cuillère pour 250 ml d'eau tiède. Le processus a pris 15 minutes.
Les trous pour les transitions intercouches et pour le montage du support de batterie ont été percés avec un mini-foret DREMEL 3000 monté sur un support de forage DREMEL 220. Les trous pour les transitions intercouches ont été percés avec un foret de 0,4 mm, les trous pour le support de batterie avec un foret de 1,1 mm. La coupe le long des bordures de la planche a été effectuée avec le même mini-foret avec une buse DREMEL 540 (molette de coupe d = 32,0 mm). Le recadrage a été effectué dans un respirateur.
L'étamage du carton gravé a été effectué en utilisant un alliage de Rose dans une solution aqueuse (1 cuillère à café d'acide citrique cristallisé dans 300 ml d'eau).

Le processus de soudage a pris environ une heure, la plupart du temps a été consacré à la soudure du fil (étamé, 0,4 mm de diamètre) dans les trous pour les transitions intercouches.

La planche a été lavée avec le nettoyant aérosol FLUX OFF.




Le développement du boîtier de l'appareil a été réalisé dans un éditeur de conception assistée par ordinateur en trois dimensions. Dimensions du boîtier 78,5 mm X 78,5 mm X 12 mm.


Le modèle fini du boîtier et du couvercle de la batterie a été enregistré au format STL, il a ensuite fallu préparer ces modèles pour l'impression sur une imprimante SLA (ajout de supports, orientation). À ce stade, un petit problème est survenu, car la zone d'impression des imprimantes SLA domestiques est petite. Le modèle du corps de l'appareil dans la position la plus optimale par rapport au temps d'impression ne correspondait pas à la taille de la zone d'impression. En plaçant le modèle à 45 degrés, cela a également donné un résultat décevant, le poids du support était égal au poids du modèle de boîtier. Il a été décidé d'imprimer le modèle verticalement, en faisant un support sur une des faces avant, préalablement d'accord avec le fait du post-traitement. Il a fallu 5 heures pour sceller le boîtier avec une couche de 50 microns. Ensuite, le traitement a été effectué à l'aide de papier de verre à grain très fin (je n'écrirai pas le nombre, car je ne sais pas :)). Le couvercle de la batterie a été imprimé pendant 40 minutes.


Les panneaux de verre avec Aliexpress sont vendus avec un cadre en plastique déjà collé, il n'y a eu aucun problème pour retirer le cadre. J'ai enlevé le préchauffage du panneau de verre avec un sèche-cheveux ordinaire.




Le diffuseur pour le rétroéclairage LED était fait de ruban adhésif double face avec un adhésif acrylique 3M 9088-200. Pour l'éclairage fluorescent, il y avait plusieurs matériaux au choix, du ruban adhésif chinois et du papier adhésif découpé en bandes de la société nationale Luminophore. Le choix a été fait en faveur d'un fabricant national; selon mes sentiments, il brillait plus longtemps et plus longtemps. Un carré en papier avec un pigment fluorescent a été collé sur le ruban adhésif double face 3M 9088-200.

Le verre a été collé au boîtier du disjoncteur en utilisant du ruban adhésif double face avec un adhésif acrylique 3M VHB 4910.


Le couvercle a été fixé avec une vis M 1,4 X 5 mm.

Le coût de l'appareil était de 890 roubles.

Vint ensuite la partie logicielle. Pas de problème. Il s'avère que les microcircuits du capteur TTP223 fonctionnent parfaitement avec une puissance stabilisée à 3,3 V et ne sont pas très bons lorsqu'ils sont alimentés directement à partir d'une batterie bien déchargée. Au début de l'appareil avec une puissance de l'ordre de 2,5 V, plus après un "rabattement" supplémentaire lors de l'élaboration de la présentation Mysensors, la puce TTP223 (immédiatement après l'étalonnage) a provoqué l'interruption du MC car elle était avec le déclencheur actif.

Le circuit d'alimentation de la puce (gestion de l'alimentation TTP223 avec gpio MK) a été changé, une masse supplémentaire a été fournie, sur les lignes à led rgb (qui passent de l'autre côté de la carte du capteur capacitif), les résistances avec une résistance plus élevée ont été remplacées. Il a également été ajouté au logiciel: activation de l'alimentation d'un microcircuit capacitif après le démarrage du framework Mysensors et l'élaboration de la présentation. Le délai pour l'auto-étalonnage de la puce TTP223 est doublé lors de la mise sous tension. Toutes ces modifications ont complètement résolu ce problème.

Avant d'afficher le code du programme, je vous recommande de vous familiariser avec la structure de base des esquisses dans Mysensors.
void before()
{
// , , before() setup(), Mysensors, SPI
}

void setup()
{

}

void presentation()
{
//
sendSketchInfo("Name of my sensor node", "1.0"); // ,
present(CHILD_ID, S_WHATEVER, "Description"); // ,
}

void loop()
{

}



Code de test pour le programme de commutateur tactile:
test_sens.ino
/**
NRF_LPCOMP
*/
bool button_flag;
bool sens_flag;
bool send_flag;
bool detection;
bool nosleep;
byte timer;
unsigned long SLEEP_TIME = 21600000; //6 hours
unsigned long oldmillis;
unsigned long newmillis;
unsigned long interrupt_time;
unsigned long SLEEP_TIME_W;
uint16_t currentBatteryPercent;
uint16_t batteryVoltage = 0;
uint16_t battery_vcc_min = 2400;
uint16_t battery_vcc_max = 3000;

#define MY_RADIO_NRF5_ESB
//#define MY_PASSIVE_NODE
#define MY_NODE_ID 30
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC
#define MY_TRANSPORT_UPLINK_CHECK_DISABLED
#define IRT_PIN 3 //(PORT0, gpio 5)
#include <MySensors.h>
// see https://www.mysensors.org/download/serial_api_20
#define SENS_CHILD_ID 0
#define CHILD_ID_VOLT 254
MyMessage sensMsg(SENS_CHILD_ID, V_VAR1);
//MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE);

void preHwInit() {
sleep(2000);
pinMode(RED_LED, OUTPUT);
digitalWrite(RED_LED, HIGH);
pinMode(GREEN_LED, OUTPUT);
digitalWrite(GREEN_LED, HIGH);
pinMode(BLUE_LED, OUTPUT);
digitalWrite(BLUE_LED, HIGH);
pinMode(MODE_PIN, INPUT);
pinMode(SENS_PIN, INPUT);
}

void before()
{
NRF_POWER->DCDCEN = 1;
NRF_UART0->ENABLE = 0;
sleep(1000);
digitalWrite(BLUE_LED, LOW);
sleep(150);
digitalWrite(BLUE_LED, HIGH);
}

void presentation() {
sendSketchInfo("EFEKTA Sens 1CH Sensor", "1.1");
present(SENS_CHILD_ID, S_CUSTOM, "SWITCH STATUS");
//present(CHILD_ID_VOLT, S_MULTIMETER, "Battery");
}

void setup() {
digitalWrite(BLUE_LED, LOW);
sleep(100);
digitalWrite(BLUE_LED, HIGH);
sleep(200);
digitalWrite(BLUE_LED, LOW);
sleep(100);
digitalWrite(BLUE_LED, HIGH);
lpComp();
detection = false;
SLEEP_TIME_W = SLEEP_TIME;
pinMode(31, OUTPUT);
digitalWrite(31, HIGH);
/*
while (timer < 10) {
timer++;
digitalWrite(GREEN_LED, LOW);
wait(5);
digitalWrite(GREEN_LED, HIGH);
wait(500);
}
timer = 0;
*/
sleep(7000);
while (timer < 3) {
timer++;
digitalWrite(GREEN_LED, LOW);
sleep(15);
digitalWrite(GREEN_LED, HIGH);
sleep(85);
}
timer = 0;
sleep(1000);
}

void loop() {

if (detection) {
if (digitalRead(MODE_PIN) == 1 && button_flag == 0 && digitalRead(SENS_PIN) == 0) {
//back side button detection
button_flag = 1;
nosleep = 1;
}
if (digitalRead(MODE_PIN) == 1 && button_flag == 1 && digitalRead(SENS_PIN) == 0) {
digitalWrite(RED_LED, LOW);
wait(10);
digitalWrite(RED_LED, HIGH);
wait(50);
}
if (digitalRead(MODE_PIN) == 0 && button_flag == 1 && digitalRead(SENS_PIN) == 0) {
nosleep = 0;
button_flag = 0;
digitalWrite(RED_LED, HIGH);
lpComp_reset();
}

if (digitalRead(SENS_PIN) == 1 && sens_flag == 0 && digitalRead(MODE_PIN) == 0) {
//sens detection
sens_flag = 1;
nosleep = 1;
newmillis = millis();
interrupt_time = newmillis - oldmillis;
SLEEP_TIME_W = SLEEP_TIME_W - interrupt_time;
if (send(sensMsg.set(detection))) {
send_flag = 1;
}
}
if (digitalRead(SENS_PIN) == 1 && sens_flag == 1 && digitalRead(MODE_PIN) == 0) {
if (send_flag == 1) {
while (timer < 10) {
timer++;
digitalWrite(GREEN_LED, LOW);
wait(20);
digitalWrite(GREEN_LED, HIGH);
wait(30);
}
timer = 0;
} else {
while (timer < 10) {
timer++;
digitalWrite(RED_LED, LOW);
wait(20);
digitalWrite(RED_LED, HIGH);
wait(30);
}
timer = 0;
}
}
if (digitalRead(SENS_PIN) == 0 && sens_flag == 1 && digitalRead(MODE_PIN) == 0) {
sens_flag = 0;
nosleep = 0;
send_flag = 0;
digitalWrite(GREEN_LED, HIGH);
sleep(500);
lpComp_reset();
}
if (SLEEP_TIME_W < 60000) {
SLEEP_TIME_W = SLEEP_TIME;
sendBatteryStatus();
}
}
else {
//if (detection == -1) {
SLEEP_TIME_W = SLEEP_TIME;
sendBatteryStatus();
}
if (nosleep == 0) {
oldmillis = millis();
sleep(SLEEP_TIME_W);
}
}

void sendBatteryStatus() {
wait(20);
batteryVoltage = hwCPUVoltage();
wait(2);

if (batteryVoltage > battery_vcc_max) {
currentBatteryPercent = 100;
}
else if (batteryVoltage < battery_vcc_min) {
currentBatteryPercent = 0;
} else {
currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min);
}

sendBatteryLevel(currentBatteryPercent, 1);
wait(2000, C_INTERNAL, I_BATTERY_LEVEL);
//send(powerMsg.set(batteryVoltage), 1);
//wait(2000, 1, V_VAR1);
}

void lpComp() {
NRF_LPCOMP->PSEL = IRT_PIN;
NRF_LPCOMP->ANADETECT = 1;
NRF_LPCOMP->INTENSET = B0100;
NRF_LPCOMP->ENABLE = 1;
NRF_LPCOMP->TASKS_START = 1;
NVIC_SetPriority(LPCOMP_IRQn, 15);
NVIC_ClearPendingIRQ(LPCOMP_IRQn);
NVIC_EnableIRQ(LPCOMP_IRQn);
}

void s_lpComp() {
if ((NRF_LPCOMP->ENABLE) && (NRF_LPCOMP->EVENTS_READY)) {
NRF_LPCOMP->INTENCLR = B0100;
}
}

void r_lpComp() {
NRF_LPCOMP->INTENSET = B0100;
}

#if __CORTEX_M == 0x04
#define NRF5_RESET_EVENT(event) \
event = 0; \
(void)event
#else
#define NRF5_RESET_EVENT(event) event = 0
#endif

extern "C" {
void LPCOMP_IRQHandler(void) {
detection = true;
NRF5_RESET_EVENT(NRF_LPCOMP->EVENTS_UP);
NRF_LPCOMP->EVENTS_UP = 0;
MY_HW_RTC->CC[0] = (MY_HW_RTC->COUNTER + 2);
}
}

void lpComp_reset () {
s_lpComp();
detection = false;
NRF_LPCOMP->EVENTS_UP = 0;
r_lpComp();
}


MyBoardNRF5.cpp
#ifdef MYBOARDNRF5
#include <variant.h>

/*
* Pins descriptions. Attributes are ignored by arduino-nrf5 variant.
* Definition taken from Arduino Primo Core with ordered ports
*/
const PinDescription g_APinDescription[]=
{
{ NOT_A_PORT, 0, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // LFCLK
{ NOT_A_PORT, 1, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // LFCLK
{ PORT0, 2, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A0, PWM4, NOT_ON_TIMER},
{ PORT0, 3, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A1, PWM5, NOT_ON_TIMER},
{ PORT0, 4, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A2, PWM6, NOT_ON_TIMER},
{ PORT0, 5, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A3, PWM7, NOT_ON_TIMER},
{ PORT0, 6, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // INT3
{ PORT0, 7, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // INT4
{ PORT0, 8, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM10, NOT_ON_TIMER}, //USER_LED
{ PORT0, 9, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // NFC1
{ PORT0, 10, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // NFC2
{ PORT0, 11, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // TX
{ PORT0, 12, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // RX
{ PORT0, 13, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // SDA
{ PORT0, 14, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // SCL
{ PORT0, 15, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // SDA1
{ PORT0, 16, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // SCL1
{ PORT0, 17, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // TP4
{ PORT0, 18, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // TP5
{ PORT0, 19, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // INT2
{ PORT0, 20, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // INT1
{ PORT0, 21, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // INT1
{ PORT0, 22, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM9, NOT_ON_TIMER},
{ PORT0, 23, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM8, NOT_ON_TIMER},
{ PORT0, 24, PIO_DIGITAL, PIN_ATTR_DIGITAL, No_ADC_Channel, NOT_ON_PWM, NOT_ON_TIMER}, // INT
{ PORT0, 25, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM11, NOT_ON_TIMER}, //RED_LED
{ PORT0, 26, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM11, NOT_ON_TIMER}, //GREEN_LED
{ PORT0, 27, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), No_ADC_Channel, PWM11, NOT_ON_TIMER}, //BLUE_LED
{ PORT0, 28, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A4, PWM3, NOT_ON_TIMER},
{ PORT0, 29, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A5, PWM2, NOT_ON_TIMER},
{ PORT0, 30, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A6, PWM1, NOT_ON_TIMER},
{ PORT0, 31, PIO_DIGITAL, (PIN_ATTR_DIGITAL|PIN_ATTR_PWM), ADC_A7, PWM0, NOT_ON_TIMER}
};

// Don't remove this line
#include <compat_pin_mapping.h>

#endif


MyBoardNRF5.h
#ifndef _MYBOARDNRF5_H_
#define _MYBOARDNRF5_H_

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

// Number of pins defined in PinDescription array
#define PINS_COUNT (32u)
#define NUM_DIGITAL_PINS (32u)
#define NUM_ANALOG_INPUTS (8u)
#define NUM_ANALOG_OUTPUTS (8u)

/*
* LEDs
*
* This is optional
*
* With My Sensors, you can use
* hwPinMode() instead of pinMode()
* hwPinMode() allows to use advanced modes like OUTPUT_H0H1 to drive LEDs.
* https://github.com/mysensors/MySensors/blob/development/drivers/NRF5/nrf5_wiring_constants.h
*
*/
#define PIN_LED1 (16)
#define PIN_LED2 (15)
#define PIN_LED3 (17)
#define RED_LED (PIN_LED1)
#define GREEN_LED (PIN_LED2)
#define BLUE_LED (PIN_LED3)
#define INTERRUPT_PIN (5)
#define MODE_PIN (25)
#define SENS_PIN (27)

/*
* Analog ports
*
* If you change g_APinDescription, replace PIN_AIN0 with
* port numbers mapped by the g_APinDescription Array.
* You can add PIN_AIN0 to the g_APinDescription Array if
* you want provide analog ports MCU independed, you can add
* PIN_AIN0..PIN_AIN7 to your custom g_APinDescription Array
* defined in MyBoardNRF5.cpp
*/
static const uint8_t A0 = ADC_A0;
static const uint8_t A1 = ADC_A1;
static const uint8_t A2 = ADC_A2;
static const uint8_t A3 = ADC_A3;
static const uint8_t A4 = ADC_A4;
static const uint8_t A5 = ADC_A5;
static const uint8_t A6 = ADC_A6;
static const uint8_t A7 = ADC_A7;

/*
* Serial interfaces
*
* RX and TX are required.
* If you have no serial port, use unused pins
* CTS and RTS are optional.
*/
#define PIN_SERIAL_RX (11)
#define PIN_SERIAL_TX (12)

#ifdef __cplusplus
}
#endif

#endif



Le commutateur a un bouton tactile et un bouton d'horloge à l'arrière de l'appareil. Ce bouton d'horloge sera utilisé pour les modes de service, le mode snap aérien, la remise à zéro de l'appareil. Le bouton met en œuvre un fer anti rebond. La ligne du capteur capacitif et la ligne du bouton d'horloge à travers les diodes Schottky sont connectées et connectées à la broche analogique p0.05, les lignes aux broches MK p0.25 et p0.27 vont au capteur capacitif et au bouton d'horloge pour lire les états après avoir activé l'interruption sur la broche p0. 05. Sur la broche p0.05, une interruption via le comparateur (NRF_LPCOMP) par EVENTS_UP est activée. J'ai trouvé l'inspiration pour résoudre le problème ici et ici .

Le commutateur a été ajouté au réseau Mysensors, géré par le contrôleur de la maison intelligente, Magordomo ( site du projet )

Code PHP à ajouter à la méthode du commutateur statusUpdate
 if (getGlobal("MysensorsButton01.status")==1) { if (getGlobal('MysensorsRelay04.status') == 0) { setGlobal('MysensorsRelay04.status', '1'); } else if (getGlobal('MysensorsRelay04.status') == 1) { setGlobal('MysensorsRelay04.status', '0'); } } 



Regardez le résultat sur la vidéo





Plus tard, une option a été faite avec un convertisseur boost, mais cela n'est pas lié au fonctionnement de la puce capacitive TTP223, il y a plus de désir pour un bon éclairage uniforme lors de l'élaboration des prises pour toute la durée de vie de la batterie.

Afficher





Projet Github - github.com/smartboxchannel/EFEKTA_WIRELESS_TOUCH_SWITCH

Site communautaire de langue russe Mysensors

Telegram chat Mysensors - solution rapide aux problèmes avec Mysensors, conseils, astuces, installation de cartes, travail avec les microcontrôleurs atmega 328, stm32, nRF5 dans un IDE Arduino - @mysensors_rus

Quelques photos









Source: https://habr.com/ru/post/fr457992/


All Articles