چگونه اسیلوسکوپ کوچک خود را در خانه بسازیم؟ با استفاده از چند تجهیز و قطعات ساده، این کار آسان است! پس بیایید شروع کنیم:
قطعات مورد نیاز
برای ساخت یک اسیلوسکوپ ساده، به تجهیزات زیر نیاز خواهد بود:
بورد آردوینو نانو R3
ماژول نمایشگر OLED سایز “0.96 با رزولوشن 64×128
پوش باتون 4 پایه کوچک
خازن 100 نانوفاراد (104)
مقاومت های: 100Ω، 12K، 120K، 510K
دیود فست سوئیچ 1N4148
ویدئوی ساخت اسیلوسکوپ کوچک
برای آموزش کاملتر در ساخت اسیلوسکوپ ساده، میتوانید این ویدئو را مشاهده فرمایید.
کاربرد اسیلوسکوپ چیست؟
همانطور که میدانید، با کمک اسیلوسکوپ (با نام قدیمی اسیلوگراف) میتوان تغییر یک سیگنال الکتریکی را در طول زمان را مشاهده کرد. سپس شکل موج را می توان برای خواصی مانند دامنه، فرکانس، زمان افزایش، فاصله زمانی، اعوجاج و موارد دیگر تجزیه و تحلیل کرد. ابزارهای دیجیتال مدرن میتوانند این ویژگی ها را مستقیماً محاسبه و نمایش دهند. پیشتر، محاسبه این مقادیر مستلزم اندازهگیری دستی شکل موج در برابر مقیاسهای تعبیهشده در صفحه دستگاه بود.
حال با استفاده از تجهیزات فوق و شماتیک زیر، ساخت اسیلوسکوپ ساده خود را انجام می دهیم.
شماتیک پروژه
ابتدا فیلم کارکرد پروژه اسیلوسکوپ ساده را مشاهده فرمایید.
توجه: اطمینان حاصل کنید که تمام اتصالات در مدار شما دقیقاً مشابه شکل شماتیک باشد.
کدنویسی C یا ++C برای پروژه اسیلوسکوپ ساده
#include
#include
#include
#include // PROGMEM
#include
#define SCREEN_WIDTH 128 // OLED display width
#define SCREEN_HEIGHT 64 // OLED display height
#define REC_LENGTH 200 //
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
//
const char vRangeName[10][5] PROGMEM = {"A50V", "A 5V", " 50V", " 20V", " 10V", " 5V", " 2V", " 1V", "0.5V", "0.2V"}; // \0
const char * const vstring_table[] PROGMEM = {vRangeName[0], vRangeName[1], vRangeName[2], vRangeName[3], vRangeName[4], vRangeName[5], vRangeName[6], vRangeName[7], vRangeName[8], vRangeName[9]};
const char hRangeName[8][6] PROGMEM = {" 50ms", " 20ms", " 10ms", " 5ms", " 2ms", " 1ms", "500us", "200us"}; // (48
const char * const hstring_table[] PROGMEM = {hRangeName[0], hRangeName[1], hRangeName[2], hRangeName[3], hRangeName[4], hRangeName[5], hRangeName[6], hRangeName[7]};
int waveBuff[REC_LENGTH]; // (RAM)
char chrBuff[10]; //
String hScale = "xxxAs";
String vScale = "xxxx";
float lsb5V = 0.0055549; // 5V0.005371 V/1LSB
float lsb50V = 0.051513; // 50V 0.05371
volatile int vRange; // 0:A50V, 1:A 5V, 2:50V, 3:20V, 4:10V, 5:5V, 6:2V, 7:1V, 8:0.5V
volatile int hRange; // 0:50m, 1:20m, 2:10m, 3:5m, 4;2m, 5:1m, 6:500u, 7;200u
volatile int trigD; // 0:1:
volatile int scopeP; // 0:, 1:, 2:
volatile boolean hold = false; //
volatile boolean paraChanged = false; // true
volatile int saveTimer; // EEPROM
int timeExec; // (ms)
int dataMin; // (min:0)
int dataMax; // (max:1023)
int dataAve; // 10 max:10230)
int rangeMax; //
int rangeMin; //
int rangeMaxDisp; // max100
int rangeMinDisp; // min
int trigP; //
boolean trigSync; //
int att10x; // 1
void setup() {
pinMode(2, INPUT_PULLUP); // (int0
pinMode(8, INPUT_PULLUP); // Select
pinMode(9, INPUT_PULLUP); // Up
pinMode(10, INPUT_PULLUP); // Down
pinMode(11, INPUT_PULLUP); // Hold
pinMode(12, INPUT); // 1/10
pinMode(13, OUTPUT); //
// Serial.begin(115200); // RAM
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3C for 128x64
// Serial.println(F("SSD1306 failed"));
for (;;); // Don't proceed, loop forever
}
loadEEPROM(); // EEPROM
analogReference(INTERNAL); // ADC1.1Vvref)
attachInterrupt(0, pin2IRQ, FALLING); //
startScreen(); //
}
void loop() {
digitalWrite(13, HIGH);
setConditions(); // RAM40
readWave(); // (1.6ms )
digitalWrite(13, LOW); //
dataAnalize(); // (0.4-0.7ms)
writeCommonImage(); // (4.6ms)
plotData(); // (5.4ms+)
dispInf(); // (6.2ms)
display.display(); // (37ms)
saveEEPROM(); // EEPROM
while (hold == true) { // Hold
dispHold();
delay(10);
}
}
void setConditions() { //
// PROGMEM
strcpy_P(chrBuff, (char*)pgm_read_word(&(hstring_table[hRange]))); //
hScale = chrBuff; // hScale
//
strcpy_P(chrBuff, (char*)pgm_read_word(&(vstring_table[vRange]))); //
vScale = chrBuff; // vScale
switch (vRange) { //
case 0: { // Auto50V
// rangeMax = 1023;
// rangeMin = 0;
att10x = 1; //
break;
}
case 1: { // Auto 5V
// rangeMax = 1023;
// rangeMin = 0;
att10x = 0; //
break;
}
case 2: { // 50V
rangeMax = 50 / lsb50V; //
rangeMaxDisp = 5000; // 100
rangeMin = 0;
rangeMinDisp = 0;
att10x = 1; //
break;
}
case 3: { // 20V
rangeMax = 20 / lsb50V; //
rangeMaxDisp = 2000;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 1; //
break;
}
case 4: { // 10V
rangeMax = 10 / lsb50V; //
rangeMaxDisp = 1000;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 1; //
break;
}
case 5: { // 5V
rangeMax = 5 / lsb5V; //
rangeMaxDisp = 500;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0; //
break;
}
case 6: { // 2V
rangeMax = 2 / lsb5V; //
rangeMaxDisp = 200;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0; //
break;
}
case 7: { // 1V
rangeMax = 1 / lsb5V; //
rangeMaxDisp = 100;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0; //
break;
}
case 8: { // 0.5V
rangeMax = 0.5 / lsb5V; //
rangeMaxDisp = 50;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0; //
break;
}
case 9: { // 0.5V
rangeMax = 0.2 / lsb5V; //
rangeMaxDisp = 20;
rangeMin = 0;
rangeMinDisp = 0;
att10x = 0; //
break;
}
}
}
void writeCommonImage() { //
display.clearDisplay(); // (0.4ms)
display.setTextColor(WHITE); //
display.setCursor(86, 0); // Start at top-left corner
display.println(F("av V")); // 1
display.drawFastVLine(26, 9, 55, WHITE); //
display.drawFastVLine(127, 9, 55, WHITE); //
display.drawFastHLine(24, 9, 7, WHITE); // Max
display.drawFastHLine(24, 36, 2, WHITE); //
display.drawFastHLine(24, 63, 7, WHITE); //
display.drawFastHLine(51, 9, 3, WHITE); // Max
display.drawFastHLine(51, 63, 3, WHITE); //
display.drawFastHLine(76, 9, 3, WHITE); // Max
display.drawFastHLine(76, 63, 3, WHITE); //
display.drawFastHLine(101, 9, 3, WHITE); // Max
display.drawFastHLine(101, 63, 3, WHITE); //
display.drawFastHLine(123, 9, 5, WHITE); // Max
display.drawFastHLine(123, 63, 5, WHITE); //
for (int x = 26; x <= 128; x += 5) {
display.drawFastHLine(x, 36, 2, WHITE); // ()
}
for (int x = (127 - 25); x > 30; x -= 25) {
for (int y = 10; y < 63; y += 5) {
display.drawFastVLine(x, y, 2, WHITE); // 3
}
}
}
void readWave() { //
if (att10x == 1) { // 1/10
pinMode(12, OUTPUT); //
digitalWrite(12, LOW); // LOW
} else { //
pinMode(12, INPUT); // Hi-z
}
switch (hRange) { //
case 0: { // 50ms
timeExec = 400 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x07; // 128 (arduino
for (int i = 0; i < REC_LENGTH; i++) { // 200
waveBuff[i] = analogRead(0); // 112s
delayMicroseconds(1888); //
}
break;
}
case 1: { // 20ms
timeExec = 160 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x07; // 128 (arduino
for (int i = 0; i < REC_LENGTH; i++) { // 200
waveBuff[i] = analogRead(0); // 112s
delayMicroseconds(688); //
}
break;
}
case 2: { // 10 ms
timeExec = 80 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x07; // 128 (arduino
for (int i = 0; i < REC_LENGTH; i++) { // 200
waveBuff[i] = analogRead(0); // 112s
delayMicroseconds(288); //
}
break;
}
case 3: { // 5 ms
timeExec = 40 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x07; // 128 (arduino
for (int i = 0; i < REC_LENGTH; i++) { // 200
waveBuff[i] = analogRead(0); // 112s
delayMicroseconds(88); //
}
break;
}
case 4: { // 2 ms
timeExec = 16 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x06; // 64 (0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128)
for (int i = 0; i < REC_LENGTH; i++) { // 200
waveBuff[i] = analogRead(0); // 56s
delayMicroseconds(24); //
}
break;
}
case 5: { // 1 ms
timeExec = 8 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x05; // 16 (0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128)
for (int i = 0; i < REC_LENGTH; i++) { // 200
waveBuff[i] = analogRead(0); // 28s
delayMicroseconds(12); //
}
break;
}
case 6: { // 500us
timeExec = 4 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x04; // 16(0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128)
for (int i = 0; i < REC_LENGTH; i++) { // 200
waveBuff[i] = analogRead(0); // 16s
delayMicroseconds(4); //
// 1.875snop 110.0625s @16MHz)
asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
asm("nop"); asm("nop"); asm("nop");
}
break;
}
case 7: { // 200us
timeExec = 2 + 50; // (ms) EEPROM
ADCSRA = ADCSRA & 0xf8; // 3
ADCSRA = ADCSRA | 0x02; // :4(0x1=2, 0x2=4, 0x3=8, 0x4=16, 0x5=32, 0x6=64, 0x7=128)
for (int i = 0; i < REC_LENGTH; i++) {
waveBuff[i] = analogRead(0); // 6s
// 1.875snop 110.0625s @16MHz)
asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop");
}
break;
}
}
}
void dataAnalize() { //
int d;
long sum = 0;
//
dataMin = 1023; //
dataMax = 0; //
for (int i = 0; i < REC_LENGTH; i++) { //
d = waveBuff[i];
sum = sum + d;
if (d < dataMin) { //
dataMin = d;
}
if (d > dataMax) { //
dataMax = d;
}
}
//
dataAve = (sum + 10) / 20; // 10
// max,min
if (vRange <= 1) { // Auto1
rangeMin = dataMin - 20; // -20
rangeMin = (rangeMin / 10) * 10; // 10
if (rangeMin < 0) {
rangeMin = 0; // 0
}
rangeMax = dataMax + 20; // +20
rangeMax = ((rangeMax / 10) + 1) * 10; // 10
if (rangeMax > 1020) {
rangeMax = 1023; // 10201023
}
if (att10x == 1) { //
rangeMaxDisp = 100 * (rangeMax * lsb50V); // ADC
rangeMinDisp = 100 * (rangeMin * lsb50V); //
} else { //
rangeMaxDisp = 100 * (rangeMax * lsb5V);
rangeMinDisp = 100 * (rangeMin * lsb5V);
}
} else { //
//
}
//
for (trigP = ((REC_LENGTH / 2) - 51); trigP < ((REC_LENGTH / 2) + 50); trigP++) { //
if (trigD == 0) { // 0
if ((waveBuff[trigP - 1] < (dataMax + dataMin) / 2) && (waveBuff[trigP] >= (dataMax + dataMin) / 2)) {
break; //
}
} else { // 0
if ((waveBuff[trigP - 1] > (dataMax + dataMin) / 2) && (waveBuff[trigP] <= (dataMax + dataMin) / 2)) {
break;
} //
}
}
trigSync = true;
if (trigP >= ((REC_LENGTH / 2) + 50)) { //
trigP = (REC_LENGTH / 2);
trigSync = false; // Unsync
}
}
void startScreen() { //
display.clearDisplay();
display.setTextSize(1); // 2
display.setTextColor(WHITE); //
display.setCursor(10, 25); //
display.println(F("PM.GOHARIAN")); //
display.setCursor(10, 45); //
display.println(F("Pen oscope"));
display.display(); //
delay(5000);
display.clearDisplay();
display.setTextSize(1); //
}
void dispHold() { // Hold
display.fillRect(32, 12, 24, 8, BLACK); // 4
display.setCursor(32, 12);
display.print(F("Hold")); // Hold
display.display(); //
}
void dispInf() { //
float voltage;
//
display.setCursor(2, 0); //
display.print(vScale); //
if (scopeP == 0) { //
display.drawFastHLine(0, 7, 27, WHITE); //
display.drawFastVLine(0, 5, 2, WHITE);
display.drawFastVLine(26, 5, 2, WHITE);
}
//
display.setCursor(34, 0); //
display.print(hScale); // (time/div)
if (scopeP == 1) { //
display.drawFastHLine(32, 7, 33, WHITE); //
display.drawFastVLine(32, 5, 2, WHITE);
display.drawFastVLine(64, 5, 2, WHITE);
}
//
display.setCursor(75, 0); //
if (trigD == 0) {
display.print(char(0x18)); //
} else {
display.print(char(0x19)); //
}
if (scopeP == 2) { //
display.drawFastHLine(71, 7, 13, WHITE); //
display.drawFastVLine(71, 5, 2, WHITE);
display.drawFastVLine(83, 5, 2, WHITE);
}
//
if (att10x == 1) { // 10
voltage = dataAve * lsb50V / 10.0; // 50V
} else {
voltage = dataAve * lsb5V / 10.0; // 5V
}
dtostrf(voltage, 4, 2, chrBuff); // x.xx
display.setCursor(98, 0); //
display.print(chrBuff); //
// display.print(saveTimer); //
//
voltage = rangeMaxDisp / 100.0; // Max
if (vRange == 1 || vRange > 4) { // 5VAuto5V
dtostrf(voltage, 4, 2, chrBuff); // *.**
} else { //
dtostrf(voltage, 4, 1, chrBuff); // **.*
}
display.setCursor(0, 9);
display.print(chrBuff); // Max
voltage = (rangeMaxDisp + rangeMinDisp) / 200.0; //
if (vRange == 1 || vRange > 4) { // 5VAuto5V
dtostrf(voltage, 4, 2, chrBuff); // 2
} else { //
dtostrf(voltage, 4, 1, chrBuff); // 1
}
display.setCursor(0, 33);
display.print(chrBuff); //
voltage = rangeMinDisp / 100.0; // Min
if (vRange == 1 || vRange > 4) { // 5VAuto5V
dtostrf(voltage, 4, 2, chrBuff); // 2
} else {
dtostrf(voltage, 4, 1, chrBuff); // 1
}
display.setCursor(0, 57);
display.print(chrBuff); // Min
//
if (trigSync == false) { //
display.setCursor(60, 55); //
display.print(F("Unsync")); // Unsync
}
}
void plotData() { //
long y1, y2;
for (int x = 0; x <= 98; x++) {
y1 = map(waveBuff[x + trigP - 50], rangeMin, rangeMax, 63, 9); //
y1 = constrain(y1, 9, 63); //
y2 = map(waveBuff[x + trigP - 49], rangeMin, rangeMax, 63, 9); //
y2 = constrain(y2, 9, 63); //
display.drawLine(x + 27, y1, x + 28, y2, WHITE); //
}
}
void saveEEPROM() { // EEPROM
if (paraChanged == true) { //
saveTimer = saveTimer - timeExec; //
if (saveTimer < 0) { //
paraChanged = false; //
EEPROM.write(0, vRange); //
EEPROM.write(1, hRange);
EEPROM.write(2, trigD);
EEPROM.write(3, scopeP);
}
}
}
void loadEEPROM() { // EEPROM
int x;
x = EEPROM.read(0); // vRange
if ((x < 0) || (x > 9)) { // 0-9
x = 3; //
}
vRange = x;
x = EEPROM.read(1); // hRange
if ((x < 0) || (x > 7)) { // 0-9
x = 3; //
}
hRange = x;
x = EEPROM.read(2); // trigD
if ((x < 0) || (x > 1)) { // 0-9
x = 1; //
}
trigD = x;
x = EEPROM.read(3); // scopeP
if ((x < 0) || (x > 2)) { // 0-9
x = 1; //
}
scopeP = x;
}
void pin2IRQ() { // Pin2(int0)
//pin8,9,10,11Pin2
//
int x; //
x = PINB; // B
if ( (x & 0x07) != 0x07) { // 3High
saveTimer = 5000; // EEPROM(ms
paraChanged = true; // ON
}
if ((x & 0x01) == 0) {
scopeP++;
if (scopeP > 2) {
scopeP = 0;
}
}
if ((x & 0x02) == 0) { // UP
if (scopeP == 0) { //
vRange++;
if (vRange > 9) {
vRange = 9;
}
}
if (scopeP == 1) { //
hRange++;
if (hRange > 7) {
hRange = 7;
}
}
if (scopeP == 2) { //
trigD = 0; //
}
}
if ((x & 0x04) == 0) { // DOWN
if (scopeP == 0) { //
vRange--;
if (vRange < 0) {
vRange = 0;
}
}
if (scopeP == 1) { //
hRange--;
if (hRange < 0) {
hRange = 0;
}
}
if (scopeP == 2) { //
trigD = 1; //
}
}
if ((x & 0x08) == 0) { // HOLD
hold = ! hold; //
}
}
سوال مهم
سوال:
نتایج اندازهگیری توسط اسیلوسکوپ سادۀ من، چقدر قابل اطمینان است؟
پاسخ:
ما به نتایج قابل اعتماد نیاز داریم، یعنی باید عدم قطعیت اندازهگیری اسیلوسکوپ در محدودۀ مجاز استاندارد باشد، اما متاسفانه با توجه به اجزای مدار اسیلوسکوپ سادۀ شما و دریفتهایی که در طول زمان ممکن است رخ دهد، این نتایج چندان قابل اتکا نخواهند بود.
از طرفی، میدانیم که عدم قطعیت اندازهگیری به عوامل مختلف از جمله Accuracy تجهیزات بستگی دارد که توسط سازنده، تعیین و اعلام میشود. (برای مشاهدۀ همه فاکتورهای عدم قطعیت، به مدرک ILAC G24 / OIML D10 مراجعه کنید)
راهکار حل این مشکل، استفاده از اسیلوسکوپهایی است که Accuracy آنها توسط سازنده، تعیین و اعلام شده باشد.
نکته:
کالیبراسیون هرگونه وسیله اندازهگیری طی تواترهای مشخص، شما را به نتایج قطعی نزدیکتر میکند.
شما میتوانید در خرید اسیلوسکوپ، محصولات ما را در نظر بگیرید که accuracy مناسب، کیفیت عالی، قیمت مناسب و پشتیبانی و گارانتی ما را به همراه دارد.
شما می توانید در با کارشناسان ما در رابطه با خرید اسیلوسکوپ مناسب مشورت کنید
پس در تصمیم گیری و انتخاب مدل مناسب زمان را از دست ندهید