亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Manufacturing Technology >> 制造工艺

DIY SMD 返修台

组件和用品

SparkFun Arduino Pro Mini 328 - 5V/16MHz
× 1
Adafruit 标准 LCD - 16x2 蓝底白字
× 1
lcd i2c 模块
× 1
带按钮的旋转编码器
× 1
热风枪手柄
× 1
热风枪手柄支架 + 喷嘴
× 1
BTA12-600B
× 1
IRFZ44
× 1
MCP602
× 1
MOC3052
× 1
4N25
× 1
桥式整流器
× 1
蜂鸣器
× 1
FR107 快速整流二极管
× 1
0.01 uF 电容,400V
× 1
电容 100 nF
× 6
通孔电阻,39 ohm
× 1
通孔电阻,33 kohm
× 2
电阻 330 ohm
× 1
电阻 220 ohm
× 1
电阻 1k ohm
× 3
通孔电阻,470 ohm
× 1
500k 多圈电位器
× 1
电阻 10k ohm
× 3

必要的工具和机器

烙铁(通用)

应用和在线服务

Arduino IDE
Autodesk Eagle

关于这个项目

介绍:DIY SMD返修台

在本教程中,您可以学习如何使用 Arduino 和其他常用组件制作热风枪控制器。本项目采用PID算法计算所需功率,由隔离式可控硅驱动器控制。

本项目使用与 858D 兼容的手柄。它有一个 K 型热电偶、700 瓦 230 VAC 加热器和一个 24 VDC 风扇。

与商用控制器相比,该控制器高效可靠,易于构建。

第 1 步:接线

完整的示意图如下图所示。


I2C LCD 模块接线:

I2C 模块<--------------> Arduino Pro Mini

地<--------------->地<--------->地

VCC<------------------------>VCC<--------->5V

SDA<------------------------------------------->A4

SCL<----------------------------------------->A5.

旋转编码器模块接线:

编码器<---------------------->Arduino

地<--------------------------->地

+<-------------------------------->NC(未连接,代码使用arduino内置输入上拉)

SW<----------------------------->D5

DT<------------------------------>D3

时钟<---------------------------->D4.

手柄接线: (7 线)

3pin 连接器 -(绿色、黑色、红色)

红线<----------------------->热电偶+

绿线<-------------------->簧片开关

黑线<--------------------->公共地线。

2 针连接器 -(蓝色、黄色)

蓝线<-------------------------> 风扇+0

黄线<------------------------>Fan - (or GND)

2 大针连接器 -(白色,棕色)

白线<-----------------------> 加热器

棕线<----------------------> 加热器(无极性)

注意:

不同类型的魔杖,热风枪手柄的接线可能会有所不同。因此,请参考照片中的接线图并沿着电线的路径找到相应的引脚。

第二步:电路图

电路主要由3部分组成。

界面部分:

它由带 I2C 模块的 1602 LCD 显示器和带按钮的旋转编码器组成。显示屏显示设置温度、当前温度、风扇速度和施加的功率以及手柄的当前状态。编码器用于各种输入以及浏览选项和控件。

传感器部分:

它由一个用于温度传感的 K 型热电偶和一个用于确定手柄位置的簧片开关组成。热电偶的电压由运算放大器放大到 arduino 可测量的电压电平。运放增益由200K微调电位器控制。

控制器部分:

该电路中主要有2个控制器。一个是带有 MOSFET 的简单 PWM 风扇速度控制器。另一个是加热器的隔离控制器。它由一个由光耦合 DIAC 驱动的 TRIAC 组成,它是通过控制传送到加热器的波周期数来完成的。 4N25光耦有助于保持与交流波形的同步。

第三步:印刷电路板

这个项目的电路有点复杂,所以我建议你使用印刷电路板而不是点PCB。如果您想制作自己的 PCB,我在项目结束时附上了 eagle 文件。但是,如果您想让 PCB 制造公司完成它们,您可以从 JLCPCB 订购

.您可以通过此链接查看 Easy EDA 设计:https://easyeda.com/ManojBR/harws1-1

第 4 步:代码和库

