数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 8623|回复: 93

[工仪] 也制作开源 STC15W408AS 白光T12控制器 数码管版本 洞洞板搭建

    [复制链接]
发表于 2020-3-15 01:55:31 | 显示全部楼层 |阅读模式

马上注册,认识更多玩家好友,查阅更多资源,享有更多功能

您需要 登录 才可以下载或查看,没有帐号?立即注册 微信登录

x
本帖最后由 c106czs 于 2020-3-16 22:43 编辑

这几天看了好多T12控制器的制作帖子,很多都是OLED的,MCU(微控制器)有使用STC的,也有使用STM8 STM32的
看到@GoodCode 大神很早之前开源了数码管版本的,然后@金向维 继续改进GoodCode的代码并开源,也学习了一下。

自己重新画了电路图,然后设计了洞洞板的布线图

代码,觉得原来的控制器功能有点繁琐。我只需要能控温,能显示设定温度和加热温度就好了,什么那些休眠,步进设置之类的,温度校正参数之类的,觉得有点点繁琐。

哎,能用就行。
(干嘛不上白菜白光?)

其实也有,自己打样了any版本 LM393的板子回来用,也是很不错的。
any-sch.jpg


最初发的帖子,里面有坛友做的洞洞板版本:
http://bbs.mydigit.cn/read.php?tid=2602538


然后后来,嘉立创、捷配之类的搞PCB价格战


于是赶紧学画PCB
自己打样的第一款PCB
any_top.png


any_bottom.png


为了符合10x10cm,尽最大性价比,当时还加入了ne5532音调板和单路的TDA2030功放电路
微信截图_20200315012302.png
还正好10x10cm。哈哈哈
只是,这三款板子都是用AD的自动布线来弄的,先自动布线再自己调整。
所以可以看到 ne5532这款板子其实布线是很烂,也不想装来测试
后期重新画了一块,测试没有底噪,这块就算了。


那个TDA2030,两个脚和三个脚的顺序弄反了哈哈哈,不过把引脚掰一掰能装上,声音也正常没太大底噪。
参考的是官方PDF的单电源电路。




以上是题外话。


说回正题


有天突然看到桌子上有片荒废的STC15W408AS,就忍不住了。哈哈哈动手

sch.png (之前的原理图里面的运放正极供电画错了,这个是修正的原理图,感谢坛友提醒)

电路图,参考@GoodCode 的原理图画的,那个5.1V稳压管最后没装,因为我的运放使用的是7805稳压后的5V供电
LM358的输出电压不可能大于电源电压,除非击穿损坏哈


所以也不用担心输出电压高于5V损坏单片机IO口


所以就不需要那个稳压管了。


还有,由于使用的单片机是DIP16封装的,没有这么多IO口驱动四位数码管,就用了一片TM1650
淘宝1元两片包邮,价格还能接受吧。


然后,洞洞板布线


stc15_baiguang.png
黑色的是在背面的走线,蓝色是顶上的跳线,那根绿色的,是用于控制T12的PMOS关断控制加热用的
实在不知道怎么布线了,就直接飞线了。


但是,也不是完全按照黑色的那些线路来布线的,有的觉得太麻烦了,黑色的太长,就直接通通都飞线了。


还有DS18B20的代码还没去写,所以板子上就暂时不装了。其实用这个是想学习一下DS18B20的测温程序
如果觉得这个芯片比较贵的话,也可以用更加常见的NTC测温方法测量室温,用于显示温度的温度补偿。


IMG_20200314_123047.jpg
做出来的实物图
IMG_20200314_123055.jpg
背面,凌乱的飞线,反正能通就好了,测试也没问题。


IMG_20200314_123539.jpg
开机,首先显示7123(这个可以通过看后面的代码来解释为什么)


IMG_20200314_123540.jpg
然后显示电源电压,12.25V
IMG_20200314_123541.jpg
然后7456


IMG_20200314_123603.jpg
显示单片机供电电压,5141mv,就是5.1V左右


IMG_20200314_123609.jpg
短按一下编码器,快速进入300℃的加热模式
IMG_20200314_123621.jpg
也可以拧编码器调整设定温度,步进是5℃


IMG_20200314_123711.jpg
每次设定完温度,显示两秒后,就会返回显示测得的实际温度,这里大概是299℃
加热指示灯已经开始交替闪烁了
达到预期效果
吐槽一下,这个数码管是当时论坛 老王家 9.9包邮一盒的数码管里面的其中一种。
才发现用的这个,第一位的d段居然是缺划的。算了,也懒得换了,之后找到好的再换。
上两张这种数码管的原理图,原来是用在电磁炉上面的
YH-4471AHB-4位共阴时钟数码管原理图1.jpg
YH-4471AHB-4位共阴时钟数码管原理图2.jpg




如果你制作的时候用的不一样的数码管,也可以的,请参考TM1650的datasheet,把数码管相应管脚连接到TM1650对应的输出端口 TM1650.png

IMG_20200314_123733.jpg
化锡,这个温度测定还是很不准,容易飘


