7168浏览
查看: 7168|回复: 5

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台

[复制链接]
烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图1


#故事起源#

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图2


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



#方案介绍#

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

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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图3


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

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

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

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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图4


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

因为我们要做回流焊加热平台,它需要具备:温度调节、加热功率调节、冷却降温、电路保护等功能,接下来我们对这些功能进行介绍
温度调节
    在回流焊焊接的过程中,温度控制是非常关键的一个环节,整个过程大致分为四个阶段,预热区,温度保持区,回流区,冷却区,每个阶段的温度都需要精确控制,而温度检测功能对于回流焊设备来说就显得尤为重要了

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图5


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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图6


冷却降温
箱体中我们使用一个5V的静音风扇,目的是让各种电子元件不至于过热
而为了快速降低加热平台的温度,我们使用一个8000r/min的暴力风扇
控制风扇必不可少的就是电机驱动,这次我们本着有什么用什么的原则,使用了一个L298N型号的电机驱动
使用一个电位器来设定加热的目标温度,用一个按键作为是否开始工作的按钮
最后我们将所有检测到数据显示在0.96寸的OLED屏幕中即可

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图7


因为本次作品中接入了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一块

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图8


烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图9


#图纸设计#

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图10


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图11


加工完成后的结构如下图

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图12


#电路设计#

接着我们进行电路设计

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

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

电路接线如下图所示

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图13


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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图14


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图15


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图16


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图17


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图18


烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图19


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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图20


安装完毕后的效果如下图

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图21


烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图22


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图23


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

#程序设计#

这是Micro reflow welder的工作流程

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图24


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

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

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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图25


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图26


  1. #include <Thermocouple.h>
  2. #include <MAX6675_Thermocouple.h>
  3. #define SCK_PIN 8  //热电偶引脚
  4. #define CS_PIN 9  //热电偶引脚
  5. #define SO_PIN 10  //热电偶引脚
  6. Thermocouple* thermocouple;
  7. void setup() {
  8.   Serial.begin(9600);
  9.   thermocouple = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN);
  10. }
  11. void loop() {
  12.   const double celsius = thermocouple->readCelsius();
  13.   const double kelvin = thermocouple->readKelvin();
  14.   const double fahrenheit = thermocouple->readFahrenheit();
  15.   Serial.print("Temperature: ");
  16.   Serial.print(celsius);
  17.   Serial.print(" C, ");
  18.   Serial.print(kelvin);
  19.   Serial.print(" K, ");
  20.   Serial.print(fahrenheit);
  21.   Serial.println(" F");
  22.   delay(500);
  23. }
复制代码

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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图27


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

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

接下来我们来看一下定时器的使用方法
定时器的用法
我们编写如下程序,下载后查看运行效果

  1. #include <Thermocouple.h>
  2. #include <MAX6675_Thermocouple.h>//热电偶头文件
  3. #include <MsTimer2.h>//定时器头文件
  4. //热电偶接口声明
  5. #define SCK_PIN 8
  6. #define CS_PIN 9
  7. #define SO_PIN 2
  8. double temp_now = 0;//当前温度
  9. //热电偶定义
  10. Thermocouple* thermocouple;
  11. void setup()
  12. {
  13.   Serial.begin(9600);
  14.   MsTimer2::set(300, temp_data);//定时器
  15.   MsTimer2::start();
  16. }
  17. //获取温度函数
  18. void temp_data()
  19. {
  20.   //当前温度
  21.   temp_now = thermocouple->readCelsius();
  22.   Serial.print("temp_now: ");
  23.   Serial.print(temp_now);
  24.   Serial.println(" C, ");
  25. }
  26. void loop()
  27. {
  28.   Serial.println("Micro reflow welder");
  29.   delay(600);
  30. }
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图28


从程序中,我们不难发现

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

然后使用如下的指令就可以让< temp_data> 函数每隔0.3s执行一次
  1. MsTimer2::set(300, temp_data);