该计划是项目中最关键的部分,非常感谢 sfrwmaker 编写程序。程序使用PID算法 控制电源以保持设定温度。它的工作原理是控制每秒传递到手柄的波形周期数。

当控制器打开时,魔杖将处于关闭状态。通过旋转编码器 温度和风扇速度可以调节。 短按 编码器将在风扇速度和设置温度调节之间切换。

热风枪从支架上抬起后立即开始加热并显示就绪,并在达到设定温度时发出短促的哔声。将其放回支架后,它会立即关闭加热。但是,风扇将继续吹直到达到安全温度。温度低于50℃后会发出短促的哔声并显示COLD。

当热风枪关闭时,控制器将进入设置模式 如果编码器长按 .

设置模式有校准、调谐、保存和取消以及重置配置选项。

注意: 如果您使用的是 easyEDA 的 PCB 那么你应该将簧片开关的引脚号更改为引脚号。 8 和蜂鸣器引脚到引脚 6

您必须安装 Commoncontrols-master 库和 time-master 库才能使代码正常工作。

注意: 刷固件时请勿将控制器连接到电源插座。风扇的非隔离电源可能会损坏您的笔记本电脑。

从项目页面下载草图源代码。

第 5 步:设置

温度读数应与原始值校准以获得合理的读数。因此,为了做到这一点,您应该按照以下步骤操作。

首先,进入设置模式并选择调谐选项。在调谐模式下,屏幕上显示内部温度(0-1023)。旋转编码器以手动选择热风枪的施加功率。将喷枪加热至 400 度。当温度和分散度变低时,控制器发出哔哔声。然后调整微调锅以将内部温度设置为大约 900(在内部单位中)。长按编码器返回菜单

然后,进入设置模式选择校准选项。选择校准点:200、300或400度,按下编码器。热风枪将达到所需温度并发出蜂鸣声。通过旋转编码器,输入真实温度。然后选择另一个参考点,对所有校准点重复此过程。

长按后进入主屏幕,然后再次进入设置模式并选择保存。

现在热风返修站已经完成。

第 6 步:视频!

看看视频中控制器的工作。

感谢 sfrwmaker 编写代码。

感谢 LCSC 的支持。 LCSC Electronics是中国发展最快的电子元件供应商之一。 LCSC自2011年成立以来,一直致力于提供海量、正品、现货的商品,旨在为全世界提供更多来自亚洲的优质零部件。更多详情请访问:https://lcsc.com/

如果您必须在家制作自己的 PCB,请查看本教程:https://www.instructables.com/id/PCB-Making-1/

谢谢。

代码

  • 固件 1.4
固件 1.4C/C++
主动/被动蜂鸣器支持。请更改 BUZZER_ACTIVE 参数
不再增加旋转编码器。值变化 1.
/* * 基于 atmega328 IC 的热风枪控制器 * 1.4 版 * 2020 年 12 月 5 日发布 */#include #include #include  #include #include #include #include const uint16_t temp_minC =100; // 控制器可以准确检测的最低温度const uint16_t temp_maxC =500; // 最大可能温度const uint16_t temp_ambC =25; // 平均环境温度const uint16_t temp_tip[3] ={200, 300, 400}; //校准的温度参考点const uint16_t min_working_fan =100; // 最小可能的风扇速度const uint8_t AC_SYNC_PIN =2; // 出口 220 v 同步引脚。不要改变!const uint8_t HOT_GUN_PIN =7; // 热枪加热器管理 pinconst uint8_t FAN_GUN_PIN =9; // 热枪风扇管理引脚。不要换! const uint8_t TEMP_GUN_PIN =A0; // 热枪温度检查 pinconst uint8_t R_MAIN_PIN =3; // 旋转编码器主引脚。不要改变!const uint8_t R_SECD_PIN =4; // 旋转编码器辅助 pinconst uint8_t R_BUTN_PIN =5; // 旋转编码器按钮 pinconst uint8_t REED_SW_PIN =8; // 簧片开关 pinconst uint8_t BUZZER_PIN =6; // 蜂鸣器 pinconst bool BUZZER_ACTIVE =true; // 当 +5v 提供给它时​​,有源蜂鸣器发出哔哔声//------------------------------------ ----- 配置数据 ------------------------------------------- -----/* EEPROM中的配置记录格式如下: * uint32_t ID每次加1 * struct cfg config data, 8 bytes * byte CRC the checksum*/struct cfg { uint32_tcalibration; // 三个温度点打包校准数据 uint16_t temp; // 内部单位IRON的预设温度uint8_t fan; // 预设风扇转速 0 - 255 uint8_t off_timeout; // 自动关闭超时};class CONFIG { public:CONFIG() { can_write =false; buffRecords =0; rAddr =wAddr =0;长度 =0; nextRecID =0; uint8_t rs =sizeof(struct cfg) + 5; // 总配置记录大小 // 选择合适的记录大小;记录大小应该是 2 的幂,即 8, 16, 32, 64, ... 字节 (record_size =8; record_size  recID){ minRecID =recID; minRecAddr =地址; } if (maxRecID  eLength) wAddr =0; } else { wAddr =minRecAddr; } can_write =true;}void CONFIG::getConfig(struct cfg &Cfg) { memcpy(&Cfg, &Config, sizeof(struct cfg));}void CONFIG::updateConfig(struct cfg &Cfg) { memcpy(&Config, &Cfg, sizeof( struct cfg));}bool CONFIG::saveConfig(struct cfg &Cfg) { updateConfig(Cfg);返回保存(); // 将新数据保存到 EEPROM}bool CONFIG::save(void) { if (!can_write) return can_write;如果 (nextRecID ==0) nextRecID =1; uint16_t startWrite =wAddr; uint32_t nxt =nextRecID; uint8_t summ =0; for (uint8_t i =0; i <4; ++i) { EEPROM.write(startWrite++, nxt &0xff);总和<=2;总和 +=nxt; nxt>>=8; } uint8_t* p =(byte *)&Config; for (uint8_t i =0; i  EEPROM.length()) wAddr =0; nextRecID++; // 准备写下一条记录 return true;}bool CONFIG::load(void) { bool is_valid =readRecord(rAddr, nextRecID); nextRecID++; return is_valid;}bool CONFIG::readRecord(uint16_t addr, uint32_t &recID) { uint8_t Buff[record_size]; for (uint8_t i =0; i =0; --i) { ts <<=8; ts |=Buff[byte(i)]; recID =ts; memcpy(&Config, &Buff[4], sizeof(struct cfg));返回真; } return false;}//-------------------------------------------类热枪配置 ----------------------------------------------类HOTGUN_CFG :公共配置 { 公共:HOTGUN_CFG() { } void init(void); uint16_t tempPreset(void); // 内部单位的预设温度 uint8_t fanPreset(void); // 预设风扇转速 0 - 255 uint16_t tempInternal(uint16_t temp); // 将人类可读的温度转换为内部值 uint16_t tempHuman(uint16_t temp); // 将温度从内部单位转换为摄氏度 void save(uint16_t temp, uint8_t fanSpeed); // 在内部单位和风扇速度中保存预设温度 void applyCalibrationData(uint16_t tip[3]); void getCalibrationData(uint16_t tip[3]); void saveCalibrationData(uint16_t tip[3]); void setDefaults(bool Write); // 如果无法从 EEPROM 加载数据,则设置默认参数值 private:uint16_t t_tip[3]; const uint16_t def_tip[3] ={587, 751, 850}; // 参考温度下内部传感器读数的默认值 const uint16_t min_temp =50; const uint16_t max_temp =900; const uint16_t def_temp =600; // 默认预设温度 const uint8_t def_fan =64; // 默认预设风扇速度 0 - 255 const uint16_tambient_temp =0; const uint16_tambient_tempC=25;};void HOTGUN_CFG::init(void) { CONFIG::init(); if (!CONFIG::load()) setDefaults(false); // 如果从 EEPROM 加载数据失败,则使用默认值初始化配置数据 uint32_t cd =Config.calibration; t_tip[0] =cd &0x3FF; cd>>=10; // 每个校准参数 10 位,因为 ADC 读数是 10 位 t_tip[1] =cd &0x3FF; cd>>=10; t_tip[2] =cd &0x3FF; // 检查提示校准是否正确 if ((t_tip[0]>=t_tip[1]) || (t_tip[1]>=t_tip[2])) { setDefaults(false); for (uint8_t i =0; i <3; ++i) t_tip[i] =def_tip[i]; } return;} uint32_t校准; // 三个温度点打包校准数据 uint16_t temp; // 内部单位IRON的预设温度uint8_t fan; // 预设风扇转速 0 - 255 uint8_t off_timeout; // 自动关闭超时uint16_t HOTGUN_CFG::tempPreset(void) { return Config.temp;}uint8_t HOTGUN_CFG::fanPreset(void) { return Config.fan;}uint16_t HOTGUN_CFG::tempInternal(uint16_t t) { // 翻译人类可读温度转换为内部值 t =constrain(t, temp_minC, temp_maxC); uint16_t 左 =0; uint16_t 右 =1023; // 内部单位的最高温度值 uint16_t temp =map(t, temp_tip[0], temp_tip[2], t_tip[0], t_tip[2]); if (temp>
 (left+right)/ 2) { temp -=(right-left) / 4; } else { temp +=(right-left) / 4; } for (uint8_t i =0; i <20; ++i) { uint16_t tempH =tempHuman(temp);如果(tempH ==t){ 返回温度; } uint16_t new_temp;如果(tempH > 1; } t_tip[0] =提示[0]; t_tip[1] =提示[1];如果(提示 [2]> max_temp)提示 [2] =max_temp; t_tip[2] =tip[2];}void HOTGUN_CFG::getCalibrationData(uint16_t tip[3]) {tip[0] =t_tip[0];提示[1] =t_tip[1]; tip[2] =t_tip[2];}void HOTGUN_CFG::saveCalibrationData(uint16_t tip[3]) { if (tip[2]> max_temp) tip[2] =max_temp; uint32_t cd =提示 [2] &0x3FF; cd <<=10; // 将尖端校准数据打包到一个 32 位字中:每个值 10 位 cd |=tip[1] &0x3FF; cd <<=10; cd |=提示[0]; Config.calibration =cd; t_tip[0] =提示[0]; t_tip[1] =提示[1]; t_tip[2] =tip[2];}void HOTGUN_CFG::setDefaults(bool Write) { uint32_t c =def_tip[2] &0x3FF; c<=10; c |=def_tip[1] &0x3FF; c<=10; c |=def_tip[0] &0x3FF; Config.calibration =c; config.temp =def_temp; config.fan =def_fan;如果(写){ CONFIG::save(); }}//-------------------------------------------类蜂鸣器 -- -------------------------------------------------- --class BUZZER { public:BUZZER(byte buzzerP, bool active =true) { buzzer_pin =buzzerP;这-> 活动 =活动;无效初始化(无效); void shortBeep(void);无效lowBeep(无效); void doubleBeep(void);无效失败Beep(无效);私人:字节蜂鸣器_pin; bool active;};void BUZZER::init(void) { pinMode(buzzer_pin, OUTPUT); if (active) { digitalWrite(buzzer_pin, LOW); } else { noTone(buzzer_pin); }}void BUZZER::shortBeep(void) { if (active) { digitalWrite(buzzer_pin, HIGH);延迟(80);数字写入(蜂鸣器引脚,低); }其他{音(蜂鸣器针,3520,160); }}void BUZZER::lowBeep(void) { if (active) { digitalWrite(buzzer_pin, HIGH);延迟(160);数字写入(蜂鸣器引脚,低); } else { 音调(蜂鸣器引脚,880, 160); }}void BUZZER::doubleBeep(void) { if (active) { digitalWrite(buzzer_pin, HIGH);延迟(160);数字写入(蜂鸣器引脚,低);延迟(150);数字写入(蜂鸣器引脚,高);延迟(160);数字写入(蜂鸣器引脚,低); }其他{音(蜂鸣器针,3520,160);延迟(300);音调(蜂鸣器针,3520,160); }}void BUZZER::failedBeep(void) { if (active) { digitalWrite(buzzer_pin, HIGH);延迟(170);数字写入(蜂鸣器引脚,低);延迟(10);数字写入(蜂鸣器引脚,高);延迟(80);数字写入(蜂鸣器引脚,低);延迟(100);数字写入(蜂鸣器引脚,高);延迟(80);数字写入(蜂鸣器引脚,低); }其他{音(蜂鸣器针,3520,160);延迟(170);音调(蜂鸣器引脚,880, 250);延迟(260);音调(蜂鸣器针,3520,160); }}//-------------------------------------------类 lcd DSPLay for焊接铁 ----------------------------- 类 DSPL :受保护的 LiquidCrystal_I2C { public:DSPL(void) :LiquidCrystal_I2C(0x27, 16, 2) { } void init(void); void clear(void) { LiquidCrystal_I2C::clear(); } void tSet(uint16_t t, bool 摄氏 =真); // 显示预设温度 void tCurr(uint16_t t); // 显示当前温度 void tInternal(uint16_t t); // 以内部单位显示当前温度 void tReal(uint16_t t); // 在校准模式下以摄氏度显示真实温度 void fanSpeed(uint8_t s); // 显示风扇速度 void appliedPower(uint8_t p, bool show_zero =true); // 显示施加的功率 (%) void setupMode(uint8_t mode); void msgON(void); // 显示消息:"ON" void msgOFF(void); void msgReady(void); void msgCold(void);无效消息失败(无效); // 显示“失败”消息 void msgTune(void); // 显示 'Tune' 消息 private:bool full_second_line; // 第二行是否充满消息 char temp_units;常量uint8_t custom_symbols [3] [8] ={{0b00110,//度0b01001,0b01001,0b00110,0b00000,0b00000,0b00000,0b00000},{0b00100,//范符号0b01100,0b01100,0b00110,0b01011,0b11001,0b10000 , 0b00000 }, { 0b00011, // 功率符号 0b00110, 0b01100, 0b11111, 0b00110, 0b01100, 0b01000, 0b10000 } };};}:void DSPL::C initry LiquidCrystal_I2C::clear();对于 (uint8_t i =0; i <3; ++i) LiquidCrystal_I2C::createChar(i+1, (uint8_t *)custom_symbols[i]); full_second_line =false; temp_units ='C';}void DSPL::tSet(uint16_t t, boolCelsius) { char buff[10];如果(摄氏度){ temp_units ='C'; } else { temp_units ='F'; } LiquidCrystal_I2C::setCursor(0, 0); sprintf(buff, "Set:%3d%c%c", t, (char)1, temp_units); LiquidCrystal_I2C::print(buff);}void DSPL::tCurr(uint16_t t) { char buff[6]; LiquidCrystal_I2C::setCursor(0, 1); if (t <1000) { sprintf(buff, "%3d%c ", t, (char)1); } else { LiquidCrystal_I2C::print(F("xxx"));返回; LiquidCrystal_I2C::print(buff); if (full_second_line) { LiquidCrystal_I2C::print(F(" ")); full_second_line =false; }}void DSPL::tInternal(uint16_t t) { char buff[6]; LiquidCrystal_I2C::setCursor(0, 1); if (t <1023) { sprintf(buff, "%4d ", t); } else { LiquidCrystal_I2C::print(F("xxxx"));返回; LiquidCrystal_I2C::print(buff); if (full_second_line) { LiquidCrystal_I2C::print(F(" ")); full_second_line =false; }}void DSPL::tReal(uint16_t t) { char buff[6]; LiquidCrystal_I2C::setCursor(11, 1); if (t <1000) { sprintf(buff, ">%3d%c", t, (char)1); } else { LiquidCrystal_I2C::print(F("xxx"));返回; } LiquidCrystal_I2C::print(buff);}void DSPL::fanSpeed(uint8_t s) { char buff[6]; s =地图(s, 0, 255, 0, 99); sprintf(buff, " %c%2d%c", (char)2, s, '%'); LiquidCrystal_I2C::setCursor(11, 1); LiquidCrystal_I2C::print(buff);}void DSPL::appliedPower(uint8_t p, bool show_zero) { char buff[6];如果 (p>
 99) p =99; LiquidCrystal_I2C::setCursor(5, 1); if (p ==0 &&!show_zero) { LiquidCrystal_I2C::print(F(" ")); } else { sprintf(buff, " %c%2d%c", (char)3, p, '%'); LiquidCrystal_I2C::print(buff); }}void DSPL::setupMode(byte mode) { LiquidCrystal_I2C::clear(); LiquidCrystal_I2C::print(F("setup")); LiquidCrystal_I2C::setCursor(1,1); switch (mode) { case 0:// 尖端校准 LiquidCrystal_I2C::print(F("calibrate"));休息; case 1:// 调整 LiquidCrystal_I2C::print(F("tune"));休息; case 2:// 保存 LiquidCrystal_I2C::print(F("save"));休息; case 3:// 取消 LiquidCrystal_I2C::print(F("cancel"));休息; case 4:// 设置默认值 LiquidCrystal_I2C::print(F("reset config"));休息;默认值:中断; }}void DSPL::msgON(void) { LiquidCrystal_I2C::setCursor(10, 0); LiquidCrystal_I2C::print(F(" ON"));}void DSPL::msgOFF(void) { LiquidCrystal_I2C::setCursor(10, 0); LiquidCrystal_I2C::print(F("OFF"));}void DSPL::msgReady(void) { LiquidCrystal_I2C::setCursor(10, 0); LiquidCrystal_I2C::print(F("Ready"));}void DSPL::msgCold(void) { LiquidCrystal_I2C::setCursor(10, 0); LiquidCrystal_I2C::print(F("Cold"));}void DSPL::msgFail(void) { LiquidCrystal_I2C::setCursor(0, 1); LiquidCrystal_I2C::print(F(" -==Failed ==- "));}void DSPL::msgTune(void) { LiquidCrystal_I2C::setCursor(0, 0); LiquidCrystal_I2C::print(F("Tune"));}//--------------------------------- -------- 班级历史 ---------------------------------------- ------------#define H_LENGTH 16class HISTORY { public:HISTORY(void) { len =0; } void init(void) { len =0; } uint16_t 最后(无效); uint16_t 顶部(无效){ 返回队列 [0]; } void put(uint16_t item); // 将新条目放入历史记录 uint16_t average(void); // 计算平均值浮动离散度(void); // 计算数学离散度 private:volatile uint16_t queue[H_LENGTH];可变字节长度; // 队列中元素的个数 volatile byte index; // 当前元素位置,使用环形缓冲区};void HISTORY::put(uint16_t item) { if (len =H_LENGTH)索引=0; // 使用环形缓冲区 }}uint16_t HISTORY::last(void) { if (len ==0) return 0; uint8_t i =len - 1;如果(索引)i =索引 - 1;返回队列[i];}uint16_t HISTORY::average(void) { uint32_t sum =0;如果(len ==0)返回0;如果(len ==1)返回队列[0]; for (uint8_t i =0; i > 1; // 舍入平均总和 /=len; return uint16_t(sum);}float HISTORY::dispersion(void) { if (len <3) return 1000; uint32_t 总和 =0; uint32_t avg =平均值(); for (uint8_t i =0; i > 1;更新(值); return (emp_data + round_v) / emp_k;}void EMP_AVERAGE::update(int32_t value) { uint8_t round_v =emp_k>> 1; emp_data +=value - (emp_data + round_v) / emp_k;}int32_t EMP_AVERAGE::read(void) { uint8_t round_v =emp_k>> 1; return (emp_data + round_v) / emp_k;}//-------------------------------------- ----类PID算法来保持温度-----------------------/* PID算法 * Un =Kp*(Xs - Xn) + Ki*summ{j=0; j<=n}(Xs - Xj) + Kd(Xn - Xn-1), * 其中 Xs - 是设置温度,Xn - n 迭代步骤的温度 * 在这个程序中使用了交互式公式: * Un =Un-1 + Kp*(Xn-1 - Xn) + Ki*(Xs - Xn) + Kd*(Xn-2 + Xn - 2*Xn-1) * 第一步: * U0 =Kp*( Xs - X0) + Ki*(Xs - X0); Xn-1 =Xn; * * PID 系数历史: * 10/14/2017 [768, 32, 328] * 11/27/2019 [ 2009, 1600, 20] * 04/27/2020 [ 50, 16, 50] */class PID {公共:PID(无效){ Kp =50; Ki =16; Kd =50; } void resetPID(int temp =-1); // 重置 PID 算法历史参数 // 计算要应用的功率 long reqPower(int temp_set, int temp_curr); int changePID(uint8_t p, int k); // 设置或获取(如果参数 <0)PID 参数 private:void debugPID(int t_set, int t_curr, long kp, long ki, long kd, long delta_p); int temp_h0, temp_h1; // 先前测量的温度 bool pid_iterate; // 是否使用迭代过程 long i_summ; // Ki 汇总乘以分母 long power; // 幂迭代乘以分母 long Kp, Ki, Kd; // The PID algorithm coefficients multiplied by denominator const byte denominator_p =11; // The common coefficient denominator power of 2 (11 means divide by 2048)};void PID::resetPID(int temp) { temp_h0 =0; power =0; i_summ =0; pid_iterate =false; if ((temp>
 0) &&(temp <1000)) temp_h1 =temp; else temp_h1 =0;}int PID::changePID(uint8_t p, int k) { switch(p) { case 1:if (k>=0) Kp =k; return Kp; case 2:if (k>=0) Ki =k; return Ki; case 3:if (k>=0) Kd =k; return Kd; default:break; } return 0;}long PID::reqPower(int temp_set, int temp_curr) { if (temp_h0 ==0) { // When the temperature is near the preset one, reset the PID and prepare iterative formula if ((temp_set - temp_curr) <30) { if (!pid_iterate) { pid_iterate =true; power =0; i_summ =0; } } i_summ +=temp_set - temp_curr; // first, use the direct formula, not the iterate process power =Kp*(temp_set - temp_curr) + Ki*i_summ; // If the temperature is near, prepare the PID iteration process } else { long kp =Kp * (temp_h1 - temp_curr); long ki =Ki * (temp_set - temp_curr); long kd =Kd * (temp_h0 + temp_curr - 2*temp_h1); long delta_p =kp + ki + kd; power +=delta_p; // power kept multiplied by denominator! } if (pid_iterate) temp_h0 =temp_h1; temp_h1 =temp_curr; long pwr =power + (1 <<(denominator_p-1)); // prepare the power to delete by denominator, round the result pwr>>=denominator_p; // delete by the denominator return pwr;}//--------------------- High frequency PWM signal calss on D9 pin ------------------------- ---------------class FastPWM_D9 { public:FastPWM_D9() { } void init(void); void duty(uint8_t d) { OCR1A =d; } uint8_t fanSpeed(void) { return OCR1A; }};void FastPWM_D9::init(void) { pinMode(9, OUTPUT);数字写入(9,低); noInterrupts(); TCNT1 =0; TCCR1B =_BV(WGM13); // set mode as phase and frequency correct pwm, stop the timer TCCR1A =0; ICR1 =256; TCCR1B =_BV(WGM13) | _BV(CS10); // Top value =ICR1, prescale =1 TCCR1A |=_BV(COM1A1); // XOR D9 on OCR1A, detached from D10 OCR1A =0; // Switch-off the signal on pin 9; interrupts();}//--------------------- Hot air gun manager using total sine shape to power on the hardware ---------------class HOTGUN :public PID { public:typedef enum { POWER_OFF, POWER_ON, POWER_FIXED, POWER_COOLING } PowerMode; HOTGUN(uint8_t HG_sen_pin, uint8_t HG_pwr_pin); void init(void); bool isOn(void) { return (mode ==POWER_ON || mode ==POWER_FIXED); } void setTemp(uint16_t temp) { temp_set =constrain(temp, 0, int_temp_max); } uint16_t getTemp(void) { return temp_set; } uint16_t getCurrTemp(void) { return h_temp.last(); } uint16_t tempAverage(void) { return h_temp.average(); } uint8_t powerAverage(void) { return h_power.average(); } uint8_t appliedPower(void) { return actual_power; } void setFanSpeed(uint8_t f) { fan_speed =constrain(f, min_working_fan, max_fan_speed); } uint8_t getFanSpeed(void) { return fan_speed; } uint16_t tempDispersion(void) { return h_temp.dispersion(); } bool isCold(void) { return h_temp.average() =period) { cnt =0; last_period =millis(); // Save the current time to check the external interrupts if (!active &&(actual_power> 0)) { digitalWrite(gun_pin, HIGH); active =true; } } else if (cnt>=actual_power) { if (active) { digitalWrite(gun_pin, LOW); active =false; } } if (!active) { e_sensor.update(analogRead(sen_pin)); } return (cnt ==0); // End of the Power period (period AC voltage shapes)}void HOTGUN::switchPower(bool On) { switch (mode) { case POWER_OFF:if (hg_fan.fanSpeed() ==0) { // Not power supplied to the Fan if (On) // !FAN &&On mode =POWER_ON; } else { if (On) { if (isGunConnected()) { // FAN &&On &&connected mode =POWER_ON; } else { // FAN &&On &&!connected shutdown(); } } else { if (isGunConnected()) { // FAN &&!On &&connected if (isCold()) { // FAN &&!On &&connected &&cold shutdown(); } else { // FAN &&!On &&connected &&!cold mode =POWER_COOLING; } } } } break; case POWER_ON:if (!On) { mode =POWER_COOLING; } 休息; case POWER_FIXED:if (hg_fan.fanSpeed()) { if (On) { // FAN &&On mode =POWER_ON; } else { // FAN &&!On if (isGunConnected()) { // FAN &&!On &&connected if (isCold()) { // FAN &&!On &&connected &&cold shutdown(); } else { // FAN &&!On &&connected &&!cold mode =POWER_COOLING; } } } } else { // !FAN if (!On) { // !FAN &&!On shutdown(); } } break; case POWER_COOLING:if (hg_fan.fanSpeed()) { if (On) { // FAN &&On if (isGunConnected()) { // FAN &&On &&connected mode =POWER_ON; } else { // FAN &&On &&!connected shutdown(); } } else { // FAN &&!On if (isGunConnected()) { if (isCold()) { // FAN &&!On &&connected &&cold shutdown(); } } else { // FAN &&!On &&!connected shutdown(); } } } else { if (On) { // !FAN &&On mode =POWER_ON; } } } h_power.init();}// This routine is used to keep the hot air gun temperature near required valuevoid HOTGUN::keepTemp(void) { //uint16_t temp =analogRead(sen_pin); // Check the hot air gun temperature //uint16_t temp =emulateTemp(); uint16_t temp =e_sensor.read(); // Average value of the hot air gun temperature h_temp.put(temp); ...This file has been truncated, please download it to see its full contents.
Github
https://github.com/ManojBR105/ARDUINO-SMD-REWORK-STATIONhttps://github.com/ManojBR105/ARDUINO-SMD-REWORK-STATION

示意图

This is the power supply circuit to provide necessary voltage for the controller. hot_air_gunsch_l627KvauMg.sch

制造工艺

  1. 液晶显示器 (LCD)
  2. 制作 DIY Thermocam
  3. Raspberry Pi 2 气象站
  4. Raspberry Pi 气象站
  5. 拥有肖像 – 更新
  6. Weather Station V 2.0
  7. UVC 盒装 DIY 紫外线消毒器
  8. 诺基亚 5110 LCD 上的 DIY 简单 20 kHz Arduino 示波器
  9. LCD 动画和游戏
  10. DIY 10Hz-50kHz 示波器在 128x64 LCD 显示器上
  11. 当地气象站
  12. AI LCD 朋友!