Saudações a todos os leitores da seção faça você mesmo ou faça você mesmo em Habr! O artigo de hoje será sobre o interruptor de toque no chip TTP223 |
datasheet . O switch opera no microcontrolador nRF52832 |
datasheet , módulo YJ-17103 com uma antena impressa e um conector para uma antena externa MHF4. O interruptor sensível ao toque é alimentado por baterias CR2430 ou CR2450. O consumo no modo de transmissão não é superior a 8mA, no modo de suspensão não é superior a 6mA.

Como todos os projetos anteriores, este também é um projeto do Arduino, o programa está escrito no IDE do Arduino. A implementação do software do dispositivo é baseada no protocolo Mysensors |
Bibliotecas do GitHub ,
suporte do GitHub para placas nRF5 nos Mysensors. Fórum da comunidade em inglês -
http://forum.mysensors.org , fórum da comunidade em russo -
http://mysensors.ru/forum/(Para aqueles que desejam estudar -
Documentação ,
Protocolo Serial ,
API ,
Protocolo ,
Analisador | para aqueles que desejam ajudar no desenvolvimento do projeto -
Documentação )
A placa do interruptor de toque foi desenvolvida no programa Diptrace, levando em consideração a fabricação subsequente, de acordo com o método da Laser Iron Technology (LUT). A placa foi desenvolvida em tamanhos de 60x60mm (o painel de vidro padrão tem dimensões de 80x80mm). O circuito foi impresso nas páginas da revista Antena e transferido por um ferro da Bosch com a configuração “Len” (potência máxima) para uma placa de fibra de vidro revestida com papel de dupla face de 1,5 mm, 35 µm (por falta de outro).

A gravação foi realizada com uma solução de cloreto férrico, previamente preparada nas proporções de 1,5 partes de uma colher por 250 ml de água morna. O processo levou 15 minutos.
Os furos para as transições entre camadas e para a montagem do suporte da bateria foram perfurados com uma mini furadeira DREMEL 3000 montada em um suporte de broca DREMEL 220. Os furos para as transições entre camadas foram perfurados com uma broca de 0,4 mm, os furos para o suporte da bateria com uma broca de 1,1 mm. O corte ao longo das bordas da placa foi realizado com a mesma mini-broca com um bico DREMEL 540 (roda de corte d = 32,0 mm). A colheita foi realizada em um respirador.
O estanho do cartão gravado foi realizado usando uma liga de Rosa em uma solução aquosa (1 colher de chá de ácido cítrico cristalizado em 300 ml de água).
O processo de soldagem levou cerca de uma hora, a maior parte do tempo foi gasta na soldagem do fio (estanhado, 0,4 mm de diâmetro) nos orifícios para transições entre camadas.
A placa foi lavada com o limpador de aerossol FLUX OFF.


O desenvolvimento do gabinete do dispositivo foi realizado em um editor de design tridimensional auxiliado por computador. Dimensões da caixa: 78,5 mm x 78,5 mm x 12 mm.

O modelo acabado da carcaça e a tampa da bateria foram salvos no formato STL; então, foi necessário preparar esses modelos para impressão em uma impressora SLA (adição de suportes, orientação). Nesse ponto, surgiu um pequeno problema, já que a área de impressão das impressoras domésticas de SLA é pequena. O modelo do corpo do dispositivo na posição mais ideal em relação ao tempo de impressão não se encaixava no tamanho da área de impressão. Ao colocar o modelo em 45 graus, também deu um resultado decepcionante, o peso do suporte foi igual ao peso do modelo do gabinete. Decidiu-se imprimir o modelo verticalmente, apoiando-se em uma das laterais, concordando previamente com o fato do pós-processamento. Demorou 5 horas para selar o gabinete com uma configuração de camada de 50 mícrons. Em seguida, o processamento foi realizado com uma lixa de granulação muito fina (não escrevo o número, porque não sei :)). A tampa da bateria foi impressa por 40 minutos.

Os painéis de vidro com Aliexpress são vendidos com uma armação de plástico já colada, não houve problemas ao remover a armação. Tirei o pré-aquecimento do painel de vidro com um secador de cabelo comum.


O difusor para a luz de fundo do LED foi feito de fita dupla face com adesivo acrílico 3M 9088-200. Para iluminação fluorescente, havia vários materiais para escolher: fita adesiva chinesa e papel adesivo cortado em fitas da empresa doméstica Luminophore. A escolha foi feita em favor de um fabricante nacional; de acordo com meus sentimentos, brilhou mais e mais. Um quadrado feito de papel com pigmento fluorescente foi colado sobre a fita dupla face 3M 9088-200.
O vidro foi colado ao gabinete do disjuntor usando fita dupla face com adesivo acrílico 3M VHB 4910.

A cobertura foi fixada com um parafuso M 1,4 X 5 mm.
O custo do dispositivo foi de 890 rublos.
A seguir veio a parte do software. Não tem problema Acontece que os microcircuitos do sensor TTP223 funcionam perfeitamente com energia estabilizada a 3,3V e não são muito bons quando alimentados diretamente de uma bateria bem descarregada. No início do dispositivo com energia na região de 2,5v, mais após um "rebaixamento" adicional ao elaborar a apresentação dos Mysensors, o chip TTP223 (imediatamente após a calibração) fez com que o MC interrompesse porque estava com o gatilho ativo.
O circuito para fornecer energia ao chip (gerenciamento de energia TTP223 com gpio MK) foi alterado, foi fornecido terra adicional, nas linhas de led rgb (que passam do outro lado da placa do sensor capacitivo), foram substituídos resistores com maior resistência. Também foi adicionado ao software: ativação de energia para um microcircuito capacitivo após iniciar o framework Mysensors e elaborar a apresentação. O atraso para a calibração automática do chip TTP223 é dobrado quando a energia é aplicada a ele. Todas essas alterações corrigiram completamente esse problema.
Antes de visualizar o código do programa, recomendo que você se familiarize com a estrutura básica dos esboços nos 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()
{
}
Código de teste para o programa touch switch: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
O switch possui um botão de toque e um botão de relógio na parte traseira do dispositivo. Este botão do relógio será usado para modos de serviço, modo de pressão de ar, zerando o dispositivo. O botão implementa um anti-rebote de ferro. A linha do sensor capacitivo e a linha do botão do relógio através dos diodos Schottky são conectadas e conectadas ao pino analógico p0.05, as linhas aos pinos p0.25 e p0.27 MK vão para o sensor capacitivo e o botão do relógio para ler os estados após ativar a interrupção no p0 p0. 05 No pino p0.05, é ativada uma interrupção via comparador (NRF_LPCOMP) por EVENTS_UP. Tive inspiração para resolver o problema
aqui e
aqui .
O switch foi adicionado à rede Mysensors, gerenciada pelo controlador da casa inteligente, Magordomo (
site do projeto )
Código PHP a ser adicionado ao método de alternância 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'); } }
Assista ao resultado em vídeo

Mais tarde, uma opção foi feita com um conversor de impulso, mas isso não está relacionado à operação do chip capacitivo TTP223, há mais desejo de uma iluminação boa e uniforme ao trabalhar com torneiras durante toda a vida útil da bateria.
Projeto Github -
github.com/smartboxchannel/EFEKTA_WIRELESS_TOUCH_SWITCHSite da comunidade em língua russa Mysensors
Chat de telegrama da Mysensors - solução rápida para problemas, dicas, truques, instalação de placas da Mysensors, trabalhando com microcontroladores atmega 328, stm32, nRF5 no Arduino IDE -
@mysensors_rus