集中式控制面板,用于光源TsPKIO-2D转子

图片

抱歉,很长时间以来,我都没有对命名以及家庭自动化外围设备的乐趣。 具体来说,这个东西-灯光的遥控器-之所以出现,是因为我想要一个带有推扭式点击界面的东西,而不是通常分散的按钮。 效果还没达到:在家里,我没有注意到遥控器处于近距离范围,但是至少我关闭了格式塔。

简介TOR:

1)管理厨房中的三个照明组
2)管理房间中的三个照明组
3)同时管理所有光源
4)合理的电池寿命(从一周开始)
5)兼容Livolo编码,SC2260,EV1527

因此,如果您不喜欢Arduino,Livolo开关和中文收音机插座,则无需进一步阅读。 因为第一个是远程的基础,第二个和第三个是外围设备。

概念图


在我看来,控制逻辑如下:

  1. 按下“旋钮”可在环形(厨房-房间-一切)之间切换照明组的区域。
  2. 根据旋转方向旋转旋钮,可以打开或关闭所选组的照明。
  3. 通过不显眼的LED指示显示操作模式(选定的组)。

由于我是根据最不屑一顾的选项使用无线电控制的,因此没有受到干扰和反馈的保护,因此同时提供了一些技巧,以防错过操作。

如果旋转旋钮不能达到预期的效果,则同时按下和反向旋转组合键可以跳过该命令。 然后可以像往常一样重复该命令。

也就是说,如果我顺时针旋转旋钮而主灯没有点亮,则可以按下旋钮,逆时针旋转,然后松开并再次顺时针旋转以重复打开。


为什么这么辛苦? 然后,除了笨拙的协议外,我还拥有笨拙的外围设备。 例如,具有相同的打开和关闭命令的无线电控制的灯光开关Livolo和无线电继电器,以及普通的无线电插座,其中打开和关闭的命令是分开的。

团队跳过技巧可让您创造性地击败非包容性(non-inclusion),而不会破坏一般的照明方案。 此外,跳过命令可让您跳过不需要打开或关闭的光源。

好吧,当然,为了了解遥控器的状况,它有一个单独的指示器,在发送命令时会亮起。

如果在一段时间内未触摸控制台(在代码中配置),则控制器进入睡眠状态。 但是,他没有保存最后的状态,并且当他通过按下笔唤醒时,他从头开始了生活。

这不是一个错误。 我再说一遍,我有没有反馈的开关,并且控制台实际上无法获得有关每个受控外围设备当前状态的信息。

因此,在唤醒后立即转动旋钮即可打开或关闭从头开始的灯。

第一种方法


您可能会猜到,“带有扭曲的盒子”类型的视觉概念需要两件事:盒子和扭曲。 在第一个版本中,盒子的作用是由薄薄的移动电源发挥的,薄薄的移动电源可立即解决两个问题:我既有保护壳又有电池充电方案,还有连接器。 当然,电池本身必须更换为更紧凑的电池,否则填充物将不再适合。

图片

结果变得更加复杂。 当我进行搜索时,我发现电位计旋钮越漂亮,其旋钮越大,其克成本与一克黄金成本越接近。 因此,我购买了一支笔,这种笔极少适合我的审美特性。

图片

控制部分是使用ATmega328P进行实验的结果,以及现有家庭自动化(在相同的Arduino和原始无线电协议上)设定的故事情节的逻辑延续。

我不是很昂贵地购买了上述控制器的分散件,并有条件地制作了原型(实际上是一个从小机箱到大台阶的适配器)电路板,目的是尝试以最少(但合理)的元件数量从中制造出低成本的Arduino版本。

图片

图片

图片

实验证明是成功的,并且在吞下经典的Blink之后,为Arduino环境配置的控制器非常成功地使LED闪烁。 好吧,然后,按照“完成猫头鹰”的原则,我在最终的板上增加了编码器(带按钮),三个LED和一个带有幅度调制的正常发送器,其载波频率为433.92 MHz。

为了将所有元素都放在一个小盒子中,我不得不承受一点痛苦,但是遥控器仍然有效。 尽管看起来问题已经解决了,但我还是想要更多-原始案例。

图片

图片

第二种方法


实际上,出现了一组同志的第一个版本(抱怨)被粉碎了,所以我无限期地推迟了它。 但是他没有指出:很可惜。

但是当3D打印机出现时,他保证自己有一天会制作相同的原始盒子,并用遥控器解决问题。

我不知道结果是好是坏-我真的不知道如何评估我的事情。 但是,在3DToday上,该团队比在MySKU上更热情(我没有抱怨-这不是我自己的礼物),他们对该案例的评价比我高。