复制代码

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

温度检测和定时器的功能掌握后,我们来了解数字信号的处理,首先是数字输入信号
数字输入信号
    在本次项目中,我们使用一个按键作为开始按钮,而这个按键的作用就是典型的数字输入信号,我们定义11号数字管脚为按键输入,接着我们下载下面的程序看一下效果
  1. #define button 11 //按键引脚
  2. void setup()
  3. {
  4.   Serial.begin(9600);
  5. }
  6. void loop()
  7. {
  8.   int start_button = digitalRead(button);//存储按键状态
  9.   if(start_button == 0)
  10.   {
  11.     Serial.print("down!\n\r");
  12.   }
  13. }
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图29

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

我们对上面的程序进行修改,一起来看程序
  1. #define button 11 //按键引脚
  2. void setup()
  3. {
  4.   Serial.begin(9600);
  5. }
  6. void loop()
  7. {
  8.   int start_button = digitalRead(button);//存储按键状态
  9.   if(start_button == 0)//两次检测按键的状态
  10.   {
  11.       delay(1000);
  12.       if ( digitalRead(button) == 0)
  13.       {
  14.         Serial.print("start! \n\r");
  15.       }
  16.   }
  17. }
复制代码

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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图30

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

  1. digitalWrite(relay,LOW);
  2. digitalWrite(relay,HIGH);
复制代码

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

  1. #define button 11 //按键引脚
  2. #define relay 12 //继电器引脚
  3. void setup()
  4. {
  5.   Serial.begin(9600);
  6.   pinMode(relay, OUTPUT);//继电器
  7. }
  8. void loop()
  9. {
  10.   int start_button = digitalRead(button);//存储按键状态
  11.   if(start_button == 0)//两次检测按键的状态
  12.   {
  13.       delay(1000);
  14.       if ( digitalRead(button) == 0)
  15.       {
  16.         digitalWrite(relay,HIGH);
  17.         Serial.print("start! \n\r");
  18.       }
  19.   }
  20.   else
  21.   {
  22.     digitalWrite(relay,LOW);
  23.   }
  24. }
复制代码

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

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

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

我们将电位器连接主控板的A0引脚,编写如下程序
  1. void setup()
  2. {
  3.   Serial.begin(9600);
  4. }
  5. void loop()
  6. {
  7.   Serial.println( analogRead(A0));
  8.   delay(1000);
  9. }
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图31

由于回流焊的峰值温度不宜超过230℃,我们可以利用<map>函数将电位器的模拟信号做一次映射,这样就可以将原本0-1023的范围缩小到0-230了,我们需要将上面的程序做如下改动即可
  1. void setup()
  2. {
  3.   Serial.begin(9600);
  4. }
  5. void loop()
  6. {
  7.   int temp_target = analogRead(A0);
  8.   temp_target = map(temp_target, 0, 1023, 0, 230);
  9.   Serial.println( temp_target);
  10.   delay(1000);
  11. }
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图32

其实,我们还可以将程序做如下调整,把映射后的整数类型的数据转换成字符串类型,这样就可以方便的显示在OLED屏幕中了
  1. temp_target = analogRead(A0);
  2. temp_target = map(temp_target, 0, 1023, 0, 230);
  3. temp_target_str = String(temp_target);//将整数类型转换为字符串类型
  4. Serial.print("temp_now:\n\r");
  5. 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)>就可以调节加热功率了
  1. #define PWM_PIN 10 //可控硅功率调节
  2. void setup()
  3. {
  4.   Serial.begin(9600);
  5.   pinMode(PWM_PIN, OUTPUT);//可控硅功率调节
  6. }
  7. void loop()
  8. {
  9.   analogWrite(PWM_PIN,255);//范围是0-255
  10.   delay(1000);
  11. }
复制代码