关于这个温度的测算,当时找了比较多的资料,由于不太确定T12的热电偶到底是什么类型的
有人说是K型的,有人说是N型的,也没有人能给出温度分度表


算了,自己测吧


用新买的万用表,随便测了几十组数据,丢到matlab中拟合出一条公式出来
微信截图_20200315014323.png


matlab拟合结果
2degree.png
以上是2次多项式的拟合结果
3degree.png
以上是三次多项式的拟合结果


由于单片机的算力有限,加上更加高次的多项式,模拟出来的图像也不太好,于是最后挑选了一条最高3次方的多项式,作为计算温度的公式。


最后放出BOM表
bom.png


手头有闲置元件的可以动手试试,还挺好玩的。


如果你真的什么元件也没有,那么来一套大概在25块左右。(103电容用104电容代替,电解电容统一用35V耐压的)
只是,就单单做一套的话,这样买元件会多出来好多,有点浪费了。


随便淘宝找了一家,找到所有需要的元件(真的是随便找的,没有任何打广告的意思)
9ec91c35221cbd52bb80c5a924eeb4a.jpg


好吧是有点贵了,好像闲鱼有成品到手就用就是20不包邮哈哈哈
(好像还漏了洞洞板没买,这个洞洞板好像要买比较大的,应该要3块钱左右吧,啊啊好贵啊,嘉立创5元不香吗)

next



打赏

参与人数 10M币 +170 收起 理由
jdsuchen + 5 谢谢分享
xiaoxuanfeng + 20 謝謝分享
stely + 20 優秀文章
newnet1234 + 20 謝謝分享
沙漠臭屁虫 + 20
moontree + 20 謝謝分享
qrut + 20 謝謝分享
8139 + 20 優秀文章
williamgarci + 20 原創內容
keye + 5 謝謝分享

查看全部打赏

 楼主| 发表于 2020-3-15 01:59:48 | 显示全部楼层
本帖最后由 c106czs 于 2020-3-15 02:06 编辑


直接上源代码,请勿用于商业用途!

