#故事起源#

最近想要吃烤肉,可是没有烤炉怎么办呢,家里有个破电熨斗,改改也许可以,拿来试试吧

不,故事不是这样的,重新再来,最近旺仔爸爸设计的一个作品《斜视矫正器》,该作品是将所有电路做在一个眼镜中的,对电路的体积要求比较高,虽然已经完成了,但作为强迫症的我来说,还是想改进一下,要改进眼镜的电路部分这就需要按照需求重新设计PCB板啦,于是旺仔爸爸先设计一块小型电路板练手,以便将丢失已久PCB设计知识重新拾起来,PCB板设计好了,可是没有贴片机,又不想手工焊,怎么办呢,很早之前在油管上看到一位大佬用电熨斗做的回流焊加热台非常的好用,家里正好有电熨斗,那就改造一个微型回流焊热台吧,以表达我对大佬的敬意和感谢,我给它起名Micro reflow welder,先来欣赏一下它的制作视频

#方案介绍#

声明:本次分享的是一个模拟回流焊加工工艺的DIY作品,并非工业级的回流焊设备

首先科普一下回流焊焊接工艺

电子焊接技术广泛应用在电子制造领域,随着更小封装体积的贴片元件的出现,让电子产品更新换代的速度变得越来越快、越来越智能,PCB电路板的集成度也变得越来越高,而为了满足各种贴片元件的焊接,回流焊工艺技术就应运而生了,目前几乎在所有电子产品领域都已得到应用,我们的电脑,手机内使用的各种电子元件都是通过这种工艺焊接到电路板上的

综上所述就是,选择贴片回流焊的焊接工艺可以设计制作体积更加小巧的PCB电路板

这种焊接设备的内部有加热平台,焊接时需要在PCB电路板的焊盘上刷锡膏,接着将各种贴片元件正确放置在焊盘上,当加热到足够锡膏融化的温度时,电子元件就会与PCB电路板牢固的贴合在一起了

而我们本次使用一种DIY的方法制作一个微型的回流焊加热台

加热平台选择了电熨斗的加热板

电熨斗有自动加热断电、温度调节的功能,这么低廉的价格能把这些功能都做进去太佩服我国的制造业水平了,我们来看下电熨斗拆开后的样子

中间旋钮部分通过物理方式来调节温度,电熨斗自带过载保护电路,在拆解下来的电熨斗中我们只需要加热平台的部分

因为我们要做回流焊加热平台,它需要具备:温度调节、加热功率调节、冷却降温、电路保护等功能,接下来我们对这些功能进行介绍

温度调节

在回流焊焊接的过程中,温度控制是非常关键的一个环节,整个过程大致分为四个阶段,预热区,温度保持区,回流区,冷却区,每个阶段的温度都需要精确控制,而温度检测功能对于回流焊设备来说就显得尤为重要了

回流焊焊接工艺中的峰值温度不宜超过250℃,温度太高容易损坏元器件,所以我们使用测温范围较大的MAX6675热电偶作为温度检测模块,测温范围在0-1024℃,温度分辨率0.25℃

加热功率调节

接着就是根据检测到的温度来调节加热功率,

我们使用一个可以直接输出220V交流电的可控硅模块来调节加热功率,由于可控硅模块自身的缺陷问题,不能完全降压到0v,也就是不能让电熨斗完全停止工作,于是我们需要在电路中增加一个继电器,这样可以通过继电器让加热平台停止工作,也起到了安全保护的作用

冷却降温

箱体中我们使用一个5V的静音风扇,目的是让各种电子元件不至于过热

而为了快速降低加热平台的温度,我们使用一个8000r/min的暴力风扇

控制风扇必不可少的就是电机驱动,这次我们本着有什么用什么的原则,使用了一个L298N型号的电机驱动

使用一个电位器来设定加热的目标温度,用一个按键作为是否开始工作的按钮

最后我们将所有检测到数据显示在0.96寸的OLED屏幕中即可

因为本次作品中接入了220v交流电,我们只需要再找了一块手机充电头里的电路板,就可以将220V的电源经过转换给控制器供电了,这里需要强调的是,由于用到了强电,在制作和调试的过程中一定要注意安全

各种器材确定后,我们就可以开始制作了

#设计制作#

本次我们制作的Micro reflow welder,用到的材料清单如下:

#硬件清单#

  • arduino nano控制器+扩展板*1

  • MAX6675热电偶模块*1

  • 可控硅模块*1

  • 数字按键*1

  • 电位器*1

  • 0.96寸OLED屏幕*1

  • L298N电机驱动*1

  • 手机充电电路板*1

  • 5v散热风扇*2

  • 开关*1

  • AC接口*1

  • 电熨斗加热平台*1

  • 万向臂*1

  • 五金杜邦线若干

  • 3mm奥松板40*60一块

#图纸设计#

使用Fusion360计算机辅助设计软件设计3维模型

利用lasermaker软件处理图纸并使用激光切割机把它加工出来,材料选择3mm的奥松板

加工完成后的结构如下图

#电路设计#

接着我们进行电路设计

