有時候管理者無法第一時間知道生產線的不良,這時候如果有一台警報器可以提醒管理者就很不錯了,依照慣例還是以Arduino來完成它,或許日後可以加上WIFI功能
這一些寫工作都是下班時間利用自己的時間逐步完成的。
#include // Main Loop 使用的函數
#include // IIC communication I2C使用的函數
#include // I2C LCD 使用的函數 使用LiquidCrystal目錄之下的LiquidCrystal_I2C.h
#include // SPI使用的函數【與涂書田馬達通信的函數】
#include // EEPROM
//#include
/*
//***********************************************************************************
// 程式設計:李進衛
// Arduino UNO
// Compiler Arduino IDE
// 延續以前的程式架構採用main loop 架構
// main loop 5ms
// 2014-06-29將microchip程式keyboard process base移植到arduino 系統
// 2014-06-29 移植check time process to Arduino
// 2014-06-29 compiler OK 需要再做hardware test
// Pin 13 has a LED connected on most Arduino boards
// 因為LCD顯示速度比較慢如果還要讓文字有閃爍效果會造成MAIN LOOP的check time副程式超時時序產生錯誤,所以MAIN LOOP改為20MS【2016-03-23李進衛修改】
// 2016-03-23 新增加可以設定NG的數字使它更有彈性
//【按住P_clear按鍵--》開電--》當版本顯示完之後放開P_clear按鍵LCD顯示Set...閃爍狀態就可輸入set counter次數,設定完之後再按一次P_clear
// 確認就可以了】
//
//***********************************************************************************
*/
#define TBASE 20 // main loop time base for 20mS
// #define T100MS 20 //
#define T20MS 20/TBASE //4
#define T30MS 30/TBASE //6
#define T100MS 100/TBASE
#define T150MS 150/TBASE
#define T200MS 200/TBASE
#define T250MS 250/TBASE
#define T300MS 300/TBASE //60
//*******************2014-08-10 由PAD TEST V3 移植過來
#define P_counter 2
#define P_clear 3
#define P_version 4
#define P_revers 5
#define P_relay 8
#define P_ss 10
#define P_LED 13
//#define swd 10
#define adcwait 20
#define ADC_margin 250 //ADC margin
#define relayOn 1
#define relayOff 0
#define user_setcounter_address 0
#define user_counter_address 1
const byte startport = 2; //設定起始pin為第2腳
const byte stopport = 13; //設定掃描線結束位置為13pin
int adcval = 0;
int padval = 0;
byte counter = 0; //counter NG
byte set_counter = 5;
byte keycount = 0;
byte usercounter = 0;
boolean f_keyon;
boolean f_Warning = 0;
boolean f_setting = 0;
boolean f_user_set_counter = 0;
// boolean key4ok = 0;
// boolean key5ok = 0;
// boolean key6ok = 0;
// boolean key7ok = 0;
// boolean key8ok = 0;
// boolean key9ok = 0;
// boolean key10ok = 0;
// boolean key11ok = 0;
// boolean key12ok = 0;
boolean allok = 0;
byte keycode;
//*****************************************************
byte ledState;
boolean Blink1HZ; //1HZ閃爍旗標
boolean Blink2HZ; //2HZ閃爍旗標
boolean TMAIN;
byte T_CNT1;
byte SQN = 0;
byte TB_100MS;
byte TB_250MS;
byte TB_500MS;
byte TB_1SEC;
byte TB_1MINS;
byte TB_1HOURS;
byte T_Blink_Count;
byte KEY_NEW = 0xff; // = 0xFF;
byte KEY_OLD; // = 0xFF;
byte KEY_CMD; // = 0xFF;
byte KEY_CHT; // = T20MS;
byte KEY_SQN = 0; // = 1;
boolean F_CMDON;
boolean F_KEYREP;
byte KEY_CHEN;
byte KEY_REP;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
void setup()
{
DDRD = 0x00; //設定埠D為輸入模式
// pinMode(P_ss,OUTPUT);
pinMode(P_LED,OUTPUT); // LED output pin for output mode
pinMode(P_relay,OUTPUT); // control relay port
digitalWrite(P_LED,LOW); // LED OFF
T_CNT1 = 0; // CLEAR T_CNT1
TMAIN = 0;
usercounter = EEPROM.read(user_setcounter_address);
if (usercounter ==0xA5)
{
set_counter = EEPROM.read(user_counter_address);
}
//pinMode(LED, OUTPUT);
//*************************
//****** LCD setting ********
//*************************
lcd.begin(16,2); // initialize the lcd for 20 chars 4 lines, turn on backlight
lcd.backlight(); //點亮背光
// Print a message to the LCD.
lcd.setCursor(2, 0); //設定游標在第2列第0行
lcd.print("YA Horng PE ");
lcd.setCursor(2, 1);
lcd.print("Lee Chin Wei");
// Serial.println("Ya horng");
//*******************************************
//設定通信模式
//*******************************************
Serial.begin(115200); // 開啟UART 鮑率為 115200
// SPI.begin();
// SPI.setBitOrder(MSBFIRST); // MSB先送
// SPI.setDataMode(SPI_MODE1); // setting SPI mode clock 由0--> 1 資料由負緣取樣
// SPI.setClockDivider(SPI_CLOCK_DIV64); // SPI clock
delay(2500);
lcd.clear();
lcd.setCursor(2, 0); //設定游標在第2列第0行
lcd.print("Counter ");
lcd.setCursor(2, 1);
lcd.print(counter,DEC);
// Disable Arduino's default millisecond counter (from now on, millis(), micros(),
// delay() and delayMicroseconds() will not work)
disableMillis();
// Prepare Timer1 to send notifications every 1000000us (1s)
// On 16 MHz Arduino boards, this function has a resolution of 4us for intervals <= 260000,
// and a resolution of 16us for other intervals
// On 8 MHz Arduino boards, this function has a resolution of 8us for intervals <= 520000,
// and a resolution of 32us for other intervals
// startTimer1(1000000L);
startTimer1(20000); // main loop setting for 20mS by Lee Chin Wei 2016-03-23 modify
if (!digitalRead(P_clear))
{
delay(20);
if (!digitalRead(P_clear))
{
f_setting = 1;
while ( !digitalRead(P_clear));
delay(20);
}
}
}
void read_key(void)
{
if (!digitalRead(P_counter))
{
KEY_NEW = 1;
// Serial.println("KEY_NEW=1");
return;
}
if (!digitalRead(P_clear))
{
KEY_NEW = 2;
// Serial.println("KEY_NEW=2");
return;
}
KEY_NEW = 0xff;
//Serial.println("KEY_NEW=0xff");
}
//************************************
//***** NG 按鍵處理
//************************************
void key1_pro(void)
{
if (F_KEYREP ==1) // 已經執行過了就返回不再重複執行
return;
if (f_setting ==1)
{
EEPROM.write(user_setcounter_address,0xA5);
set_counter++;
} else{
counter++;
}
lcd.setCursor(2, 0); //設定游標在第2列第0行
lcd.print("Counter ");
lcd.setCursor(2, 1);
if (f_setting ==1)
{
lcd.print(set_counter,DEC);
} else{
lcd.print(counter,DEC);
}
if ((counter >= set_counter ) &&(f_setting ==0))
{
digitalWrite(P_LED,HIGH); // LED ON
digitalWrite(P_relay,relayOn);
lcd.setCursor(6, 1);
lcd.print("Warning !!");
f_Warning = 1;
}
}
//******************************************
//***** CLEAR counter
//******************************************
void key2_pro(void)
{
if (F_KEYREP ==1)
return;
if ( f_setting ==1)
{
EEPROM.write(user_counter_address,set_counter);
f_setting = 0;
lcd.setCursor(10, 0); //設定游標在第2列第0行
lcd.print(" ");
}
counter = 0;
lcd.clear();
lcd.setCursor(2, 0); //設定游標在第2列第0行
lcd.print("Counter ");
lcd.setCursor(2, 1);
lcd.print(counter,DEC); //
digitalWrite(P_LED,LOW); // LED Off
digitalWrite(P_relay,relayOff); // Relay turn off
f_Warning = 0; //clear Warning flag
}
//******************************************
//***** 顯示版本處理副程式
//******************************************
/*
void key3_pro(void)
{
if (F_KEYREP ==1)
return;
check_version();
}
*/
//******************************************
//***** 馬達正轉 反轉處理副程式
//******************************************
/*
void key4_pro(void)
{
if (F_KEYREP ==1)
return;
if (f_rf == 0)
{
f_rf = 1;
motor_reverse();
}else{
f_rf = 0;
motor_forward();
}
}
void key5_pro(void)
{
if (F_KEYREP ==1)
return;
}
*/
//******************************************************************************
//;****************************
//;***** KEYON_PROCESS *****
//;****************************
//;FOR CHECK KEY FUNCTION WHEN FIRST KEY PRESSED
//;當KEY按住不放時,仍然只執行一次
void KEYON_PROCESS()
{
switch ( KEY_CMD )
{
case 1 : key1_pro(); break;
case 2 : key2_pro(); break;
// case 3 : key3_pro(); break;
// case 4 : key4_pro(); break;
// case 5 : key5_pro(); break;
// case 6 : key6_pro(); break;
// case 7 : key7_pro(); break;
// case 8 : key8_pro(); break;
// case 9 : key9_pro(); break;
// case 10 : key10_pro(); break;
// case 11 : key11_pro(); break;
// case 12 : key12_pro(); break;
// case 13 : key13_pro(); break;
// case 14 : key14_pro(); break;
// case 15 : key15_pro(); break;
// case 16 : key16_pro(); break;
}
}
//;****************************
//;***** KEYOFF_PROCESS *****
//;****************************
//;FOR CHECK KEY FUNCTION WHEN KEY RELEASED
void KEYOFF_PROCESS()
{
switch ( KEY_CMD )
{
// case 1: key1_off_pro(); break;
// case 2: key2_off_pro(); break;
// case 3: key3_off_pro(); break;
// case 4: key4_off_pro(); break;
// case 5: key5_off_pro(); break;
// case 6: key6_off_pro(); break;
// case 7: key7_off_pro(); break;
// case 8: key8_off_pro(); break;
// case 9: key9_off_pro(); break;
// case 10: key10_off_pro(); break;
// case 11: key11_off_pro(); break;
// case 12: key12_off_pro(); break;
// case 13: key13_off_pro(); break;
// case 14: key14_off_pro(); break;
// case 15: key15_off_pro(); break;
// case 16: key16_off_pro(); break;
}
}
void KEYCHT_440()
{
KEY_SQN = 1;
KEYOFF_PROCESS(); // 按鍵放開的第一時間處理
}
void initial_key() //.............. Step 0
{
KEY_NEW = 0xFF;
KEY_OLD = 0xFF;
KEY_CMD = 0xFF;
KEY_CHT = T20MS;
KEY_SQN = 1;
}
void new_old_check() //.............. Step 1
{
if ( (KEY_NEW!=KEY_OLD)&&(KEY_NEW!=0XFF) )
{
KEY_OLD = KEY_NEW;
KEY_CHT = T100MS;
KEY_SQN = 2;
}
if ( (KEY_NEW!=KEY_OLD)&&(KEY_NEW==0XFF) )
{
KEY_SQN = 0;
}
}
void confirm_key() //.............. Step 2
{
if ( KEY_NEW == KEY_OLD )
{
// Serial.println("key confirm !!");
KEY_CMD = KEY_NEW;
F_CMDON = 1; // 按鍵生效
KEY_REP = T200MS; // 原來的值 T700MS,T500MS
KEY_CHT = T30MS;
KEYON_PROCESS(); // 按鍵按下的第一時間處理
KEY_SQN = 3;
}
else
{
if ( (KEY_NEW!=0xFF) || ((KEY_NEW==0xFF)&&(KEY_CHT==0)) )
{
KEY_OLD = KEY_NEW;
KEY_SQN = 1;
}
}
}
void hold_key() //.............. Step 3
{
if ( KEY_NEW == KEY_OLD ) // === KEY REPEAT
{
if (KEY_NEW==0)
{
KEY_CHT = T20MS;
F_KEYREP = 0; //
KEY_SQN = 4; //2004.12.07 APPEND BY JEREMY(對應按鍵失效)
}
KEY_CHT = T30MS;
if ( KEY_REP == 0 )
{
KEY_REP = T200MS; // 200 ms time out
F_CMDON = 1; // 按鍵生效
F_KEYREP = 1; // KEY REPEAT
KEY_COD_PROCESS(); // 2016-03-21 by leecw Append for key on process
}
} else
if ( (KEY_NEW==0xFF)&&(KEY_CHT==0) )
{
KEY_OLD = KEY_NEW;
KEY_CHT = T20MS;
F_KEYREP = 0; // CLEAR KEY REPEAT FLAG
KEY_SQN = 4; //執行release_key的判斷
}
// else if ( KEY_NEW < KEY_OLD ) // === 按住 X 鍵(KEY CODE較大的按鍵)再按 Y 鍵(KEY CODE較小的按鍵)
// {
// if ( (KEY_CHT == 0) && (KEY_NEW == 1) || (KEY_NEW == 2) )//KEY_CODE(BEND-)=1,KEY_CODE(BEND+)=2
// {
// F_KEYREP = 0;
// KEYCHT_440(); //須執行按鍵的動作
// }
// }
// else if ( KEY_NEW > KEY_OLD ) // === KEY RELEASE或再按住 X 鍵(KEY CODE較大的按鍵)
// {
// if ( (KEY_NEW==0xFF)&&(KEY_CHT==0) )
// {
// KEY_OLD = KEY_NEW;
// KEY_CHT = T20MS;
// F_KEYREP = 0; // CLEAR KEY REPEAT FLAG
// KEY_SQN = 4; //執行release_key的判斷
// }
// else if ( KEY_NEW != 0xFF )
// {
// if ( (KEY_CHEN==0)&&( (KEY_NEW==1)||(KEY_NEW==2) ) ) // 對應按住 BEND- 放開後迅速按 BEND+ 的處理
// {
// F_KEYREP = 0; // CLEAR KEY REPEAT FLAG
// KEYCHT_440(); //
// }
// }
// }
}
void release_key(void) //.............. Step 4
{
if ( KEY_NEW == KEY_OLD )
{
if ( KEY_CHT == 0 )
KEYCHT_440();
}
else if ( (KEY_NEW!=KEY_OLD)&&(KEY_NEW!=KEY_CMD) ) // 對應在處理 KEY_CHT 的 timming 再按到 BEND +/-
{ //
if ( (KEY_CHEN==0)&&((KEY_NEW==1)||(KEY_NEW==2)) ) //
{ //
KEYCHT_440(); //
} //
else //
{ //
KEY_OLD = KEY_NEW; //
KEY_CHT = T30MS; //
} //
}
else if ( (KEY_NEW!=KEY_OLD)&&(KEY_NEW==KEY_CMD) )
{
KEY_OLD = KEY_NEW;
KEY_SQN = 3;
}
}
//;***********************************
//;***** KEY CHATTER & CHECK *****
//;***** HAVE ANY KEY INPUT *****
//;***********************************
//;IN :KEY_NEW,KEY_SQN,KEY_CHT
//;OUT :KEY_OLD,KEY_CMD,F_KEYREP
//;KEY_SQN = 0 --> INITIAL ALL REGISTER
//;KEY_SQN = 1 --> CHECK KEY_NEW & KEY_OLD
//;KEY_SQN = 2 --> KEY ON CHATTER CHECK
//;KEY_SQN = 3 --> KEY REPEAT CHECK
//;KEY_SQN = 4 --> KEY OFF CHATTER
//;KEY_SQN = 32 --> 按住 X 按鍵再按 Y 鍵
void KEY_CHT_PROCESS()
{
switch ( KEY_SQN )
{
case 0:
initial_key(); // *** 初始所使用的暫存器
break;
case 1:
new_old_check(); // *** 檢查新碼和舊碼
break;
case 2:
confirm_key(); // *** 承認按下的按鍵
break;
case 3:
hold_key(); // *** 保持按鍵按下的處理
break;
case 4:
release_key(); // *** 放開按鍵
break;
default:
KEY_SQN = 0;
break;
}
}
void K_counter_add(void)
{
if (f_setting ==1)
{
set_counter++;
} else{
counter++;
}
if ((counter >= set_counter ) &&(f_setting ==0))
{
digitalWrite(P_LED,HIGH); // LED ON
digitalWrite(P_relay,relayOn);
lcd.setCursor(6, 1);
lcd.print("Warning !!");
f_Warning = 1;
}
lcd.setCursor(2, 0); //設定游標在第2列第0行
lcd.print("Counter ");
lcd.setCursor(2, 1);
if (f_setting ==1)
{
lcd.print(set_counter,DEC);
} else{
lcd.print(counter,DEC);
}
}
//;*****************************************
//;***** KEY CODE PROCESS SUBROUTINE *****
//;*****************************************
//;IN :KEY_CMD
//;OUT :當KEY按住不放時,利用KEY_REP的設定,可重複執行KEY CODE動作
void KEY_COD_PROCESS()
{
if ( F_CMDON == 1 )
{
F_CMDON = 0;
switch ( KEY_CMD )
{
// case 0 : K_PITCH(); break;
case 1 : K_counter_add(); break; //K_PIT_M(); break;
// case 2 : K_PIT_P(); break;
// case 3 : K_STOP(); break;
// case 4 : K_SINGLE(); break;
// case 5 : K_TIME(); break;
// case 6 : K_PLYPAS(); break;
// case 7 : K_PTEN(); break;
// case 8 : K_CUE1(); break;
// case 9 : K_BSKIP(); break;
// case 10: K_FSKIP(); break;
// case 11: K_FBS(); break;
// case 12: K_FFS(); break;
// case 13: K_OPCL(); break;
// case 14: K_BPM(); break;
}
}
}
//******************************************************************************
void t100ms_process()
{
if (TB_500MS ==0)
{
TB_500MS = 5;
//0.5sec要處理的程式放這裡
// ledState ^= 1;
Blink1HZ ^=1; // Blink1HZ與1 互斥或 【反向的意思】
} else {
TB_500MS--;
}
}
//***************************
//***** 系統時間
//***************************
void check_time()
{
if (TB_100MS ==0)
{
TB_100MS = T100MS;
t100ms_process();
} else {
TB_100MS--;
}
if (TB_250MS ==0)
{
TB_250MS = T250MS;
Blink2HZ ^=1; // Blink2HZ與1 互斥或 【反向的意思】
} else{
TB_250MS--;
}
if (T_Blink_Count ==0)
{
T_Blink_Count = 50; //100;
// Blink1HZ ^=1; // Blink1HZ與1 互斥或 【反向的意思】
// Blink2HZ ^=1; // Blink2HZ與1 互斥或 【反向的意思】
} else{
T_Blink_Count--;
if (T_Blink_Count == 25) //50)
{
// Blink2HZ ^=1;
}
}
if (T_CNT1 !=0)
T_CNT1--;
if (KEY_CHT !=0)
KEY_CHT--;
if (KEY_REP !=0)
KEY_REP--;
}
void display_process()
{
if (f_setting ==1)
{
if (Blink1HZ == 1)
{
lcd.setCursor(10, 0);
lcd.print("Set...");
} else{
lcd.setCursor(10, 0);
lcd.print(" ");
}
}
if (f_Warning ==1)
{
if ( Blink1HZ==1)
{
digitalWrite(P_LED,HIGH);
digitalWrite(P_relay,relayOn);
lcd.setCursor(6, 1);
lcd.print("Warning !!");
} else {
digitalWrite(P_LED,LOW);
digitalWrite(P_relay,relayOff);
lcd.setCursor(6, 1);
lcd.print(" ");
}
}
}
//********************************************************************
//********************************************************************
//***** Main Loop
//***** Program by Chin Wei Lee
//***** Date : 2014-06 28
//********************************************************************
//********************************************************************
void loop()
{
while (TMAIN){
check_time(); // 檢查系統時間【所有的時間處理】
read_key(); // 讀取按鍵
KEY_CHT_PROCESS(); //按鍵的反彈跳處理及按鍵的處理
display_process(); // Warning 的處理
TMAIN = 0;
}
}
// Define the function which will handle the notifications
ISR(timer1Event)
{
TMAIN = 1;
// Reset Timer1 (resetTimer1 should be the first operation for better timer precision)
// Serial.println("time interrupt 5ms");
resetTimer1();
// check_time();
// For a smaller and faster code, the line above could safely be replaced with a call
// to the function resetTimer1Unsafe() as, despite its name, it IS safe to call
// that function in here (interrupts are disabled)
// Make sure to do your work as fast as possible, since interrupts are automatically
// disabled when this event happens (refer to interrupts() and noInterrupts() for
// more information on that)
}