希望大家能提出宝贵意见,把它写得更加完善。

  1. /**
  2. 数码之家 c106czs 编写于 2020年3月13日
  3. 请勿用于商业用途!
  4. */
  5. #include <STC15.h>
  6. #include <intrins.h>
  7. #include <math.h>

  8. sbit t12 = P3 ^ 7;         //T12控制
  9. sbit encoderb = P1 ^ 0;    //编码器的b脚
  10. sbit encodera = P1 ^ 1;    //编码器的a脚
  11. sbit encoderd = P1 ^ 2;    //编码器的按键d脚
  12. sbit DIO = P3 ^ 3;         // TM1650 数码管驱动的sda引脚
  13. sbit CLK = P3 ^ 2;         // TM1650 数码管驱动的scl引脚
  14. sbit DO = P5 ^ 5;          //DS18B20数据脚
  15. unsigned long VREF = 2390; // 用万用表测量基准电压的真实值,单位mv

  16. bit lastb = 0;
  17. bit lasta = 0;
  18. unsigned short push_last_time = 0; //记录按下编码器按钮的时间,短按和长按

  19. unsigned long t12_voltage;    // 计算t12热电偶电压
  20. unsigned long system_voltage; // 计算单片机供电电压
  21. unsigned long input_voltage;  // 计算整个板子的输入电压(12~24V)

  22. // PID控制算法
  23. #define KP 1.2f       // 比例系数
  24. #define KI 0.2f       // 积分系数
  25. #define KD 0.1f       // 微分系数
  26. #define MAX_UK 400.0f // 系统允许输出的最大控制量,这里表现为加热数,400个0.5ms加热周期,最长连续加热时间为200ms

  27. int ek = 0, ek_1 = 0, ek_2 = 0; // 记录连续三次的偏差值(设定值-实际测量值)
  28. float uk_1 = 0.0f, uk = 0.0f;   // 记录当前计算的PID调整值和上次计算的PID调整值
  29. long integralSum = 0;           // 位置式PID算法的累计积分项

  30. // 定义一个数码管段码表,0~F
  31. unsigned char CODE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x77, 0X7C, 0X39, 0X5E, 0X79, 0X71};

  32. unsigned int t12SetTemperature = 10;   // 记录当前设定的温度
  33. unsigned int t12ActualTemperature = 0; // 保存T12当前的实际温度
  34. bit isChangeTemperature = 0;           // 标记是否更改过设定温度
  35. unsigned int setTempShowTime = 0;      // 记录显示设置温度的时长

  36. unsigned int need_heat_time = 0;       // 需要加热的时长
  37. unsigned int heat_time_count = 0;      //当前已经加热的时长
  38. unsigned int actualTempShowTime = 250; //设定当前温度的显示时长,避免采集温度过快造成数码管乱跳

  39. /*延时函数,使用STC-ISP自动生成的,比较准确*/
  40. void Delay_ms(unsigned int k) //@12.000MHz
  41. {
  42.   unsigned char i, j;
  43.   for (; k > 0; k--)
  44.   {
  45.     i = 12;
  46.     j = 169;
  47.     do
  48.     {
  49.       while (--j)
  50.         ;
  51.     } while (--i);
  52.   }
  53. }

  54. void Delay_us(unsigned int i)
  55. {
  56.   for (; i > 0; i--)
  57.   {
  58.     _nop_();
  59.     _nop_();
  60.     _nop_();
  61.     _nop_();
  62.   }
  63. }

  64. // 初始化各个IO口
  65. void initIO()
  66. {
  67.   // 配置各个端口的输入模式,M1M0:00普通,01推挽,10高阻输入,11开漏
  68.   /*
  69.         以下列出需要配置的端口,其他端口保持默认即可
  70.         t12 = P3^7;             //T12控制  推挽输出模式
  71.         ADC3:系统输入电压检测 P1^3 输入模式
  72.         ADC4:T12热电偶电压检测 P1^4 输入模式
  73.         ADC5:2.5V参考电压输入 P1^5 输入模式
  74.         */

  75.   //P1M0 |= 0x00; //0000 0000
  76.   P1M1 |= 0x38; //0011 1000

  77.   P3M0 = 0x80; //1000 0000
  78.   P3M1 = 0x00; //0000 0000
  79. }

  80. /*初始化ADC*/
  81. void initADC(void)
  82. {
  83.   /*
  84.         开启相应ADC口的模拟输入功能(相应位置1)
  85.         ADC3:系统输入电压检测 P1^3
  86.         ADC4:T12热电偶电压检测 P1^4
  87.         ADC5:2.5V参考电压输入 P1^5
  88.         */
  89.   P1ASF = 0x38; //0011 1000
  90.   ADC_RES = 0;  // 清楚结果寄存器
  91.   ADC_RESL = 0;
  92.   /*
  93.         ADC控制寄存器
  94.         ADC_POWER | SPEED1 | SPEED0 | ADC_FLAG | ADC_START | CHS2 | CHS1 | CHS0
  95.         */
  96.   // 这里初始化的时候,可以先打开电源和设置转换速度
  97.   ADC_CONTR = 0x80; // 1000 0000
  98.   Delay_ms(5);      // 上电之后延时等待一段时间
  99. }

  100. // 关闭ADC电源,在进入空闲(休眠)模式的时候启用,降低功耗
  101. void closeADC(void)
  102. {
  103.   /*
  104.         ADC控制寄存器
  105.         ADC_POWER | SPEED1 | SPEED0 | ADC_FLAG | ADC_START | CHS2 | CHS1 | CHS0
  106.         */
  107.   ADC_CONTR = 0x00;
  108. }

  109. // 直接插入排序
  110. void insertionSort(unsigned int A[], unsigned int n)
  111. {
  112.   unsigned int i, j;
  113.   for (i = 1; i < n; i++)
  114.   {
  115.     for (j = i; j > 0; j--)
  116.     {
  117.       if (A[j] < A[j - 1])
  118.       {
  119.         // 不使用第三变量交换两个数,使用异或运算速度快
  120.         A[j - 1] ^= A[j];
  121.         A[j] ^= A[j - 1];
  122.         A[j - 1] ^= A[j];
  123.       }
  124.     }
  125.   }
  126. }

  127. #define ADC_FLAG 0x10  // ADC转换完成标志
  128. #define ADC_START 0x08 // ADC开始置位
  129. // 获取某个ADC通道的转换值
  130. // 为了提高结果的准确性,每次测量,测5次,并且去掉一个最高值,一个最低值,最后取中间3个的均值返回
  131. unsigned int getADCResult(unsigned int channel)
  132. {
  133.   unsigned int res[5], i, result = 0;
  134.   for (i = 0; i < 5; i++)
  135.   {
  136.     /*
  137.         ADC控制寄存器
  138.         ADC_POWER | SPEED1 | SPEED0 | ADC_FLAG | ADC_START | CHS2 | CHS1 | CHS0
  139.         */
  140.     ADC_CONTR = (0x80 | channel | ADC_START); // 选择需要读取的通道,并开启转换
  141.     Delay_us(1);
  142.     while (!(ADC_CONTR & ADC_FLAG))
  143.       ;                                            //等待ADC转换完成
  144.     res[i] = ((ADC_RES << 2) | (ADC_RESL & 0x03)); // 计算转换出来的原始结果
  145.     ADC_RES = 0x00;
  146.     ADC_RESL = 0x00; // 清零结果寄存器
  147.   }
  148.   // 对结果进行排序
  149.   insertionSort(res, 5);
  150.   // 去掉一个最高值,去掉一个最低值,剩余三个求平均值
  151.   result = (res[1] + res[2] + res[3]) / 3;
  152.   return result;
  153. }
  154. /*以下是计算各种电压的函数,返回结果的单位都是mv*/
  155. // 计算公式(mv) output_voltage = (VREF万用表测的TL431基准电压值(mv) * 待测通道的ADC值 / TL431基准通道ADC值)
  156. // 计算获取T12的电压
  157. void getT12Voltage(void)
  158. {
  159.   t12_voltage = (VREF * getADCResult(4) / getADCResult(5)); //计算t12电压,单位mV
  160. }

  161. // 计算获取单片机的电源电压
  162. void getSystemVoltage(void)
  163. {
  164.   system_voltage = (VREF * 1024 / getADCResult(5)); //计算单片机的电源电压,单位mV;
  165. }

  166. // 计算获取输入电源电压
  167. void getInputVoltage(void)
  168. {
  169.   input_voltage = (VREF * getADCResult(3) / getADCResult(5) * 11); // 计算下分压电阻点的电压,并乘分压比,获得实际的输入电压
  170. }

  171. /* 计算T12热电偶温度 */
  172. void getT12Temperature(void)
  173. {
  174.   float x = 0.0f;
  175.   t12 = 0;         //测温的时候,关闭电烙铁
  176.   Delay_us(10);    // 等待一段时间,等电容放完电后再测量温度比较准确
  177.   getT12Voltage(); // 更新T12热电偶电压
  178.                    //T12实际温度 = (ADC电压(mV)-失调电压(mV))/运放增益*热电偶分度值(℃/mV)+室温(℃)
  179.                    //t12Temp = 1.0f*getT12Voltage() / 231.0f * 54.0f + 23.0f;

  180.   // 插值函数计算T12温度,上面的算得不够准确,自己测量了t12温度与热电偶电动势的关系,用matlab拟合出来的公式
  181.   x = 1.0f * t12_voltage / 231.0f;
  182.   x = -0.9f * x * x + 48.0f * x + 22.0f;
  183.   t12ActualTemperature = (unsigned int)x;
  184. }

  185. /*
  186. // 增量式PID控制算法,该算法用在温度控制效果不佳,调参调了比较久,不是很理想
  187. // 输入设定温度和当前温度
  188. // 返回当前应该加热的时长
  189. void incrementalPID(unsigned int setTemperature, unsigned int actualTemperature)
  190. {
  191.   float delta_uk = 0.0f;                   // 用于计算PID增量值
  192.   uk_1 = uk;                               // 记录上次计算的PID调整值
  193.   ek_2 = ek_1;                             // 记录上上次计算的偏差值
  194.   ek_1 = ek;                               // 记录上次计算的偏差值
  195.   ek = setTemperature - actualTemperature; // 计算当前偏差值
  196.   if (ek < 0)
  197.   {
  198.     // 如果实际温度比设定温度还要高,那么不执行加热
  199.     need_heat_time = 0;
  200.     return;
  201.   }
  202.   if (abs(ek) > 100)
  203.   {
  204.     // 如果温差大于100℃,则执行系统的动态加速,不管比例项为正还是为负,都取正数
  205.     delta_uk = KP * abs(ek - ek_1) + KI * ek + KD * (ek - 2 * ek_1 + ek_2); // 计算PID增量值
  206.   }
  207.   else
  208.   {
  209.     // 当快要接近目标温度的时候,执行正常的调节
  210.     delta_uk = KP * (ek - ek_1) + KI * ek + KD * (ek - 2 * ek_1 + ek_2); // 计算PID增量值
  211.   }
  212.   uk = uk_1 + delta_uk; // 计算当前应该输出的PWM值
  213.   // 判断是否超出了系统控制量的边界范围,如果超出,则赋值为边界
  214.   if (uk < 1e-9)
  215.   {
  216.     uk = 0.0f;
  217.   }
  218.   if (uk > MAX_UK)
  219.   {
  220.     uk = MAX_UK;
  221.   }
  222.   need_heat_time = (unsigned int)uk;
  223. }
  224. */

  225. // 位置式PID控制算法,这个控制算法运行起来比较理想
  226. void positionalPID(unsigned int setTemperature, unsigned int actualTemperature)
  227. {
  228.   ek_1 = ek;                               // 记录上次计算的偏差值
  229.   ek = setTemperature - actualTemperature; // 计算当前偏差值
  230.   if (ek < 0)
  231.   {
  232.     // 如果实际温度比设定温度还要高,那么不执行加热
  233.     need_heat_time = 0;
  234.     return;
  235.   }
  236.   // 当偏差较大时,取消积分作用
  237.   if (abs(ek) > 100)
  238.   {
  239.     integralSum = 0;
  240.   }
  241.   else
  242.   {
  243.     // 否则,根据情况进行累计积分
  244.     if (integralSum > 100) //积分超过上限时,只累计负的积分量
  245.     {
  246.       if (ek < 0)
  247.       {
  248.         integralSum += ek;
  249.       }
  250.     }
  251.     else if (integralSum < -10) //积分超过下限时,只累计正的积分量
  252.     {
  253.       if (ek > 0)
  254.       {
  255.         integralSum += ek;
  256.       }
  257.     }
  258.     else
  259.     {
  260.       integralSum += ek;
  261.     }
  262.   }
  263.   uk = KP * ek + KI * integralSum + KD * (ek - ek_1); // 计算当前应该输出的控制量值
  264.   // 判断是否超出了系统控制量的边界范围,如果超出,则赋值为边界
  265.   if (uk < 1e-9)
  266.   {
  267.     uk = 0.0f;
  268.   }
  269.   if (uk > MAX_UK)
  270.   {
  271.     uk = MAX_UK;
  272.   }
  273.   need_heat_time = (unsigned int)uk; // 更新当前需要加热的时间数
  274. }

  275. /********************************以下是TM1650数码管显示相关的函数****************************************************/

  276. void Start1650(void)
  277. { //开始信号
  278.   CLK = 1;
  279.   DIO = 1;
  280.   Delay_us(5);
  281.   DIO = 0;
  282.   Delay_us(5);
  283.   DIO = 0;
  284. }

  285. void Ask1650(void)
  286. { //ACK信号
  287.   unsigned char timeout = 1;
  288.   CLK = 1;
  289.   Delay_us(5);
  290.   CLK = 0;
  291.   while ((DIO) && (timeout <= 100))
  292.   {
  293.     timeout++;
  294.   }
  295.   Delay_us(5);
  296.   CLK = 0;
  297. }

  298. void Stop1650(void)
  299. { //停止信号
  300.   CLK = 1;
  301.   DIO = 0;
  302.   Delay_us(5);
  303.   DIO = 1;
  304.   Delay_us(5);
  305. }

  306. void WrByte1650(unsigned char oneByte)
  307. { //写一个字节,高位在前,低位在后
  308.   unsigned char i;
  309.   CLK = 0;
  310.   Delay_us(1);
  311.   for (i = 0; i < 8; i++)
  312.   {
  313.     oneByte = oneByte << 1;
  314.     DIO = CY;
  315.     CLK = 0;
  316.     Delay_us(5);
  317.     CLK = 1;
  318.     Delay_us(5);
  319.     CLK = 0;
  320.   }
  321. }
  322. /*
  323. unsigned char Scan_Key(void)
  324. { // 按键扫描
  325.   unsigned char i;
  326.   unsigned char rekey;
  327.   Start1650();
  328.   WrByte1650(0x49); //读按键命令
  329.   Ask1650();
  330.   //DIO = 1;
  331.   for (i = 0; i < 8; i++)
  332.   {
  333.     CLK = 1;
  334.     rekey = rekey << 1;
  335.     if (DIO)
  336.     {
  337.       rekey++;
  338.     }
  339.     Delay_us(5);
  340.     CLK = 0;
  341.   }
  342.   Ask1650();
  343.   Stop1650();
  344.   return (rekey);
  345. }
  346. */

  347. void Set1650(unsigned char add, unsigned char dat)
  348. { //数码管显示
  349.   //写显存必须从高地址开始写
  350.   Start1650();
  351.   WrByte1650(add); //第一个显存地址
  352.   Ask1650();
  353.   WrByte1650(dat);
  354.   Ask1650();
  355.   Stop1650();
  356. }

  357. // 初始化1650,传入亮度参数,范围0~7
  358. void init1650(unsigned char light)
  359. {
  360.   Set1650(0x48, ((light << 4) | 0x01));
  361. }

  362. // 数码管显示函数
  363. void display(signed int num)
  364. {
  365.   // 计算这个数字对应的千百十个位的数字
  366.   unsigned int tmpnum, qian, bai, shi, ge;
  367.   if (num < 0)
  368.     num = -num;
  369.   tmpnum = num;
  370.   qian = tmpnum / 1000;
  371.   tmpnum %= 1000;
  372.   bai = tmpnum / 100;
  373.   tmpnum %= 100;
  374.   shi = tmpnum / 10;
  375.   ge = tmpnum % 10;

  376.   Set1650(0x68, CODE[qian]);
  377.   Set1650(0x6A, CODE[bai]);
  378.   Set1650(0x6C, CODE[shi]);
  379.   Set1650(0x6E, CODE[ge]);
  380. }

  381. /************************************************************************************************
  382.     函数名称:Encoder
  383.     函数功能:编码器旋转的扫描及处理
  384.     入口参数:无
  385.     出口参数:char型    0-无旋转   'R'-正转(向右转)   'L'-反转(向左转)
  386. ************************************************************************************************/
  387. unsigned char Encoder(void)
  388. {
  389.   static bit Enc0 = 0;
  390.   static unsigned char EncOld, EncX = 0;
  391.   unsigned char EncNow;

  392.   encodera = 1; //PINA置高电平
  393.   encoderb = 1; //PINB置高电平
  394.   if (Enc0 == 0)
  395.   {
  396.     EncOld = (encodera ? 0x02 : 0x00) + (encoderb ? 0x01 : 0x00);
  397.     Enc0 = 1; //记住初次调用时编码器的状态
  398.   }
  399.   EncNow = (encodera ? 0x02 : 0x00) + (encoderb ? 0x01 : 0x00); //根据两个IO当前状态组合成16进制的0x00|0x01|0x02|0x03
  400.   if (EncNow == EncOld)
  401.     return (0); //如果新数据和原来的数据一样(没有转动)就直接返回0

  402.   if (EncOld == 0x00 && EncNow == 0x02 || EncOld == 0x03 && EncNow == 0x01)
  403.     EncX = EncNow;                                                                                          //00-10|11-01
  404.   if (EncOld == 0x00 && EncX == 0x02 && EncNow == 0x03 || EncOld == 0x03 && EncX == 0x01 && EncNow == 0x00) //00-10-11|11-01-00右转
  405.   {
  406.     EncOld = EncNow, EncX = 0;
  407.     return ('R'); //两定位一脉冲
  408.   }

  409.   if (EncOld == 0x00 && EncNow == 0x01 || EncOld == 0x03 && EncNow == 0x02)
  410.     EncX = EncNow;                                                                                          //00-01|11-10
  411.   if (EncOld == 0x00 && EncX == 0x01 && EncNow == 0x03 || EncOld == 0x03 && EncX == 0x02 && EncNow == 0x00) //00-01-11|11-10-00左转
  412.   {
  413.     EncOld = EncNow;
  414.     EncX = 0;
  415.     return ('L'); //两定位一脉冲
  416.   }
  417.   return (0); //没有正确解码返回0
  418. }

  419. // 编码器函数,用于设置t12的设定温度
  420. void bianmaqi()
  421. {
  422.   unsigned char enc;
  423.   enc = Encoder(); //扫描编码器,取得返回值
  424.   if (enc == 'R')
  425.   {
  426.     t12SetTemperature += 5;
  427.     if (t12SetTemperature > 500)
  428.       t12SetTemperature = 500;
  429.     isChangeTemperature = 1;
  430.   }
  431.   else if (enc == 'L')
  432.   {
  433.     t12SetTemperature -= 5;
  434.     if (t12SetTemperature < 10)
  435.       t12SetTemperature = 10;
  436.     isChangeTemperature = 1;
  437.   }

  438.   while (!encoderd)
  439.   {
  440.     push_last_time++;
  441.     Delay_ms(100);
  442.   }
  443.   if (push_last_time > 0 && push_last_time < 8)
  444.   {
  445.     push_last_time = 0;
  446.     Delay_ms(80); // 等待延时一段时间,看看有没有第二次按下
  447.     while (!encoderd)
  448.     {
  449.       push_last_time++;
  450.       Delay_ms(100);
  451.     }
  452.     if (push_last_time > 0 && push_last_time < 8)
  453.     {
  454.       // 双击了编码器按钮,关闭电烙铁输出
  455.       t12SetTemperature = 10;
  456.       t12 = 0;
  457.       isChangeTemperature = 1;
  458.     }
  459.     else
  460.     {
  461.       // 短按一次编码器按钮,设定为300℃输出
  462.       t12SetTemperature = 300;
  463.       isChangeTemperature = 1;
  464.     }
  465.   }
  466.   else if (push_last_time >= 8)
  467.   {
  468.     // 长按编码器按钮,设定为250℃输出
  469.     t12SetTemperature = 250;
  470.     isChangeTemperature = 1;
  471.   }
  472.   if (isChangeTemperature)
  473.   {
  474.     // 如果有改变设置温度,那么就要显示新的设置温度
  475.     setTempShowTime = 600;
  476.   }
  477.   push_last_time = 0;
  478. }

  479. // 该定时器初始化函数部分使用STC-ISP下载软件生成,加入开启中断的寄存器赋值
  480. void Timer0Init(void) //500微秒 0.5ms @12.000MHz
  481. {

  482.   AUXR |= 0x80; //定时器时钟1T模式
  483.   TMOD &= 0xF0; //设置定时器模式
  484.   TL0 = 0x90;   //设置定时初值
  485.   TH0 = 0xE8;   //设置定时初值
  486.   TF0 = 0;      //清除TF0标志
  487.   ET0 = 1;      //开启定时器0中断
  488.   TR0 = 1;      //定时器0开始计时
  489.   EA = 1;       // CPU总中断允许控制位
  490. }

  491. //定时0中断函数,每隔0.5ms执行一次
  492. void timer0(void) interrupt 1
  493. {
  494.   bianmaqi(); // 调用编码器函数,获取编码器当前状态(左旋,右旋,短按,长按)
  495.   if (heat_time_count < need_heat_time)
  496.   {
  497.     // 如果当前还没完成需要加热的时长,就控制t12加热
  498.     t12 = 1;
  499.     heat_time_count++;
  500.   }
  501.   else
  502.   {
  503.     // 已经完成相应的加热时长,调用PID函数获取下一个需要的加热数
  504.     t12 = 0;
  505.     getT12Temperature();                                    // 获取当前T12的温度
  506.     positionalPID(t12SetTemperature, t12ActualTemperature); // 更新当前需要加热的时间计数
  507.     heat_time_count = 0;                                    //重新开始统计加热时长
  508.   }

  509.   if (setTempShowTime > 0)
  510.   {
  511.     // 还没显示够显示设置温度的时长,需要继续显示,这里用7开头表示显示设定温度
  512.     display(t12SetTemperature + 7000);
  513.     setTempShowTime--;
  514.     // 已经显示了设置温度了,那么要把这个更改过设置温度的标志开关关闭
  515.     isChangeTemperature = 0;
  516.   }
  517.   else
  518.   {
  519.     if (actualTempShowTime < 2)
  520.     {
  521.       display(t12ActualTemperature); // 显示当前的t12实际温度
  522.       actualTempShowTime = 250;
  523.     }
  524.     actualTempShowTime--;
  525.   }
  526. }

  527. void main()
  528. {
  529.   initIO(); // 初始化IO口
  530.   t12 = 0;
  531.   init1650(1); // 初始化TM1650显示
  532.   initADC();   // 初始化ADC

  533.   getSystemVoltage(); //检测单片机电源电压
  534.   getInputVoltage();  //检测输入电压

  535.   // 显示输入电压,这里的7123和7456仅仅只是用于标识显示什么内容,毕竟没有OLED屏幕这么高大上可以显示很多内容
  536.   display(7123);
  537.   Delay_ms(1000);
  538.   display(input_voltage / 10); // 最大输入电压24000mv, 只有4位数码管
  539.   Delay_ms(1500);
  540.   // 显示单片机电源电压
  541.   display(7456);
  542.   Delay_ms(1000);
  543.   display(system_voltage);
  544.   Delay_ms(1500);

  545.   Timer0Init(); // 初始化定时器0
  546.   while (1)
  547.   {
  548.   }
  549. }
