☛ 功能說明
利用 4 × 4 矩陣鍵盤控制步進馬達的轉速及轉向,其中 0~9 鍵設定馬達的轉動模式或步數,A 鍵設定馬達正轉;B 鍵使馬達反轉;C 鍵設定馬達轉動的步進模式 ( 全步、半步、1/4 步、1/8 步、1/16 步等五種模式 );D 鍵使馬達停止轉動。例如鍵盤輸入 60A,設定馬達正轉 60 步;輸入 1C,馬達步進模式爲半步模式;輸入 50B,馬達反轉 50 步。
☛ 使用材料
Arduino UNO R3 開發板 × 1、A4988 步進馬達控制模塊 × 1、電解電容 47μF × 1、四線二相步進馬達 × 1、4×4 薄膜矩陣鍵盤 × 1。
☛ 電路圖及麪包板接線圖
☛ 程式碼
const int dirPin = 2; // 驅動模塊的 DIR 引腳連接至數位引腳 2 const int stepPin = 3; // 驅動模塊的 STEP 引腳連接至數位引腳 3 const int stepsPerRevolution = 200; // 旋轉一圈 200 步 const int modePin[3]={12,13,14}; // 步進模式接腳連接至開發板接腳 12~14 int motoSpeeds[5][3]= {{0,0,0}, // 全步模式 {1,0,0}, // 半步模式 {0,1,0}, // 四分之一步 {1,1,0}, // 八分之一步 {1,1,1}}; // 十六分之一步 int col; // 鍵盤行號 int row; // 鍵盤列號 int steps = 0; char keyVal; // 按鍵值 const int numCols = 4; // 鍵盤行數 const int numRows = 4; // 鍵盤列數 const int debounceDelay = 20; // 消除按鍵彈跳時間 20ms const int colPin[]={8,9,10,11}; // 鍵盤行連接至數位接腳 8~11 const int rowPin[]={4,5,6,7}; // 鍵盤列連接至數位接腳 4~7 const char keyMap[numRows][numCols]= {{'1','2','3','A'}, // 按鍵 1、2、3、A {'4','5','6','B'}, // 按鍵 4、5、6、B {'7','8','9','C'}, // 按鍵 7、8、9、C {'*','0','#','D'}}; // 按鍵 *、0、#、D int x; void setup() { pinMode(dirPin,OUTPUT); // 數位引腳 2 爲輸出模式 pinMode(stepPin,OUTPUT); // 數位引腳 3 爲輸出模式 for(int m=0;m<3;m++) // 數位接腳 12~14 爲輸出模式 pinMode(modePin[m],OUTPUT); initKeyCol(); // 初始化鍵盤行 initKeyRow(); // 初始化鍵盤列 setModeStep(0); // 預設步進模式爲全步模式 Serial.begin(9600); // 初始化串列埠,鮑率爲 9600bps Serial.println("Press '0'~'9' Setting steps"); Serial.println("Press 'A' Right Turn"); Serial.println("Press 'B' Left Turn"); Serial.println("Press 'C' Setting Step Mode"); Serial.println("Press 'D' Stop"); } void loop() { char key=getKey(); // 讀取按鍵值 if(key!='X') { keyVal=key; // 存儲鍵值 if(key>='0' && key<='9') // 鍵值爲 '0'~'9' steps=steps*10+key-'0'; // 加權並存儲 } switch(key) { case 'A': MotoTurn(steps,key); // 步進馬達正轉 steps 步 steps=0; break; case 'B': // 步進馬達反轉 steps 步 MotoTurn(steps,key); steps=0; break; case 'C': // 設置步進馬達的步進模式 setModeStep(steps); steps=0; break; case 'D': // 步進馬達停止轉動 MotoTurn(0,key); steps=0; break; } key='X'; // 清除讀取鍵盤按鍵的值 } void MotoTurn(int msteps,char mKey) // 步進馬達轉動步數及方向 { if(mKey=='A') // 順時針旋轉 { Serial.print("Right Turn Step:"); Serial.println(msteps); digitalWrite(dirPin,HIGH); } if(mKey=='B') // 逆時針旋轉 { Serial.print("Left Turn Step:"); Serial.println(msteps); digitalWrite(dirPin,LOW); } for(x=0; x < msteps; x++) // 步進馬達轉動指定步數 { digitalWrite(stepPin,HIGH); // 對 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 digitalWrite(stepPin,LOW); // 停止 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 } } void setModeStep(int modeSTEP) // 步進模式設定 { Serial.print("Step Mode:"); Serial.println(steps); for(int i=0;i<3;i++) // 設定步進模式:全步、半步、1/4 步、1/8 步、1/16 步 digitalWrite(modePin[i],motoSpeeds[modeSTEP][i]); } void initKeyCol() // 初始化鍵盤行 { for(col=0;col<numCols;col++) { pinMode(colPin[col],OUTPUT); digitalWrite(colPin[col],HIGH); } } void initKeyRow() // 初始化鍵盤列 { for(row=0;row<numRows;row++) { pinMode(rowPin[row],INPUT); digitalWrite(rowPin[row],HIGH); } } char getKey() // 取得鍵盤按鍵值 { int i,j; char key='X'; // 按鍵 key='X',代表未按下任何按鍵 for(i=0;i<numCols;i++) { digitalWrite(colPin[i],LOW); // 掃描第 i 行 for(j=0;j<numRows;j++) // 檢測每一列的按鍵是否已經被按下 { if(digitalRead(rowPin[j])==LOW) // 按鍵已經被按下? { delay(debounceDelay); // 消除按鍵的機械彈跳不穩定現象 while(digitalRead(rowPin[j])==LOW) // 等待按鍵放開 ; key=keyMap[j][i]; // 儲存按鍵值 } } digitalWrite(colPin[i],HIGH); // 除能行掃描 } return(key); // 傳回按鍵值 }
☛ 練習
⑴ 設計 Arduino 程式,接續例題功能,新增 *、# 兩個按鍵功能,用以設定連續正、反轉功能。# 鍵使馬達連續正轉,* 鍵使馬達連續反轉。
const int dirPin = 2; // 驅動模塊的 DIR 引腳連接至數位引腳 2 const int stepPin = 3; // 驅動模塊的 STEP 引腳連接至數位引腳 3 const int stepsPerRevolution = 200; // 旋轉一圈 200 步 const int modePin[3]={12,13,14}; // 步進模式接腳連接至開發板接腳 12~14 int motoSpeeds[5][3]= {{0,0,0}, // 全步模式 {1,0,0}, // 半步模式 {0,1,0}, // 四分之一步 {1,1,0}, // 八分之一步 {1,1,1}}; // 十六分之一步 int col; // 鍵盤行號 int row; // 鍵盤列號 int steps = 0; char keyVal; // 按鍵值 const int numCols = 4; // 鍵盤行數 const int numRows = 4; // 鍵盤列數 const int debounceDelay = 20; // 消除按鍵彈跳時間 20ms const int colPin[]={8,9,10,11}; // 鍵盤行連接至數位接腳 8~11 const int rowPin[]={4,5,6,7}; // 鍵盤列連接至數位接腳 4~7 const char keyMap[numRows][numCols]= {{'1','2','3','A'}, // 按鍵 1、2、3、A {'4','5','6','B'}, // 按鍵 4、5、6、B {'7','8','9','C'}, // 按鍵 7、8、9、C {'*','0','#','D'}}; // 按鍵 *、0、#、D int x; int turnFlag=0; // 連續轉動旗標 void setup() { pinMode(dirPin,OUTPUT); // 數位引腳 2 爲輸出模式 pinMode(stepPin,OUTPUT); // 數位引腳 3 爲輸出模式 for(int m=0;m<3;m++) // 數位接腳 12~14 爲輸出模式 pinMode(modePin[m],OUTPUT); initKeyCol(); // 初始化鍵盤行 initKeyRow(); // 初始化鍵盤列 setModeStep(0); // 預設步進模式爲全步模式 Serial.begin(9600); // 初始化串列埠,鮑率爲 9600bps Serial.println("Press '0'~'9' Setting steps"); Serial.println("Press 'A' Right Turn"); Serial.println("Press 'B' Left Turn"); Serial.println("Press 'C' Setting Step Mode"); Serial.println("Press 'D' Stop"); Serial.println("Press '*' Continuous Left Turn"); Serial.println("Press '#' Continuous Right Turn"); } void loop() { char key=getKey(); // 讀取按鍵值 if(key!='X') { keyVal=key; // 存儲鍵值 if(key>='0' && key<='9') // 鍵值爲 '0'~'9' steps=steps*10+key-'0'; // 加權並存儲 } switch(key) { case 'A': MotoTurn(steps,key); // 步進馬達正轉 steps 步 steps=0; turnFlag=0; break; case 'B': // 步進馬達反轉 steps 步 MotoTurn(steps,key); steps=0; turnFlag=0; break; case 'C': // 設置步進馬達的步進模式 setModeStep(steps); steps=0; turnFlag=0; break; case 'D': // 步進馬達停止轉動 MotoTurn(0,key); steps=0; turnFlag=0; break; case '*': turnFlag = 2; // 步進馬達連續左轉 break; case '#': turnFlag =1; // 步進馬達連續右轉 break; } key='X'; if(turnFlag == 1) { digitalWrite(dirPin,HIGH); // 順時針旋轉 digitalWrite(stepPin,HIGH); // 對 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 digitalWrite(stepPin,LOW); // 停止 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 } if(turnFlag==2) { digitalWrite(dirPin,LOW); // 逆時針旋轉 digitalWrite(stepPin,HIGH); // 對 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 digitalWrite(stepPin,LOW); // 停止 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 } } void MotoTurn(int msteps,char mKey) // 步進馬達轉動步數及方向 { if(mKey=='A') // 順時針旋轉 { Serial.print("Right Turn Step:"); Serial.println(msteps); digitalWrite(dirPin,HIGH); } if(mKey=='B') // 逆時針旋轉 { Serial.print("Left Turn Step:"); Serial.println(msteps); digitalWrite(dirPin,LOW); } for(x=0; x < msteps; x++) // 步進馬達轉動指定步數 { digitalWrite(stepPin,HIGH); // 對 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 digitalWrite(stepPin,LOW); // 停止 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 } } void setModeStep(int modeSTEP) // 步進模式設定 { Serial.print("Step Mode:"); Serial.println(steps); for(int i=0;i<3;i++) // 設定步進模式:全步、半步、1/4 步、1/8 步、1/16 步 digitalWrite(modePin[i],motoSpeeds[modeSTEP][i]); } void initKeyCol() // 初始化鍵盤行 { for(col=0;col<numCols;col++) { pinMode(colPin[col],OUTPUT); digitalWrite(colPin[col],HIGH); } } void initKeyRow() // 初始化鍵盤列 { for(row=0;row<numRows;row++) { pinMode(rowPin[row],INPUT); digitalWrite(rowPin[row],HIGH); } } char getKey() // 取得鍵盤按鍵值 { int i,j; char key='X'; // 按鍵 key='X',代表未按下任何按鍵 for(i=0;i<numCols;i++) { digitalWrite(colPin[i],LOW); // 掃描第 i 行 for(j=0;j<numRows;j++) // 檢測每一列的按鍵是否已經被按下 { if(digitalRead(rowPin[j])==LOW) // 按鍵已經被按下? { delay(debounceDelay); // 消除按鍵的機械彈跳不穩定現象 while(digitalRead(rowPin[j])==LOW) // 等待按鍵放開 ; key=keyMap[j][i]; // 儲存按鍵值 } } digitalWrite(colPin[i],HIGH); // 除能行掃描 } return(key); // 傳回按鍵值 }
⑵ 設計 Arduino 程式,接續例題功能,新增 *、# 兩個按鍵功能,用以設定連續正、反轉角度功能。例如輸入 90# 鍵使馬達正轉 90°;輸入 45* 鍵使馬達反轉 45°。
const int dirPin = 2; // 驅動模塊的 DIR 引腳連接至數位引腳 2 const int stepPin = 3; // 驅動模塊的 STEP 引腳連接至數位引腳 3 const int stepsPerRevolution = 200; // 旋轉一圈 200 步 const int modePin[3]={12,13,14}; // 步進模式接腳連接至開發板接腳 12~14 int motoSpeeds[5][3]= {{0,0,0}, // 全步模式 {1,0,0}, // 半步模式 {0,1,0}, // 四分之一步 {1,1,0}, // 八分之一步 {1,1,1}}; // 十六分之一步 int col; // 鍵盤行號 int row; // 鍵盤列號 int steps = 0; char keyVal; // 步進模式值 const int numCols = 4; // 鍵盤行數 const int numRows = 4; // 鍵盤列數 const int debounceDelay = 20; // 消除按鍵彈跳時間 20ms const int colPin[]={8,9,10,11}; // 鍵盤行連接至數位接腳 8~11 const int rowPin[]={4,5,6,7}; // 鍵盤列連接至數位接腳 4~7 const char keyMap[numRows][numCols]= {{'1','2','3','A'}, // 按鍵 1、2、3、A {'4','5','6','B'}, // 按鍵 4、5、6、B {'7','8','9','C'}, // 按鍵 7、8、9、C {'*','0','#','D'}}; // 按鍵 *、0、#、D int x; void setup() { pinMode(dirPin,OUTPUT); // 數位引腳 2 爲輸出模式 pinMode(stepPin,OUTPUT); // 數位引腳 3 爲輸出模式 for(int m=0;m<3;m++) // 數位接腳 12~14 爲輸出模式 pinMode(modePin[m],OUTPUT); initKeyCol(); // 初始化鍵盤行 initKeyRow(); // 初始化鍵盤列 setModeStep(0); // 預設步進模式爲全步模式 Serial.begin(9600); // 初始化串列埠,鮑率爲 9600bps Serial.println("Press '0'~'9' Setting steps"); Serial.println("Press 'A' Right Turn"); Serial.println("Press 'B' Left Turn"); Serial.println("Press 'C' Setting Step Mode"); Serial.println("Press 'D' Stop"); Serial.println("Press '*' Left Turn Angle"); Serial.println("Press '#' Right Turn Angle"); } void loop() { char key=getKey(); // 讀取按鍵值 if(key!='X') { if(key>='0' && key<='9') // 鍵值爲 '0'~'9' steps=steps*10+key-'0'; // 加權並存儲 } switch(key) { case 'A': MotoTurn(steps,key); // 步進馬達正轉 steps 步 steps=0; break; case 'B': // 步進馬達反轉 steps 步 MotoTurn(steps,key); steps=0; break; case 'C': // 設置步進馬達的步進模式 setModeStep(steps); keyVal=steps; // 記錄步進模式 steps=0; break; case 'D': // 步進馬達停止轉動 MotoTurn(0,key); steps=0; break; case '*': MotoAngle(steps,key); // 步進馬達反轉至指定角度 steps=0; break; case '#': MotoAngle(steps,key); // 步進馬達正轉至指定角度 steps=0; break; } key='X'; } void MotoTurn(int msteps,char mKey) // 步進馬達轉動步數及方向 { if(mKey=='A') // 順時針旋轉 { Serial.print("Right Turn Step:"); Serial.println(msteps); digitalWrite(dirPin,HIGH); } if(mKey=='B') // 逆時針旋轉 { Serial.print("Left Turn Step:"); Serial.println(msteps); digitalWrite(dirPin,LOW); } for(x=0; x < msteps; x++) // 步進馬達轉動指定步數 { digitalWrite(stepPin,HIGH); // 對 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 digitalWrite(stepPin,LOW); // 停止 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 } } void MotoAngle(int msteps,char mKey) // 步進馬達轉動角度及方向 { if(mKey=='#') // 順時針旋轉角度 { Serial.print("Right Turn Angle:"); Serial.println(msteps); digitalWrite(dirPin,HIGH); } if(mKey=='*') // 逆時針旋轉角度 { Serial.print("Left Turn Angle:"); Serial.println(msteps); digitalWrite(dirPin,LOW); } switch(keyVal) // 判斷步進模式 { case 0: msteps = msteps*0.56; // 全步模式的步進數 break; case 1: msteps = msteps*2*0.56; // 半步模式的步進數 break; case 2: msteps = msteps*4*0.56; // 四分之一模式的步進數 break; case 3: msteps = msteps*8*0.56; // 八分之一模式的步進數 break; case 4: msteps = msteps*16*0.56; // 十六分之一模式的步進數 break; } for(x=0; x < msteps; x++) // 步進馬達轉動指定步數 { digitalWrite(stepPin,HIGH); // 對 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 digitalWrite(stepPin,LOW); // 停止 STEP 引腳輸出信號 delayMicroseconds(2000); // 延遲 2 秒 } } void setModeStep(int modeSTEP) // 步進模式設定 { Serial.print("Step Mode:"); Serial.println(steps); for(int i=0;i<3;i++) // 設定步進模式:全步、半步、1/4 步、1/8 步、1/16 步 digitalWrite(modePin[i],motoSpeeds[modeSTEP][i]); } void initKeyCol() // 初始化鍵盤行 { for(col=0;col<numCols;col++) { pinMode(colPin[col],OUTPUT); digitalWrite(colPin[col],HIGH); } } void initKeyRow() // 初始化鍵盤列 { for(row=0;row<numRows;row++) { pinMode(rowPin[row],INPUT); digitalWrite(rowPin[row],HIGH); } } char getKey() // 取得鍵盤按鍵值 { int i,j; char key='X'; // 按鍵 key='X',代表未按下任何按鍵 for(i=0;i<numCols;i++) { digitalWrite(colPin[i],LOW); // 掃描第 i 行 for(j=0;j<numRows;j++) // 檢測每一列的按鍵是否已經被按下 { if(digitalRead(rowPin[j])==LOW) // 按鍵已經被按下? { delay(debounceDelay); // 消除按鍵的機械彈跳不穩定現象 while(digitalRead(rowPin[j])==LOW) // 等待按鍵放開 ; key=keyMap[j][i]; // 儲存按鍵值 } } digitalWrite(colPin[i],HIGH); // 除能行掃描 } return(key); // 傳回按鍵值 }