Micro reflow welder用到的电子器件会稍微有点多,需要仔细按照接线图接线

主控我们选择最普通的arduino nano,为了给控制器提供5v电压,这里拆解了一个手机充电器中的电路板来将200v电源转换为5v电源给控制器供电,在风扇接线时一定要注意正负极,正负极反接是不会工作的,还有可能损坏风扇

电路接线如下图所示

#组装#

Micro reflow welder的组装非常的简单,只需几步即可完成

1.将所有电子器件安装在底板、前面板和左右侧板上

开关、OLED屏幕、电位器和按键安装在前面板上

静音风扇和交流电源接口安装在右侧板上

暴力风扇的电线穿过万向臂然后将万向臂安装在左侧板上,

2.电子器件安装完成后,将4块侧板拼装在一起,然后将拼装好的4块侧板与底板安装在一起

3.结构件安装完毕后按照前文中的电路图连接内部电路

4.将电熨斗加热平台安装在顶板上,并与前面已经安装好的部分拼装在一起

安装完毕后的效果如下图

别忘记将测温电路和加热电路从顶板穿出与加热平台连接

最后就是程序设计了,开始程序设计前,我们需要先捋一下Micro reflow welder的运作方式

#程序设计#

这是Micro reflow welder的工作流程

本次作品程序编写我们使用Arduino IDE编程环境,关于Arduino IDE 编程环境的下载安装,可以在<mixly.org>官网下载到最新版本的mixly软件,自带的Arduino IDE 编程环境做好了各种配置,省去了我们去配置各种控制板的过程,大大提高了效率

编程环境配置好后下面我们从最简单的温度测量开始掌握

温度测量

从前文中我们知道本次我们使用MAX6675热电偶模块来检测温度,电路正确连接后,我们进行测试

第一步添加库文件,我们打开Arduino IDE编程环境,选择<库管理>,搜索栏输入“MAX6675”关键词,找到<MAX6675_Thermocouple>库文件并安装

打开如下示例程序,设定好引脚编号,选择正确的板卡和串口后下载并运行

#include <Thermocouple.h>
#include <MAX6675_Thermocouple.h>
#define SCK_PIN 8  //热电偶引脚
#define CS_PIN 9  //热电偶引脚
#define SO_PIN 10  //热电偶引脚
Thermocouple* thermocouple;
void setup() {Serial.begin(9600);thermocouple = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN);
}
void loop() {const double celsius = thermocouple->readCelsius();const double kelvin = thermocouple->readKelvin();const double fahrenheit = thermocouple->readFahrenheit();Serial.print("Temperature: ");Serial.print(celsius);Serial.print(" C, ");Serial.print(kelvin);Serial.print(" K, ");Serial.print(fahrenheit);Serial.println(" F");delay(500);
}

下载完成,打开串口监视器,如果看到了3种不同单位的温度数值,说明我们运行成功了,这一步非常的关键,意味着我们已经可以用MAX6675来测量温度,接着只需要将程序摄氏度℃单位的温度数据保留,其他删除即可

(K)为国际单位热力学温标,华氏温标(°F)是另一种国际上用得较多的温标

认真阅读上面的示例程序,我们可以知道,温度数据是通过<delay(500)>这条指令实现每隔0.5s检测一次的,而本次项目程序运行过程中如果每次刷新都需要延时等待0.5s的话,显然效率有点太低了,假设我们把这个等待时间删除,或者改成0.05s,这时候你会发现由于刷新速度太快温度数据检测不到了,该如何解决这个问题呢,这时候我们可以引入一个定时器每隔0.3s检测一次温度数据,这样也就再也不会影响主程序的运行了

什么是定时器呢,我们可以简单理解为一个单独运行的闹钟,每隔一段时间就去执行设定好的事情,对主程序不产生任何影响

接下来我们来看一下定时器的使用方法

定时器的用法

我们编写如下程序,下载后查看运行效果

#include <Thermocouple.h>
#include <MAX6675_Thermocouple.h>//热电偶头文件
#include <MsTimer2.h>//定时器头文件
//热电偶接口声明
#define SCK_PIN 8
#define CS_PIN 9
#define SO_PIN 2
double temp_now = 0;//当前温度
//热电偶定义
Thermocouple* thermocouple;
void setup()
{Serial.begin(9600);MsTimer2::set(300, temp_data);//定时器MsTimer2::start();
}
//获取温度函数
void temp_data()
{//当前温度temp_now = thermocouple->readCelsius();Serial.print("temp_now: ");Serial.print(temp_now);Serial.println(" C, ");
}
void loop()
{Serial.println("Micro reflow welder");delay(600);
}

打开串口监视器,我们会看到,温度数据每隔0.3s打印输出一次,字符串"Micro reflow welder"每隔0.6s打印输出一次,相互之间不影响

从程序中,我们不难发现

要使用定时器需要先导入#include <MsTimer2.h>定时器库文件

然后使用如下的指令就可以让< temp_data> 函数每隔0.3s执行一次

MsTimer2::set(300, temp_data);
MsTimer2::start();