复制代码


附件是我用的固件

开机首先显示7123
然后显示系统电压,单位mv
然后显示7456
然后显示单片机供电电压,单位mv

然后进入工作模式

可以通过旋转编码器调整设定温度,调整设定温度的时候,数码管会以7开头

可以通过短按编码器快速设置设定温度为300℃
通过长按编码器快速设置温度为250℃
通过双击编码器快速关闭T12输出(设定温度为10℃)

暂时只有这么多功能。


STC15W408AS_T12_Controller_hex.zip (5.05 KB, 下载次数: 19, 售价: 20 M币)

打赏

参与人数 7M币 +140 收起 理由
cushion + 20 優秀文章
ch104517745 + 20
超级女生 + 20 認真發帖
zhuqing-1920 + 20
zhwj8025 + 20 謝謝分享
8139 + 20 優秀文章
花生仔 + 20 優秀文章

查看全部打赏

回复 支持 3 反对 0

使用道具 举报

发表于 2020-3-15 02:20:57 来自手机浏览器 | 显示全部楼层
不错,学习下!
回复 支持 反对

使用道具 举报

发表于 2020-3-15 07:44:35 | 显示全部楼层
虽然我看不懂 ,我还是要点个赞
回复 支持 1 反对 0

使用道具 举报

发表于 2020-3-15 08:43:34 来自手机浏览器 | 显示全部楼层
谢谢分享,很厉害。
现在知道为啥老王老五之类店铺东西便宜了吧,都是工厂淘汰下来的不良品,捡捡垃圾折腾玩还行,真指望它们能派上正经用场是不行的。