图片

但是,由于拥有完全的行动自由,我放弃了脆弱的中国电池,取而代之的是将老式的18650用作电源,正如您可以轻易看到的那样,正是它的尺寸在很大程度上决定了整个外壳的尺寸。

我开始使机壳本身模块化,该机壳由许多部分组成,这使我只能重印单个(错误或不是非常理想的)元素,而不重印整个产品。

还有一点是,我真的不喜欢做连接器的切口,这是我做不到的。 因此,在供应链中,刺猬伊夫琳(Evelyn)知道了另一个窍门:无线充电。



在我的zashashnik中,刚刚放置了另一个接收器,我立即将其付诸行动。


最后,最后一招很明显,但仍然如此:为了使遥控器不会在桌子上爬行,我将一块防滑汽车防滑垫粘在了底部。 最后,尽管将其重新布置到另一个地方也不是问题,但它绝对是一个整体。

重复什么


铁片


1)ATmega328P控制器-1个 (在我的TQFP软件包中,但任何人都可以)
2)10 kOhm电阻器-5个 (4个抑制编码器反弹,1个抑制控制器)
3)100欧姆电阻-3个
4)陶瓷电容器0.1微法拉-4个 (对控制器和编码器弹跳的抑制)
5)推式编码器(valcoder)-1个 (我有PEC12-4220F-S0024
6)LED-3个 (直径3毫米)
7)锂电池充电板-1个 (理论上,从出现的移动电源中,任何在负载下自动开启的人都可以使用)
8)Qi无线充电接收器-1个
9)具有433 MHz幅度调制的发射机-1 pc。 ( 像这样
10)一些玻璃纤维编码器板
11)3D打印机
12)合适的塑料(我印有PLA)
13)M4x30螺钉-4个

通常,可以减少组件的数量。 例如,在一个非常小的版本中,该控制器根本不需要捆绑,尽管我决定听从Nick Gammon的建议,并且没有多余的电容器和电阻器。

以同样的方式,您不必为硬件抑制接触反弹而烦恼,而可以尝试使用软件。 然后,您可以交叉另外四个电阻和一对电容器。

另外,您可以使用现成的Arduino开发板,例如Pro Mini,但是在这种情况下,我不能保证能耗低,您必须自己动手。 同时,这种情况必须纠正。

方案:



作为参考, Hobby Electronics的TQFP-32封装中的ATmega328p引脚排列:



对于我的编码器,我画了一个小板:







如果效果良好,则必须在安装编码器时进行钻孔,或者将其“向下”固定在板上(注意隔离,以确保没有短路),以便编码器a)或多或少均匀地安装并且b)不会摆动。 从历史上看,我有第二种选择。

在这种情况下,重要的是带有零件的板的高度(不包括编码器)不得超过(或不超过)5毫米。

如果Arduino开发板还没有准备好,那么为了使所有功能正常工作,您需要首先将Arduino引导加载程序写入ATmega328P控制器。
为此,首先,将控制器描述添加到Arduino环境。 为此,请访问Arduino官方网站并下载适合您的环境版本的描述档案( 对于1.6对于1.5对于1.0 )。

存档的内容应提取到Arduino环境文件夹的hardware文件夹中。 将来,我将描述仍在使用的1.0.3环境示例所发生的情况。

复制描述后,您应该启动Arduino并将编程器草图加载到Arduino中,它将用作该编程器本身。 草图位于文件-示例-ArduinoISP菜单中。

图片

当然,您应该选择板子和端口。 我选择兆丰,因为我有:

图片

加载编程器草图后,需要切换到目标板。 即 在我们的例子中-频率为8 MHz的ATmega328和一个内部主振荡器。 如果正确复制了上述描述,它将在主板列表中:

图片

现在,您需要将编程器板的MISO,MOSI和SCK线以及将来的Arduino与板连接,还需要连接RESET,GND和VCC。 最后,电源是最好的。

根据上面的信息图和Arduino Mega的描述,出现了以下图片:

SPI-Arduino Mega-ATmega328p

MISO-50-16
MOSI-51-15
SCK-52-17
SS(重置)-53-29

根据您的口味进行物理连接,我使用了一种专门的野蛮方法-将普通面包板电线直接插入板孔中,而无需焊接和绝缘:

图片

如果一切准备就绪,请记下引导加载程序。 首先,请确保选择了正确的程序员(服务-程序员-Arduino作为ISP):

图片

然后我们执行Service-Record bootloader:

图片