在回流焊焊接的过程中,功率调节遍布于4个不同的阶段,我们可以将加热功率的程序封装成一个函数,这样就可以很方便的调用,在函数中还可以顺便把前文中讲到的继电器的控制指令加进去,调节加热功率的函数如下:
加热功率调节
  1. #define PWRFULL  230//满加热功率
  2. #define PWM_PIN  10 //可控硅功率调节
  3. #define relay  12 //继电器引脚
  4. //加热功率函数
  5. void setup()
  6. {
  7.     pinMode(relay, OUTPUT);//继电器
  8.     pinMode(PWM_PIN, OUTPUT);//可控硅功率调节
  9. }
  10. void set_heat(int PWR_HEAT)
  11. {
  12.   if (PWR_HEAT == 0)
  13.   {
  14.     digitalWrite(relay,LOW);//继电器断开
  15.     analogWrite(PWM_PIN,0);
  16.   }
  17.   else
  18.   {
  19.     digitalWrite(relay,HIGH);
  20.     //设置功率
  21.     PWR = PWRFULL*PWR_HEAT/100; //PWRFUL为满加热功率
  22.     hot = String(PWR_HEAT);//转换成字符串类型,方便屏幕显示
  23.     analogWrite(PWM_PIN,PWR);
  24.   }
  25. }
复制代码

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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图33


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

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

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

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

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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图34


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

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



控制降温风扇

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

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

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

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

下面我们来看一个例子

  1. #define dirpin 7  //方向引脚
  2. #define speedpin 6  //速度引脚
  3. digitalWrite(dirpin, LOW);//HIGH正转,LOW反转
  4. analogWrite(speedpin, 200);
复制代码

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

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

  1. //控制电机函数
  2. void setMotor(int speedpin, int dirpin, int speed)
  3. {
  4.   if (speed == 0)
  5.   {
  6.     digitalWrite(dirpin, LOW);
  7.     analogWrite(speedpin, 0);
  8.   }
  9.   else if (speed > 0)
  10.   {
  11.     digitalWrite(dirpin, LOW);
  12.     analogWrite(speedpin, speed);
  13.   }
  14.   else
  15.   {
  16.     digitalWrite(dirpin, HIGH);
  17.     analogWrite(speedpin, 255 + speed);
  18.   }
  19. }
复制代码

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

最后是OLED屏幕的使用方法

下面我们从屏幕显示最基础的方法开始介绍
OLED屏幕显示
    OLED其实就是一个M x N 的像素点阵,想显示什么内容就得把具体位置的像素点亮起来。我们用坐标系来表示每一个像素点,

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图35


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

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图36


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

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

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

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

  1. #include <U8g2lib.h>
  2. void setup() {
  3.   // put your setup code here, to run once:
  4. }
  5. void loop() {
  6.   // put your main code here, to run repeatedly:
  7. }
复制代码

如果编译成功,没有报错,说明U8g2库文件已经可以使用了,我们编写下面的程序,查看效果
  1. #include <U8g2lib.h>//显示屏头文件
  2. #include <Wire.h>//i2c头文件
  3. //显示屏定义
  4. U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
  5. //oled屏幕显示函数
  6. void page1() {
  7.   //设置字体,字号,字形
  8.   u8g2.setFont(u8g2_font_timR10_tf);
  9.   u8g2.setFontPosTop();
  10.   //设置光标位置
  11.   u8g2.setCursor(0,20);
  12.   u8g2.print("Micro reflow welder");
  13. }
  14. void setup(){
  15.   //初始化,设置I2C地址
  16.   u8g2.setI2CAddress(0x3C*2);
  17.   u8g2.begin();
  18.   //启用 UTF8打印,我们的中文字符就是UTF8;
  19.   u8g2.enableUTF8Print();
  20. }
  21. void loop(){
  22.   u8g2.firstPage();
  23.   do
  24.   {
  25.     page1();
  26.   }while(u8g2.nextPage());
  27. }
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图37


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

  1. 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中选择