打赏

参与人数 1M币 +5 收起 理由
c106czs + 5

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2020-3-15 08:46:06 | 显示全部楼层
不错 一次完整的开发,就是板子体积太大了,可以优化一下。使用效果和pid算法有很大关系,没有所谓的最佳参数,换个烙铁头都变化很大,建议采取多组pid参数调取来应对不同种类烙铁头才有最佳效果~
回复 支持 反对

使用道具 举报

发表于 2020-3-15 10:39:10 | 显示全部楼层
多向发展,很好的技术
回复 支持 反对

使用道具 举报

发表于 2020-3-15 13:35:03 | 显示全部楼层
谢谢分享。都是大婶级别的。。。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 13:47:19 | 显示全部楼层
aacyxjz 发表于 2020-3-15 08:43
谢谢分享,很厉害。
现在知道为啥老王老五之类店铺东西便宜了吧,都是工厂淘汰下来的不良品,捡捡垃圾折腾 ...

嗐,其实也不能这么说,毕竟这个价格还要什么自行车。曾经在老五家买过QC3.0充电宝的板子,9.9那个,IP5328的主板,使用一切正常,性价比还是可以的。
不过,批量做产品的话,肯定就不能用这些不良品了。自己玩玩还是可以的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 13:50:43 | 显示全部楼层
qrut 发表于 2020-3-15 08:46
不错 一次完整的开发,就是板子体积太大了,可以优化一下。使用效果和pid算法有很大关系,没有所谓的最佳参 ...

