极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 15768|回复: 8

arduino uno 第一次用于商业项目

[复制链接]
发表于 2014-12-16 23:21:34 | 显示全部楼层 |阅读模式

       深入学习arduino基本上是从极客工坊这个论坛开始的,看了精华区的很多教程,非常感谢有这个论坛,也非常感谢那些愿意跟大家分享学习心得的朋友。

       为了回馈论坛,特地奉献上本人最近利用arduino uno开发的一个商业项目源代码,PCB以及其它器件资料因为商业因素,不便透露,敬请谅解。

        本项目用了18B20进行温度测量,用到PID对温度进行恒温控制,用到定时器TIMER1进行了步进电机的速度控制,另外对串口、EEPROM的读写操作也比较多,有兴趣的朋友可以作为参考。

         本人之前从事过一些C51项目的开发,对arduino其实不算精通,因此基本上是拿来主义,不求甚解,因此很多细节的问题我无法做深入的解答,但设计思路方面,可以与我讨论(其实最重要是解决问题的思路)。


  1. #include <EEPROM.h>
  2. unsigned char recordMaxID = 0;                                                                                  //组号
  3. unsigned int  targetTemp = 0;                                                                                   //设定温度
  4. unsigned char targetSpeed = 0;                                                                                  //设定速度
  5. //========================================================================================================================================
  6. #include <TimerOne.h>
  7. #define PIN_ENCODER 2                                                                                                //光电位移计数开关(外部中断源0)
  8. #define PIN_LIMIT 3                                                                                                //极限位置开关(外部中断源1)
  9. #define PIN_ZERO 4                                                                                                //零位开关
  10. #define PIN_PULSE 5                                                                                             //脉冲
  11. #define PIN_DIR 6                                                                                               //方向
  12. boolean pulseLevel = LOW;                                                                                       //脉冲
  13. boolean pulseDir = HIGH;                                                                                        //方向(LOW-正转,HIGH-反转)
  14. unsigned int Distence = 0;                                                                                        //位移计数值
  15. boolean FlagRun = false;                                                                                        //运行状态
  16. //========================================================================================================================================
  17. #include <OneWire.h>
  18. #include <DallasTemperature.h>
  19. #define TEMPERATURE_PRECISION 12                                                                                //温度采集精度12位
  20. #define PIN_TEMP  8                                                                                                  //温度传感器                                                                                                                
  21. DeviceAddress tempDeviceAddress1;
  22. OneWire oneWire1(PIN_TEMP);                                 
  23. DallasTemperature sensors1(&oneWire1);
  24. double CurrentTemp = 0;
  25. //========================================================================================================================================
  26. #include <PID_v1.h>
  27. #define PIN_BUMP 11                                                                                                //水泵
  28. #define PIN_HOT  12                                                                                                //加热管继电器
  29. #define PIN_COOL 13                                                                                                //压缩机继电器
  30. double Ki = 0,Kp = 0,Kd = 0;
  31. double Setpoint, Input, Output;                                                                                        //目标温度值,输入值,输出值
  32. PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
  33. int WindowSize = 5000;                                                                                                //温度控制周期5s
  34. unsigned long windowStartTime = 0;

  35. boolean FlagTempCtrl = false;
  36. boolean BumpState = HIGH;
  37. //========================================================================================================================================
  38. unsigned char SampleID = 0;
  39. unsigned int Ductility[3];
  40. unsigned char readRecordID = 1;
  41. //========================================================================================================================================
  42. void initGPIO()
  43. {
  44.   pinMode(PIN_ENCODER,INPUT);
  45.   pinMode(PIN_LIMIT,INPUT);
  46.   pinMode(PIN_ZERO,INPUT);

  47.   pinMode(PIN_BUMP,OUTPUT);
  48.   pinMode(PIN_HOT,OUTPUT);
  49.   pinMode(PIN_COOL,OUTPUT);

  50.   pinMode(PIN_PULSE,OUTPUT);
  51.   pinMode(PIN_DIR,OUTPUT);

  52.   digitalWrite(PIN_BUMP,HIGH);
  53.   digitalWrite(PIN_HOT,HIGH);
  54.   digitalWrite(PIN_COOL,HIGH);

  55.   digitalWrite(PIN_PULSE,LOW);
  56.   digitalWrite(PIN_DIR,LOW);  
  57. }
  58. //========================================================================================================================================
  59. void init18B20()
  60. {
  61.   sensors1.begin();
  62.   sensors1.getAddress(tempDeviceAddress1,0);
  63.   sensors1.setResolution(tempDeviceAddress1,TEMPERATURE_PRECISION);
  64. }

  65. void initPID()
  66. {
  67.   Setpoint = float(targetTemp / 10.0);
  68.   myPID.SetTunings(Kp,Ki,Kd);
  69.   myPID.SetOutputLimits(0, WindowSize);
  70.   myPID.SetControllerDirection(DIRECT);
  71.   myPID.SetMode(AUTOMATIC);
  72. }

  73. void tempCtrlStart()
  74. {
  75.   //1.打开压缩机
  76.   initPID();
  77.   digitalWrite(PIN_COOL,LOW);       

  78.   //2.采集温度,温控输出
  79.   sensors1.requestTemperatures();
  80.   CurrentTemp = sensors1.getTempC(tempDeviceAddress1);
  81.   unsigned int Temp=CurrentTemp*100;
  82.   unsigned char tempChar[8] = {
  83.     0x5A,0xA5,0x05,0x82,0x00,0x0F, char(Temp>>8), char(Temp & 0x00FF)  };
  84.   Serial.write(tempChar,8);  

  85.   //3.温度控制
  86.   Input = CurrentTemp;
  87.   myPID.Compute();

  88.   unsigned long now = millis();
  89.   if(now - windowStartTime > WindowSize)
  90.     windowStartTime += WindowSize;

  91.   if(Output < now - windowStartTime)
  92.     digitalWrite(PIN_HOT,HIGH);//OFF
  93.   else
  94.     digitalWrite(PIN_HOT,LOW);//ON
  95. }

  96. void tempCtrlStop()
  97. {
  98.   FlagTempCtrl = false;
  99.   digitalWrite(PIN_COOL,HIGH);
  100.   digitalWrite(PIN_HOT,HIGH);  
  101. }

  102. //========================================================================================================================================
  103. unsigned long getTime;
  104. void getDistance()
  105. {
  106.   if(pulseDir == LOW)
  107.   {
  108.     if(digitalRead(PIN_LIMIT) == LOW)
  109.     {
  110.       Timer1.stop();
  111.     }   
  112.   }
  113.   if(pulseDir == HIGH)
  114.   {
  115.     if(digitalRead(PIN_ZERO) == LOW)
  116.     {
  117.       Timer1.stop();
  118.     }      
  119.   }

  120.   if(FlagRun == true)
  121.   {     
  122.     if(digitalRead(PIN_ENCODER) == LOW)
  123.     {
  124.       unsigned int delayTime = 0;
  125.       if(targetSpeed == 50)
  126.       {
  127.         delayTime = 480;
  128.       }
  129.       else
  130.       {
  131.         delayTime = 2400;
  132.       }
  133.       if((millis() - getTime) > delayTime)
  134.       {
  135.         getTime = millis();
  136.         Distence++;
  137.         unsigned char setChar[8] = {
  138.           0x5A,0xA5,0x05,0x82,0x00,0x09+SampleID,Distence>>8,Distence & 0x00FF };
  139.         Serial.write(setChar,8);
  140.       }
  141.     }
  142.   }
  143. }

  144. void pulse()
  145. {
  146.   getDistance();

  147.   pulseLevel =! pulseLevel;
  148.   digitalWrite(PIN_PULSE,pulseLevel);
  149. }

  150. void initTimer1()
  151. {
  152.   Timer1.initialize(58);
  153.   Timer1.attachInterrupt(pulse);  
  154.   Timer1.stop();
  155. }

  156. void moveMotor(unsigned int mySpeed ,boolean myDir)
  157. {
  158.   digitalWrite(PIN_DIR,myDir);
  159.   pulseDir = myDir;
  160.   switch(mySpeed)
  161.   {
  162.   case 10:
  163.     Timer1.setPeriod(2344);
  164.     break;   
  165.   case 50:
  166.     Timer1.setPeriod(469);
  167.     break;   
  168.   case 400:
  169.     Timer1.setPeriod(58);
  170.     break;   
  171.   default:
  172.     Timer1.setPeriod(58);   
  173.     break;
  174.   }
  175.   Timer1.restart();
  176. }
  177. //========================================================================================================================================
  178. void readSetting()
  179. {
  180.   recordMaxID = EEPROM.read(0);
  181.   if(recordMaxID > 100)
  182.   {
  183.     recordMaxID = 1;
  184.     EEPROM.write(0,recordMaxID);
  185.   }
  186.   targetTemp = (EEPROM.read(1)<<8)+EEPROM.read(2);
  187.   targetSpeed = EEPROM.read(3);
  188.   unsigned int iKp,iKi,iKd;
  189.   iKp = (EEPROM.read(4)<<8)+EEPROM.read(5);
  190.   iKi = (EEPROM.read(6)<<8)+EEPROM.read(7);
  191.   iKd = (EEPROM.read(8)<<8)+EEPROM.read(9);
  192.   Ki = float(iKi);
  193.   Kd = float(iKd);
  194.   Kp = float(iKp);
  195.   unsigned char Para[22] = {
  196.     0x5A,0xA5,0x13,0x82,0x00,0x70,0x00,recordMaxID,targetTemp>>8,targetTemp & 0x00FF,0x00,targetSpeed,iKp>>8,iKp & 0x00FF,iKi>>8,iKi & 0x00FF,iKd>>8,iKd & 0x00FF,0x00,targetSpeed,targetTemp>>8,targetTemp & 0x00FF };
  197.   Serial.write(Para,22);
  198. }

  199. void saveSetting()
  200. {
  201.   String indata = "";
  202.   unsigned char getPara[7] = {
  203.     0x5A,0xA5,0x04,0x83,0x00,0x71,0x05 };
  204.   Serial.write(getPara,7);
  205.   delay(200);
  206.   while (Serial.available() > 0)
  207.   {
  208.     indata += char(Serial.read());
  209.     delay(2);
  210.   }
  211.   if(indata.length() > 0)
  212.   {
  213.     EEPROM.write(1,indata[7]);
  214.     EEPROM.write(2,indata[8]);
  215.     //targetTemp = (indata[7]<<8)+indata[8];写法有错但没找到原因,所以用下一句实现
  216.     targetTemp = (EEPROM.read(1)<<8)+EEPROM.read(2);
  217.     EEPROM.write(3,indata[10]);
  218.     targetSpeed = indata[10];

  219.     EEPROM.write(4,indata[11]);
  220.     EEPROM.write(5,indata[12]);
  221.     Kp = float((indata[11]<<8)+indata[12]);
  222.     EEPROM.write(6,indata[13]);
  223.     EEPROM.write(7,indata[14]);
  224.     Ki = float((indata[13]<<8)+indata[14]);       
  225.     EEPROM.write(8,indata[15]);
  226.     EEPROM.write(9,indata[16]);
  227.     Kd = float((indata[15]<<8)+indata[16]);       

  228.     unsigned char setPara[10] = {
  229.       0x5A,0xA5,0x07,0x82,0x00,0x76,0x00,indata[10],indata[7],indata[8] };
  230.     Serial.write(setPara,10);
  231.   }
  232.   indata = "";
  233. }

  234. void saveRecord()
  235. {
  236.   Ductility[SampleID] = Distence;
  237.   SampleID++;
  238.   
  239.   if(SampleID == 3)
  240.   {
  241.     Timer1.stop();
  242.     FlagRun = false;
  243.     unsigned char TestOFF[8] = {
  244.       0x5A,0xA5,0x05,0x82,0x00,0x12,0x00,0x00  
  245.     };
  246.     Serial.write(TestOFF, 8);  
  247.     delay(50);
  248.        
  249.     SampleID = 0;
  250.     unsigned int AVG = 0;
  251.     AVG = int((Ductility[0]+Ductility[1]+Ductility[2])/3);
  252.     unsigned char setPara[8] = {
  253.       0x5A,0xA5,0x05,0x82,0x00,0x0C,AVG>>8,AVG & 0x00FF  };
  254.     Serial.write(setPara,8);

  255.     EEPROM.write(0,recordMaxID);
  256.     EEPROM.write(20+recordMaxID*6 + 1,Ductility[0]>>8);
  257.     EEPROM.write(20+recordMaxID*6 + 2,Ductility[0] & 0x00FF);
  258.     EEPROM.write(20+recordMaxID*6 + 3,Ductility[1]>>8);
  259.     EEPROM.write(20+recordMaxID*6 + 4,Ductility[1] & 0x00FF);
  260.     EEPROM.write(20+recordMaxID*6 + 5,Ductility[2]>>8);
  261.     EEPROM.write(20+recordMaxID*6 + 6,Ductility[2] & 0x00FF);            

  262.     if(recordMaxID < 100)
  263.       recordMaxID++;
  264.     else
  265.       recordMaxID = 1;   
  266.   }
  267. }

  268. void readRecord(unsigned char id)
  269. {
  270.   delay(50);
  271.   unsigned int s1,s2,s3,avg;
  272.   s1=(EEPROM.read(20+id*6 + 1)<<8)+EEPROM.read(20+id*6 + 2);
  273.   s2=(EEPROM.read(20+id*6 + 3)<<8)+EEPROM.read(20+id*6 + 4);
  274.   s3=(EEPROM.read(20+id*6 + 5)<<8)+EEPROM.read(20+id*6 + 6);
  275.   avg=(s1+s2+s3)/3;
  276.   
  277.   unsigned char setRecord[16] = {
  278.     0x5A,0xA5,0x0D,0x82,0x00,0x13,0x00,id,s1>>8,s1 & 0x00ff,s2>>8,s2 & 0x00ff,s3>>8,s3 & 0x00ff,avg>>8,avg & 0x00ff
  279.   };
  280.   Serial.write(setRecord,16);
  281. }

  282. //========================================================================================================================================
  283. void readComm()
  284. {
  285. unsigned char TestOFF[8] = {
  286.    0x5A,0xA5,0x05,0x82,0x00,0x12,0x00,0x00  };  
  287. unsigned char TestON[8] = {
  288.    0x5A,0xA5,0x05,0x82,0x00,0x12,0x00,0x01  };  
  289.    
  290. unsigned char TempON[8] = {
  291.    0x5A,0xA5,0x05,0x82,0x00,0x0E,0x00,0x01  };   
  292. unsigned char TempOFF[8] = {
  293.    0x5A,0xA5,0x05,0x82,0x00,0x0E,0x00,0x00  };

  294. unsigned char BumpON[8] = {
  295.    0x5A,0xA5,0x05,0x82,0x00,0x0D,0x00,0x01  };
  296. unsigned char BumpOFF[8] = {
  297.    0x5A,0xA5,0x05,0x82,0x00,0x0D,0x00,0x00  };   

  298. unsigned char setChar[14] = {
  299.    0x5A,0xA5,0x0b,0x82,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00  };   
  300. unsigned char setmaxRecordID[8] = {
  301.    0x5A,0xA5,0x05,0x82,0x00,0x70,0x00,recordMaxID  };

  302.   String indata = "";
  303.   while (Serial.available() > 0)  
  304.   {
  305.     indata += char(Serial.read());
  306.     delay(2);
  307.   }
  308.   if(indata.length() > 0)
  309.   {
  310.     switch (indata[8])
  311.     {
  312.     case 0x01://归零
  313.       if(FlagRun == false)
  314.         moveMotor(400,HIGH);
  315.       break;
  316.     case 0x02://记录
  317.       if(FlagRun == true)
  318.         saveRecord();
  319.       break;
  320.     case 0x03://前进
  321.       if(FlagRun == false)
  322.         moveMotor(targetSpeed,LOW);
  323.       break;
  324.     case 0x04://后退
  325.       if(FlagRun == false)
  326.         moveMotor(targetSpeed,HIGH);
  327.       break;
  328.     case 0x05://开始   
  329.       if(FlagRun == false)
  330.       {
  331.         FlagRun = true;
  332.         Serial.write(TestON, 8);
  333.         delay(50);               
  334.         
  335.         SampleID = 0;
  336.         Distence = 0;
  337.         Ductility[0] = 0;
  338.         Ductility[1] = 0;
  339.         Ductility[2] = 0;   

  340.         Serial.write(setChar,14);
  341.         delay(50);
  342.         Serial.write(setmaxRecordID,8);
  343.         
  344.         moveMotor(targetSpeed,LOW);      
  345.       }
  346.       break;
  347.     case 0x06://水泵
  348.       BumpState = !BumpState;
  349.       digitalWrite(PIN_BUMP,BumpState);   
  350.       if(BumpState == false)
  351.       {
  352.         Serial.write(BumpON,8);        
  353.       }
  354.       else
  355.       {       
  356.         Serial.write(BumpOFF,8);
  357.       }   
  358.       break;
  359.     case 0x07://温控
  360.       FlagTempCtrl = !FlagTempCtrl;
  361.       if(FlagTempCtrl == false)
  362.       {
  363.         tempCtrlStop();                     
  364.         Serial.write(TempOFF, 8);
  365.       }
  366.       else
  367.       {          
  368.         Serial.write(TempON, 8);
  369.       }
  370.       break;
  371.     case 0x08: //停止  
  372.       Timer1.stop();
  373.       FlagRun = false;
  374.       Serial.write(TestOFF, 8);
  375.       break;
  376.     case 0x11: //参数保存
  377.       saveSetting();   
  378.       break;   
  379.     case 0x18://查询前翻页
  380.       readRecordID--;
  381.       if(readRecordID==0)
  382.       {
  383.         readRecordID = 100;
  384.       }
  385.       readRecord(readRecordID);
  386.       break;
  387.     case 0x19://查询后翻页
  388.       readRecordID++;
  389.       if(readRecordID==101)
  390.       {
  391.         readRecordID = 1;
  392.       }
  393.       readRecord(readRecordID);   
  394.       break;
  395.     }                 
  396.   }
  397.   indata = "";
  398. }
  399. //========================================================================================================================================
  400. void setup()
  401. {
  402.   unsigned char LED[7] = {
  403.     0x5A,0xA5,0x03,0x80,0x01,0x40 };
  404.   unsigned char PIC[8] = {
  405.     0x5A,0xA5,0x04,0x80,0x03,0x00,0x01 };
  406.    
  407.   Serial.begin(9600);
  408.   delay(2500);
  409.   Serial.write(LED, 7);  
  410.   delay(50);
  411.   Serial.write(PIC, 8);  
  412.   delay(50);
  413.   readSetting();

  414.   initGPIO();
  415.   init18B20();

  416.   windowStartTime = millis();

  417.   initTimer1();
  418.   //moveMotor(400,HIGH);
  419. }

  420. void loop()
  421. {
  422.   readComm();

  423.   if(FlagTempCtrl == true)
  424.     tempCtrlStart();
  425. }