接着我们来设置显示的坐标位置
  1. /**
  2. * 设置绘制光标位置(x,y)
  3. * 关联方法 print
  4. */void U8G2::setCursor(u8g2_uint_t x, u8g2_uint_t y)
  5. u8g2.setCursor(0,20);
复制代码

示例:在坐标(0,15)的位置显示“Hello,Worldf”
  1. u8g2.setFont(u8g2_font_ncenB14_tr);
  2. u8g2.setCursor(0, 15);
  3. u8g2.print("Hello World!");
复制代码

其中<u8g2.print("Hello World!")>来设置显示的内容
  1. /**
  2. * 绘制内容
  3. * 关联方法  setFont setCursor enableUTF8Print
  4. */void U8G2::print(...)
复制代码

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

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

关于OLED屏幕划线的方法有两种
第一种:u8g2.drawHLine() —— 绘制水平线
  1. **
  2. * 绘制水平线
  3. *  x 左上角的x坐标
  4. *  y 左上角的y坐标
  5. * pw 水平线的长度
  6. *  关联方法 setDrawColor
  7. */
  8. void U8G2::drawHLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w)
复制代码

我们在前文中OLED屏幕显示字符的程序中增加下面的代码
  1. u8g2.drawHLine(0,40,128);//在(0,40)位置绘制一条长度为128的横线
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图38


第二种:u8g2.drawLine() —— 两点之间绘制线
  1. /**
  2. * 绘制线,从坐标(x0,y0) 到(x1,y1)
  3. *  x0 端点0的x坐标
  4. *  y0 端点0的y坐标
  5. *  x1 端点1的x坐标
  6. *  y1 端点1的y坐标
  7. *  setDrawColor
  8. */
  9. void U8G2::drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1)
复制代码

接着我们继续在上面的程序中增加如下代码
  1. u8g2.drawLine(0,0,0,64);//在(0,0)点和(0,64)点之间绘制一条直线
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图39


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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图40


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