嗯,我也觉得,早知道是飞线的话,数码管那个完全不用占这么大体积,甚至用贴片的TM1650直接在数码管背后飞线就好了,引出VCC GND CLK DAT四根线(其实淘宝买个现成的TM1650四位数码管也就2块钱左右)

PID算法,随便调调参数,能用就好,温度显示也不用太精准。
为什么就没有烙铁头厂家愿意放出温度分度表,这样每次用新的烙铁头都要自己标定也很麻烦。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-3-15 13:51:29 | 显示全部楼层
mhtlov 发表于 2020-3-15 10:39
多向发展,很好的技术

代码觉得也不难理解,自己本来就是计算机专业的码农 哈哈哈,可能硬件设计方面要加强。
回复 支持 反对

使用道具 举报

发表于 2020-3-15 14:49:44 | 显示全部楼层
本帖最后由 wuheart 于 2020-3-15 23:47 编辑

   Rebuild target 'Target 1'assembling STARTUP.A51...
compiling main.c...
linking...
*** WARNING L16: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS
    SEGMENT: ?PR?CLOSEADC?MAIN
*** WARNING L15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?_GETADCRESULT?MAIN
    CALLER1: ?C_C51STARTUP
    CALLER2: ?PR?TIMER0?MAIN
*** WARNING L15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?_INSERTIONSORT?MAIN
    CALLER1: ?C_C51STARTUP
    CALLER2: ?PR?TIMER0?MAIN
*** WARNING L15: MULTIPLE CALL TO SEGMENT
    SEGMENT: ?PR?_DISPLAY?MAIN
    CALLER1: ?C_C51STARTUP
    CALLER2: ?PR?TIMER0?MAIN
*** ERROR L107: ADDRESS SPACE OVERFLOW
    SPACE:   DATA   
    SEGMENT: _DATA_GROUP_
    LENGTH:  0032H
Program Size: data=125.4 xdata=0 code=3971
Target not created.
Build Time Elapsed:  00:00:01
怎么 不能创建 ,这是什么问题
回复 支持 反对

使用道具 举报

发表于 2020-3-15 14:55:55 | 显示全部楼层
休眠还是需要的,我的白菜白光是24小时待机的,从来不关,没休眠每次要开懒啊
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2020-3-15 15:58:59 来自手机浏览器 | 显示全部楼层
ww5223017240 发表于 2020-3-15 14:55
休眠还是需要的,我的白菜白光是24小时待机的,从来不关,没休眠每次要开懒啊 ...

暂时没加,现在是双击编码器休眠。
回复 支持 反对

使用道具 举报

发表于 2020-3-15 16:45:06 | 显示全部楼层
你竟然为了拼版加几条线把几块板子连起来哈哈哈哈哈,666
回复 支持 反对

