查看: 2054|回復: 12
打印 上一主題 下一主題

[項目] 莫斯精靈

[復制鏈接]
  • TA的每日心情
    擦汗
    2019-9-15 19:13
  • 簽到天數: 22 天

    [LV.4]偶爾看看III

    跳轉到指定樓層
    樓主
    發表于 2019-3-10 22:43 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
      在抗戰和諜情影片中無線電臺發出的嘀嘀嗒嗒聲大家一定印象深刻吧?其實就是將信息轉換成莫爾斯碼再通過電臺發射出去,發莫爾斯碼的工具如上圖所示。左邊是人工將信息轉換成莫爾斯碼,速度慢,易出錯,不易掌握;中間是電子鍵,內置了單片機,為半自動轉換,速度有所提升,但易出錯,不易掌握;右邊是當前一些無線電愛好者使用的,為左邊的改進版,特點與左邊的相同。
      本人的項目是制作一款全新的莫爾斯碼拍發設備,具備簡單易用,準確高效等特點,本設備的出錯將一統無線電江湖!看完本帖你會相信它具備這個實力!
      上圖是本項目用到的材料,本人窮,都是湊合的,簡單介紹一下哈。上邊一排左邊是arduino due,為什么選它?因為我只會使用arduino的板子,有大神告訴我只有due才能接收處理USB鍵盤的按鍵信息。Due角色為主MCU,主要是接收處理USB鍵盤的按鍵信息,以及除翻譯莫爾斯電碼外的其它事務。
      
    游客,如果您要查看本帖隱藏內容請回復
      屏旁邊的是供電部分,使用了2節三洋大紅炮,動力強勁,一個充電放電保護一體板,一個可調2A升壓板,因DUE要求供電不能低于6V(絕對不能使用5V供電!),升壓板輸出9V供電。
      再往右邊的是arduinonano,擔負從MCU的角色,通過控制模擬開關實現將字符翻譯成莫爾斯碼的功能。為什么采用主從雙MCU設計呢?因為翻譯莫爾斯電碼時需要延時,而接收USB鍵盤信息使用的庫中也用到了延時,如果使用一個MCU二者會相互影響,嚴重影響穩定性。
      再往右邊是SD卡模塊,很便宜,SD卡是報廢手機里的。SD卡模塊主要是實現保存、調用報文功能時用。
      最右邊是模擬開關,使用的是國產的,ch440g,4路通道,導通電阻9歐姆左右,它是最終實現莫爾斯碼的電氣開關。
    下面依次是蜂鳴器模塊(發出電影里嘀嘀嗒嗒的聲音),無鎖按鈕(作用是當本設備故障時,起手鍵的作用),電源開關,DC電源插座,洞洞板焊的母板(上邊的USB母口用來連接USB鍵盤),一些連接線和螺釘,外殼(使用的華為手機的包裝盒file:///C:/Users/ADMINI~1/AppData/Local/Temp/msohtmlclip1/01/clip_image001.gif)
      下面我們把它組裝起來吧!
    組裝好設備上蓋
      使用智能屏廠家提供的上位機軟件設計各交互界面,設計好后將程序下載到智能屏。智能屏使用的串口,隨便找一個下載工具就可以,只要電源正負不接反,若連通失敗對倒一下收發。本項目不需要觸摸功能,所以關閉了觸摸功能,算是資源的浪費。
      組裝設備下半部分,因身邊沒有電臺,與電臺相連的接口暫未安裝。
    設備運行后主界面圖
    設備運行后發報界面圖
    系統設置界面
    關于界面
      本設備特點:本設備采用雙MCU設計,無死機、變碼、多碼、連碼等現象,運行穩定;采用通用標準USB鍵盤直接輸入信息,拍發速度更快,更換方便;設置有應急按鍵;顯示屏可一次性顯示254個字符,操作者可在校對無誤后再發送,提高了拍發準確率;界面美觀交互性強;具備自動呼叫、報文調用、工作記錄等功能;提供專用輔助工具。因保密原因部分功能簡化了。
      目前第二版本正在順利推進中,主要是代碼優化、改進主從MCU的通信、供電、專用工具,增加上位機等,歡迎大家一起討論。歡迎廣大影視公司、無線電愛好者和特殊行業和我聯系(本設備已申請專利)!
      視頻鏈接:http://kuai.#/play?id=3423067
      本項目資料(主從MCU代碼、智能屏文件、母板PCB):https://pan.baidu.com/s/179JGW6cy7WJXnMXp-g_5gg 提取碼:fopm
    或者直接掃描正面的二維碼:


  • TA的每日心情
    擦汗
    2019-9-15 19:13
  • 簽到天數: 22 天

    [LV.4]偶爾看看III

    沙發
     樓主| 發表于 2019-3-10 23:15 | 只看該作者

    kittenblock中小學創客名師推薦的圖形化編程軟件

    主MCU代碼:
    //due端,鍵盤輸入、字符作用區分、屏幕顯示、菜單控制
    #include <SPI.h>
    #include <SdFat.h>
    
    #include <KeyboardController.h>
    USBHost usb;
    KeyboardController keyboard(usb);
    
    #define STARTCHAR '{'//分段,開始
    #define ENDCHAR '@'//完結
    #define PAGECHAR '}'//句號
    #define RADIOCHAR '^'//無線電信號
    #define WARNCALL "XXX"//警報信號
    #define DIAGONAL "/"//斜線
    #define BRACKET "<"//括號
    #define CORRECTS "?"//改錯,數碼
    #define CORRECTL "|"//改錯,字碼、混合碼
    #define POINT "."//小數點
    #define MAXSPEED 200//最大發報速度
    #define MINSPEED 60//最小發報速度
    #define FREELENGTHMAX 50//自由區內容最大長度
    #define MSGMAXLENGTH 254//報文區最大字符數
    
    //命令代碼
    #define AUTOCALLSTART 242//警報臺自動呼叫開始
    #define AUTOCALLSTOP 243//警報臺自動呼叫結束
    #define CHANGESPEED 240//調整速度命令,發給nano時用
    #define RECORDSTART 246//開始記錄發報內容
    #define RECORDSTOP 247//結束記錄發報內容
    #define UPLOADLOG 248//通知Nano回傳記錄的發報內容
    #define USEDATASTART 251//開始調用報底發報
    #define USEDATAEND 252//結束調用報底發報
    #define STOPFORREADY 250//通知Nano停止發報,并將除發報記錄外的各參數復位
    #define NEXTPAGE 126//Nano請求發下一頁報文
    
    SdFat sd;
    const byte pinChipSelect =44;// 30;
    const byte pinLedR = 38;//32;
    const byte pinLedG = 36;//34;
    const byte pinLedB = 34;//36;
    //const byte pinDisplayPower=25;//此腳控制顯示屏的供電
    const byte numberLong=-15;
    
    byte sys0=1;//電報的報文內容是隨輸隨發1,還是一頁一鍵發送0,還是調用發送2(調用報底發送時用)sendActId
    //byte wordsTotal=0;//報文組數
    //byte proFlag=0;//一般電報處理進程標識,0沒有開始,1已發報頭,2已發開始符號,3已發結束符號
    
    int sendActId=1;//發報界面活動控件:0報文區,1自由勤務,2速度,3號數,4組數,5等級,6日期,7時間,8備注,9號數2,10組數2;調用報文界面:0種類,1頁碼,2組數;
    byte actIdPre=0;//前一活動控件id
    byte sys1=1;//報文分類:1電  報,2業務公電,3無線信號,4警報信號,5通信檢查,0自由聯絡
    byte scrId=1;//當前所處界面:0主界面main,1發報send,2自動呼叫autoCall,3調用報文useData,4工作日志workLog,5系統設置sysSet,6關于about,7輸入對話框,8確認對話框
    byte sys2=0;//標識數碼電報是長碼1還是短碼0
    byte endFlag=0xff;
    byte saveOrUse=0;//標識調用自動呼叫界面時,是保存1還是調入0
    byte autoCallIndex=0;
    byte cSave=0;//標識當前是否記錄工作日志
    
    String msgFileName="";//文件名
    //String msgFileName2="";//文件名
    
    String msgSpeed="100";//范圍60-250
    String numberForNano="";
    String numberForScrn="";
    String msgGroup="";
    String msgClass="";
    String msgDate="";
    String msgTime="";
    String msgMarket="";
    String msg="";//報文區內容,發往Nano的
    String msgForDisplay="";//報文區內容,發往顯示屏顯示的
    String freeForNano="";//自由區內容,發往nano的
    String freeForScrn="";//自由區內容,發往顯示屏的
    //報底調用變量
    byte dataKind=0;//報底種類:0數碼(共有999頁),1字碼(共99頁),2混合碼(共99頁)
    bool dataSendStarted=false;//調用報底時使用,標識報底是否已發送 // note check kil
    int dataPageNow=1;//當前界面顯示發送的是第幾頁
    int dataPage=1;//共有多少頁
    int dataGroup=100;//剩多少組沒讀取發送
    int dataPositionFrom=0;//起始位置
    //String dataMsg="";//調用報底內容
    byte pgIndex=0;//系統調試項目下標
    
    void closeOrOpenDisplay(){
      //digitalWrite(pinDisplayPower,!digitalRead(pinDisplayPower));
      return;
    }
    bool initDataNum(bool balance=false){//999頁
      sd.remove("SYSDATANUM.txt");
      if (sd.exists("SYSDATANUM.txt")) {
        Serial.println(" delete fail !");
        return false;
      }
      randomSeed(analogRead(0));
      SdFile myFile("SYSDATANUM.txt", FILE_WRITE);
      if (myFile.isOpen()) {
        for(int i=1;i<1000;i++){
          for(int j=1;j<101;j++){
             myFile.print(random(10));
             myFile.print(random(10));
             myFile.print(random(10));
             myFile.print(random(10));
             myFile.print(" ");
          }}
        //myFile.save();
        myFile.close();
        Serial.println("init success !");
        return true;
      } else {
        Serial.println("write fail !");
        return false;
      }
    }
    bool initDataChr(bool balance=false){//99頁
      sd.remove("SYSDATACHR.txt");
      if (sd.exists("SYSDATACHR.txt")) {
        Serial.println(" delete fail !");
        return false;
      }
      randomSeed(analogRead(0));
      SdFile myFile("SYSDATACHR.txt", FILE_WRITE);
      if (myFile.isOpen()) {
        for(int i=1;i<1000;i++){
          for(int j=1;j<101;j++){
             myFile.write(random(65,91));
             myFile.write(random(65,91));
             myFile.write(random(65,91));
             myFile.write(random(65,91));
             myFile.print(" ");
          }}
        myFile.close();
        Serial.println("init success !");
        return true;
      } else {
        Serial.println("write fail !");
        return false;
      }
    }
    bool initDataBoth(){//99頁
      sd.remove("SYSDATABOTH.txt");
      if (sd.exists("SYSDATABOTH.txt")) {
        Serial.println(" delete fail !");
        return false;
      }
      randomSeed(analogRead(0));
      SdFile myFile("SYSDATABOTH.txt", FILE_WRITE);
      if (myFile.isOpen()) {
        for(int i=1;i<100;i++){
          for(int j=1;j<101;j++){
             if(random(2)){
                myFile.write(random(48,58));
             }else{
                myFile.write(random(65,91));}
             if(random(2)){
                myFile.write(random(48,58));
             }else{
                myFile.write(random(65,91));}
             if(random(2)){
                myFile.write(random(48,58));
             }else{
                myFile.write(random(65,91));}
             if(random(2)){
                myFile.write(random(48,58));
             }else{
                myFile.write(random(65,91));}
             myFile.print(" ");
          }}
        myFile.close();
        Serial.println("init success !");
        return true;
      } else {
        Serial.println("write fail !");
        return false;
      }
    }
    //讀取1頁系統報底,2個使用場合:調用發送時調用報底,供sendDataNextPage調用
    bool readData(){
      if(dataGroup<=0)return false;
    
      String tem="";  
      char* fileName;
      unsigned int dataPositionEnd=0;
    
      if(dataGroup>=100){
        dataPositionEnd=dataPositionFrom+500;
        dataGroup=dataGroup-100;
      }else{
        dataPositionEnd=dataPositionFrom+dataGroup*5;
        dataGroup=0;
      }
      if(dataKind==0){
        fileName="SYSDATANUM.txt";
        }else if(dataKind==1){
          fileName="SYSDATACHR.txt";
        }else{
          fileName="SYSDATABOTH.txt";
          }
    
      SdFile myFile4(fileName, FILE_READ);
    
      if (myFile4.isOpen()) {
        myFile4.seekSet(dataPositionFrom);
        while (dataPositionFrom<=dataPositionEnd && myFile4.available()) {
          tem=tem + char(myFile4.read());
        }
        myFile4.close();
        dataPositionFrom=dataPositionEnd;
        Serial.println("read success");
        if(dataGroup){
          msgForDisplay=String(STARTCHAR) + tem + String(PAGECHAR);
        }else{
          msgForDisplay=String(STARTCHAR) + tem + String(ENDCHAR);
        }
        return true;
      } else {
        Serial.println("open error");
        return false;
      }
    }
    String replaceNumberToLong(String msg){
      msg.replace('0','!');
      msg.replace('1','"');
      msg.replace('2','#');
      msg.replace('3','$');
      msg.replace('4','%');
      msg.replace('5','&');
      msg.replace('6','\'');
      msg.replace('7','(');
      msg.replace('8',')');
      msg.replace('9','*');
      return msg;
    }
    //讀取并使用1頁報底,使用在2個地方:Nano發來的請求命令,調用發送時在報文區按回車開始發送(fistPage=true)
    bool sendDataNextPage(bool fistPage=false){  
      if(!fistPage){
        if(!readData())return false;
        cmdToDisplay("t10.txt=\"" + msgForDisplay + "\"");//顯示報文
    
      }else{
        byteToNano(USEDATASTART);
        dataSendStarted=true;//標識開始發送
      }
      dataPageNow=dataPageNow+1;
      cmdToDisplay("nPage.txt=\"" + String(dataPageNow) + "/" + String(dataPage) + "\"");//更新界面頁碼
      msg=msgForDisplay;
      if(sys2==1 || dataKind==2){//數字發長碼
        msg=replaceNumberToLong(msg);
      }
      msgToNano(msg);
      if(dataPageNow>=dataPage){
          byteToNano(USEDATAEND);//已發送完,通知Nano,且發送模式自動變為一鍵發送
          sys0=0;
          cmdToDisplay("sys0=0");
          cmdToDisplay("click t11,0");
          return false;
      }
    }
    //讀worklog
    String readLog(){
      String msg="";  
      SdFile myFile("WORKLOG.txt", FILE_READ);
      if (myFile.isOpen()) {
        while (myFile.available()) {
          msg=msg + String(char(myFile.read()));
        }
        myFile.close();
        Serial.println(msg);
        return msg;
        } else {
        Serial.println("read error");
        myFile.close();
        return "";
      }
    }
    //電報記錄
    bool saveLog(String fileContent){
      //SdFile myFile;
      File myFile;
      myFile = sd.open("WORKLOG.txt", FILE_WRITE);//Nano的內容
      if (myFile.isOpen()) {
        myFile.println(fileContent);
        myFile.close();
        Serial.println("SAVELOG ok !");
        return true;
      }else{
        Serial.println("SAVELOG FAIL !");
        myFile.close();
        return false;
      }
    }
    
    //保存自動呼叫
    bool saveCall(){
       freeForScrn.replace("  "," ");
       freeForScrn.replace("  "," ");
       freeForScrn.replace("  "," ");
       String call=String(autoCallIndex) + "." +freeForScrn;
       SdFile myFile("AUTOCALL.txt", FILE_WRITE);
       if (myFile.isOpen()) {
          Serial.println("writing:" + call); 
          myFile.seekSet(15*autoCallIndex);
          myFile.print(call);
          myFile.close();
          autoCallIndex=0;
          Serial.println("save ok ...");
          return true;
       }
       myFile.close();
       autoCallIndex=0;
       return false;
    }
    bool initAutocall(){//初始化自動呼叫文件
      SdFile myFile("AUTOCALL.txt", FILE_WRITE);
      if (!myFile.isOpen())return false;
      for(byte i=0;i<10;i++){
        myFile.seekSet(15*i);
        myFile.print(String(i)+".             ");
      }
      myFile.close();
      return true;
    }
    //讀取全部呼叫
    String readAll(){
      String tem="";
      for(int i=0;i<10;i++){
         tem=tem + readCall(i) + char(13) + char(10);
      }
      Serial.println(tem); 
      return tem;
    }
    //讀取單條呼叫,主要被readAll調用
    String readCall(byte index){
      String msg="";
      byte i=0;
    
      SdFile myFile("AUTOCALL.txt",FILE_READ);
      if (myFile.isOpen()) {
        myFile.seekSet(15*index);
        while (i<15 && myFile.available()) {
          i++;
          msg=msg + String(char(myFile.read()));
        }
        myFile.close();
        Serial.println(msg); 
        return msg;
        } else {
      Serial.println("read error");
      myFile.close();
      return "";
      }
    }
    bool saveAs(char * fileName){
      SdFile myFile("WORKLOG.txt", FILE_READ);
      if (!myFile.isOpen())return false;
      if (!myFile.rename(sd.vwd(),fileName)) return false;
      return true;
    }
    //發往顯示屏的字符
    bool charToDisplay(String cmd){
      cmdToDisplay("send.valStrS.txt=\"" + cmd + "\"");
      cmdToDisplay("click btnDisplay,1");
    }
    //發往顯示屏的命令
    bool cmdToDisplay(String cmd){
      Serial.println(cmd);
      //return true;
      Serial1.print(cmd);
      Serial1.write(endFlag);
      Serial1.write(endFlag);
      Serial1.write(endFlag);
      return true;
      }
    //發往Nano的消息
    bool msgToNano(String msg){
      Serial3.print(msg);
      Serial.println(msg);
      return true;
    }
    bool byteToNano(byte msg){
      Serial3.write(msg);
      Serial.println(msg);
      return true;
    }
    //速度值驗證
    void checkSpeed(){
      //if(sendActId || scrId!=1)return;
      int temVal=msgSpeed.toInt();
      if(temVal>=60 && temVal<=250)return;
      if(temVal<60)temVal=60;
      if(temVal>250)temVal=250;  
      msgSpeed=String(temVal);
      byteToNano(CHANGESPEED);
      byteToNano(byte(msgSpeed.toInt()));
      cmdToDisplay("t0.txt=\"" + msgSpeed + "\"");
    }
    //號數中0的處理,若號數為數字與字母混合,數字0發長碼,被sendEnter調用
    String SLTranslate(String numberForNano){
      if(numberForNano.indexOf("/")>-1 && numberForNano.indexOf("0")>-1){
        numberForNano.replace('0','!');
        }
      return numberForNano;
    }
    
    //所有退格的處理
    void proBackSpace(){
      switch(sendActId){
        case 0:
          msgSpeed=msgSpeed.substring(0,msgSpeed.length()-1);
          cmdToDisplay("t0.txt=t0.txt-1");
          break;
        case 1:
          freeForNano=freeForNano.substring(0,freeForNano.length()-1);
          freeForScrn=freeForScrn.substring(0,freeForScrn.length()-1);
          cmdToDisplay("t1.txt=t1.txt-1");
          break;
        case 2:
          numberForNano=numberForNano.substring(0,numberForNano.length()-1);
          numberForScrn=numberForScrn.substring(0,numberForScrn.length()-1);
          cmdToDisplay("t2.txt=t2.txt-1");
          break;
        case 3:
          msgGroup=msgGroup.substring(0,msgGroup.length()-1);
          cmdToDisplay("t3.txt=t3.txt-1");
          break;
        case 4:
          msgClass=msgClass.substring(0,msgClass.length()-1);
          cmdToDisplay("t4.txt=t4.txt-1");
          break;
        case 5:
          msgDate=msgDate.substring(0,msgDate.length()-1);
          cmdToDisplay("t5.txt=t5.txt-1");
          break;
        case 6:
          msgTime=msgTime.substring(0,msgTime.length()-1);
          cmdToDisplay("t6.txt=t6.txt-1");
          break;
        case 7:
          numberForNano=numberForNano.substring(0,numberForNano.length()-1);
          numberForScrn=numberForScrn.substring(0,numberForScrn.length()-1);
          cmdToDisplay("t7.txt=t7.txt-1");
          break;
        case 8:
          msgGroup=msgGroup.substring(0,msgGroup.length()-1);
          cmdToDisplay("t8.txt=t8.txt-1");
          break;
        case 9:
          msgMarket=msgMarket.substring(0,msgMarket.length()-1);
          cmdToDisplay("t9.txt=t9.txt-1");
          break;
        case 10://發報界面-報文區
          msg=msg.substring(0,msg.length()-1);
          msgForDisplay=msgForDisplay.substring(0,msgForDisplay.length()-1);
          cmdToDisplay("t10.txt=t10.txt-1");
          break;
        case 11://調用報文界面-報文種類
          break;
        case 12://調用報文界面-起始頁碼
          dataPage=dataPage/10;
          //if(dataPage)dataPage=1;
          cmdToDisplay("n1.val=" + String(dataPage));
          break;
        case 13://調用報文界面-調用組數
          dataGroup=dataGroup/10;
          //if(dataGroup)dataGroup=1;
          cmdToDisplay("n2.val=" + String(dataGroup));
          break;
        case 71://輸入對話框
          msgFileName=msgFileName.substring(0,msgFileName.length()-1);
          cmdToDisplay("t0.txt=t0.txt-1");
          break;
        default:
          break;  
        }
    }
    //所有清空的處理
    void proDel(){
      switch(sendActId){
        case 0:
          msgSpeed="";
          cmdToDisplay("t0.txt=\"\"");
          break;
        case 1:
          freeForNano="";
          freeForScrn="";
          cmdToDisplay("t1.txt=\"\"");
          break;
        case 2:
          numberForNano="";
          numberForScrn="";
          cmdToDisplay("t2.txt=\"\"");
          break;
        case 3:
          msgGroup="";
          cmdToDisplay("t3.txt=\"\"");
          break;
        case 4:
          msgClass="";
          cmdToDisplay("t4.txt=\"\"");
          break;
        case 5:
          msgDate="";
          cmdToDisplay("t5.txt=\"\"");
          break;
        case 6:
          msgTime="";
          cmdToDisplay("t6.txt=\"\"");
          break;
        case 7:
          numberForNano="";
          numberForScrn="";
          cmdToDisplay("t7.txt=\"\"");
          break;
        case 8:
          msgGroup="";
          cmdToDisplay("t8.txt=\"\"");
          break;
        case 9:
          msgMarket="";
          cmdToDisplay("t9.txt=\"\"");
          break;
        case 10:
          if(sys0==2)return;
          msg="";
          msgForDisplay="";
          cmdToDisplay("t10.txt=\"\"");
          break;
        case 11://調用報文界面-報文種類
          break;
        case 12://調用報文界面-起始頁碼
          dataPage=0;
          cmdToDisplay("n1.val=0");
          break;
        case 13://調用報文界面-調用組數
          dataGroup=0;
          cmdToDisplay("n2.val=0");
          break;
        case 71://輸入對話框
          msgFileName="";
          cmdToDisplay("t0.txt=\"\"");
          break;
      }
    }
    //隱藏字符輸入驗證及處理;按下ctrl鍵即響應
    void checkHide(byte chOemKey,int chMod){//掃描碼,控制鍵狀態(ctrl alt shift)
      Serial.println(chOemKey);
      //Serial.println(chMod);
      //-------del(76)-------清空
      if(chOemKey==76){
        proDel();
        return;
      }
      //-------backSpace(42)-------退格
      if(chOemKey==42){
        proBackSpace();
        return;
      }
    
      if(!chMod)return;
    
      //--------F12(69)--------焦點定位移動至報文區
      if(chOemKey==69){
        if(sendActId==0)checkSpeed();//糾正速度值至合理范圍
        if(sendActId<10){//當為10時已在報文區,故不響應
          sendActId=10;
          cmdToDisplay("click t1,0");
          cmdToDisplay("send.sendActId.val=10");
        }
        return;
      }
      //--------F11(68)-------焦點定位移動至自由區
      if(chOemKey==68){
        if(sendActId==0)checkSpeed();
        if(sendActId<11 && sendActId!=1){
          sendActId=1;
          cmdToDisplay("click t1,0");
          cmdToDisplay("send.sendActId.val=1");
        }
        return;
      }
      //--------左箭頭(80)-------焦點前移
      if(chOemKey==80){
        if(sendActId<21)cmdToDisplay("click t1,0");//先去掉原光標符號
        switch(sendActId){
          case 0:
            checkSpeed();//糾正速度值
            sendActId=10;
            break;
          case 1:
            sendActId=0;
            break;
          case 2:
            sendActId=1;
            break;
          case 3:
            sendActId=2;
            break;
          case 4:
            sendActId=3;
            break;
          case 5:
            sendActId=4;
            break;
          case 6:
            sendActId=5;
            break;
          case 7:
            sendActId=1;
            break;
          case 8:
            sendActId=7;
            break;
          case 9:
            if(sys1==1)
              sendActId=6;
            else
              sendActId=8;
            break;
          case 10:
            sendActId=9;
            break;
          case 11://調用報文界面-報文種類(理論上不會為11)
            sendActId=13;
            cmdToDisplay("n1.picc=2");
            cmdToDisplay("n2.picc=4");
            break;
          case 12://調用報文界面-起始頁碼
            sendActId=13;
            cmdToDisplay("n1.picc=2");
            cmdToDisplay("n2.picc=4");
            break;
          case 13://調用報文界面-調用組數
            sendActId=12;
            cmdToDisplay("n1.picc=4");
            cmdToDisplay("n2.picc=2");
            break;
          case 51://計算器第1個數
            sendActId=52;
            cmdToDisplay("n0.picc=2");
            cmdToDisplay("n1.picc=4");
            break;
          case 52://計算器第1個數
            sendActId=51;
            cmdToDisplay("n0.picc=4");
            cmdToDisplay("n1.picc=2");
            break;
          case 71://輸入對話框
            break;
          default:
            if(sendActId>=20 && sendActId<=25){//---main界面---
              cmdToDisplay("click b" + String(sendActId-20) + ",0");
              if(sendActId==20){
                sendActId=25;
              }else{
                sendActId=sendActId-1;
              }
              cmdToDisplay("click b" + String(sendActId-20) + ",1");
            }
            return;
        }
        cmdToDisplay("send.sendActId.val=" + String(sendActId));
        return;
      }
      //-------右箭頭(79)-------焦點后移
      if(chOemKey==79){
        if(sendActId<21)cmdToDisplay("click t1,0");//先去掉原光標符號
        switch(sendActId){
          case 0:
            checkSpeed();//糾正速度值
            sendActId=1;
            break;
          case 1:
            if(sys1==1)
              sendActId=2;
            else
              sendActId=7;
            break;
          case 2:
            sendActId=3;
            break;
          case 3:
            sendActId=4;
            break;
          case 4:
            sendActId=5;
            break;
          case 5:
            sendActId=6;
            break;
          case 6:
            sendActId=9;
            break;
          case 7:
            sendActId=8;
            break;
          case 8:
            sendActId=9;
            break;
          case 9:
            sendActId=10;
            break;
          case 10:
            sendActId=0;
            break;
          case 11://調用報文界面-報文種類(理論上不會為11的)
            sendActId=12;
            cmdToDisplay("n1.picc=4");
            cmdToDisplay("n2.picc=2");
            break;
          case 12://調用報文界面-起始頁碼
            sendActId=13;
            cmdToDisplay("n1.picc=2");
            cmdToDisplay("n2.picc=4");
            break;
          case 13://調用報文界面-調用組數
            sendActId=12;
            cmdToDisplay("n1.picc=4");
            cmdToDisplay("n2.picc=2");
            break;
          case 51://計算器第1個數
            sendActId=52;
            cmdToDisplay("n0.picc=2");
            cmdToDisplay("n1.picc=4");
            break;
          case 52://計算器第1個數
            sendActId=51;
            cmdToDisplay("n0.picc=2");
            cmdToDisplay("n1.picc=4");
          case 71://輸入對話框
            break;
          default:
            if(sendActId>=20 && sendActId<=25){//---main界面---
              cmdToDisplay("click b" + String(sendActId-20) + ",0");
              if(sendActId==25){
                sendActId=20;
              }else{
                sendActId=sendActId+1;
              }
              cmdToDisplay("click b" + String(sendActId-20) + ",1");
            }
        }
        cmdToDisplay("send.sendActId.val=" + String(sendActId));
        return;
      }
    
      //-------F9(66)-------調整工作業務類型,僅發報界面
      if(chOemKey==66){
        if(sendActId<=10){
          //wordsTotal=0;//報文組數
          //proFlag=0;
          if(sys1==5){
            sys1=1;
            if(sendActId==7)sendActId=2;
            if(sendActId==8)sendActId=3;
          }else{
            sys1+=1;
            if(sendActId==2)sendActId=7;
            if(sendActId>2 && sendActId<7)sendActId=8;
          }
          msgToNano(String(char(AUTOCALLSTOP)));// 通知NANO暫停警報臺自動呼叫(249命令不存在,但nano收到任何信息都會先暫停自動呼叫)
          cmdToDisplay("sys1=" + String(sys1));
          cmdToDisplay("click t21,0");//改顯示屏上報文類型
        }
        return;
      }
      //-------上箭頭(82)---------調高數值,改變枚舉變量類型內容
      if(chOemKey==82){
         if(chMod==3){//ctrl+shift,調高屏幕亮度,彈起事件
            cmdToDisplay("click tDisplayCtr,0");
            return;
         }
         if(sendActId==0){//發報界面速度控件t0接受,調高發報速度
           if(msgSpeed.toInt()+5<=MAXSPEED){
              msgSpeed=String(msgSpeed.toInt()+5);
              cmdToDisplay("t0.txt=\"" + msgSpeed + "\"");
              byteToNano(CHANGESPEED);
              byteToNano(byte(msgSpeed.toInt()));}
           return;
         }
         if(sendActId==31){//自動呼叫界面,循環遞增自動呼叫下標0-9
            if(autoCallIndex==9){
              autoCallIndex=0;
            }else{
              autoCallIndex++;
            }
            cmdToDisplay("t1.txt=\"" + String(autoCallIndex) + "\"");
            return;
         }
         if(sendActId>=11 && sendActId<=19){//調用報底界面:循環改變報底種類:數碼、字碼、混合碼
            if(dataKind==2)
               dataKind=0;
            else
               dataKind++;
            cmdToDisplay("va0.val=" + String(dataKind));
            cmdToDisplay("click t3,0");
         }
         if(sendActId==101){//系統調試
            if(pgIndex==9){
              pgIndex=0;
            }else{
              pgIndex++;
            }
            cmdToDisplay("t1.txt=\"" + String(pgIndex) + "\"");
            return;
         }
         if(sendActId==51 || sendActId==52){//計算器,循環改變運算符+-*/%
            cmdToDisplay("click t3,1");
            return;
         }
         return;
      }
      //-------下箭頭(80)--------調低數值
      if(chOemKey==81){
         if(chMod==3){//ctrl+shift,調暗屏幕,按下事件
            cmdToDisplay("click tDisplayCtr,1");
            return;
         }
         if(sendActId==0){//發報界面速度控件t0,調低發報速度
           if(msgSpeed.toInt()-5>=MINSPEED){
              msgSpeed=String(msgSpeed.toInt()-5);
              cmdToDisplay("t0.txt=\"" + msgSpeed + "\"");
              byteToNano(CHANGESPEED);
              byteToNano(byte(msgSpeed.toInt()));}
           return;
         }
         if(sendActId==31){//自動呼叫界面,循環遞減自動呼叫下標0-9
            if(autoCallIndex==0){
              autoCallIndex=9;
            }else{
              autoCallIndex--;
            }
            cmdToDisplay("t1.txt=\"" + String(autoCallIndex) + "\"");
            return;
         }
         if(sendActId>=11 && sendActId<=19){//調用報底界面:循環改變報底種類:數碼、字碼、混合碼
            if(dataKind==0)
               dataKind=2;
            else+
               dataKind--;
            cmdToDisplay("va0.val=" + String(dataKind));
            cmdToDisplay("click t3,0");
            return;
         }
         if(sendActId==51 || sendActId==52){//計算器,循環改變運算符+-*/%
            cmdToDisplay("click t3,0");
            return;
         }
         if(sendActId==73){//自動呼叫界面,循環遞減自動呼叫下標0-9
            if(pgIndex==0){
              pgIndex=9;
            }else{
              pgIndex--;
            }
            cmdToDisplay("t1.txt=\"" + String(pgIndex) + "\"");
            return;
         }
         return;
      }
      //--------F10(67)---------調整發送模式,僅發報界面
      if(chOemKey==67){
        if(sendActId<=10){
          if(sys0>=1){
            sys0=0;
            }else{
              sys0++;
            }
          cmdToDisplay("sys0=" + String(sys0));
          cmdToDisplay("click t11,0");
        }
        return;
      }
      //--------F8(65)---------調整長短碼,僅發報界面
      if(chOemKey==65){
         if(sendActId<=10){
            if(sys2==1){
              sys2=0;
              cmdToDisplay("sys2=0");
            }else{
              sys2=1;
              cmdToDisplay("sys2=1");
            }
            cmdToDisplay("click t12,0");
         }
         return;
      }
      //--------home()74-------返回主界面
      if(chOemKey==74){
        sendActId=20;
        cmdToDisplay("page main");
        return;
        }
      //--------F1(58)-------保存,工作日志的保存
      if(chOemKey==58){
        if(sendActId<=10 && cSave){//僅發報界面且處于保存狀態下時響應
           actIdPre=sendActId;
           sendActId=71;//輸入對話框界面
           cmdToDisplay("page inputBox");
           cmdToDisplay("t0.txt=\"" + msgFileName + "\"");//此處沒有賦空串值,在不重啟情況下默認為上次輸入的名字
           byteToNano(UPLOADLOG);//讓nano把剩余的、未滿頁的內容發過來
        }
        return;
      }
      //--------F2(59)-------保存 //警報呼叫:自呼與被用的保存
      if(chOemKey==59){
          if(sendActId<=10 && sys1==4){//僅發報界面,且為警報信號時響應
             actIdPre=sendActId;
             sendActId=31;
             saveOrUse=1;
             autoCallIndex=0;
             cmdToDisplay("page autoCall");
             cmdToDisplay("va0.val=1");//標識保存
             cmdToDisplay("click t1,0");
             cmdToDisplay("t2.txt=\"" + readAll() + "\"");//將當前的自呼與自用全部讀出展示
             }     
          return;
       }
      //--------F3(60)-------報底調用,僅用于電報(調入系統報底、工作記錄)、警報呼叫(調入自動呼叫的自呼和被用)
      if(chOemKey==60){
        if(sendActId<=10){
          if(sys1==1){//發界面,電報,報底的調入
             dataPage=1;
             dataGroup=100;
             dataKind=0;
             actIdPre=sendActId;
             sendActId=12;//激活控件id
             cmdToDisplay("page useData");
             cmdToDisplay("va0.val=0");
             cmdToDisplay("n1.picc=4");
             cmdToDisplay("n2.picc=2");
             return;
          }
          if(sys1==4){//發界面,警報呼叫,調入自呼與被用
             actIdPre=sendActId;
             sendActId=31;//激活控件id
             saveOrUse=0;
             autoCallIndex=0;
             cmdToDisplay("page autoCall");
             cmdToDisplay("va0.val=0");//標識調用
             cmdToDisplay("click t1,0");
             cmdToDisplay("t2.txt=\"" + readAll() + "\"");
             return;
          }
          return;
        }
        return;
        }
      //--------F4(61)-------日志保存開始/結束切換(若要保存日志,必須先保存,再結束,因為一但結束就會清空日志緩存變量)
      if(chOemKey==61){
         if(sendActId<=10){
           if(cSave){
             cSave=0;
             byteToNano(RECORDSTART);
           }else{
             cSave=1;
             byteToNano(RECORDSTOP);
           }
           cmdToDisplay("cSave.val=" + String(cSave));//更新顯示顯示屏上的選擇框
           if(cSave)sd.remove("WORKLOG.txt");//刪除原日志文件,可能會有上次的記錄(如上次開始記錄了,但沒有保存)
         }
         return;
      }
      //--------ESC(41)-------取消
      if(chOemKey==41){
         if((sendActId>=11 && sendActId<=19) || sendActId==31 || sendActId==71){
            sendActId=actIdPre;
            if(sendActId>10)sendActId=1;//防止意外發生
            cmdToDisplay("page send");
            return;
         }
         if(sendActId<=10 || sendActId==41 || sendActId==91 || sendActId==51 || sendActId==52){
            sendActId=20;
            cmdToDisplay("page main");
         }
         return;
        }
      //--------PgUp(73)-------上一頁
      if(chOemKey==173){//暫時取消
         return;
         if(sendActId<=10 && sys0==2){//發報界面,調用報底,顯示上一頁,循環式
            if(dataPageNow==1){//當前為第一頁則顯示最后一頁
              dataPageNow=dataPage;
            }else{
              dataPageNow=dataPageNow-1;
            }
            msgForDisplay=msg.substring((dataPageNow-1)*500,499);//報文全部讀出,需視情更改
            cmdToDisplay("t10.txt=\"" + msgForDisplay + "\"");//顯示第一頁報文
            cmdToDisplay("nPage.val="+dataPageNow);//更新界面頁碼
            }
          return;
        }
      //--------PgDn(81)-------下一頁
      if(chOemKey==81){//暫時取消
         return;
         if(sendActId<=10 && sys0==2){//發報界面,調用報底,顯示下一頁
            if(dataPageNow==dataPage){
              dataPageNow=1;
            }else{
              dataPageNow=dataPageNow+1;
            }
            msgForDisplay=msg.substring((dataPageNow-1)*500,499);
            cmdToDisplay("t10.txt=\"" + msgForDisplay + "\"");//顯示第一頁報文
            cmdToDisplay("nPage.val="+dataPageNow);//更新界面頁碼
            }
          return;
        }
      //--------PrtSc(55)-------打開、關閉顯示屏(控制顯示屏的供電)
      if(chOemKey==55){
         closeOrOpenDisplay();
        }
      //--------insert(73)-------編程調試
      if(chOemKey==73){
         sendActId=101;
         pgIndex=0;
         cmdToDisplay("page sysPg");
        }
    }
    //所有界面回車的處理sendActId
    void sendEnter(byte sys,int chMod){
      String tem;
      switch(sys){
        case 0://在速度區按回車,速度值糾正,并焦點移動至自由區kill
          checkHide(byte(79),1);
          break;
        case 1://在自由區按回車
          if(sys1==4){//若警報業務,則自動呼叫開始
            freeForNano.trim();
            if(!freeForNano.length())return;//空,不響應
            Serial.println("warn auto call start !");
            msgToNano(String(char(AUTOCALLSTART)) + freeForNano + String(char(AUTOCALLSTART)));
          }else{
            msgToNano(freeForNano);
            }
          break;
        case 2://在2--8按回車等價于后移焦點
          return checkHide(79,1);
          break;
        case 3:
          return checkHide(79,1);
          break;
        case 4:
          return checkHide(79,1);
          break;
        case 5:
          return checkHide(79,1);
          break;
        case 6:
          return checkHide(79,1);
          break;
        case 7:
          return checkHide(79,1);
          break;
        case 8:
          return checkHide(79,1);
          break;
        case 9://附注區
          //if(proFlag>0)return checkHide(79,1);//報頭已發,跳至報文區
          if(sys1==1){//為電報業務或業務公電,在附注區按回車發送電報頭
            numberForScrn.trim();
            msgClass.trim();
            msgDate.trim();
            msgTime.trim();
            msgMarket.trim();
    
            if(numberForScrn.length()<1)return;//交付時更改條件
            if(msgGroup.toInt()<1)return;
            if(msgClass.length()<1)return;
            if(msgDate.length()<1)return;
            if(msgTime.length()<1)return;
            tem="NR " + SLTranslate(numberForScrn) + " CK " + msgGroup + " " + msgClass + " " + msgDate + " " + msgTime;
            if(msgMarket.length()>0)tem=tem +" RMKS " + msgMarket;
          }else{
            if(sys1==4)return;
            numberForScrn.trim();
            msgTime.trim();
            msgMarket.trim();
            if(numberForScrn.length()<1)return;//交付時更改條件
            if(msgTime.length()<1)return;
            tem="NR " + SLTranslate(numberForScrn) + " " + msgTime;
            if(msgMarket.length()>0)tem=tem +" RMKS " + msgMarket;
          }
          msgToNano(tem);
          checkHide(79,1);//調用右箭頭
          break;
        case 10://報文區
          msg.trim();//去掉空格
          msgForDisplay.trim();
          if(!chMod){
            msgForDisplay=msgForDisplay + char(13)+char(10);
            charToDisplay(String(char(13)));
            charToDisplay(String(char(10)));
            msg=msg+" ";
            return;
          }
          //以下為用戶發出整頁發送命令
          if(msg.length()<1)return;
          if(sys1==1){//電報,一次性發送或調用發送
             if(sys0==1)return;
             if(sys0==0){
               if(!msg.startsWith("{") && !dataSendStarted)msg=msg+"{";
               msgToNano(msg);
               msg="";//一次性發送后清屏
               msgForDisplay="";
               cmdToDisplay("t10.txt=\"\"");
               dataSendStarted=true;//標識已經開始發送了
             }
             if(sys0==2){
               sendDataNextPage(true);
             }
           return;;
          }
          if(sys1==2){//業務公電,一次性發送
             msgToNano(msg);
             return;
            }
          if(sys1==3){//無線電信號,一次性發送
             msgToNano(String(RADIOCHAR) + " NR " + numberForNano + " " + msgTime + " " + String(STARTCHAR) + " " + msg + " " + String(ENDCHAR));
             return;
            }
          if(sys1==4){//發警報信號,nano處于自動警報呼叫時,收到數據即停止自動呼叫!
             byteToNano(AUTOCALLSTOP);
             msgToNano("XXX "+ String(STARTCHAR)+ " " + msg + " " + String(ENDCHAR) + "     XXX "+ String(STARTCHAR) + " " + msg + " " + String(ENDCHAR));
             return;;
            }
          if(sys1==5){//通信檢查,一次性發送
             if(msg.indexOf("{")==-1)msgToNano("V V V " + String(STARTCHAR) + " " + msg + " " + msg + " " + msg + " " + String(ENDCHAR));
            }
          break;  
        case 11://報底調用,回車后僅當前顯示改變,不發送
          if(dataPage<1 || dataGroup<1) return;//非法,不處理
          dataPositionFrom=(dataPage-1)*500;
    
          if(!readData())return;
    
          dataPage=dataGroup/100;
          if(dataGroup%100)dataPage=dataPage+1;
          dataPageNow=0;
          dataSendStarted=false;
          //界面顯示
          sendActId=actIdPre;
          sys0=2;
          cmdToDisplay("page send");//返回發報界面
          cmdToDisplay("sys0=2");//此處兩行更改發送模式為“調用發送”
          cmdToDisplay("t10.txt=\"" + msgForDisplay + "\"");//顯示第一頁報文
          cmdToDisplay("nPage.val=0/"+String(dataPage));//更新界面頁碼
          break;
        case 12:  
          sendEnter(11,chMod);
          break;
        case 13:
          sendEnter(11,chMod);
          break;
        case 20:
          sendActId=1;
          actIdPre=20;
          cmdToDisplay("page send");
          break;
        case 21:
          sendActId=31;
          actIdPre=20;
          saveOrUse=2;
          autoCallIndex=0;
          cmdToDisplay("page autoCall");
          cmdToDisplay("va0.val=2");//標識瀏覽
          cmdToDisplay("click t1,0");
          cmdToDisplay("t2.txt=\"" + readAll() + "\"");
          break;
        case 22:
          sendActId=12;
          cmdToDisplay("page useData");
          break;
        case 23://輔助工具`
          sendActId=51;
          cmdToDisplay("page tool");
          break;
        case 24://系統設置
          sendActId=41;
          cmdToDisplay("page sysSet");
          break;
        case 41:
          sendActId=20;
          cmdToDisplay("page main");
          break;
        case 25://關于
          sendActId=91;
          cmdToDisplay("page about");
          break;
        case 91:
          sendActId=20;
          cmdToDisplay("page main");
          break;
        case 31://自動呼叫的回車
          sendActId=actIdPre;
          if(actIdPre==20){
             cmdToDisplay("page main");
             return;
          }else{
             cmdToDisplay("page send");
          }
          if(saveOrUse==1){//保存
             saveCall();
           }else{//調用
             freeForScrn=readCall(autoCallIndex);
             freeForScrn.trim();
             freeForScrn=freeForScrn.substring(2);
             cmdToDisplay("t1.txt=\"" + freeForScrn + "\"");
             freeForNano=replaceNumberToLong(freeForScrn);
           }
          break;
        case 101:
          sendActId=1;
          cmdToDisplay("page send");
          switch(pgIndex){
            case 0://初始化自動呼叫文件
              if(initAutocall()){
                Serial.println("initAutocall init ok !");
              }else{
                Serial.println("initAutocall init fail !");
              }
              break;
            case 1://初始化數碼報底
              if(initDataNum()){
                Serial.println("initDataNum init ok !");
              }else{
                Serial.println("initDataNum init fail !");
              }
              break;
            case 2://初始化字碼報底
              if(initDataChr()){
                Serial.println("initDataChr init ok !");
              }else{
                Serial.println("initDataChr init fail !");
              }
              break;
            case 3://初始化混合報底
              if(initDataBoth()){
                Serial.println("initDataBoth init ok !");
              }else{
                Serial.println("initDataBoth init fail !");
              }
              break;
          }
    
          break;
        case 51:
          cmdToDisplay("click t5,1");
          break;
        case 52:
          cmdToDisplay("click t5,1");
          break;
        case 71://輸入對話框:工作日志保存
          msgFileName.trim();
          if(!msgFileName.length())return;
          sendActId=1;
          tem=msgFileName + ".txt";
          //sd.remove("WORKLOG.txt");
          SdFile myFile("WORKLOG.txt", FILE_WRITE);
          if (!myFile.rename(sd.vwd(),tem.c_str())){
            Serial.println("WORKLOG RENAME OK !");
          }else{
            Serial.println("WORKLOG RENAME fAIL !");
          }
          sendActId=actIdPre;
          cmdToDisplay("page send");//返回發報界面
          break;
      }
    }
    
    //顯示字符輸入驗證,僅對輸入的字符本身驗證以及長度驗證,不驗證數值;true通過驗證,false驗證失敗
    void checkShow(byte sys,byte chKey,byte chOemKey,int chMod){
      if(chKey>=97 && chKey<=122)chKey-=32;//小寫轉為大寫
      if(chKey==19)sendEnter(sendActId,chMod);//回車處理:發送
      switch(sys){
        case 10://報文區
          //if(wordsTotal>=100)return;//滿頁不再接受輸入
          if(msgForDisplay.length()>=MSGMAXLENGTH)return;
          //空格的處理
          if(chKey==32){
            if(msg.endsWith(" ") || !msg.length())return;//無效空格
            if(sys1==1){//業務類型為電報
               msg=msg + " ";
               msgForDisplay=msgForDisplay + " ";
               charToDisplay(" ");
               if(sys0==1)msgToNano(" ");//當前為隨輸隨發模式,發送
               //wordsTotal++;//更新組數
            }
            return;
          }
          if((chKey>=48 && chKey<=57) || (chKey>=65 && chKey<=90) || chKey==46 || chKey==63 || chKey==33 || chKey==47 || chKey==95){//數字,字母,句號,問號(數碼改錯),感嘆號(混合碼改錯),“/-”
              msgForDisplay=msgForDisplay+char(chKey);
              charToDisplay(String(char(chKey)));
              if((sys2==1 || sys1>1) && (chKey>=48 && chKey<=57))chKey+=numberLong;//僅為電報短碼時數字按短碼處理,否則轉為長碼98->107
              if(sys0) msgToNano(String(char(chKey)));//隨輸隨發模式
              msg=msg+char(chKey);
          }
          break;
        case 1://自由勤務區,不受sys1限制,數字一律按長碼發送
          if(freeForScrn.length()>=FREELENGTHMAX) return;//長度驗證
          if(chKey==32 || (chKey>=48 && chKey<=57) || (chKey>=65 && chKey<=90) || chKey==63 || chKey==47 || chKey==33 || chKey==45){//空格、數字、字母、問號、!、“/-”
            freeForScrn=freeForScrn+char(chKey);
            charToDisplay(String(char(chKey)));
            if(chKey>=48 && chKey<=57)chKey+=numberLong;
            freeForNano=freeForNano+String(char(chKey));}
          break;
        case 2://號數,受限于電報
          if(sys1!=1)return;//僅電報時可輸入
          if(numberForScrn.length()>=8)return;//長度驗證
          if(chKey>=48 && chKey<=57){//數字
            numberForNano+=char(chKey);
            numberForScrn+=char(chKey);
            cmdToDisplay("t2.txt=\"" + numberForScrn + "\"");
            //charToDisplay(String(char(chKey)));
            return;}
          if(chKey==47 && numberForScrn.indexOf("/")==-1){
            numberForScrn+=char(chKey);
            numberForNano+=char(chKey);
            cmdToDisplay("t2.txt=\"" + numberForScrn + "\"");
            return;
          }
          if((chKey==69) && numberForScrn.indexOf("E")==-1){
            numberForScrn+=char(chKey);
            numberForNano+=char(chKey);
            cmdToDisplay("t2.txt=\"" + numberForScrn + "\"");
            return;
          }
          if((chKey==88) && numberForScrn.indexOf("X")==-1){
            numberForScrn+=char(chKey);
            numberForNano+=char(chKey);
            cmdToDisplay("t2.txt=\"" + numberForScrn + "\"");
          }
          break;
        case 3://組數,受限于電報
          if(sys1!=1)return;//僅電報時可輸入
          if(msgGroup.length()>=5) return;//長度驗證
          if(chKey>=48 && chKey<=57){
            msgGroup+=char(chKey);
            cmdToDisplay("t3.txt=\"" + msgGroup + "\"");
          }
          break;
        case 4://等級,受限于電報
          if(sys1!=1)return;//僅電報時可輸入
          if(msgClass.length()>=5) return;//長度驗證
          if(chKey>=48 && chKey<=57){
            msgClass+=char(chKey);
            cmdToDisplay("t4.txt=\"" + msgClass + "\"");
          }
          break;
        case 5://日期,受限于電報
          if(sys1!=1)return;//僅電報時可輸入
          if(msgDate.length()>=4) return;//長度驗證
          if(chKey>=48 && chKey<=57){
            msgDate+=char(chKey);
            cmdToDisplay("t5.txt=\"" + msgDate + "\"");
          }
          break;
        case 6://時間,受限于電報
          if(sys1==0 || sys1==4)return;//僅電報時可輸入
          if(msgTime.length()>=4) return;//長度驗證
          if(chKey>=48 && chKey<=57){
            msgTime+=char(chKey);
            cmdToDisplay("t6.txt=\"" + msgTime + "\"");
          }
          break;
        case 7://號數2,受限于無線電信號,公電
          if(sys1!=2 && sys1!=3 && sys1!=5)return;//通信檢查、無線電信號,公電時可輸入
          if(numberForScrn.length()>=8) return;//長度驗證
          if(chKey>=48 && chKey<=57){
            numberForScrn+=char(chKey);
            numberForNano+=char(chKey);
            cmdToDisplay("t7.txt=\"" + numberForScrn + "\"");
            return;
          }
          if(chKey==47 && numberForScrn.indexOf("/")==-1){
            numberForScrn+=char(chKey);
            numberForNano+=char(chKey);
            cmdToDisplay("t7.txt=\"" + numberForScrn + "\"");
            return;
          }
          if((chKey==69 || chKey==101) && numberForScrn.indexOf("E")==-1){
            numberForScrn+=char(chKey);
            numberForNano+=char(chKey);
            cmdToDisplay("t7.txt=\"" + numberForScrn + "\"");
            return;
          }
          if((chKey==88 || chKey==120) && numberForScrn.indexOf("X")==-1){
            numberForScrn+=char(chKey);
            numberForNano+=char(chKey);
            cmdToDisplay("t7.txt=\"" + numberForScrn + "\"");
          }
          break;
        case 8://時間2,受限于無線電信號,公電
          if(sys1!=2 && sys1!=3 && sys1!=5)return;//通信檢查、無線電信號,公電時可輸入
          if(msgTime.length()>=4) return;//長度驗證
          if(chKey>=48 && chKey<=57){
            msgTime+=char(chKey);
            cmdToDisplay("t8.txt=\"" + msgTime + "\"");
          }
          break;
        case 9://附注,受限于電報,無線電信號,公電
          if(sys1==0 || sys1==4 || sys1==5)return;//僅電報,無線電信號,公電時可輸入
          if(msgMarket.length()>=50) return;//長度驗證
          if((chKey>=65 && chKey<=90) || (chKey>=48 && chKey<=57) || chKey==47 || chKey==45){//字母、數字、“/”、“-”
            msgMarket+=char(chKey);
            charToDisplay(String(char(chKey)));
            //cmdToDisplay("click btnDisplay,1");
          }
          break;
        case 0://速度
          if(msgSpeed.length()>=3) return;//長度驗證
          if(chKey>=48 && chKey<=57){//數字
            msgSpeed+=char(chKey);
            cmdToDisplay("t0.txt=\"" + msgSpeed + "\"");
          }
          break;
        case 51://計算器的第1個數,僅響應數字
          if(chKey>=48 && chKey<=57){//數字
            cmdToDisplay("va0.val=" + String(chKey-48));
            cmdToDisplay("click n0,1");
          }
          break;
        case 52://計算器的第2個數,僅響應數字
          if(chKey>=48 && chKey<=57){//數字
            cmdToDisplay("va0.val=" + String(chKey-48));
            cmdToDisplay("click n1,1");
          }
          break;
        case 71://日志保存輸入框
          if(msgFileName.length()>=15) return;//長度驗證
          if((chKey>=48 && chKey<=57) || (chKey>=97 && chKey<=122) || (chKey>=65 && chKey<=90)){//數字字母
            msgFileName+=char(chKey);
            cmdToDisplay("t0.txt=\"" + msgFileName + "\"");
          } 
          break;
       case 12://報底調用:起始頁碼
          if(chKey>=48 && chKey<=57){//數字
            long tem;
            tem=dataPage*10+chKey-48;
            if(dataKind==0 && tem<=999){
               dataPage=tem;
               if(dataGroup>(999-tem+1)*100)dataGroup=(999-tem+1)*100;//自動糾正組數
               cmdToDisplay("n1.val=" + String(dataPage));
               cmdToDisplay("n2.val=" + String(dataGroup));
               return;
            }
            if(dataKind>0 && tem<=99){
               dataPage=tem;
               if(dataGroup>(99-tem+1)*100)dataGroup=(99-tem+1)*100;//自動糾正組數
               cmdToDisplay("n1.val=" + String(dataPage));
               cmdToDisplay("n2.val=" + String(dataGroup));
            }
          }
          break;
        case 13://報底調用:調用組數
          if(chKey>=48 && chKey<=57){
            long tem;
            tem=dataGroup*10+chKey-48;
            if((dataKind==0 && (dataPage*100+tem)<=99900) || (dataKind>0 && (dataPage*100+tem)<=9900)){
               dataGroup=tem;
               cmdToDisplay("n2.val="+String(dataGroup));
            }
          }
          break;
      }
    }
    void keyPressed() {
      byte chKey=keyboard.getKey();//內碼
      byte chOemKey=keyboard.getOemKey();//掃描碼
      int chMod = keyboard.getModifiers();//修飾符
    //Serial.println(chKey);
      if(chKey>0){    
        checkShow(sendActId,chKey,chOemKey,chMod);//輸入的顯示字符非法,不響應
      }else{
        checkHide(chOemKey,chMod);//輸入的隱藏字符非法,不響應
        }
    }
    
    void setup() {
      //pinMode(pinDisplayPower, OUTPUT);
      //digitalWrite(pinDisplayPower,HIGH);
      pinMode(pinLedR, OUTPUT);
      digitalWrite(pinLedR,LOW);
      pinMode(pinLedG, OUTPUT);
      digitalWrite(pinLedG,HIGH);
      pinMode(pinLedB, OUTPUT);
      digitalWrite(pinLedB,HIGH);
    
      Serial.begin(115200);//調試用
      while (!Serial);
      Serial3.begin(115200);//去往Nano
      while (!Serial1);
      Serial1.begin(115200);//去往顯示屏
      while (!Serial3);
      Serial.println("due started");
    
      if (!sd.begin(pinChipSelect, SD_SCK_MHZ(5))) {
        Serial.println("sd failed!");
      }else{ 
        Serial.println("sd ok...");
        sd.remove("WORKLOG.txt");
        sd.remove("WORKLOG2.txt");
        }
      //系統初始化,讓屏幕保持一致
      delay(3000);
      cmdToDisplay("page send");
      cmdToDisplay("sys1=1");//設定工作類型為電報
      cmdToDisplay("sys0=1");//設定發送模式為隨輸隨發
      cmdToDisplay("send.sendActId.val=1");//設定焦點為自由輸入區
      cmdToDisplay("tmr0.en=1");//啟動光標效果
    
      digitalWrite(pinLedR,HIGH);
      digitalWrite(pinLedG,LOW);
    }
    
    void loop() {
      usb.Task();
      SerialEventP();
    }
    
    void SerialEventP(){
      if(!Serial3.available())return;
      String tem="";
      while (Serial3.available()) {
        tem=tem + char(Serial3.read());
        }
      if(tem.length()>1){
         Serial.println("information for save !");
         saveLog(tem);
      }else{
         if(msg.equals("~"))sendDataNextPage();//調用發送模式下,nano請求下一頁內容 
      }
    }
    
  • TA的每日心情
    擦汗
    2019-9-15 19:13
  • 簽到天數: 22 天

    [LV.4]偶爾看看III

    板凳
     樓主| 發表于 2019-3-10 23:18 | 只看該作者

    kittenblock中小學創客名師推薦的圖形化編程軟件

    從MCU代碼:
    //nano端:字符譯碼、發報
    
    String msg="";//報文內容
    byte mcode[10];//字符翻譯后的點hua
    int eIndexCode=-1;//mcode的最大下標!
    float pTime=50;//點持續時間,單位ms
    byte wTime=7;//組間隔等于多少個點的持續時間,取值:5,7,用于改變音調
    String warnMsg="";//警報臺自動呼叫時的內容
    bool autoCall=false;//當前是否處于自動呼叫狀態,false否,true是
    int autoCallDelay=1000;//自動呼叫時,每次發送完自呼被用后延遲的時間
    
    byte cwPin=9;//去往芯片,控制信號腳
    byte ePin=8;//去往芯片,使能腳f-+
    bool cSave=false;//工作記錄標識
    String msgSave="";//工作日志內容,達到500個字符后遇空格或無發送內容時,或收到due命令,將日志內容發至due
    
    bool sendMode=false;//標識是否為調用報底模式,true是
    bool nextPage=false;//true標識等待下一頁報文
    //譯碼核心
    boolean MsgCoded(int index){
      char charTranslate=msg.charAt(index);
      msgSave=msgSave + msg.charAt(index);
      msg=msg.substring(1);//去掉將發送的第一個字符
      switch(charTranslate){
        case ' ':
          mcode[0]=0;
          eIndexCode=0; 
          break;
        case '1':
          mcode[0]=1;
          mcode[1]=3;
          eIndexCode=1;
          break;
        case '2':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=3;
          eIndexCode=2;
          break;
        case '3':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=3;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '4':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '5':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '6':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '7':
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '8':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          eIndexCode=2;
          break;  
        case '9':
          mcode[0]=3;
          mcode[1]=1;
          eIndexCode=1;
          break;
        case '0':
          mcode[0]=3;
          eIndexCode=0;
          break;
        case 'A':
          mcode[0]=1;
          mcode[1]=3;
          eIndexCode=1;
          break;
        case 'B':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          eIndexCode=3;
          break;
        case 'C':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=3;
          mcode[3]=1;
          eIndexCode=3;
          break;
        case 'D':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          eIndexCode=2;
          break;
        case 'E':
          mcode[0]=1;
          eIndexCode=0;
          break;
        case 'F':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=3;
          mcode[3]=1;
          eIndexCode=3;
          break;
        case 'G':
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=1;
          eIndexCode=2;
          break;
        case 'H':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          eIndexCode=3;
          break;  
        case 'I':
          mcode[0]=1;
          mcode[1]=1;
          eIndexCode=1;
          break;
        case 'J':
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=3;
          mcode[3]=3;
          eIndexCode=3;
          break;
        case 'K':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=3;
          eIndexCode=2;
          break;  
        case 'L':
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=1;
          eIndexCode=3;
          break;
        case 'M':
          mcode[0]=3;
          mcode[1]=3;
          eIndexCode=1;
          break;
        case 'N':
          mcode[0]=3;
          mcode[1]=1;
          eIndexCode=1;
          break;
        case 'O':
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=3;
          eIndexCode=2;
          break;
        case 'P':
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=3;
          mcode[3]=1;
          eIndexCode=3;
          break;
        case 'Q':
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=3;
          eIndexCode=3;
          break;
        case 'R':
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=1;
          eIndexCode=2;
          break;
        case 'S':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          eIndexCode=2;
          break;
        case 'T':
          mcode[0]=3;
          eIndexCode=0;
          break;
        case 'U':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=3;
          eIndexCode=2;
          break;
        case 'V':
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=3;
          eIndexCode=3;
          break;  
        case 'W':
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=3;
          eIndexCode=2;
          break;
        case 'X':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=3;
          eIndexCode=3;
          break;
        case 'Y':
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=3;
          mcode[3]=3;
          eIndexCode=3;
          break;
        case 'Z':
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=1;
          eIndexCode=3;
          break;
        case '!'://0
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=3;
          mcode[3]=3;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '"'://1
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=3;
          mcode[3]=3;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '#'://2
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=3;
          mcode[3]=3;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '$'://3
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=3;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '%'://4
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '&'://5
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '\''://6
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '('://7
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case ')'://8
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=3;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;  
        case '*'://9
          mcode[0]=3;
          mcode[1]=3;
          mcode[2]=3;
          mcode[3]=3;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '/'://斜線
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=3;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '?'://數碼的改錯
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=3;
          mcode[3]=3;
          mcode[4]=1;
          mcode[5]=1;
          eIndexCode=5;
          break;
        case '|'://字碼、混合碼的改錯
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          mcode[5]=1;
          mcode[6]=1;
          mcode[7]=1;
          eIndexCode=7;
          break;
        case '{'://分段,開始
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=3;
          eIndexCode=4;
          break;
        case '}'://句號
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          mcode[5]=1;
          eIndexCode=5;
          break;
        case '@'://完結
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=3;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '^'://無線電信號^
          mcode[0]=1;
          mcode[1]=1;
          mcode[2]=3;
          mcode[3]=1;
          mcode[4]=1;
          eIndexCode=4;
          break;
        case '.'://小數點
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=3;
          mcode[4]=1;
          mcode[5]=3;
          eIndexCode=5;
          break;    
          case '<'://括號
          mcode[0]=1;
          mcode[1]=3;
          mcode[2]=1;
          mcode[3]=3;
          mcode[4]=1;
          mcode[5]=3;
          eIndexCode=5;
          break;    
        case '-'://頁標
          mcode[0]=3;
          mcode[1]=1;
          mcode[2]=1;
          mcode[3]=1;
          mcode[4]=1;
          mcode[5]=3;
          eIndexCode=5;
          break;
        default:
          return false;
        }
      return true;
    }
    //發碼核心
    void sendMorse(){
      if(msgSave.length()>=500){//.保存的內容已有一頁,先給due
            Serial.print(msgSave);
            msgSave="";
          }
    
      if(!msg.length()){
        if(autoCall){//警報臺自動呼叫
          delay(autoCallDelay);
          msg=warnMsg;
        }else{
          sendMode=false;
          delay(500);return;
        }//無報文等待發送
      }else{
        if(sendMode && msg.length()<=5)if(nextPage)Serial.write(126);//126波浪號,即將發送完,通知due發下一頁
      }
      if(!MsgCoded(0))return;//譯碼失敗
    
      if(mcode[0]==0){delay(pTime*(wTime-3));return;}//當前字符為組間隔,-3因為上一字符的碼間隔已經占用了3個點的時間
    
      //有效報文發報
      for(byte i=0;i<eIndexCode;i++){//一次性發送當前字符
        digitalWrite(cwPin,LOW);//打開模擬開關
        delay(pTime*mcode);//point or dash 持續時間
        digitalWrite(cwPin,HIGH);//關閉模擬開關
        delay(pTime);//thi time between point and dash
        }
      digitalWrite(cwPin,LOW);//發碼的最后一個點(hua)
      delay(pTime*mcode[eIndexCode]);
      digitalWrite(cwPin,HIGH);//碼間隔
      delay(pTime*3);  
    }
    
    void cmdPro(byte cmd){
      byte inChar=0;
      switch(cmd){
        case 240://發報速度調整
          inChar = Serial.read();
          if(inChar<60 || inChar>250)return;
          pTime= 50*100/inChar;
          break;
        case 242://警報臺自動呼叫開始命令
          warnMsg="";
          inChar=Serial.read();
          while (Serial.available()) {
          warnMsg=warnMsg + String(char(inChar));
          inChar=Serial.read();}
          if(warnMsg.length()<1 || inChar!=242)return;
          msg=warnMsg + String(char(inChar));
          autoCall=true;
          autoCallDelay=int(pTime*20);
          break;
        case 243://警報臺自動呼叫停止命令
          msg="";
          autoCall=false;
          break;
        case 246://開始記錄發報內容
          cSave=true;
          msgSave="";
          break;
        case 247://停止記錄發報內容
          cSave=false;
          msgSave="";
          break;
        case 248://發送記錄的內容到due
          Serial.print(msgSave);
          msgSave="";
          break;
        case 250://通知Nano停止發報,并將各參數復位
          sendMode=false;
          nextPage=false;
          msg="";
          autoCall=false;
          warnMsg="";
          break;
        case 251://開始調用報底自動發送模式,每次發一頁,余5個字符時nano請求due發一下頁
          sendMode=true;
          nextPage=true;
          msg="";
          break;
        case 252://結束調用報底自動發送模式;
          nextPage=false;
          break;
        }
    }
    void setup()
    { 
      pinMode(cwPin, OUTPUT);
      pinMode(ePin, OUTPUT);
      digitalWrite(ePin,HIGH);
      digitalWrite(cwPin,HIGH);
      Serial.begin(115200);
      while (!Serial);
      //Serial.println("nano started");
      digitalWrite(ePin,LOW);
    }
    
    void loop()
    {  
      sendMorse(); 
    }
    void serialEvent() {
      if(autoCall){
        msg="";
        autoCall=false;//停止警報臺自動呼叫
        nextPage=false;//停止調用報底發報
      }
      while (Serial.available()) {
        byte inChar = Serial.read();
        if(inChar<220){//發送的符號
          msg=msg + char(inChar);
        }else{//來自due的命令
          cmdPro(inChar);
        }
      }  
    }
    
  • TA的每日心情
    擦汗
    2019-9-15 19:13
  • 簽到天數: 22 天

    [LV.4]偶爾看看III

    地板
     樓主| 發表于 2019-3-11 00:38 | 只看該作者
    自己的沙發自己坐
  • TA的每日心情
    擦汗
    2019-9-15 19:13
  • 簽到天數: 22 天

    [LV.4]偶爾看看III

    5#
     樓主| 發表于 2019-4-25 20:18 | 只看該作者
    最近進行了升級,V1.0版正式誕生,4月24日進行了實際工作檢測,證明可以用于工作,具體無法細說,領導不讓,僅貼出最新的外形圖,有意可私下共同研究。最后一張為arduino due開發板和我焊接的母板,母板上的東西都扣在了下面,以節省空間。

  • TA的每日心情
    擦汗
    2019-9-15 19:13
  • 簽到天數: 22 天

    [LV.4]偶爾看看III

    6#
     樓主| 發表于 2019-4-25 23:03 | 只看該作者
    鏈接:https://pan.baidu.com/s/1Ryeci9kmw_unnfQsE4_OBQ
    提取碼:47fc
    復制這段內容后打開百度網盤手機App,操作更方便哦
    有問題可聯系我QQ:2554276567

    該用戶從未簽到

    7#
    發表于 2019-5-31 01:11 | 只看該作者
    創意不錯,比較有前途!請加好友2363395579

    該用戶從未簽到

    8#
    發表于 2019-5-31 06:37 來自手機 | 只看該作者
    感謝大神的分享,收獲匪淺!加油!
  • TA的每日心情
    擦汗
    2019-9-15 19:13
  • 簽到天數: 22 天

    [LV.4]偶爾看看III

    9#
     樓主| 發表于 2019-6-13 18:59 | 只看該作者
    寫了文章
    申請了專利
    希望能拿個大獎
  • TA的每日心情
    開心
    2017-10-25 19:33
  • 簽到天數: 1 天

    [LV.1]初來乍到

    10#
    發表于 2019-6-18 17:48 | 只看該作者
    666不錯不錯
    您需要登錄后才可以回帖 登錄 | 立即注冊  

    本版積分規則

    熱門推薦

    【原創】全球最小口袋3D打印機mini one直播教程貼
    【原創】全球最小口袋3D打
    最近閑得蛋疼,沒事搞個掌上3D打印機,先放效果圖吧。 搞了半天,終于能正常打印,
    Blink——Arduino的Hello World!
    Blink——Arduino的Hello
    本教程節選自《Arduino程序設計基礎》 Arduino編程基礎(零)——Blink,Arduino的He
    ATmega2560-16AU刷BootLoader好慢
    ATmega2560-16AU刷BootLoa
    各位朋友,ATmega2560-16AU刷BootLoader好慢,有沒有比較快的辦法,一塊板子要5分鐘左
    【Arduino】108種傳感器模塊系列實驗(104)---MAX30102手腕心率
    【Arduino】108種傳感器模
    37款傳感器與模塊的提法,在網絡上廣泛流傳,其實Arduino能夠兼容的傳感器模塊肯定是
    Arduino MEGA 與UNO 通過nRF24L模塊通訊
    Arduino MEGA 與UNO 通過n
    之前在深水寶很“實惠”的店鋪買了一些原件,隨手砍了esp8266以及nRF24L*3 因為缺
    Copyright   ©2015-2016  Arduino中文社區  Powered by©Discuz!   ( 蜀ICP備14017632號-3 )
    快速回復 返回頂部 返回列表
    六肖六码中特