最后奉上完整代码,有兴趣的伙伴可以根据自己的喜好修改
  1. #include <Thermocouple.h>
  2. #include <MAX6675_Thermocouple.h>//热电偶头文件
  3. #include <U8g2lib.h>//显示屏头文件
  4. #include <Wire.h>//i2c头文件
  5. #include <MsTimer2.h>
  6. //热电偶接口声明
  7. #define SCK_PIN 8
  8. #define CS_PIN 9
  9. #define SO_PIN 2
  10. #define PWM_PIN 10//可控硅功率调节
  11. #define fan_small 7//小风扇引脚
  12. #define fan_small_speed 6
  13. #define fan_big 4//大风扇引脚
  14. #define fan_big_speed 5
  15. #define button 11 //按键引脚
  16. #define relay 12 //继电器引脚
  17. #define PWRFULL 230//满加热功率
  18. #define PRE 0    //预热阶段
  19. #define KEEP 1  //保持阶段
  20. #define FAST 2    //快速加热阶段
  21. bool is_working = false;//工作中的标志变量
  22. bool is_free = true;//空闲的标志变量
  23. bool is_cooling = false;//冷却的标志变量
  24. bool is_preheat = false;//预热的标志变量
  25. char MODEL;          //模式
  26. int i=0;//屏幕中显示模式的索引
  27. int count;//计时的变量
  28. int count_keep=0;//保温计数器
  29. int count_fast=0;//快速加热计数器
  30. int count_cooling=0;//冷却计数器
  31. int nowtime;//存储时间变量
  32. double temp_now = 0;//当前温度
  33. String time_sec_str;//屏幕显示秒数
  34. int temp_target,PWR=0;//温度设定,加热功率调节0-255
  35. int start_button;//开始按键
  36. String temp_target_str,hot,temp_now_str;//目标温度,转换后的加热功率0-100,当前温度字符串
  37. //显示屏定义
  38. U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE);
  39. //热电偶定义
  40. Thermocouple* thermocouple;
  41. //oled屏幕显示函数
  42. void page1() {
  43.   u8g2.setFont(u8g2_font_ncenR10_tf);
  44.   u8g2.setFontPosTop();
  45.   //当前温度
  46.   u8g2.setCursor(3,2);
  47.   u8g2.print("Now :");
  48.   u8g2.setCursor(3,15);
  49.   u8g2.print(temp_now_str+" C");
  50.   //目标温度
  51.   u8g2.setCursor(78,2);
  52.   u8g2.print("Target:");
  53.   u8g2.setCursor(80,15);
  54.   u8g2.print(temp_target_str+" C");
  55.   //加热功率
  56.   u8g2.drawHLine(0,0,128);//在(0,0)位置绘制一条长度为128的横线
  57.   u8g2.drawHLine(0,30,128);//在(0,30)位置绘制一条长度为128的横线
  58.   //u8g2.drawHLine(0,46,128);
  59.   u8g2.drawHLine(0,63,128);//在(0,30)位置绘制一条长度为128的横线
  60.   u8g2.drawLine(0,0,0,64);//在(0,0)点和(0,64)点之间绘制一条直线
  61.   u8g2.drawLine(127,0,127,64);//在(127,0)点和(127,64)点之间绘制一条直线
  62.   u8g2.drawLine(76,0,76,64);//在(76,0)点和(76,64)点之间绘制一条直线
  63.   u8g2.setCursor(3,32);
  64.   u8g2.print("PWR:"+hot+"%");
  65.   //运行时间
  66.   u8g2.setCursor(3,49);
  67.   u8g2.print("Time:"+time_sec_str+"S");
  68.   //模式
  69.   u8g2.setCursor(78,30);
  70.   u8g2.print("Model:");
  71.   u8g2.setCursor(80,49);
  72.   switch (i)
  73.   {
  74.   case 0:
  75.     u8g2.print("FREE");
  76.     break;
  77.   case 1:
  78.     u8g2.print("PRE");
  79.     break;
  80.   case 2:
  81.     u8g2.print("KEEP");
  82.     break;
  83.   case 3:
  84.     u8g2.print("FAST");
  85.     break;
  86.   case 4:
  87.     u8g2.print("cooling");
  88.     break;
  89.   }
  90. }
  91. //初始化
  92. void setup(){
  93.   Serial.begin(9600);
  94.   u8g2.begin();
  95.   //启用 UTF8打印,我们的中文字符就是UTF8;
  96.   u8g2.enableUTF8Print();
  97.   thermocouple = new MAX6675_Thermocouple(SCK_PIN, CS_PIN, SO_PIN);
  98.   pinMode(button, INPUT);//start按键
  99.   pinMode(relay, OUTPUT);//继电器
  100.   pinMode(PWM_PIN, OUTPUT);//可控硅功率调节
  101.   pinMode(fan_small_speed, OUTPUT);//small风扇速度
  102.   pinMode(fan_small, OUTPUT);//small风扇方向
  103.   digitalWrite(fan_small_speed, LOW);//
  104.   digitalWrite(fan_small, LOW);//
  105.   pinMode(fan_big_speed, OUTPUT);//big风扇速度
  106.   pinMode(fan_big, OUTPUT);//big风扇方向
  107.   digitalWrite(fan_big_speed, LOW);//
  108.   digitalWrite(fan_big, LOW);//
  109.   MsTimer2::set(300, temp_data);//定时器
  110.   MsTimer2::start();
  111. }
  112. void temp_data()
  113. {
  114.   //获取当前温度
  115.   temp_now = thermocouple->readCelsius();
  116.   temp_now_str = String(temp_now);
  117.   //调节温度
  118.   temp_target = analogRead(A0);
  119.   temp_target = map(temp_target, 0, 1023, 0, 230);
  120.   temp_target_str = String(temp_target);
  121.   //计时程序
  122.   count+=3;
  123.   if(count%9==0)  {nowtime++;}
  124.   time_sec_str = nowtime;
  125. }
  126. void loop()
  127. {
  128.   //屏幕显示
  129.   u8g2.firstPage();
  130.   do
  131.   {
  132.     page1();
  133.   }while(u8g2.nextPage());
  134.   //====================等待开始===================
  135.   if(start_button == 1 && digitalRead(button) == 0)//两次检测按键的状态
  136.   {
  137.     delay(1000);
  138.     if ( digitalRead(button) == 0 && is_free == true) //且设备处于空闲状态进入工作模式
  139.     {
  140.       count=0;
  141.       is_free = false;
  142.       is_working = true;
  143.       if (temp_now < temp_target) //加热模式
  144.       {
  145.         is_preheat = true;
  146.         is_cooling = false;
  147.         Serial.print("preheat! \n\r");
  148.       }
  149.       else//冷却模式
  150.       {
  151.         is_preheat = false;
  152.         is_cooling = true;
  153.         Serial.print("cooling! \n\r");
  154.       }
  155.     }
  156.     else if( digitalRead(button) == 0 && is_free == false)//工作中再次按下按键进入冷却模式
  157.     {
  158.       is_preheat = false;
  159.       is_cooling = true;
  160.       Serial.print("cooling2! \n\r");
  161.     }
  162.   }
  163.   start_button = digitalRead(button);//存储按键状态
  164.   //==============加热工作模式=================
  165.   if(is_free == false && is_working == true && is_preheat == true && is_cooling == false)
  166.   {
  167.     if(temp_now < temp_target && temp_now <130)  { MODEL = PRE; count_keep = 0;i=1;}    //温度小于140℃,预热状态
  168.     else if(temp_now < temp_target && temp_now >=130 && count_keep < 450)      { MODEL = KEEP;i=2; }    //温度大于140℃,进入保持状态,计数开始
  169.     else if(temp_now < temp_target && temp_now >=130 && count_keep >= 450)    { MODEL = FAST;i=3;  }    //保持结束,进入爬升状态   
  170.     if(MODEL == PRE && temp_now <= 110)//预热状态,高功率升到140度
  171.     {
  172.         //设置功率
  173.       set_heat(60);
  174.       Serial.print("heat60-1! \n\r");
  175.     }
  176.     if(MODEL == PRE && temp_now > 110)    //预热状态,高功率升到140度
  177.     {
  178.         //设置功率
  179.         set_heat(40);
  180.         Serial.print("heat40! \n\r");
  181.     }
  182.     else if(MODEL == KEEP)  //保持状态,延时计数,过温断电
  183.     {
  184.         if(temp_now >= 155) set_heat(1);  //高于155℃就断电,否则就低功率
  185.         else if(temp_now <= 140 ) set_heat(40);//130-140加热的功率40
  186.         else
  187.         { set_heat(30); }//140-150加热功率25
  188.         delay(10);
  189.         Serial.print("fast! \n\r");
  190.         Serial.println(count_keep);
  191.         count_keep ++;
  192.     }
  193.     else if(MODEL == FAST)  //进入温度爬升阶段,大功率,当温度达到设定值减偏移量后,断电,将保持计数器清零,进入冷却状态
  194.     {
  195.         if(temp_now < temp_target - 20)
  196.         {
  197.           //设置功率
  198.           set_heat(60);
  199.           Serial.print("heat60-2! \n\r");
  200.         }
  201.         else if(temp_now >= temp_target - 20)                        //此处假定温度不降下去,否则会出现重复加温的情况
  202.         {
  203.           is_preheat = false;
  204.           is_cooling = true;
  205.           count_keep = 0;
  206.           set_heat(0);
  207.         }
  208.     }
  209.   }
  210.   //==============冷却工作模式=================
  211.   else if(is_free == false && is_working == true && is_preheat == false && is_cooling == true)  //冷却状态
  212.   {
  213.     set_heat(0);
  214.     i = 4;
  215.     if(count_cooling < 50)
  216.     {
  217.         Serial.print("fan starting! \n\r");
  218.         Serial.println(count_cooling);
  219.         count_cooling++ ;
  220.         delay (10);
  221.     }
  222.     else if(temp_now >= 190)  //当温度高于190度,用小风量降温
  223.     {
  224.         setMotor(fan_big_speed, fan_big, 240);
  225.     }
  226.     else if(temp_now >= 55 && temp_now < 190)  //低于190度,大风降温
  227.     {
  228.         setMotor(fan_big_speed, fan_big, 255);
  229.     }
  230.     else if(temp_now < 55)  //温度低于55度,进入idle状态,记得计数器清零
  231.     {
  232.           is_working = false;
  233.           is_preheat = false;
  234.           is_cooling = false;
  235.           is_free = true;
  236.           count_cooling = 0;      
  237.     }
  238.   }
  239.   //空闲状态,恢复各个状态寄存器,并且将系统降温到40度以下
  240.   else if(is_free == true && is_working == false && is_preheat == false && is_cooling == false)  //空闲状态
  241.   {
  242.     set_heat(0);
  243.     i = 0;
  244.     if(temp_now > 50)  setMotor(fan_big_speed, fan_big, 255);
  245.     else setMotor(fan_big_speed, fan_big, 0);
  246.   }
  247.   else
  248.   {
  249.     Serial.print("System State Erro! Default idle state recovered !\n \r");  //其它所有状态均为错误状态,恢复系统初始状态
  250.     i = 0;
  251.     set_heat(0);
  252.     is_free = true;
  253.     is_working = false;
  254.     is_preheat = false;
  255.     is_cooling = false;
  256.   }
  257.     setMotor(fan_small_speed, fan_small, 150);//内部散热风扇
  258. }
  259. //控制电机函数
  260. void setMotor(int speedpin, int dirpin, int speed)
  261. {
  262.   if (speed == 0)
  263.   {
  264.     digitalWrite(dirpin, LOW);
  265.     analogWrite(speedpin, 0);
  266.   }
  267.   else if (speed > 0)
  268.   {
  269.     digitalWrite(dirpin, LOW);
  270.     analogWrite(speedpin, speed);
  271.   }
  272.   else
  273.   {
  274.     digitalWrite(dirpin, HIGH);
  275.     analogWrite(speedpin, 255 + speed);
  276.   }
  277. }
  278. //加热功率函数
  279. void set_heat(int PWR_HEAT)
  280. {
  281.   if (PWR_HEAT == 0)
  282.   {
  283.     digitalWrite(relay,LOW);
  284.     hot = String(PWR_HEAT);
  285.     analogWrite(PWM_PIN,0);
  286.   }
  287.   else
  288.   {
  289.     digitalWrite(relay,HIGH);
  290.     //设置功率
  291.     PWR = PWRFULL*PWR_HEAT/100;
  292.     hot = String(PWR_HEAT);
  293.     analogWrite(PWM_PIN,PWR);
  294.   }
  295. }
复制代码

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

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图41


#总结#

烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图42


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

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

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

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

更多有趣的项目,欢迎旺仔爸爸造物社公众号
烤肉vs贴片 | 电熨斗改造的微型回流焊加热台图43


gray6666  初级技神

发表于 2021-5-19 09:12:29

自制烤肠机
回复

使用道具 举报

shangwe4416  初级技神

发表于 2021-5-20 07:19:02

热转印 LED拆焊都可以啊
回复

使用道具 举报

gyc13597926778  学徒

发表于 2021-5-28 22:27:19

嗯,是比较厉害
回复

使用道具 举报

刘思宇hhhhhhhhh  学徒

发表于 2021-5-29 10:47:08

不粗不错,有点意思
回复

使用道具 举报

晨硕  见习技师

发表于 2021-6-2 12:21:20

牛皮厉害
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2024 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail