arduino uno 第一次用于商业项目
深入学习arduino基本上是从极客工坊这个论坛开始的,看了精华区的很多教程,非常感谢有这个论坛,也非常感谢那些愿意跟大家分享学习心得的朋友。
为了回馈论坛,特地奉献上本人最近利用arduino uno开发的一个商业项目源代码,PCB以及其它器件资料因为商业因素,不便透露,敬请谅解。
本项目用了18B20进行温度测量,用到PID对温度进行恒温控制,用到定时器TIMER1进行了步进电机的速度控制,另外对串口、EEPROM的读写操作也比较多,有兴趣的朋友可以作为参考。
本人之前从事过一些C51项目的开发,对arduino其实不算精通,因此基本上是拿来主义,不求甚解,因此很多细节的问题我无法做深入的解答,但设计思路方面,可以与我讨论(其实最重要是解决问题的思路)。
#include <EEPROM.h>
unsigned char recordMaxID = 0; //组号
unsigned inttargetTemp = 0; //设定温度
unsigned char targetSpeed = 0; //设定速度
//========================================================================================================================================
#include <TimerOne.h>
#define PIN_ENCODER 2 //光电位移计数开关(外部中断源0)
#define PIN_LIMIT 3 //极限位置开关(外部中断源1)
#define PIN_ZERO 4 //零位开关
#define PIN_PULSE 5 //脉冲
#define PIN_DIR 6 //方向
boolean pulseLevel = LOW; //脉冲
boolean pulseDir = HIGH; //方向(LOW-正转,HIGH-反转)
unsigned int Distence = 0; //位移计数值
boolean FlagRun = false; //运行状态
//========================================================================================================================================
#include <OneWire.h>
#include <DallasTemperature.h>
#define TEMPERATURE_PRECISION 12 //温度采集精度12位
#define PIN_TEMP8 //温度传感器
DeviceAddress tempDeviceAddress1;
OneWire oneWire1(PIN_TEMP);
DallasTemperature sensors1(&oneWire1);
double CurrentTemp = 0;
//========================================================================================================================================
#include <PID_v1.h>
#define PIN_BUMP 11 //水泵
#define PIN_HOT12 //加热管继电器
#define PIN_COOL 13 //压缩机继电器
double Ki = 0,Kp = 0,Kd = 0;
double Setpoint, Input, Output; //目标温度值,输入值,输出值
PID myPID(&Input, &Output, &Setpoint,2,5,1, DIRECT);
int WindowSize = 5000; //温度控制周期5s
unsigned long windowStartTime = 0;
boolean FlagTempCtrl = false;
boolean BumpState = HIGH;
//========================================================================================================================================
unsigned char SampleID = 0;
unsigned int Ductility;
unsigned char readRecordID = 1;
//========================================================================================================================================
void initGPIO()
{
pinMode(PIN_ENCODER,INPUT);
pinMode(PIN_LIMIT,INPUT);
pinMode(PIN_ZERO,INPUT);
pinMode(PIN_BUMP,OUTPUT);
pinMode(PIN_HOT,OUTPUT);
pinMode(PIN_COOL,OUTPUT);
pinMode(PIN_PULSE,OUTPUT);
pinMode(PIN_DIR,OUTPUT);
digitalWrite(PIN_BUMP,HIGH);
digitalWrite(PIN_HOT,HIGH);
digitalWrite(PIN_COOL,HIGH);
digitalWrite(PIN_PULSE,LOW);
digitalWrite(PIN_DIR,LOW);
}
//========================================================================================================================================
void init18B20()
{
sensors1.begin();
sensors1.getAddress(tempDeviceAddress1,0);
sensors1.setResolution(tempDeviceAddress1,TEMPERATURE_PRECISION);
}
void initPID()
{
Setpoint = float(targetTemp / 10.0);
myPID.SetTunings(Kp,Ki,Kd);
myPID.SetOutputLimits(0, WindowSize);
myPID.SetControllerDirection(DIRECT);
myPID.SetMode(AUTOMATIC);
}
void tempCtrlStart()
{
//1.打开压缩机
initPID();
digitalWrite(PIN_COOL,LOW);
//2.采集温度,温控输出
sensors1.requestTemperatures();
CurrentTemp = sensors1.getTempC(tempDeviceAddress1);
unsigned int Temp=CurrentTemp*100;
unsigned char tempChar = {
0x5A,0xA5,0x05,0x82,0x00,0x0F, char(Temp>>8), char(Temp & 0x00FF)};
Serial.write(tempChar,8);
//3.温度控制
Input = CurrentTemp;
myPID.Compute();
unsigned long now = millis();
if(now - windowStartTime > WindowSize)
windowStartTime += WindowSize;
if(Output < now - windowStartTime)
digitalWrite(PIN_HOT,HIGH);//OFF
else
digitalWrite(PIN_HOT,LOW);//ON
}
void tempCtrlStop()
{
FlagTempCtrl = false;
digitalWrite(PIN_COOL,HIGH);
digitalWrite(PIN_HOT,HIGH);
}
//========================================================================================================================================
unsigned long getTime;
void getDistance()
{
if(pulseDir == LOW)
{
if(digitalRead(PIN_LIMIT) == LOW)
{
Timer1.stop();
}
}
if(pulseDir == HIGH)
{
if(digitalRead(PIN_ZERO) == LOW)
{
Timer1.stop();
}
}
if(FlagRun == true)
{
if(digitalRead(PIN_ENCODER) == LOW)
{
unsigned int delayTime = 0;
if(targetSpeed == 50)
{
delayTime = 480;
}
else
{
delayTime = 2400;
}
if((millis() - getTime) > delayTime)
{
getTime = millis();
Distence++;
unsigned char setChar = {
0x5A,0xA5,0x05,0x82,0x00,0x09+SampleID,Distence>>8,Distence & 0x00FF };
Serial.write(setChar,8);
}
}
}
}
void pulse()
{
getDistance();
pulseLevel =! pulseLevel;
digitalWrite(PIN_PULSE,pulseLevel);
}
void initTimer1()
{
Timer1.initialize(58);
Timer1.attachInterrupt(pulse);
Timer1.stop();
}
void moveMotor(unsigned int mySpeed ,boolean myDir)
{
digitalWrite(PIN_DIR,myDir);
pulseDir = myDir;
switch(mySpeed)
{
case 10:
Timer1.setPeriod(2344);
break;
case 50:
Timer1.setPeriod(469);
break;
case 400:
Timer1.setPeriod(58);
break;
default:
Timer1.setPeriod(58);
break;
}
Timer1.restart();
}
//========================================================================================================================================
void readSetting()
{
recordMaxID = EEPROM.read(0);
if(recordMaxID > 100)
{
recordMaxID = 1;
EEPROM.write(0,recordMaxID);
}
targetTemp = (EEPROM.read(1)<<8)+EEPROM.read(2);
targetSpeed = EEPROM.read(3);
unsigned int iKp,iKi,iKd;
iKp = (EEPROM.read(4)<<8)+EEPROM.read(5);
iKi = (EEPROM.read(6)<<8)+EEPROM.read(7);
iKd = (EEPROM.read(8)<<8)+EEPROM.read(9);
Ki = float(iKi);
Kd = float(iKd);
Kp = float(iKp);
unsigned char Para = {
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 };
Serial.write(Para,22);
}
void saveSetting()
{
String indata = "";
unsigned char getPara = {
0x5A,0xA5,0x04,0x83,0x00,0x71,0x05 };
Serial.write(getPara,7);
delay(200);
while (Serial.available() > 0)
{
indata += char(Serial.read());
delay(2);
}
if(indata.length() > 0)
{
EEPROM.write(1,indata);
EEPROM.write(2,indata);
//targetTemp = (indata<<8)+indata;写法有错但没找到原因,所以用下一句实现
targetTemp = (EEPROM.read(1)<<8)+EEPROM.read(2);
EEPROM.write(3,indata);
targetSpeed = indata;
EEPROM.write(4,indata);
EEPROM.write(5,indata);
Kp = float((indata<<8)+indata);
EEPROM.write(6,indata);
EEPROM.write(7,indata);
Ki = float((indata<<8)+indata);
EEPROM.write(8,indata);
EEPROM.write(9,indata);
Kd = float((indata<<8)+indata);
unsigned char setPara = {
0x5A,0xA5,0x07,0x82,0x00,0x76,0x00,indata,indata,indata };
Serial.write(setPara,10);
}
indata = "";
}
void saveRecord()
{
Ductility = Distence;
SampleID++;
if(SampleID == 3)
{
Timer1.stop();
FlagRun = false;
unsigned char TestOFF = {
0x5A,0xA5,0x05,0x82,0x00,0x12,0x00,0x00
};
Serial.write(TestOFF, 8);
delay(50);
SampleID = 0;
unsigned int AVG = 0;
AVG = int((Ductility+Ductility+Ductility)/3);
unsigned char setPara = {
0x5A,0xA5,0x05,0x82,0x00,0x0C,AVG>>8,AVG & 0x00FF};
Serial.write(setPara,8);
EEPROM.write(0,recordMaxID);
EEPROM.write(20+recordMaxID*6 + 1,Ductility>>8);
EEPROM.write(20+recordMaxID*6 + 2,Ductility & 0x00FF);
EEPROM.write(20+recordMaxID*6 + 3,Ductility>>8);
EEPROM.write(20+recordMaxID*6 + 4,Ductility & 0x00FF);
EEPROM.write(20+recordMaxID*6 + 5,Ductility>>8);
EEPROM.write(20+recordMaxID*6 + 6,Ductility & 0x00FF);
if(recordMaxID < 100)
recordMaxID++;
else
recordMaxID = 1;
}
}
void readRecord(unsigned char id)
{
delay(50);
unsigned int s1,s2,s3,avg;
s1=(EEPROM.read(20+id*6 + 1)<<8)+EEPROM.read(20+id*6 + 2);
s2=(EEPROM.read(20+id*6 + 3)<<8)+EEPROM.read(20+id*6 + 4);
s3=(EEPROM.read(20+id*6 + 5)<<8)+EEPROM.read(20+id*6 + 6);
avg=(s1+s2+s3)/3;
unsigned char setRecord = {
0x5A,0xA5,0x0D,0x82,0x00,0x13,0x00,id,s1>>8,s1 & 0x00ff,s2>>8,s2 & 0x00ff,s3>>8,s3 & 0x00ff,avg>>8,avg & 0x00ff
};
Serial.write(setRecord,16);
}
//========================================================================================================================================
void readComm()
{
unsigned char TestOFF = {
0x5A,0xA5,0x05,0x82,0x00,0x12,0x00,0x00};
unsigned char TestON = {
0x5A,0xA5,0x05,0x82,0x00,0x12,0x00,0x01};
unsigned char TempON = {
0x5A,0xA5,0x05,0x82,0x00,0x0E,0x00,0x01};
unsigned char TempOFF = {
0x5A,0xA5,0x05,0x82,0x00,0x0E,0x00,0x00};
unsigned char BumpON = {
0x5A,0xA5,0x05,0x82,0x00,0x0D,0x00,0x01};
unsigned char BumpOFF = {
0x5A,0xA5,0x05,0x82,0x00,0x0D,0x00,0x00};
unsigned char setChar = {
0x5A,0xA5,0x0b,0x82,0x00,0x09,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
unsigned char setmaxRecordID = {
0x5A,0xA5,0x05,0x82,0x00,0x70,0x00,recordMaxID};
String indata = "";
while (Serial.available() > 0)
{
indata += char(Serial.read());
delay(2);
}
if(indata.length() > 0)
{
switch (indata)
{
case 0x01://归零
if(FlagRun == false)
moveMotor(400,HIGH);
break;
case 0x02://记录
if(FlagRun == true)
saveRecord();
break;
case 0x03://前进
if(FlagRun == false)
moveMotor(targetSpeed,LOW);
break;
case 0x04://后退
if(FlagRun == false)
moveMotor(targetSpeed,HIGH);
break;
case 0x05://开始
if(FlagRun == false)
{
FlagRun = true;
Serial.write(TestON, 8);
delay(50);
SampleID = 0;
Distence = 0;
Ductility = 0;
Ductility = 0;
Ductility = 0;
Serial.write(setChar,14);
delay(50);
Serial.write(setmaxRecordID,8);
moveMotor(targetSpeed,LOW);
}
break;
case 0x06://水泵
BumpState = !BumpState;
digitalWrite(PIN_BUMP,BumpState);
if(BumpState == false)
{
Serial.write(BumpON,8);
}
else
{
Serial.write(BumpOFF,8);
}
break;
case 0x07://温控
FlagTempCtrl = !FlagTempCtrl;
if(FlagTempCtrl == false)
{
tempCtrlStop();
Serial.write(TempOFF, 8);
}
else
{
Serial.write(TempON, 8);
}
break;
case 0x08: //停止
Timer1.stop();
FlagRun = false;
Serial.write(TestOFF, 8);
break;
case 0x11: //参数保存
saveSetting();
break;
case 0x18://查询前翻页
readRecordID--;
if(readRecordID==0)
{
readRecordID = 100;
}
readRecord(readRecordID);
break;
case 0x19://查询后翻页
readRecordID++;
if(readRecordID==101)
{
readRecordID = 1;
}
readRecord(readRecordID);
break;
}
}
indata = "";
}
//========================================================================================================================================
void setup()
{
unsigned char LED = {
0x5A,0xA5,0x03,0x80,0x01,0x40 };
unsigned char PIC = {
0x5A,0xA5,0x04,0x80,0x03,0x00,0x01 };
Serial.begin(9600);
delay(2500);
Serial.write(LED, 7);
delay(50);
Serial.write(PIC, 8);
delay(50);
readSetting();
initGPIO();
init18B20();
windowStartTime = millis();
initTimer1();
//moveMotor(400,HIGH);
}
void loop()
{
readComm();
if(FlagTempCtrl == true)
tempCtrlStart();
}
小弟最近在做一款gprs考勤机,希望可以多多交流 是工业级别的应用还是消费级别的应用? zoologist 发表于 2014-12-17 08:33 static/image/common/back.gif
是工业级别的应用还是消费级别的应用?
算是工业级别吧 novelcrab 发表于 2014-12-17 09:04 static/image/common/back.gif
算是工业级别吧
不错! 厉害! 5S的控制周期会不会有点大呢? 代码中,“光电位移计数开关”和“极限位置开关”并没有用到外部中断哦 451506709 发表于 2014-12-17 14:11 static/image/common/back.gif
5S的控制周期会不会有点大呢?
作为水温控制这样大滞后控制,控制周期为5-20s都是适宜的,所以我取了5秒。
在这个项目中,PID的控制效果应该说还可以,可以控制到0.25摄氏度。
PS:该水温环境有隔热保护,且几乎是密闭的,所以温控效果还令人满意。 451506709 发表于 2014-12-17 14:24 static/image/common/back.gif
代码中,“光电位移计数开关”和“极限位置开关”并没有用到外部中断哦
在我尝试的过程中发现引脚的中断和定时器TIMER1这个库函数是有冲突的,会导致无法进入中断,所以采用电平检测的方式,而因为在主线程里有一个18B20测温,里面有几百毫秒的延时(delay函数),所以只能把电平检测挪到定时器函数里进行检测。
页:
[1]