而< temp_data> 函数的作用正是前文中我们提到的温度检测的程序,不过旺仔爸爸发现,<MsTimer2.h>定时器使用时会和3号数字引脚冲突,所以要尽量避开

温度检测和定时器的功能掌握后,我们来了解数字信号的处理,首先是数字输入信号

数字输入信号

在本次项目中,我们使用一个按键作为开始按钮,而这个按键的作用就是典型的数字输入信号,我们定义11号数字管脚为按键输入,接着我们下载下面的程序看一下效果

#define button 11 //按键引脚
void setup()
{Serial.begin(9600);
}
void loop()
{int start_button = digitalRead(button);//存储按键状态if(start_button == 0){Serial.print("down!\n\r");}
}

从运行结果中可以看出,当我们按下一次按键时<start_button == 0>,也就是低电平时,会在串口监视器中打印很多字符串“down”

为什么按了一次会打印很多个字符串出来呢,那是因为控制器的刷新频率非常快,它误以为我们按了很多次按键,所以会打印多个字符串,理论上如果我们的手速足够快是可以做到按下一次打印一次的,但那样好像并不太现实,有没有其他方法能做到每按一次就打印一个字符串呢,这里就涉及到了我们常用的消抖技巧了

我们对上面的程序进行修改,一起来看程序

#define button 11 //按键引脚
void setup()
{Serial.begin(9600);
}
void loop()
{int start_button = digitalRead(button);//存储按键状态if(start_button == 0)//两次检测按键的状态{delay(1000); if ( digitalRead(button) == 0){Serial.print("start! \n\r");} }
}

这时候我们在程序中设置对按键的状态进行了两次检测

当我们按下按键时长超过1s会在串口监视器打印一个“start”字符串,而误触按键是不会起到任何作用的

数字输入信号的知识掌握后,我们来看一下数字输出信号如何处理

数字输出信号

本次作品用到的继电器模块就是典型的数字输出信号的应用,通常继电器有常闭和常开两种接线端子可以用来连接电路,当我们使用常开引脚接线时,数字引脚输出高电平<HIGH>时继电器导通,数字引脚输出低电平<LOW>时继电器断开,指令如下:

digitalWrite(relay,LOW);
digitalWrite(relay,HIGH);

接着我们将继电器的控制与按键程序结合,改进后的程序如下

#define button 11 //按键引脚
#define relay 12 //继电器引脚
void setup()
{Serial.begin(9600);pinMode(relay, OUTPUT);//继电器
}
void loop()
{int start_button = digitalRead(button);//存储按键状态if(start_button == 0)//两次检测按键的状态{delay(1000); if ( digitalRead(button) == 0){digitalWrite(relay,HIGH);Serial.print("start! \n\r");} }else{digitalWrite(relay,LOW);}
}

程序中,我们增加了12号数字引脚为继电器控制引脚,这里需要注意的是在<void setup()>初始化的程序中需要将继电器的引脚设置为输出状态<pinMode(relay, OUTPUT)>,然后就可以在数字按键检测程序的基础上增加继电器控制了,程序下载后可以看到的运行结果是,当按键按下时长超过1s继电器导通,松开后继电器断开

数字输入和数字输出引脚掌握后,我来学习模拟信号的处理

模拟输入信号

在此次作品中用来调节温度的电位器是典型的模拟输入信号

我们将电位器连接主控板的A0引脚,编写如下程序

void setup()
{Serial.begin(9600);
}
void loop()
{Serial.println( analogRead(A0));delay(1000);
}

运行程序,调节电位器可以在串口监视器中看到模拟信号在0-1023之间变化

由于回流焊的峰值温度不宜超过230℃,我们可以利用<map>函数将电位器的模拟信号做一次映射,这样就可以将原本0-1023的范围缩小到0-230了,我们需要将上面的程序做如下改动即可

void setup()
{Serial.begin(9600);
}
void loop()
{int temp_target = analogRead(A0);temp_target = map(temp_target, 0, 1023, 0, 230);Serial.println( temp_target);delay(1000);
}

从串口监视器中的结果中我们可以发现,数据由原来的0-1023变成了0-230

其实,我们还可以将程序做如下调整,把映射后的整数类型的数据转换成字符串类型,这样就可以方便的显示在OLED屏幕中了

temp_target = analogRead(A0);
temp_target = map(temp_target, 0, 1023, 0, 230);
temp_target_str = String(temp_target);//将整数类型转换为字符串类型
Serial.print("temp_now:\n\r");
Serial.print( temp_target_str);

模拟输入信号的处理告一段落,下面我们来了解模拟输出信号

模拟输出信号处理

在我们本次的作品中,用来调节平台加热功率的数据是典型的模拟输出信号,即PWM脉冲宽度调制信号,在Arduino uno或者nano等类型的主控中有6个PWM信号引脚,分别是3、5、6、9、10、11,每个引脚的模拟信号数值范围是0-255,这次我们使用10号引脚作为模拟输出来调节加热功率

