一千萬個為什麽

搜索

使用Arduino Uno從外部設備捕獲輸出

我無法在任何地方找到這個問題,但我想使用我的Arduino Uno來捕獲來自單獨設備的Code 39信號的輸出。目前,我的設置類似於:

enter image description here

我有一個輸出Code 39信號的生物識別手持式閱讀器沿著D1,而D0保持在常數0,這可以在這裏看到:

enter image description here

最後,我想使用Arduino Uno從數據線獲取輸入並將Code 39信號轉換為ASCII。該過程應該像這樣:

  1. User enters their code into the hand reader and hand reader measures their hand
  2. Reader outputs Code 39 signal to Arduino and software on Arduino converts barcode format to ASCII.
    • Note: I believe the Code 39 signal will represent something similar to this *12345*. The user ID code will always be five digits. * represent the start and stop characters for Code 39 barcode format
  3. Arduino sends ASCII code to computer which checks remote database to ensure user is valid

我的正確引腳設置如下:

#include 
#define D1 3
#define D0 2

void setup() {
    pinMode(D1, INPUT);
    pinMode(D0, INPUT);
}

Is it possible to either print out the binary representation of the signal via the Serial console or write to a file that I can view later on? My idea is to use the loop function to listen for the signals via digitalRead()

void loop() {
    digitalRead(D1);
    digitalRead(D0);
}

最後一部分是我遇到問題,因為我似乎無法將信息打印到串行控制臺或寫入文件。我嘗試了這個,但它不起作用:

void loop() {
    foo();
}

void foo() {
    digitalRead(D1) == HIGH ? Serial.print("0") : Serial.print("1");
    Serial.println("");
    digitalRead(D0) == HIGH ? Serial.print("0") : Serial.print("1");
}

關於如何實現這一點的任何想法或者是不可能的?我想看看設備的輸出,所以我可以驗證它輸出我認為它是什麽。

最後,我使用Visual Studio與Visual Micro插件,所以我可以嘗試調試我的代碼。我還有一臺OS X機器上安裝了Arduino IDE,如果我需要Mac的話。

Addendum: I don't have ready access to an oscilloscope. However, I have tested this device on an oscilloscope and I did have output that seemed all wrong. I want to see what the arduino says it is to verify things before I continue with this project.

最佳答案

首先,讓我們找到你的方法有什麽問題。您嘗試連續輪詢信號引腳並將其寫入串行。默認串行速率為9600.這意味著,您可以傳輸約。每秒900個字符。看一下你的波形圖我們可以看出,你要分析的信號的基本時鐘大約為2.5 kHz。這意味著您絕對無法使用您的方法對每個級別的更改進行采樣。

實際上,當您提高串行波特率時,可以使用 loop()函數來監聽更改,即輪詢信號。但我建議使用中斷。

我的建議是一個三步過程。

  1. 使用有關信號的所有相關信息徹底記錄信號。這包括通過串行接口傳輸到PC。
  2. 離線分析信號。即在電腦上收到後
  3. 調整您的arduino代碼,然後再將其解碼,然後再將其傳輸到您的PC

讓我們來到第1部分: 閱讀有關中斷的Arduino文檔 中斷允許您防止兩個任務的幹擾(讀取輸入和寫入串行)。 有趣的信息是什麽?我認為這是波形(即您可以提供的最佳分辨率的信號)。您可以高速采樣波形,但結果數據量將超過串行輸出。幸運的是,你的信號有一些明顯的特征。哪個是:

  • 服從一些時間(即時鐘)
  • 具有有限的傳輸長度(協議幀)
  • 具有有限的傳輸速率(從示波器中可以看出)

通過減少串行傳輸量來保持盡可能多的信號信息的最佳方法是記錄每個級別變化的時間。

更新:緩沖區使用,接收超時後緩沖輸出

#define RECVTIMEOUT 2000//we think, more than 2000 usec is end of transmission
#define MAXEVENTS 100    

uint8_t inpin=2;
volatile unsigned long timestart=0;
uint8_t transmitLevel=LOW;

volatile uint8_t state=0;//little state machine: 0=nothing happened yet, 1=receiving data, 2=receiving timeout
volatile uint16_t tstamps[MAXEVENTS];//we store timestamps of received symbols here
volatile uint16_t levels[MAXEVENTS];//we store levels of received symbols here
volatile uint8_t index=0;//we save index of data here.
uint8_t count=0;//counter for later use.

volatile bool conflict=false;//will be set, if transmission conflicts with receive function.

void pinchange()//the ISR (interrupt service routine)
{
    switch(state)
    {
    case 0:       
       timestart=micros();
       tstamps[index]=0;
       levels[index]=digitalRead(inpin);
       state=1;
       ++index;
    break;
    case 1:
       tstamps[index]=micros()-timestart;
       levels[index]=digitalRead(inpin);
       ++index;
    break;
    case 2:
       conflict=true;
    }
}

void setup()
{
    Serial.begin(115200);//high serial rate. don't forget to set the same in your IDE
    attachInterrupt(0, &pinchange, CHANGE);//the controller needs to know, where your ISR is.
}

void loop()
{
    switch(state)
    {
    case 1:
       if (index > 20)
       {
          if (micros()-timestart > RECVTIMEOUT)
          {
             state=2;
          }
       }
       if (index >= MAXEVENTS)
       {
          state=2;
       }

    break;
    case 2:   
       for (count=0; count

這應該輸出一個精細的csv,其中包含所有信號邊緣,以微秒為單位,您可以將其直接粘貼到您喜歡的電子表格應用程序中。這僅適用於一個信號。要分析兩者,您必須相應地進行增強。

更新1

第2部分)

來自我們之前的代碼版本的獲得數據(簡潔代碼段)

time signal timedifference
2614592 0   468
2615056 1   464
2615524 0   468
2616496 0   972
2616960 1   464
2617956 0   996
2618960 1   1004
2620424 1   1464
2621352 1   928
2622324 1   972
2623320 0   996

我們可以看到兩件事。

  1. 我的第一個版本的答案中的代碼無法正常運行。每1應在第2列後跟0,反之亦然。這顯然是不正確的,這導致了我們錯過了一些事件的結論。
  2. 時間差異似乎是大約470μs的倍數。我們可以將其視為符號的長度。

那麽代碼有什麽問題呢?我使用noInterrupts()來中斷復制數據的中斷。我希望,在這麽短的時間內不會有水平變化,但顯然這不是真的。怎麽解決?我們最好找到另一種註冊事件並傳輸它們的方法。 我建議堅持中斷技術,但改變我們存儲事件並將其讀出的方式。讓我們使用足夠大的緩沖區來傳輸所有事件。在傳輸之後,我們可以通過串口將所有數據無故障地發送到PC。

我們能期待什麽? 0和1應交替傳輸,時間合理。如果我們可以證明這一點,我們可以再次更改主循環以解碼代碼39。

第3部分)

  • 編寫將代碼字39存儲在緩沖區中的代碼
  • 另一個代碼,當緩沖區已滿時將該字解碼為一個字節
  • 通過串行傳輸該字節

(可能有很多改進)。

轉載註明原文: 使用Arduino Uno從外部設備捕獲輸出