复制代码


回复

使用道具 举报

发表于 2014-12-17 08:19:03 来自手机 | 显示全部楼层
小弟最近在做一款gprs考勤机,希望可以多多交流
回复 支持 反对

使用道具 举报

发表于 2014-12-17 08:33:46 | 显示全部楼层
是工业级别的应用还是消费级别的应用?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-12-17 09:04:59 | 显示全部楼层
zoologist 发表于 2014-12-17 08:33
是工业级别的应用还是消费级别的应用?

算是工业级别吧
回复 支持 反对

使用道具 举报

发表于 2014-12-17 10:02:34 | 显示全部楼层
novelcrab 发表于 2014-12-17 09:04
算是工业级别吧

不错! 厉害!
回复 支持 反对

使用道具 举报

发表于 2014-12-17 14:11:20 | 显示全部楼层
5S的控制周期会不会有点大呢?
回复 支持 反对

使用道具 举报

发表于 2014-12-17 14:24:15 | 显示全部楼层
代码中,“光电位移计数开关”和“极限位置开关”并没有用到外部中断哦
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-12-18 21:10:22 | 显示全部楼层
451506709 发表于 2014-12-17 14:11
5S的控制周期会不会有点大呢?

作为水温控制这样大滞后控制,控制周期为5-20s都是适宜的,所以我取了5秒。

在这个项目中,PID的控制效果应该说还可以,可以控制到0.25摄氏度。

PS:该水温环境有隔热保护,且几乎是密闭的,所以温控效果还令人满意。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-12-18 21:12:54 | 显示全部楼层
451506709 发表于 2014-12-17 14:24
代码中,“光电位移计数开关”和“极限位置开关”并没有用到外部中断哦

在我尝试的过程中发现引脚的中断和定时器TIMER1这个库函数是有冲突的,会导致无法进入中断,所以采用电平检测的方式,而因为在主线程里有一个18B20测温,里面有几百毫秒的延时(delay函数),所以只能把电平检测挪到定时器函数里进行检测。
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-16 17:56 , Processed in 0.042848 second(s), 20 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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