☛ 功能說明

利用 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);                                 // 傳回按鍵值
}