在程序中,我们可以定义变量<PWM_PIN>为10号引脚,通过代码<analogWrite(PWM_PIN,255)>就可以调节加热功率了

#define PWM_PIN 10 //可控硅功率调节
void setup()
{Serial.begin(9600);pinMode(PWM_PIN, OUTPUT);//可控硅功率调节
}
void loop()
{analogWrite(PWM_PIN,255);//范围是0-255delay(1000);
}

在回流焊焊接的过程中,功率调节遍布于4个不同的阶段,我们可以将加热功率的程序封装成一个函数,这样就可以很方便的调用,在函数中还可以顺便把前文中讲到的继电器的控制指令加进去,调节加热功率的函数如下:

加热功率调节

#define PWRFULL  230//满加热功率
#define PWM_PIN  10 //可控硅功率调节
#define relay  12 //继电器引脚
//加热功率函数
void setup()
{pinMode(relay, OUTPUT);//继电器pinMode(PWM_PIN, OUTPUT);//可控硅功率调节
}
void set_heat(int PWR_HEAT)
{if (PWR_HEAT == 0){digitalWrite(relay,LOW);//继电器断开analogWrite(PWM_PIN,0);}else{digitalWrite(relay,HIGH);//设置功率PWR = PWRFULL*PWR_HEAT/100; //PWRFUL为满加热功率hot = String(PWR_HEAT);//转换成字符串类型,方便屏幕显示analogWrite(PWM_PIN,PWR);}
}

现在我们已经掌握了调节加热功率的函数,那么都有哪些阶段需要调节加热功率呢,我们一起来了解一下

加热功率的划分

首先我们需要知道回流焊焊接工艺的温度曲线

根据上图,我们解读一下每个阶段的作用

预热阶段:其目的是将电路板及元件的温度从室温提升到锡膏内助焊剂发挥作用所需的活性温度135℃,加热速率应控制在每秒 1~3℃,温度升得太快会引起元件损坏

温度保持阶段:其目的是将电路板及元件维持在某个特定温度范围并持续一段时间,使各个区域的元器件温度相同,减少他们的相对温差,并使锡膏内部的助焊剂充分的发挥作用,一般普遍的活性温度范围是 135-170℃,时间设定在 60-90 秒。时间设定的过长会使锡膏内的助焊剂过度挥发,致使在焊接时焊点易氧化,时间太短则参与焊接的助焊剂过多,可能会出现锡球,锡珠等焊接不良的情况

回流阶段:其目的是使电路板的温度提升到锡膏的熔点温度以上并维持一定的焊接时间,完成元器件引脚与焊盘的焊接。该区的温度设定在 183℃以上,时间为 30-90秒,峰值不宜超过 230℃,如果温度低于183℃将无法形成合金实现不了焊接,若高于 230℃会对元器件带来损害,如果时间不足会使合金层较薄,焊点的强度不够,时间较长则合金层较厚使焊点较脆。

冷却阶段:其目的是使电路板降温,通常设定为每秒 3-4℃。如速率过高会使焊点出现龟裂现象,过慢则会加剧焊点氧化。理想的冷却曲线应该是和回流阶段曲线成镜像关系

我们从回流焊的温度曲线可以知道,完成一次回流焊的过程对时间和温度的把控要求非常高,灵活的控制温度是本次编写程序的核心,旺仔爸爸将本次作品温度控制的每个阶段进行了划分,我们需要按照每个阶段的温度要求来编写程序

这里解读部分代码给大家做进一步了解,我们查看如下程序,程序中<PRE>表示预热阶段,<KEEP>表示温度保持阶段,<FAST>表示温度快速爬升阶段,我们通过几组条件判断语句比较当前温度和目标温度的大小来切换进入不同的阶段

if(temp_now < temp_target && temp_now <130) { MODEL = PRE; count_keep = 0;i=1;} //温度小于140℃,预热状态
else if(temp_now < temp_target && temp_now >=130 && count_keep < 450)      { MODEL = KEEP;i=2; }    //温度大于140℃,进入保持状态,计数开始
else if(temp_now < temp_target && temp_now >=130 && count_keep >= 450)    { MODEL = FAST;i=3;  }    //保持结束,进入爬升状态

控制降温风扇

为了控制两个降温风扇,我们需要掌握电机驱动的编程方法

普通的直流电机控制无外乎正反转和速度这两方面

通过调节数字引脚的高低电平实现电机正反转

通过调节PWM引脚的数值实现电机调速

下面我们来看一个例子

#define dirpin 7  //方向引脚
#define speedpin 6  //速度引脚
digitalWrite(dirpin, LOW);//HIGH正转,LOW反转
analogWrite(speedpin, 200);

我们定义7号数字引脚来控制直流电机正反转,高电平正转,低电平反转,定义6号PWM引脚来控制直流电机的转速,速度范围是0-255

因为我们有两个风扇,需要用到两个数字引脚和两个PWM引脚,为了调用起来更加方便我们可以封装一个函数

//控制电机函数
void setMotor(int speedpin, int dirpin, int speed)
{if (speed == 0){digitalWrite(dirpin, LOW);analogWrite(speedpin, 0);}else if (speed > 0){digitalWrite(dirpin, LOW);analogWrite(speedpin, speed);}else{digitalWrite(dirpin, HIGH);analogWrite(speedpin, 255 + speed);}
}

使用时只需要修改引脚号和速度值就可以实现对两个风扇的任意控制了

最后是OLED屏幕的使用方法

下面我们从屏幕显示最基础的方法开始介绍

OLED屏幕显示

OLED其实就是一个M x N 的像素点阵,想显示什么内容就得把具体位置的像素点亮起来。我们用坐标系来表示每一个像素点,

在坐标系中,左上角是原点,向右是X轴,向下是Y轴。

对OLED有了基本了解后,我们开始编写程序

第一步添加库文件,在Arduino ide编程环境中选择<库管理>,搜索栏输入“U8g2”关键词,找到<U8g2>库文件并安装

为什么要用U8g2库?主要考虑几个方面:

  • U8g2库支持绝大部分Arduino开发板和市面上绝大多数型号的OLED屏幕;

  • U8g2库 API众多,特别支持了中文,支持了不同字体,这对于一个开发者来说是福音,可以大大减小工作量。

U8g2库安装完毕,测试一下库是否安装成功:

#include <U8g2lib.h>
void setup() {// put your setup code here, to run once:
}
void loop() {// put your main code here, to run repeatedly:
}

如果编译成功,没有报错,说明U8g2库文件已经可以使用了,我们编写下面的程序,查看效果

#include <U8g2lib.h>//显示屏头文件
#include <Wire.h>//i2c头文件
//显示屏定义
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
//oled屏幕显示函数
void page1() {//设置字体,字号,字形u8g2.setFont(u8g2_font_timR10_tf);u8g2.setFontPosTop();//设置光标位置u8g2.setCursor(0,20);u8g2.print("Micro reflow welder");
}
void setup(){//初始化,设置I2C地址u8g2.setI2CAddress(0x3C*2);u8g2.begin();//启用 UTF8打印,我们的中文字符就是UTF8;u8g2.enableUTF8Print();
}
void loop(){u8g2.firstPage();do{page1();}while(u8g2.nextPage());
}

运行后,我们可以在屏幕中看到显示了一行字符串“Micro reflow welder”,效果如下图

其中设置字体,字号,字形用到了下面的语句

u8g2.setFont(u8g2_font_timB08_tf);
  • 在指令<timB08>中<tim>为字体类型,除了这个字体类型外,还有<u8g2_font_helvB08_tf>

  • <u8g2_font_ncenB08_tf>

  • <u8g2_font_courB08_tf>

    等字体供我们选选择,

指令<timB08>中<B>为字体加粗类型,常规类型为<R>,数字<08>为字体大小,字体大小可以在08、10、12、14、18、24中选择

接着我们来设置显示的坐标位置

/**
* 设置绘制光标位置(x,y)
* 关联方法 print
*/void U8G2::setCursor(u8g2_uint_t x, u8g2_uint_t y)
u8g2.setCursor(0,20);

示例:在坐标(0,15)的位置显示“Hello,Worldf”

u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(0, 15);
u8g2.print("Hello World!");

其中<u8g2.print("Hello World!")>来设置显示的内容

/**
* 绘制内容
* 关联方法  setFont setCursor enableUTF8Print
*/void U8G2::print(...)

如果显示的内容比较多,刷新比较频繁的话还可以封装成一个函数,这样可以提高效率

我们本次要显示的内容相对比较固定,所以就不封装函数了

屏幕划线

OLED可以显示的内容是比较丰富的,比如可以显示中文、英文、各种图形以及取模后的图片,对于我们本次作品来说,只需要在屏幕中绘制一个表格并显示几个简单的英文单词就足够了,我们这里介绍一个划线的方法,用来在OLED屏幕中绘制一个表格,至于其他图形和图片的显示方法,以后有机会再给大家展开介绍了

关于OLED屏幕划线的方法有两种

第一种:u8g2.drawHLine() —— 绘制水平线

**
* 绘制水平线
*  x 左上角的x坐标
*  y 左上角的y坐标
* pw 水平线的长度
*  关联方法 setDrawColor
*/
void U8G2::drawHLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w)