使用道具 举报

发表于 2020-3-15 16:45:22 | 显示全部楼层
c106czs 发表于 2020-3-15 13:50
嗯,我也觉得,早知道是飞线的话,数码管那个完全不用占这么大体积,甚至用贴片的TM1650直接在数码管背后 ...

其实pid比温度分度更重要,我手底下的一把数控t12论功能估计可能找不到第二把这么完善细致了,想到想不到的功能全都有,包括换各类烙铁头的预设参数,但是只是针对3种 深圳山寨货,南京头 和原装头,作者根据三种烙铁的结构和参数设计了3组参数来适应这3种头,但是仍旧不能很好的解决换头带来的温度波动,例如两个原装头,一个刀头,一个细尖弯头,调到300度时刀头基本不会过冲,尖头就会出现5-10度过冲,这时调整到200度,100度(他这个最低可以到100,自由设定),过冲越来越大能到几十度,其实就是单一pid算法不能时候所以烙铁头,我和作者沟通后作者答应后期考虑加入pid多组调用功能。他解决测温问题才用了段落校正的方法,比如100-200算一个段落基本看做线性,设置一个中心校正点,用户可以校准温度。200-250一个,以此类推,这样每个小段落基本都可以近似看做线性,也就不需要程序上再去设计合适的测温算法,因为没有一种算法适合所有烙铁头,只有装上以后手工校准才最准~

打赏

参与人数 1M币 +5 收起 理由
c106czs + 5

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2020-3-15 17:15:20 | 显示全部楼层
做的很不错,洞洞板更得支持了
回复 支持 反对

使用道具 举报

发表于 2020-3-15 17:31:38 | 显示全部楼层
qrut 发表于 2020-3-15 16:45
其实pid比温度分度更重要,我手底下的一把数控t12论功能估计可能找不到第二把这么完善细致了,想到想不到 ...

这种实在是太复杂了,而且真的有必要吗?又不是3D打印这种,烙铁能化锡就可以了吧?难道是为了考虑头子的寿命?

打赏

参与人数 1M币 +1 收起 理由
bxak + 1 够用好用就行,我也是用自己算法.

查看全部打赏

回复 支持 1 反对 0

使用道具 举报

发表于 2020-3-15 18:55:15 | 显示全部楼层
知识综合性很强的制作,好多方面比我强太多,佩服佩服

打赏

参与人数 1M币 +5 收起 理由
c106czs + 5 感谢大佬指导!

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2020-3-15 19:15:40 | 显示全部楼层
感谢楼主的无私分享,学习中……
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|手机版|小黑屋|关于我们|联系我们|网站条款|数码之家 ( 闽ICP备05031405号 )

GMT+8, 2020-6-4 16:25 , Processed in 0.078000 second(s), 14 queries , Redis On.

Powered by Discuz!

© 2001-2019 Comsenz Inc.

快速回复 返回顶部 返回列表