# Máy, thiết bị và sản phẩm khác > Điện - Điện tử - Tự động hóa > Arduino >  Arduino - Máy hiện sóng đơn giản - XOscillo

## CKD

Với bo mạch Arduino UNO đơn giản, chúng ta có thể ứng dụng và biến nó thành một thiết bị hổ trợ đo đạt và phân tích. Hổ trợ rất nhiều trong công cuộc nghiên cứu.. ngâm và cứu được  :Wink: .

CKD giới thiệu dự án mở (open source) *XOscillo* cho các bạn thích tìm tòi nghiên cứu với chi phí rất thấp  :Embarrassment: .

Với chi phí khoảng dưới 200K (board Arduino khoảng 150K và vài linh kiện điện tử khác khoảng dưới 50K) hoặc có thể ít hơn nếu tận dụng các board Arduino có sẵn cũng như các linh kiện tận dụng. Bằng cách kết hợp máy tính với Arduino, chúng ta có thể chế tạo được thiết bị do và phân tích tích hiệu như "*Máy hiện sóng*" (oscilloscope) hay máy phân tích logic (logic analyzer).

Link gốc XOscillo - A software oscilloscope that acquires data using an arduino or a parallax (more platforms to come).
Các bạn có thể tìm hiểu thêm nhiều thông tin liên quan với *link trên*

Vài hình ảnh:
- XOscillo phân tích tín hiệu tương tự (analog)


- XOscillo phân tích tín hiệu số (digital/logic analyzer)









- Tần số max: 7kHz.
- Số kênh analog: 4 kênh (tần số lấy mẫu khi này là 7/4 kHz).
- Độ phân giải (tạo sóng) 8bit (256)
- Độ phân giải ADC 10bit (1024)
- Ngưỡng đo: 0-5V
- Trigger trên kênh 0.

_Do Arduino giới hạn về tốc độ làm việc, tốc độ truyền do đó.. các dự án phát triển trên nền arduino đều bị giới hạn này. XOscillo cũng không ngoại lệ, tần số lấy mẫu khá thấp._