我们在前文中OLED屏幕显示字符的程序中增加下面的代码

u8g2.drawHLine(0,40,128);//在(0,40)位置绘制一条长度为128的横线

程序运行后,我们会在屏幕上看到在原来字符串的下方绘制了一条横线

第二种:u8g2.drawLine() —— 两点之间绘制线

/**
* 绘制线,从坐标(x0,y0) 到(x1,y1)
*  x0 端点0的x坐标
*  y0 端点0的y坐标
*  x1 端点1的x坐标
*  y1 端点1的y坐标
*  setDrawColor
*/
void U8G2::drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1)

接着我们继续在上面的程序中增加如下代码

u8g2.drawLine(0,0,0,64);//在(0,0)点和(0,64)点之间绘制一条直线

运行后,会看到在屏幕中多出了一条竖线,效果如下

最后我们综合使用介绍过的显示方法就可以设计本次作品的显示界面了

至此,Micro reflow welder的所有程序功能都已介绍完毕

最后奉上完整代码,有兴趣的伙伴可以根据自己的喜好修改

#include <Thermocouple.h>
#include <MAX6675_Thermocouple.h>//热电偶头文件
#include <U8g2lib.h>//显示屏头文件
#include <Wire.h>//i2c头文件
#include <MsTimer2.h>
//热电偶接口声明
#define SCK_PIN 8
#define CS_PIN 9
#define SO_PIN 2
#define PWM_PIN 10//可控硅功率调节
#define fan_small 7//小风扇引脚
#define fan_small_speed 6
#define fan_big 4//大风扇引脚
#define fan_big_speed 5
#define button 11 //按键引脚
#define relay 12 //继电器引脚
#define PWRFULL 230//满加热功率
#define PRE 0    //预热阶段
#define KEEP 1  //保持阶段
#define FAST 2    //快速加热阶段
bool is_working = false;//工作中的标志变量
bool is_free = true;//空闲的标志变量
bool is_cooling = false;//冷却的标志变量
bool is_preheat = false;//预热的标志变量
char MODEL;          //模式
int i=0;//屏幕中显示模式的索引
int count;//计时的变量
int count_keep=0;//保温计数器
int count_fast=0;//快速加热计数器
int count_cooling=0;//冷却计数器
int nowtime;//存储时间变量
double temp_now = 0;//当前温度
String time_sec_str;//屏幕显示秒数
int temp_target,PWR=0;//温度设定,加热功率调节0-255
int start_button;//开始按键
String temp_target_str,hot,temp_now_str;//目标温度,转换后的加热功率0-100,当前温度字符串
//显示屏定义
U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
//热电偶定义
Thermocouple* thermocouple;
//oled屏幕显示函数
void page1() {u8g2.setFont(u8g2_font_ncenR10_tf);u8g2.setFontPosTop();//当前温度u8g2.setCursor(3,2);u8g2.print("Now :");u8g2.setCursor(3,15);u8g2.print(temp_now_str+" C");//目标温度u8g2.setCursor(78,2);u8g2.print("Target:");u8g2.setCursor(80,15);u8g2.print(temp_target_str+" C");//加热功率u8g2.drawHLine(0,0,128);//在(0,0)位置绘制一条长度为128的横线u8g2.drawHLine(0,30,128);//在(0,30)位置绘制一条长度为128的横线//u8g2.drawHLine(0,46,128);u8g2.drawHLine(0,63,128);//在(0,30)位置绘制一条长度为128的横线u8g2.drawLine(0,0,0,64);//在(0,0)点和(0,64)点之间绘制一条直线u8g2.drawLine(127,0,127,64);//在(127,0)点和(127,64)点之间绘制一条直线u8g2.drawLine(76,0,76,64);//在(76,0)点和(76,64)点之间绘制一条直线u8g2.setCursor(3,32);u8g2.print("PWR:"+hot+"%");//运行时间u8g2.setCursor(3,49);u8g2.print("Time:"+time_sec_str+"S");//模式u8g2.setCursor(78,30);u8g2.print("Model:");u8g2.setCursor(80,49);switch (i){case 0:u8g2.print("FREE");break;case 1:u8g2.print("PRE");break;case 2:u8g2.print("KEEP");break;case 3:u8g2.print("FAST");break;case 4:u8g2.print("cooling");break;}
}
//初始化
void setup(){Serial.begin(9600);u8g2.begin();//启用 UTF8打印,我们的中文字符就是UTF8;u8g2.enableUTF8Print();thermocouple = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN);pinMode(button, INPUT);//start按键pinMode(relay, OUTPUT);//继电器pinMode(PWM_PIN, OUTPUT);//可控硅功率调节pinMode(fan_small_speed, OUTPUT);//small风扇速度pinMode(fan_small, OUTPUT);//small风扇方向digitalWrite(fan_small_speed, LOW);//digitalWrite(fan_small, LOW);//pinMode(fan_big_speed, OUTPUT);//big风扇速度pinMode(fan_big, OUTPUT);//big风扇方向digitalWrite(fan_big_speed, LOW);//digitalWrite(fan_big, LOW);// MsTimer2::set(300, temp_data);//定时器MsTimer2::start();
}
void temp_data()
{//获取当前温度temp_now = thermocouple->readCelsius();temp_now_str = String(temp_now);//调节温度temp_target = analogRead(A0);temp_target = map(temp_target, 0, 1023, 0, 230);temp_target_str = String(temp_target);//计时程序count+=3;if(count%9==0)  {nowtime++;}time_sec_str = nowtime;
}
void loop()
{//屏幕显示u8g2.firstPage();do{page1();}while(u8g2.nextPage());//====================等待开始===================if(start_button == 1 && digitalRead(button) == 0)//两次检测按键的状态{delay(1000);if ( digitalRead(button) == 0 && is_free == true) //且设备处于空闲状态进入工作模式{count=0;is_free = false;is_working = true;if (temp_now < temp_target) //加热模式{is_preheat = true;is_cooling = false;Serial.print("preheat! \n\r");}else//冷却模式{is_preheat = false;is_cooling = true;Serial.print("cooling! \n\r");} }else if( digitalRead(button) == 0 && is_free == false)//工作中再次按下按键进入冷却模式{is_preheat = false;is_cooling = true;Serial.print("cooling2! \n\r");}}start_button = digitalRead(button);//存储按键状态//==============加热工作模式=================if(is_free == false && is_working == true && is_preheat == true && is_cooling == false){if(temp_now < temp_target && temp_now <130)  { MODEL = PRE; count_keep = 0;i=1;}    //温度小于140℃,预热状态else if(temp_now < temp_target && temp_now >=130 && count_keep < 450)      { MODEL = KEEP;i=2; }    //温度大于140℃,进入保持状态,计数开始else if(temp_now < temp_target && temp_now >=130 && count_keep >= 450)    { MODEL = FAST;i=3;  }    //保持结束,进入爬升状态   if(MODEL == PRE && temp_now <= 110)//预热状态,高功率升到140度{//设置功率set_heat(60);Serial.print("heat60-1! \n\r");}if(MODEL == PRE && temp_now > 110)    //预热状态,高功率升到140度 {//设置功率set_heat(40);Serial.print("heat40! \n\r");}else if(MODEL == KEEP)  //保持状态,延时计数,过温断电{if(temp_now >= 155) set_heat(1);  //高于155℃就断电,否则就低功率else if(temp_now <= 140 ) set_heat(40);//130-140加热的功率40else{ set_heat(30); }//140-150加热功率25delay(10);Serial.print("fast! \n\r");Serial.println(count_keep);count_keep ++;}else if(MODEL == FAST)  //进入温度爬升阶段,大功率,当温度达到设定值减偏移量后,断电,将保持计数器清零,进入冷却状态{if(temp_now < temp_target - 20) {//设置功率set_heat(60);Serial.print("heat60-2! \n\r");}else if(temp_now >= temp_target - 20)                        //此处假定温度不降下去,否则会出现重复加温的情况{is_preheat = false;is_cooling = true;count_keep = 0;set_heat(0);}}}//==============冷却工作模式=================else if(is_free == false && is_working == true && is_preheat == false && is_cooling == true)  //冷却状态{set_heat(0);i = 4;if(count_cooling < 50){ Serial.print("fan starting! \n\r");Serial.println(count_cooling);count_cooling++ ;delay (10);}else if(temp_now >= 190)  //当温度高于190度,用小风量降温{setMotor(fan_big_speed, fan_big, 240);}else if(temp_now >= 55 && temp_now < 190)  //低于190度,大风降温{setMotor(fan_big_speed, fan_big, 255);}else if(temp_now < 55)  //温度低于55度,进入idle状态,记得计数器清零{is_working = false;is_preheat = false;is_cooling = false;is_free = true;count_cooling = 0;       }}//空闲状态,恢复各个状态寄存器,并且将系统降温到40度以下else if(is_free == true && is_working == false && is_preheat == false && is_cooling == false)  //空闲状态{set_heat(0);i = 0;if(temp_now > 50)  setMotor(fan_big_speed, fan_big, 255);else setMotor(fan_big_speed, fan_big, 0);}else{Serial.print("System State Erro! Default idle state recovered !\n \r");  //其它所有状态均为错误状态,恢复系统初始状态i = 0;set_heat(0);is_free = true;is_working = false;is_preheat = false;is_cooling = false;}setMotor(fan_small_speed, fan_small, 150);//内部散热风扇
}
//控制电机函数
void setMotor(int speedpin, int dirpin, int speed)
{if (speed == 0){digitalWrite(dirpin, LOW);analogWrite(speedpin, 0);}else if (speed > 0){digitalWrite(dirpin, LOW);analogWrite(speedpin, speed);}else{digitalWrite(dirpin, HIGH);analogWrite(speedpin, 255 + speed);}
}
//加热功率函数
void set_heat(int PWR_HEAT)
{if (PWR_HEAT == 0){digitalWrite(relay,LOW);hot = String(PWR_HEAT);analogWrite(PWM_PIN,0);}else{digitalWrite(relay,HIGH);//设置功率PWR = PWRFULL*PWR_HEAT/100;hot = String(PWR_HEAT);analogWrite(PWM_PIN,PWR);}
}

首次试机,焊接效果还是可以的

#总结#

本次Micro reflow welder微型回流焊机的设计,总结一下,我们掌握了数字、模拟信号的原理,学会使用U8g2库在OLED屏幕上显示数字,定时器的使用方法,学会了使用热电偶模块测量温度,以及通过可控硅控制加热平台的技巧

总体评价,这是一个玩家DIY的作品,使用了各种廉价的器件,验证了基本功能对于想要深入学习各种硬件、运用各种学科知识完成综合项目的伙伴会有一定帮助,但多数电子硬件都没有经过耐久性测试,所以它并不是一个成熟的产品,不能作为产品去推广,有兴趣的伙伴可以去尝试并改进方案,期待一起交流

接下来旺仔爸爸将会使用Micro reflow welde加工一些PCB电路板,我们一起期待

造物让生活更美好,我们下期再见!

DIY烤肉加热台,了解一下?相关推荐

  1. COOK100推荐:在家做新奥尔良烤翅的做法

    COOK100推荐:在家做新奥尔良烤翅的做法  烤翅在KFC销售很好,深受广大消费者的青睐.但是,其价格较高又让很多爱好者犹豫. 今天我给大家介绍自己在家里做新奥良烤翅,风味很好,成本算了算也只要KF ...

  2. 立创开源|Open T12朱雀T12

    1.工程描述 先夸一夸:这是一台颜值与实力并存的焊台,不止有漂亮的UI,更有出色的控温性能.作者@createskyblue以上古神灵朱雀命名. (1)工程使用的是ESP32PicoD4主控.三仪表放 ...

  3. [STM32]PID恒温加热台(DIY回流焊)

    考试结束之后在家,终于觉得有必要把之前鸽了很久得ESP32驱动墨水屏的项目提上日程. 但是俗话说的好,工欲善其事,必先利其器,我加工好了PCB,在某宝买焊锡浆的时候瞥到一个220V某仙子的加热台,10 ...

  4. 老司机带你飞——DIY桌面小电视

    桌面小电视 本期福利 活动规则: [1]添加客服微信(xutoubee)领取作品开源资料 [2]转发该篇文章到朋友圈,并停留30分钟,凭截图联系客服微信,进群参与抽奖(免费送作品)     活动截止时 ...

  5. 【超级实用】最强DIY级毕设级DCDC电源模块HGD01

    Hello,大家好,今天给大家带来一款非常好用的DCDC电源模块,这款模块在DIY中或者做毕设的时候会给我们带来很大的便利,好了,废话不多说先上图. 紫色的板子看起来是不是特别帅气,好,接下来我们来讲 ...

  6. 单片机练习-RC-5红外遥控器程序及简单制造DIY PC遥控器

    本程序采用的芯片为SAA3010, 参考资料有: 1. 常用红外遥控接收头引脚图解 2. 红外遥控编码资料 3. RC-5红外遥控程序 4. GIRDER中文教程与电脑遥控器制作资料 5. Girde ...

  7. arduino下载库出错_【arduino】DIY音乐播放器,arduino播放wav音乐,TRMpcm库测试及使用...

    微信关注 "DLGG创客DIY"设为"星标",重磅干货,第一时间送达. arduino特点库超多,想必大家都领教了,今天来分享一下之前玩过的TRMpcm库. 这 ...

  8. diy高性能存储服务器,diy存储服务器

    diy存储服务器 内容精选 换一换 帮助用户完成专属云服务器备份任务的创建,快速完成服务器数据保护.专属云服务器不支持应用一致性备份.当专属对象存储的容量不足时,会导致专属云服务器备份创建失败.已开通 ...

  9. DIY强大的虚拟化环境-技术可行性部分

    [技术可行性部分]大体的cpu支不支持呀,实际效果使用呀,截图 效果截图嵌套虚拟化[esxi,xenserver,Hyper-V] 嵌套虚拟化:经过各种查资料,和测试验证[只测过intel的,amd的 ...

最新文章

  1. 零基础学汇编 --小甲鱼
  2. Eclipse使用的小细节归档
  3. kafka 分区和副本以及kafaka 执行流程,以及消息的高可用
  4. 016_logback中的Encoder
  5. win10操作系统vscode如何配置c++开发环境
  6. Ubuntu录制GIF动画
  7. 【算法】红黑树-二叉树-算法
  8. Cannot find 'Enhance Component' button in BSP Workbench
  9. mysql 查找课程最高分_mysql 查询 学生id最高分的科目和日期
  10. 重定向地址_JavaWeb - Servlet:重定向和转发,状态管理
  11. 从源码角度解析线程池中顶层接口和抽象类
  12. 现实给了梦想多少时间?
  13. 两独立样本率的非劣效性试验-样本量计算
  14. 软件测试DAY3-执行用例
  15. js 拉勾网效果_js仿拉勾网首页穿墙广告效果
  16. cookie中__jsl_clearance参数的破解。
  17. MYSQL相关内容(引擎、隔离级别、实现原理)
  18. 【GDOI2017模拟11.7】太阳神
  19. All in 区块链的百度昨日发布了白皮书,说了些什么?
  20. 多列转单列表格的三种办法,你会几种?

热门文章

  1. appium(3)-Running Tests
  2. Android中脱离WebView使用WebSocket实现群聊和推送功能
  3. 物理光学1 波动方程与基础波函数
  4. TSQL编写存储过程计算1!+2!+3!+…+N!
  5. C++ const char* 学习
  6. 超图预览osgb格式倾斜摄影文件
  7. VS2019 开发第一个Windows驱动程序
  8. C# 泛型类型参数的约束
  9. Docker核心技术 1
  10. python路径找类并获取静态字段