数字酒保。 成人初学者电子产品的Arduino项目。 第一部分

我有很多朋友。 年轻人,中年男人,当然还有各个年龄段的女士。 大概每个人。 很难确定现代女性的年龄。 而且我真的不想。
所以在这里。 由于我的能力,我带着朋友和熟人的孩子一起学习电子产品。 我们制造小型机器人,各种萤火虫甚至光剑的虫子。 孩子们几乎总是成功,他们当然会向那些复兴电子产品的父母吹牛。 依此类推。 但是有一天,我的一个朋友看着女儿的另一种自豪感说-我也想深入研究这种电子设备,编程,甚至焊接一些东西。 没问题 让我们展示如何在轮式平台上组装机器人。 将在地板上骑脱衣舞。 或者,我们将制作一个游戏(例如python),或者只是使LED闪烁,或者...我们经历了许多示例。 事实证明,对于初学者来说,一切都是幼稚的;如果不是儿童,那么一切都不适合初学者。 出问题了! BEGINNERS,ADULTS电子工程师需要上课。 随便吧-数字调酒师或混合鸡尾酒的机器。

今天的项目尚未完成。 如果需要添加,请直接在注释中写。 在照片中有一个摊位,您可以在其中看到该调酒师的设计。



这是Arduino项目风格的图表。



现在工作的设计和逻辑。 根据方案和照片。

将四个微型泵的接收管放入四个瓶子中。 这些微型泵连接到组装在MOSFET场效应晶体管上的四个键。 按键依次连接到任何Arduina的端子3、5、6、9(如果写入结论**,则表示Arduina的结论)。 这是执行部分。 执行部分的逻辑由五个电位器设置。 顺序:将最左侧的电位计连接到端子A4,设置准备鸡尾酒的玻璃杯的体积。 在其上方,您看到一个16 RGB LED刻度,带有所谓的像素寻址WS2812b。 当我们旋转第一个电位计时,LED依次点亮,有条件地显示玻璃的体积。 该标尺连接到引脚11。

在接下来的四个滑动电位器(连接到端子A0,A1,A2,A3)上,我们设置了需要从特定瓶中倒出的饮料总量的比例。 滑块上方是每个8个LED的小刻度(串联到一个长的LED)。 移动电位器时,我们从底部到顶部选择比例和小比例尺,每种都涂有自己的颜色。 同时,左侧的长标尺,或者更确切地说是其最初点亮的部分,以与小比例的相同颜色进行绘制。

立即看到鸡尾酒的成分。 我们按下按钮(销钉7),然后泵从左到右依次打开,将饮料装入玻璃杯中。

在草图中,您可以配置:

1.各种刻度的活动颜色及其背景照明。
2.泵的速度,通过脉宽调制。 因此,泵不包括继电器,而是晶体管开关。 例如,如果您要使用汽车玻璃清洗泵,则这是必需的。 她很有生产力。
3.玻璃的最大物理体积。 默认值为750毫升。
4.倒数和指示之前液体抽吸的时间。 这是为了在暂停期间填充空管。
5.暂停后再从下一瓶开始食用。
6. LED中刻度尺的大小。 默认情况下,大型LED有16个,小型LED有8个。 您可以根据需要进行更改。 会很美。
这样的东西。

这是一个演示视频。



我建议为初学者的电子产品组装这种设计。 将草图倒入Arduin,然后使用调酒师的设置进行演奏。 当您习惯了代码并在行中导航时,可以添加新功能,例如“停止”按钮或“冰”按钮。 后者可以根据冰块的体积自动减少饮料的总量。

我希望这样的项目会吸引成年的新手电子程序员。 然后他们慢慢地整理设计和代码,并带着孩子们将自尊心提高几个层次。

周末愉快!

最后,在视频中,我将尝试提出意见和建议。 在后续和实际项目中,我将考虑到这一点。

可以在此处下载代码(草图)。 或参阅:

您需要Adafruit_NeoPixel.h (用于LED的库)和PinChangeInt.h (用于中断的库)。