之后,输出是一个极简的Arduino板,可以将USB-Serial适配器或带有该适配器的完整Arduino板加载到其中,以加载草图。 在第一种情况下,您需要交叉连接RX和TX,并且不要忘记连接公共地线。 在第二种情况下,还必须将用作适配器的RESET Arduino接地。

如果像我一样,如果您没有在下载草图之前自动重置控制器的电路,则有两种选择:要么拉其重置,要么在Arduino环境表明下载已开始时简单地打开其电源。

房屋


正如我所说,这种情况是模块化的。 这意味着,在眼睛看不到的内部,可以放入陈旧且不再合适的塑料。 您可以在上面放置电子产品:

图片

我提请注意以下事实:该案例是特定的,旨在适合我的填充版本。

我建议使转子透明,以使其散射指示器的光线。 为了增加重量,可以在转子内部插入一个M16螺母:

图片

仍然需要一件运动衫和一件外衣。 盖子可以简单地向内插入,并保持摩擦。 而且,当然,离不开外壳的上部和下部。

我打印了填充为10%的转子,其余元素填充为5%。 塑料-PLA。 在我的打印机上,喷嘴的设置温度在前三层中为200℃,在下一层中为185℃。 不幸的是,我不能说喷嘴的真实温度是多少。 桌子很冷。

组装很简单。



板放置在耐用箱的凹槽中,LED放置在耐用箱下部的凹槽中。 发射器的天线放倒,无线充电接收器以相同的方式放倒-使其更接近相同的电荷。



填充物由中间板固定,中间板的槽中穿过编码器线束。

编码器固定在上板上,并全部用M4x30螺钉拧紧,螺钉本身用塑料切割。

现在,可以将耐用的外壳封装在外壳的两半中。 转子放在编码器轴上,衬衫在转子上。 可选地,将防滑垫粘在车身底部。 另一种选择是装饰性插入物,将接缝隐藏在身体的两半之间。

代号
在代码中,您需要指定命令来打开和关闭外围设备。 可选-更改自动关机超时时间。

这些都位于变量部分。

