附加螢光背光的無線觸控開關

向 Habr 上“DIY 或自己動手”部分的所有讀者問好! 今天的文章將介紹TTP223晶片上的觸控開關| 數據表。 此開關在 nRF52832 微控制器上運作 | 數據表,使用帶有印刷天線和外部 MHF17103 天線連接器的 YJ-4 模組。 觸控開關使用 CR2430 或 CR2450 電池供電。 傳輸模式的功耗不超過 8 mA,睡眠模式的功耗不超過 6 µA。
附加螢光背光的無線觸控開關

和之前的所有專案一樣,這個也是一個 Arduino 項目,程式是在 Arduino IDE 中寫的。 設備的軟體實作基於Mysensors協定 | GitHub 庫, nRF5 板支援 GitHub 在我的感測器中。 英語社群論壇 - http://forum.mysensors.org, 俄語社群論壇 - http://mysensors.ru/forum/
(對於那些想學習的人—— Документация, 串行協議, API, 協議, 解析器 | 對於那些希望提供幫助的人(捐款)在專案的開發過程中 - Документация)

觸控開關板是在 Deeptrace 計劃中開發的,考慮到使用雷射熨燙技術 (LUT) 方法進行後續製造。 該板的開發尺寸為 60x60mm(標準玻璃面板的尺寸為 80x80mm)。 該電路被印在《天線》雜誌的頁面上,並使用具有「Len」設定(最大功率)的博世熨斗轉移到雙面箔玻璃纖維板 1.5mm、35μm(在沒有另一個的情況下)。
附加螢光背光的無線觸控開關

使用預先以每1.5ml溫水250茶匙的比例製備的氯化鐵溶液進行蝕刻。 該過程持續了 15 分鐘。
使用安裝在 DREMEL 3000 鑽架上的 DREMEL 220 小型鑽頭進行層間過孔和固定電池座的鑽孔。層間過孔的鑽孔使用 0,4mm 鑽頭,電池座的孔使用 1,1mm 鑽頭鑽孔。 。 使用帶有 DREMEL 540 附件的相同迷你鑽頭沿板邊緣進行修整(切割圓 d=32.0mm)。 修剪是在呼吸器中完成的。
使用水溶液中的玫瑰合金(每 1 毫升水 300 茶匙結晶檸檬酸)對蝕刻板進行鍍錫。

焊接過程大約需要一個小時,大部分時間都花在將焊錫絲(鍍錫,直徑0.4毫米)插入層間過孔的孔中。

用 FLUX OFF 氣溶膠清潔劑清洗電路板。
附加螢光背光的無線觸控開關

附加螢光背光的無線觸控開關

裝置主體的設計是在三維電腦輔助設計編輯器中進行的。 錶殼尺寸 78,5 毫米 X 78,5 毫米 X 12 毫米。
附加螢光背光的無線觸控開關

外殼和電池倉蓋的完整模型以 STL 格式保存,然後需要準備這些模型以在 SLA 印表機上列印(添加支撐、方向)。 在這個階段,出現了一個小問題,因為家用SLA印表機的列印面積很小。 相對於列印時間處於最佳位置的設備外殼模型不適合列印區域的尺寸。 當模型放置在45度時,也給出了令人失望的結果;支撐物的重量等於人體模型的重量。 事先同意後處理的事實後,決定垂直列印模型,在正面之一提供支撐。 列印身體需要 5 個小時,層設定為 50 微米。 接下來,使用非常細粒度的砂紙進行加工(我不會寫數字,因為我不知道:))。 列印電池蓋花了 40 分鐘。
附加螢光背光的無線觸控開關

全球速賣通的玻璃面板在出售時已經粘有塑膠框架;移除框架沒有任何問題。 用普通吹風機預熱後,我拆下了玻璃面板。
附加螢光背光的無線觸控開關

附加螢光背光的無線觸控開關

LED 背光源的擴散器由帶有丙烯酸黏合劑 3M 9088-200 的雙面膠帶製成。 對於螢光燈,有多種材料可供選擇,中國膠帶和國內公司Luminofor切割成膠帶的膠帶。 選擇了一家國內製造商;根據我的感覺,它的光芒更亮、更長久。 用 3M 9088-200 雙面膠帶將一張塗有螢光顏料的方形紙黏在上面。

使用帶有 3M VHB 4910 丙烯酸黏合劑的雙面膠帶將玻璃黏合到開關主體上。
附加螢光背光的無線觸控開關

蓋子用 M 1,4 X 5 mm 螺絲固定。

該設備的成本為890盧布。

接下來是節目部分。 出現了一些問題。 事實證明,TTP223 感測器晶片在穩定的 3.3V 電源下工作得很好,但在直接由放電良好的電池供電時則不太好。 當使用 2.5v 左右的電源啟動裝置時,加上在進行 Mysensors 演示時進行額外的「下降」之後,TTP223 微電路(校準後立即)會導致 MK 中斷,因為它帶有活動觸發器。

更改了微電路的電源電路(帶有gpio MK 的電源管理TTP223),提供了額外的接地,並更換了RGB LED 線路(在電容式感測器板的另一側運行)上具有更高電阻的電阻器。 它也被添加到軟體中:啟動 Mysensors 框架並完成演示後啟動電容微電路的電源。 TTP223晶片上電時自動校準的延遲增加了一倍。 所有這些變化完全消除了這個問題。

在查看程式碼之前,我建議您熟悉一下 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()
{

}

觸控開關程式測試代碼: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

此開關在裝置背面有一個觸控按鈕和一個輕觸按鈕。 此輕觸按鈕將用於服務模式、無線綁定模式和裝置重設。 該按鈕具有鐵防彈功能。 電容感測器的線和輕觸按鈕的線透過蕭特基二極體連接並連接到類比引腳 p0.05,並且還從電容感測器和輕觸按鈕有線連接到 MK 引腳 p0.25 和 p0.27 .0.05 用於在引腳p0.05 上啟動中斷後讀取狀態。 在引腳 pXNUMX 上,透過 EVENTS_UP 透過比較器 (NRF_LPCOMP) 的中斷被啟動。 我收到了解決問題的靈感 這裡 и 這裡.

該交換器已添加到 Mysensors 網絡,由智慧家庭控制器 Majordomo 管理(項目網站)

用於向 statusUpdate 方法新增開關的 PHP 程式碼

if (getGlobal("MysensorsButton01.status")==1) {
if (getGlobal('MysensorsRelay04.status') == 0) {
setGlobal('MysensorsRelay04.status', '1');
} else if (getGlobal('MysensorsRelay04.status') == 1) {
setGlobal('MysensorsRelay04.status', '0');
} 
}

查看影片中的結果

附加螢光背光的無線觸控開關

後來又選擇了升壓轉換器,但這與TTP223電容微電路的操作無關;更希望在整個電池壽命期間按鍵時獲得良好且均勻的照明。

附加螢光背光的無線觸控開關

附加螢光背光的無線觸控開關

專案Github - github.com/smartboxchannel/EFEKTA_WIRELESS_TOUCH_SWITCH

俄文 社群網站 我的感測器

電報聊天 Mysensors — 快速解決 Mysensors 問題、提示、技巧、安裝板、在 Arduino IDE 中使用 atmega 328、stm32、nRF5 微控制器 — @mysensors_rus

一些照片附加螢光背光的無線觸控開關

附加螢光背光的無線觸控開關

附加螢光背光的無線觸控開關

附加螢光背光的無線觸控開關

附加螢光背光的無線觸控開關

來源: www.habr.com

添加評論