```
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

//
// pins assignment
//
#define BUILTINLED 13
#define PWM_GENERATOR 11
#define ledPin 13    // LED connected to digital pin 13

//
// globals
//
unsigned char triggerVoltage = 0;
unsigned char lastADC = 0;
unsigned char triggered = 0;
unsigned int DataRemaining = 1500;
unsigned char channel=0;
unsigned char numChannels=1;
unsigned char channels[4];

//
// Commands
//
#define CMD_IDLE 0
#define CMD_RESET 175
#define CMD_PING '?'
#define CMD_READ_ADC_TRACE 170
#define CMD_READ_BIN_TRACE 171

void StartAnalogRead(uint8_t pin)
{
        // set the analog reference (high two bits of ADMUX) and select the
        // channel (low 4 bits).  this also sets ADLAR (left-adjust result)
        // to 0 (the default).
        ADMUX = (DEFAULT << 6) | (pin & 0x07);
        ADMUX |= _BV(ADLAR);  
        
#if defined(__AVR_ATmega1280__)
        // the MUX5 bit of ADCSRB selects whether we're reading from channels
        // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high).
        ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
        // without a delay, we seem to read from the wrong channel
        //delay(1);

        // start the conversion
        sbi(ADCSRA, ADSC);
}

uint8_t EndAnalogRead()
{
        uint8_t low, high;

  // ADSC is cleared when the conversion finishes
  while (bit_is_set(ADCSRA, ADSC));

  // we have to read ADCL first; doing so locks both ADCL
  // and ADCH until ADCH is read.  reading ADCL second would
  // cause the results of each conversion to be discarded,
  // as ADCL and ADCH would be locked when it completed.
  uint8_t result = ADCH;
  
  return result;
}


void setup() 
{
  // set prescale to 16
  sbi(ADCSRA,ADPS2) ;
  cbi(ADCSRA,ADPS1) ;
  cbi(ADCSRA,ADPS0) ;

  pinMode( PWM_GENERATOR, OUTPUT );
  analogWrite(PWM_GENERATOR, 128);

  pinMode( 4, OUTPUT );
  pinMode( 5, OUTPUT );
  digitalWrite(4, HIGH);    
  digitalWrite(5, LOW);    
  
  //Serial.begin(115200);
  Serial.begin(1000000);  
  for(int i=2;i<8;i++)
  {
    pinMode(i, INPUT);      // sets the digital pin 7 as input
    digitalWrite(i, LOW);    
  }

  
//  Serial.begin(1000000);
//  Serial.begin(153600);
//  Serial.begin(9600);  
}

unsigned char command = 0;

void ProcessSerialCommand( byte in )
{
  if ( in == CMD_PING )
  {
    Serial.write( 79 ) ;
    Serial.write( 67 ) ;
    Serial.write( triggerVoltage ) ;
    Serial.write( DataRemaining>>8 ) ;
    Serial.write( DataRemaining&0xff ) ;
    for (int i=0;i<2;i++)
    {
      Serial.write( triggerVoltage ) ;
    }
  } 
  else if ( in == CMD_RESET ) 
  {
    command = CMD_IDLE;
    Serial.write( "OK" ) ;    
    digitalWrite(ledPin, LOW);
  } 
  else if ( in == CMD_READ_ADC_TRACE )
  {
    while( Serial.available() < 9);

    triggerVoltage = Serial.read();
    DataRemaining = Serial.read()<<8;
    DataRemaining |= Serial.read();
 
    numChannels = Serial.read();
    for (int i=0;i<4;i++)
    {
      channels[i] = Serial.read();
    }
 
    analogWrite(PWM_GENERATOR, Serial.read());
    
    Serial.write( 85 );
  
    triggered = 0;     
    
    //get a fresher value for lastADC
    channel = 0;
    StartAnalogRead(channels[channel]);
    lastADC = EndAnalogRead();    

    digitalWrite(ledPin, HIGH);
    command = CMD_READ_ADC_TRACE;
  }
  else if ( in == CMD_READ_BIN_TRACE )
  {
    while( Serial.available() < 3);
    triggerVoltage = Serial.read();
    DataRemaining = Serial.read()<<8;
    DataRemaining |= Serial.read();

    analogWrite(9, 64);
    analogWrite(10, 128);
    analogWrite(11, 192);
    
    triggered = 0;     
    digitalWrite(ledPin, HIGH);
    command = CMD_READ_BIN_TRACE;
    Serial.write( 85 );
  }
}

void loop() 
{
  if (Serial.available() > 0) 
  {
    ProcessSerialCommand( Serial.read() );
  }
  
  if ( command == CMD_READ_ADC_TRACE )
  {
    unsigned char v = EndAnalogRead();      
    
    if ( triggered == 0  )
    {
      if ( ((v >= triggerVoltage) && ( lastADC < triggerVoltage )) || (triggerVoltage == 0) )
      {
        triggered = 1;
        digitalWrite(ledPin, LOW);
      }
      else
      {
        lastADC = v;        
        StartAnalogRead(channels[channel]);  
        return;
      }
    }
      
    channel++;   
    if ( channel == numChannels )
    {
      channel=0;
      
      DataRemaining--;
      if ( DataRemaining == 0 )
      {
        command = CMD_IDLE;
      }
    }    
    
    Serial.write(v);      
    StartAnalogRead(channels[channel]);  
  }
  else if ( command == CMD_READ_BIN_TRACE )
  {
    unsigned char v = PIND>>2;  // remove tx/rx lines

    Serial.write(v);

    DataRemaining--;
    if ( DataRemaining == 0 )
    {
      command = CMD_IDLE;
    }
  }

}
```

Tham khảo thêm giải pháp đo & phân tích dữ liệu khác:
- http://forum.cncprovn.com/threads/31...en-cuu-tai-gia

----------

anhcos, CBNN

----------


## nhatson

báo cáo, 8 bit là 256, 10 bit mới đúng ah

b.r

----------


## CKD

> báo cáo, 8 bit là 256, 10 bit mới đúng ah


So ri  :Wink:  viết vừa thiếu vừa sai.

Lưu ý:
- Phần code trên để tăng tốc độ làm việc của Arduino, tác giả đã định nghĩa lại một số hàm trên Arduino, lồng ghép thêm lệnh C v.v...
- Tác giả cũng đã định nghĩa lại các bộ ADC
- Tốc độ truyền serial được thiết lập là 1Mbs (mặc định max là 115200bs).

----------


## CBNN

> báo cáo, 8 bit là 256, 10 bit mới đúng ah
> 
> b.r


bẩu bác đúng đấy ợ ! :Embarrassment:

----------


## CKD

Ngoài ra.. Để tiết kiệm thời gian trong việc truyền dữ liệu, tác giả đã
- Chỉ dùng 8bit ADC thay vì 10bit như mặc định ở mỗi ADC.
- Định hệ số xung nhip, để có thể lấy mẫu ở tần số khoảng 72kHz, hoặc 40kHz, do chưa phân tích code kỹ  :Smile:  cũng chưa thực nghiệm. Mới vơ trên google liền cho vào đây  :Embarrassment:

----------


## thehiena2

Loại ni đáp ứng được cho máy in 3D chứ nhi`? làm con máy in đi các bác.

----------


## mayboy008

đáp ứng máy in 3d là sao bác?

----------