//  : http://donalmorrissey.blogspot.ru/2010/04/sleeping-arduino-part-5-wake-up-via.html //  Livolo: http://forum.arduino.cc/index.php?action=dlattach;topic=153525.0;attach=108106 #include <avr/sleep.h> #include <avr/power.h> #include <livolo.h> #define adc_disable() (ADCSRA &= ~(1<<ADEN)) // disable ADC (before power-off) #define adc_enable() (ADCSRA |= (1<<ADEN)) // re-enable ADC #define txPin 7 //   Livolo livolo(txPin); #define PULSESHORT 450 #define PULSELONG 1350 #define PULSESYNC 13950 #define encA 5 #define encB 6 //   #define buttonPin 2 //   () #define roomLed 10 //    #define kitchenLed 9 //    #define switchLed 3 //     #define switchLedTimeOut 150 //      #define switchTreshold 4 //      #define offDelay 15000 //   #define rLev 3 //     #define kLev 3 //     #define glev 2 //     #define txPowerPin 8 //    #define kitchenBackLightOn1 12 #define kitchenBackLightOn2 34 #define kitchenMainLightOn 56 #define roomBackLightOn 12 #define roomMainLightOn1 34 #define roomMainLightOn2 56 #define mainLightOn 12 #define kitchenBackLightOff1 12 #define kitchenBackLightOff2 34 #define kitchenMainLightOff 56 #define roomBackLightOff 12 #define roomMainLighOtff1 34 #define roomMainLightOff2 56 #define mainLightOff 12 #define LivoloID 8500 volatile byte rotorMode = 0; //   byte currentMode = 0; //    int curEncA, prevEncA, curButton, prevButton; //   ,  byte encCountPlus = 0; //   byte encCountMinus = 0; //   unsigned long offTimeOut = 0; //    unsigned long modeTimeOut = 0; //        unsigned long switchLedTime = 0; //      unsigned long modeTime = 0; //   unsigned int modeTreshold = 500; //     (  ) unsigned int bounceTreshold = 200; //     byte rLevState = 0; byte kLevState = 0; byte gLevState = 0; //   k - , r - , h - , b -  boolean kBackState = false; boolean kBackState1 = false; boolean kMainState = false; boolean rBackState = false; boolean rMainState = false; boolean rMainState1 = false; boolean hMainState = false; boolean bMainState = false; boolean afterSleep = false; //      boolean modeTimeOutStart = false; boolean switchLedOn = false; boolean allOn = false; //  " "    boolean allOff = false; //  " "    static void ookPulse(int on, int off) { digitalWrite(txPin, HIGH); delayMicroseconds(on); digitalWrite(txPin, LOW); delayMicroseconds(off); } static void rcSend(long remoteCode) { for (byte reSend = 0; reSend < 8; reSend++) { for(byte repeat=0; repeat<4; repeat++){ for (byte i = 24; i>0; i--) { // transmit remoteID byte txPulse=bitRead(remoteCode, i-1); // read bits from remote ID // Serial.print(txPulse); switch (txPulse) { case 0: // 00 ookPulse(PULSESHORT,PULSELONG); //ookPulse(PULSESHORT,PULSELONG); break; case 1: // 11 ookPulse(PULSELONG,PULSESHORT); //ookPulse(PULSELONG,PULSESHORT); break; } // switch } // for loop ookPulse(PULSESHORT,PULSESYNC); // S(ync) // Serial.println(); } // repeat } delay(150); } void switchLedToggle() { digitalWrite(switchLed, HIGH); switchLedTime = millis(); switchLedOn = true; } void lightsUp(boolean lightsUpMode) { //       ""     //   "" -   if (afterSleep == true) { if (lightsUpMode == false) { gLevState = 1; rLevState = 3; kLevState = 3; } else {gLevState = 0; rLevState = 0; kLevState = 0; } afterSleep = false; //   " " } //   if (rotorMode == 2) { if (lightsUpMode == false){ if (allOff == false) { switchLedToggle(); if (digitalRead(buttonPin) == HIGH) { //   gLevState = 0; rLevState = 0; kLevState = 0; rcSend(kitchenBackLightOff1); rcSend(kitchenBackLightOff2); rcSend(roomBackLightOff); livolo.sendButton(LivoloID, mainLightOff); } allOff = true; allOn = false; } } if (lightsUpMode == true){ //  ,    if (allOn == false) { switchLedToggle(); if (digitalRead(buttonPin) == HIGH) { gLevState = 1; rLevState = 3; kLevState = 3; rcSend(kitchenBackLightOn1); rcSend(kitchenBackLightOn2); rcSend(roomBackLightOn); livolo.sendButton(LivoloID, mainLightOff); //    Livolo livolo.sendButton(LivoloID, kitchenMainLightOn); //#1   livolo.sendButton(LivoloID, roomMainLightOn1); // #2 livolo.sendButton(LivoloID, roomMainLightOn2); // #3 livolo.sendButton(LivoloID, mainLightOn); // #6 } allOn = true; allOff = false; } } } //  if (rotorMode == 1) { if (lightsUpMode == false && kLevState > 0) { switchLedToggle(); if (digitalRead(buttonPin) == HIGH) { if (kLevState == 3) { //   livolo.sendButton(LivoloID, kitchenMainLightOff); // #3 } if (kLevState == 2) { //   2 livolo.sendButton(LivoloID, kitchenBackLightOff2); // #6 } if (kLevState == 1) { //   1 rcSend(kitchenBackLightOff1); } } if (kLevState!=0) { kLevState--;} // Serial.println(kLevState); } if (lightsUpMode == true && kLevState < 3) { switchLedToggle(); kLevState++; if (digitalRead(buttonPin) == HIGH) { if (kLevState > 3) {kLevState = 3;} // Serial.println(kLevState); if (kLevState == 1) { //   1 rcSend(kitchenBackLightOn1); } if (kLevState == 2) { //   2 livolo.sendButton(LivoloID, kitchenBackLightOn2); // #6 } if (kLevState == 3) { //   livolo.sendButton(LivoloID, kitchenMainLightOn); // #3 } } } } //  if (rotorMode == 0) { if (lightsUpMode == false && rLevState > 0) { switchLedToggle(); if (digitalRead(buttonPin) == HIGH) { if (rLevState == 3) { //  1 livolo.sendButton(LivoloID, roomMainLighOtff1); //#1 } if (rLevState == 2) { //   livolo.sendButton(LivoloID, roomMainLightOff2); // #2 } if (rLevState == 1) { //   rcSend(roomBackLightOff); } } if (rLevState != 0) { rLevState--; } } if (lightsUpMode == true && rLevState < 3) { switchLedToggle(); rLevState++; if (digitalRead(buttonPin) == HIGH) { if (rLevState == 1) { //   rcSend(roomBackLightOn); } if (rLevState == 2) { //   livolo.sendButton(LivoloID, roomMainLightOn1); //#1 } if (rLevState == 3) { //   1 livolo.sendButton(LivoloID, roomMainLightOn2); // #2 } } } } } void wakeUp() { detachInterrupt(0); } void setMode() { if (rotorMode >= 2 ) { rotorMode = 0; } else { rotorMode++; } offTimeOut = millis(); } void ledBlink() { for (byte iLed = 0; iLed<3; iLed++) { digitalWrite(kitchenLed, HIGH); digitalWrite(roomLed, HIGH); delay(100); digitalWrite(kitchenLed, LOW); digitalWrite(roomLed, LOW); delay(100); } } void setLed() { if (rotorMode == 0) { //  digitalWrite(roomLed, HIGH); digitalWrite(kitchenLed, LOW); } if (rotorMode == 1) { //  digitalWrite(roomLed, LOW); digitalWrite(kitchenLed, HIGH); } if (rotorMode == 2) { //    digitalWrite(roomLed, HIGH); digitalWrite(kitchenLed, HIGH); } } void enterSleep() { // ledBlink(); afterSleep = true; digitalWrite(txPin, LOW); digitalWrite(txPowerPin, LOW); digitalWrite(roomLed, LOW); digitalWrite(kitchenLed, LOW); digitalWrite(switchLed, LOW); pinMode(txPin, INPUT); pinMode(txPowerPin, INPUT); pinMode(roomLed, INPUT); pinMode(kitchenLed, INPUT); pinMode(switchLed, INPUT); attachInterrupt(0, wakeUp, LOW); adc_disable(); set_sleep_mode(SLEEP_MODE_PWR_DOWN); sleep_enable(); sleep_mode(); sleep_disable(); power_all_enable(); pinMode(txPin, OUTPUT); pinMode(txPowerPin, OUTPUT); pinMode(roomLed, OUTPUT); pinMode(kitchenLed, OUTPUT); pinMode(switchLed, OUTPUT); digitalWrite(txPin, LOW); digitalWrite(txPowerPin, HIGH); // ledBlink(); setLed(); offTimeOut = millis(); allOn = false; allOff = false; } void setup() { // Serial.begin(115200); pinMode(txPin, OUTPUT); pinMode(txPowerPin, OUTPUT); pinMode(roomLed, OUTPUT); pinMode(kitchenLed, OUTPUT); pinMode(switchLed, OUTPUT); digitalWrite(txPin, LOW); digitalWrite(txPowerPin, HIGH); digitalWrite(roomLed, LOW); digitalWrite(kitchenLed, LOW); digitalWrite(switchLed, LOW); // pinMode(buttonPin, INPUT_PULLUP); pinMode(buttonPin, INPUT); pinMode(encA, INPUT); pinMode(encB, INPUT); prevEncA = digitalRead(encA); offTimeOut = millis(); rotorMode = 0; setLed(); prevButton = digitalRead(buttonPin); } void loop() { if ((millis() - offTimeOut) > offDelay) { enterSleep(); } else { //     if (switchLedOn == true) { if ((millis() - switchLedTime) > switchLedTimeOut) { digitalWrite(switchLed, LOW); switchLedOn = false; } } //       if (digitalRead(buttonPin) == LOW) { offTimeOut = millis(); } //   curButton = digitalRead(buttonPin); if ((prevButton == HIGH) && (curButton == LOW)) { if (modeTimeOutStart == false) { modeTimeOut = millis(); modeTimeOutStart = true; } } else { if (modeTimeOutStart == true) { modeTime = millis() - modeTimeOut; if ((modeTime < modeTreshold) && (modeTime > bounceTreshold)) { setMode(); modeTimeOutStart = false; prevButton = digitalRead(buttonPin); } else { modeTimeOutStart = false; prevButton = digitalRead(buttonPin); } } } //    if (currentMode != rotorMode) { //       ,     currentMode = rotorMode; //     setLed(); } //   curEncA = digitalRead(encA); if ((prevEncA == LOW) && (curEncA == HIGH)) { offTimeOut = millis(); if (digitalRead(encB) == LOW) { encCountMinus++; encCountPlus = 0; // Serial.println("Encoder Minus"); if (encCountMinus > switchTreshold) { encCountMinus = 0; lightsUp(false); } } else { encCountPlus++; encCountMinus = 0; // Serial.println("Encoder Plus"); if (encCountPlus > switchTreshold) { encCountPlus = 0; lightsUp(true); } } } prevEncA = curEncA; } } 


案例模型参考

仅此而已。

PS:我尽力不忘记任何事情,但我可以。 如果是这样,我深表歉意,并将尽我所能正确回答主要问题并纠正错误。

Source: https://habr.com/ru/post/zh-CN411093/


All Articles