#include <Adafruit_NeoPixel.h> #include <PinChangeInt.h> #define START_PIN 7 #define LEDS_PIN 11 #define VOLUME_1_PIN A0 #define VOLUME_2_PIN A1 #define VOLUME_3_PIN A2 #define VOLUME_4_PIN A3 #define TOTAL_VOLUME_PIN A4 #define ACT_1_PIN 3 #define ACT_2_PIN 5 #define ACT_3_PIN 6 #define ACT_4_PIN 9 #define DRINKS_NUM 4 #define PIXEL_IN_STICK 8 #define PIXEL_IN_DRINK PIXEL_IN_STICK #define PIXEL_IN_VOLUME (2 * PIXEL_IN_STICK) #define PIXEL_NUM (DRINKS_NUM * PIXEL_IN_DRINK + PIXEL_IN_VOLUME) #define VOLUME_START_PIXEL 0 #define DRINKS_START_PIXEL (VOLUME_START_PIXEL + PIXEL_IN_VOLUME) #define DRINK_START_PIXEL(DRINK) (DRINKS_START_PIXEL + DRINK * PIXEL_IN_DRINK) #define BACKGROUND_COLOUR ((uint32_t) 0x000001) #define SHADOW_1_COLOUR ((uint32_t) 0x000100) #define SHADOW_2_COLOUR ((uint32_t) 0x000100) #define SHADOW_3_COLOUR ((uint32_t) 0x000100) #define SHADOW_4_COLOUR ((uint32_t) 0x000100) #define PROCESS_1_COLOUR ((uint32_t) 0xFF0000) #define PROCESS_2_COLOUR ((uint32_t) 0x0100ff) #define PROCESS_3_COLOUR ((uint32_t) 0x111100) #define PROCESS_4_COLOUR ((uint32_t) 0xFF00FF) #define VOLUME_PROCESS_COLOUR ((uint32_t) 0x888888) #define DataThreshold ((uint16_t) (1024/PIXEL_IN_DRINK)) #define DataThresholdVol ((uint16_t) (1024/PIXEL_IN_VOLUME)) #define PROCESS (1 << 0) #define mlToTimeCoef 10 //   1  ,  #define MIN_VOLUME 1 //  ,  #define MAX_VOLUME ((uint32_t) 750) // #define mlForLED ((float)((float)MAX_VOLUME / (float)PIXEL_IN_VOLUME)) #define PREPROCESS_DELAY ((uint32_t) 2000) // #define PUMP_POWER ((uint16_t) 255) // 0 ()  255 () #define WaitShowDelay ((uint16_t) 300) //2 * WaitShowDelay -     #define WaitCycle 3 //    = WaitCycle * 2 * WaitShowDelay #define EndDelay ((uint16_t) 2500) //   typedef struct { uint8_t VolPin; uint8_t ActPin; uint16_t Volume; //  uint32_t ProcColour; uint32_t ShadColour; float mlVol; //         uint8_t LEDsNum; uint8_t LEDsPos; } DrinkType; Adafruit_NeoPixel LEDS = Adafruit_NeoPixel(PIXEL_NUM, LEDS_PIN, NEO_GRB + NEO_KHZ800); uint8_t State = 0; uint16_t TotalVolume = 0; float TotalVolml = 0; uint8_t TotVolActLEDs = 0; bool ColourMix = false; uint32_t NewColour = 0; bool SystemChange = false; DrinkType Drinks[DRINKS_NUM]; void setup() { digitalWrite(START_PIN, HIGH); uint8_t VolPINs[DRINKS_NUM] = {VOLUME_1_PIN, VOLUME_2_PIN, VOLUME_3_PIN, VOLUME_4_PIN}; uint8_t ActPINs[DRINKS_NUM] = {ACT_1_PIN, ACT_2_PIN, ACT_3_PIN, ACT_4_PIN}; uint32_t ProcCOLOURs[DRINKS_NUM] = {PROCESS_1_COLOUR, PROCESS_2_COLOUR, PROCESS_3_COLOUR, PROCESS_4_COLOUR}; uint32_t ShadCOLOURs[DRINKS_NUM] = {SHADOW_1_COLOUR, SHADOW_2_COLOUR, SHADOW_3_COLOUR, SHADOW_4_COLOUR}; for(uint8_t i = 0; i < DRINKS_NUM; i++) { Drinks[i].VolPin = VolPINs[i]; Drinks[i].ActPin = ActPINs[i]; pinMode(Drinks[i].ActPin, OUTPUT); digitalWrite(Drinks[i].ActPin, LOW); Drinks[i].Volume = 0; Drinks[i].ProcColour = ProcCOLOURs[i]; Drinks[i].ShadColour = ShadCOLOURs[i]; Drinks[i].LEDsPos = 0; } PCintPort::attachInterrupt(START_PIN, &START_ISR, FALLING); LEDS.begin(); for(byte i=0; i < PIXEL_NUM; i++) LEDS.setPixelColor(i, BACKGROUND_COLOUR); LEDS.show(); } //---------------------------------------- void loop() { if ((State & PROCESS) != PROCESS) { uint16_t Data; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { Data = analogRead(Drinks[cup].VolPin); if (abs(Data - Drinks[cup].Volume) >= DataThreshold) { Drinks[cup].Volume = Data; if (Drinks[cup].Volume > 975) Drinks[cup].Volume = 1024; uint8_t StartPixel = DRINK_START_PIXEL(cup); for(byte i = StartPixel; i < (StartPixel + PIXEL_IN_DRINK); i++) LEDS.setPixelColor(i, Drinks[cup].ShadColour); for(byte i = StartPixel; i < (StartPixel + (Drinks[cup].Volume / DataThreshold)); i++) LEDS.setPixelColor(i, Drinks[cup].ProcColour); SystemChange = true; } } Data = analogRead(TOTAL_VOLUME_PIN); if (abs(Data - TotalVolume) >= DataThresholdVol) { TotalVolume = Data; if (TotalVolume > 975) TotalVolume = 1024; TotVolActLEDs = TotalVolume / DataThresholdVol; for(byte i = VOLUME_START_PIXEL; i < (VOLUME_START_PIXEL + PIXEL_IN_VOLUME); i++) LEDS.setPixelColor(i, BACKGROUND_COLOUR); SystemChange = true; } if (SystemChange) { TotalVolml = (float)((TotalVolume * MAX_VOLUME) / 1024); uint16_t MinVol = 1025; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { if ((Drinks[cup].Volume < MinVol) && (Drinks[cup].Volume != 0)) MinVol = Drinks[cup].Volume; } float OnePartVol = 0; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { Drinks[cup].mlVol = (float)Drinks[cup].Volume / (float)MinVol; OnePartVol += Drinks[cup].mlVol; } OnePartVol = TotalVolml / OnePartVol; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { Drinks[cup].mlVol *= OnePartVol; Drinks[cup].LEDsNum = Drinks[cup].mlVol / mlForLED; if ((Drinks[cup].mlVol > 0) && (Drinks[cup].LEDsNum < 1)) Drinks[cup].LEDsNum = 1; } uint8_t LEDsSum = 0; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) LEDsSum += Drinks[cup].LEDsNum; if ((LEDsSum > 0) && (LEDsSum <= TotVolActLEDs)) { uint8_t LedsNumMAX = Drinks[0].LEDsNum; uint8_t LedsNumMAXPos = 0; for(uint8_t cup = 1; cup < DRINKS_NUM; cup++) { if (Drinks[cup].LEDsNum > LedsNumMAX) { LedsNumMAX = Drinks[cup].LEDsNum; LedsNumMAXPos = cup; } } Drinks[LedsNumMAXPos].LEDsNum += TotVolActLEDs - LEDsSum; Drinks[0].LEDsPos = VOLUME_START_PIXEL; for(uint8_t cup = 1; cup < DRINKS_NUM; cup++) Drinks[cup].LEDsPos = Drinks[cup - 1].LEDsPos + Drinks[cup - 1].LEDsNum; ColourMix = false; } else if (LEDsSum > TotVolActLEDs) { for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { Drinks[cup].LEDsNum = TotVolActLEDs; Drinks[cup].LEDsPos = VOLUME_START_PIXEL; } ColourMix = true; NewColour = 0; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) NewColour |= Drinks[cup].ProcColour; } bool EmptyCup = true; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { if (Drinks[cup].LEDsNum != 0) { EmptyCup = false; break; } } if (EmptyCup) { for(byte i = VOLUME_START_PIXEL; i < (VOLUME_START_PIXEL + TotVolActLEDs); i++) LEDS.setPixelColor(i, VOLUME_PROCESS_COLOUR); } else { if (ColourMix) { for(byte i = VOLUME_START_PIXEL; i < (VOLUME_START_PIXEL + TotVolActLEDs); i++) LEDS.setPixelColor(i, NewColour); } else { for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { if (Drinks[cup].LEDsNum != 0) { for(byte i = Drinks[cup].LEDsPos; i < (Drinks[cup].LEDsPos + Drinks[cup].LEDsNum); i++) LEDS.setPixelColor(i, Drinks[cup].ProcColour); } } } } SystemChange = false; } LEDS.show(); } else { uint8_t LEDSPos[DRINKS_NUM]; uint8_t LEDSNum[DRINKS_NUM]; for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { LEDSPos[cup] = Drinks[cup].LEDsPos; LEDSNum[cup] = Drinks[cup].LEDsNum; } for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { if (Drinks[cup].LEDsNum != 0) { float Volume = Drinks[cup].mlVol; uint16_t VolCnt = 0; uint16_t mlPerLEDCoef = Volume / LEDSNum[cup]; analogWrite(Drinks[cup].ActPin, PUMP_POWER);// delay(PREPROCESS_DELAY); while (Volume >= MIN_VOLUME) { delay(mlToTimeCoef * MIN_VOLUME); Volume -= MIN_VOLUME; VolCnt += MIN_VOLUME; { if (VolCnt >= mlPerLEDCoef) { if (ColourMix) { } else { if (LEDSNum[cup] != 0) { for(byte i = VOLUME_START_PIXEL; i < (VOLUME_START_PIXEL + PIXEL_IN_VOLUME); i++) LEDS.setPixelColor(i, BACKGROUND_COLOUR); if (LEDSNum[cup] > 0) LEDSNum[cup]--; for(uint8_t i = 0; i < DRINKS_NUM; i++) { if (LEDSPos[i] > 0) LEDSPos[i]--; } for(uint8_t i = 0; i < DRINKS_NUM; i++) { if (Drinks[i].LEDsNum != 0) { for(byte j = LEDSPos[i]; j < (LEDSPos[i] + LEDSNum[i]); j++) LEDS.setPixelColor(j, Drinks[i].ProcColour); } } } } LEDS.show(); VolCnt = 0; } } } analogWrite(Drinks[cup].ActPin, 0);// if (cup < (DRINKS_NUM - 1)) { uint8_t StickNum = cup + 1; uint8_t StartPixel = DRINK_START_PIXEL(StickNum); for (uint8_t BlinkTime = 0; BlinkTime < WaitCycle; BlinkTime++) { for(byte i = StartPixel; i < (StartPixel + PIXEL_IN_DRINK); i++) LEDS.setPixelColor(i, Drinks[cup+1].ShadColour); LEDS.show(); delay(WaitShowDelay); for(byte i = StartPixel; i < (StartPixel + (Drinks[cup+1].Volume / DataThreshold)); i++) LEDS.setPixelColor(i, Drinks[cup+1].ProcColour); LEDS.show(); delay(WaitShowDelay); } } } } delay(EndDelay); if (ColourMix) { for(byte i = VOLUME_START_PIXEL; i < (VOLUME_START_PIXEL + TotVolActLEDs); i++) LEDS.setPixelColor(i, NewColour); } else { for(uint8_t cup = 0; cup < DRINKS_NUM; cup++) { if (Drinks[cup].LEDsNum != 0) { for(byte i = Drinks[cup].LEDsPos; i < (Drinks[cup].LEDsPos + Drinks[cup].LEDsNum); i++) LEDS.setPixelColor(i, Drinks[cup].ProcColour); } } } State &= ~PROCESS; } } //---------------------------------------- void START_ISR() { State |= PROCESS; } 

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


All Articles