Đã được đăng vào 02/12/2020 @ 09:31
Đo cuộn cảm và tần số cộng hưởng mạch LC bằng Arduino
Cách đo giá trị của cuộn cảm hoặc đo tần số cộng hưởng của mạch điện LC bằng arduino là giải pháp hiệu quả, an toàn, tiết kiệm, dễ dàng và nhanh chóng dành cho học sinh, sinh viên cũng như các bạn yêu thích việc nghiên cứu, thiết kế và phân tích mạch điện tử là nội dung chính của bài viết này.
ngochoangimsat
Xem thêm:
1. Tổng quan
Hiện nay có nhiều cách để đo giá trị của cuộn cảm như: dùng máy hiện sóng, dùng đồng hồ đo điện cảm,…
Tuy nhiên các thiết bị chuyên dụng nêu trên đều có giá khá đắt trong khi nhu cầu sử dụng đối với các bạn không chuyên lại không nhiều
Đặc biệt là học sinh và sinh viên với ngân sách đầu tư thiết bị còn hạn chế trong khi một mạch arduino có giá thành khoảng dưới 100K chúng ta hoàn toàn có thể biến nó thành hầu hết các loại dụng cụ đo đạc hiện nay như: dòng điện, điện áp, tụ điện, cuộn cảm, điện trở (như một đồng hồ vạn năng thực thụ).
Trong loạt bài viết của mình, tôi sẽ dần dần giới thiệu từng phần với đầy đủ sơ đồ mạch điện, nguyên lý hoạt động, thuật toán và mã nguồn nạp vào arduino
Các bạn vừa có thể sử dụng được luôn (đối với những bạn chỉ muốn có sẵn) vừa có thể tự phát triển thêm nhằm đáp ứng nhu cầu của riêng mình (với những bạn có lòng đam mê và nhiệt huyết).
Bài viết đầu tiên của tôi trong loạt bài “Tự làm các dụng cụ đo đạc điện tử bằng Arduino” là bài viết về “Cách đo cuộn cảm và đo tần số cộng hưởng của mạch LC bằng arduino”.
Tôi đã xác minh rằng phương pháp này cho kết quả chính xác trong phạm vi từ 80µH đến 30.000µH
Nhưng nó sẽ hoạt động đối với các cuộn cảm nhỏ hơn một chút hoặc lớn hơn nhiều
Thậm chí tôi đã đo cuộn cảm có giá trị nhỏ tới 10µH với sai số không đáng kể
Điều mà nhiều chiếc đồng hồ có giá tầm vài triệu đổ lại cũng khó mà đo được.
Có một số trường hợp cần lưu ý khi đo cuộn cảm – tìm hiểu thêm về điều này trong phần “Các lưu ý khác”.
2. Những thứ cần có
Để đo đạc sử dụng arduino thì thứ cần có đầu tiên là một mạch Arduino
Theo tôi đề xuất thì các bạn nên mua mạch Arduino Nano vì giá rẻ, mạch siêu nhỏ gọn.
Ngoài arduino các bạn hoàn toàn có thể mua các loại chíp vi xử lý khác để lập trình nếu muốn
Tuy nhiên arduino là nhanh gọn nhẹ nhất vì mọi thứ đã sẵn sàng chỉ chờ bạn nạp code là chạy mà không phái mất công đi làm mạch điện.
Ngoài một bo mạch Arduino thì có vài thành phần mà bạn có thể phải mua (tùy các bạn đã có gì)
Nhưng chúng cơ bản đều có thể được mua tại hầu hết các cửa hàng điện tử như:
1 chiếc IC LM399, 1 điện trở 150 ôm, 1 điện trở 330 ôm, 1 đi ốt 1N4001 và hai tụ điện không phân cực 1uF.
3. Nguyên lý hoạt động
Một cuộn cảm mắc song song với một tụ điện được gọi là mạch LC
Khi cấp một xung khởi đầu cho nó thì nó sẽ dao động.
Tần số giao động này sẽ không thay đổi dù biên độ có bị tắt dần hay không.
Ban đầu chúng ta sẽ cấp nguồn cho mạch LC, đợi một chút để mạch cộng hưởng ổn định, sau đó tiến hành đo.
Với mạch lý tưởng, nội trở trong mạch bằng 0 thì giao động này sẽ là vĩnh cửu, tuy nhiên thực tế luôn có một điện trở dù rất thấp chứa trong dây dẫn
Trong cuộn cảm và trong chính vật liệu làm chân linh kiện nên đây thực sự là một mạch RLC do vậy dao động trong mạch sẽ tắt dần
Vì biên độ bị suy hao vào điện trở sau mỗi chu kỳ dao động (xem hình 3)
Tôi sẽ nói về điều này nhiều hơn trong phần thuật toán.
Ngày nay các chíp vi điều khiển khá đa dạng và có năng lực xử lý cũng khác nhau nhiều nhưng nhìn chung là chúng còn khá yếu trong việc phân tích các tín hiệu tương tự.
Các bộ chuyển đổi tương tự -> số (ADC) trên chíp ATMEGA328P có khả năng lấy mẫu tín hiệu analog ở tần số 9600hz hoặc chu kỳ 0.1ms
Đó là khá nhanh đối với nhiều nhu cầu khác nhưng không có nghĩa lý gì so với đòi hỏi của dự án này.
Vì thế, hãy sử dụng một con chip được thiết kế đặc biệt để chuyển tín hiệu thế giới thực thành tín hiệu kỹ thuật số cơ bản
Chính là bộ so sánh LM339 con chíp này có chức năng gần tương tự con chíp LM741 huyền thoại trong các sách kỹ thuật điện tử hay lấy làm ví dụ mà nhà trường vẫn đem ra dạy chúng ta.
LM339 có ưu điểm là chuyển đổi nhanh hơn so với LM741 (xem hình 4 về so sánh về sườn dốc khi chuyển mức tín hiệu sóng vuông giữa LM741 và LM339)
Trong bài viết này cũng sẽ có một sơ đồ cho LM741.
Với các IC thuật toán này, ngay khi điện áp trên mạch LC trở nên dương (sóng SIN đầu vào của mạch chuyển đổi sang nửa chu kỳ dương) thì đầu ra của LM339 sẽ được thả nổi, có thể được kéo lên mức cao bằng một điện trở kéo lên.
Khi điện áp trên mạch LC chuyển sang nửa chu kỳ âm của hình sin, LM339 sẽ kéo đầu ra của nó xuống mát.
Tôi nhận thấy rằng LM339 có điện dung ký sinh cao trên đầu ra của nó, đó là lý do tại sao tôi sử dụng điện trở thấp (330 ôm) để kéo lên.
4. Thuật toán
Về mặt lý thuyết, sóng điện trong mạch cộng hưởng LC là sóng hình sin thực sự nên nó dành thời gian bằng nhau trên 0 vôn và dưới 0 vôn.
Điều này có nghĩa là bộ so sánh sẽ biến nó thành một sóng vuông với độ rộng là 50% của thời gian chu kỳ
Lệnh pulseIn(pin, HIGH) trong code arduino sẽ đo thời gian tính bằng micro giây trôi qua từ cạnh lên đến cạnh xuống.
Sau đó, số đo này có thể được nhân đôi để lấy chu kỳ và nghịch đảo của chu kỳ là tần số.
Vì mạch đang có cộng hưởng nên tần số này là tần số cộng hưởng.
Tuy nhiên, theo quan sát thực tế của tôi trên máy hiện sóng thì hiện tượng hai nửa chu kỳ của sóng sin có thể không đối xứng qua mức 0V xảy ra trong nhiều thử nghiệm
Nghĩa là độ rộng của sóng vuông ở nửa chu kỳ dương có thể khác (rộng hoặc hẹp hơn) độ rộng của sóng vuông ở nửa chu kỳ âm nhưng tổng thời gian chu kỳ thì luôn luôn đúng và bằng nhau.
Điều này hoàn toàn có thể khắc phục nhờ việc điều chỉnh cách lấy thời gian một chu kỳ trong mã nguồn lập trình
Theo đó thay vì lấy độ rộng xung của nửa chu kỳ sau đó nhân 2 lần thì chúng ta sẽ tiến hành đo làm hai lần
Lần 1 lấy độ rộng xung của nửa chu kỳ dương (cạnh lên) bằng lệnh T1 = pulseIn(pin, HIGH)
Lần 2 ta lấy độ rộng xung của nửa chu kỳ âm bằng lệnh T2 = pulseIn(pin, LOW).
Tổng chu kỳ sẽ là T = T1 + T2. Tần số F = 1/T.
Ở bên dưới đây là các phương trình tính toán
Trong đó:
f là tần số cộng hưởng
c là điện dung
L là độ tự cảm.
Giải cho độ tự cảm sẽ dẫn đến phương trình cuối cùng.
Do cần tìm giá trị của cuộn cảm nên tụ điện ta chọn trước
Với sơ đồ mạch của chúng ta tụ điện gồm hai con 1uF mắc song song nên tổng dung lượng của tụ điện là 2uF.
Tụ điện chọn là loại film (tụ vàng) có sai số 5%, sai số này sẽ ảnh hưởng đến kết quả đo
Do vậy khi làm xong cần căn chỉnh lại code để đạt độ chính xác.
Trong thực tế thì mạch LC sẽ là mạch RLC nhưng nội trở sẽ không làm thay đổi bất kỳ đặc điểm nào của tần số cộng hưởng.
Mạch RLC vẫn sẽ cộng hưởng, nhưng biên độ sẽ tắt dần thay vì ổn định mãi mãi như mạch lý tưởng.
Với điện trở thấp, RLC sẽ có xu hướng ổn định tần số cộng hưởng nhanh hơn.
5. Mạch điện
Có hai sơ đồ mạch điện được đưa ra ở đây, chọn mạch nào là do bạn nhưng mạch sử dụng LM339 tốt hơn.
Cả hai tụ điện tôi chọn đều là loại tụ màng kim loại 1uf, nhưng bất loại tụ nào không phân cực đều sẽ hoạt động.
Tuy nhiên, nó sẽ cần rất gần với 2 uF.
Bạn không thể sử dụng các loại tụ điện phân cực (tụ có đánh dấu chân + và chân -).
Một điều bạn có thể nhận thấy là LM741 được thiết kế cho tính toán tương tự.
Điều này có nghĩa là nó yêu cầu một điện áp âm trên chân V- của nó.
Nếu bạn không có nguồn điện phân cực để cung cấp, hãy sử dụng hai pin AA để nối đất 3v như hình minh họa.
LM339 không cần điều này và không có vấn đề gì khi nhập điện áp âm.
Hãy nhớ rằng mạch LC có điện áp thay đổi giữa hai nửa chu kỳ đối xứng qua chân mát.
Unknow uH: là cuộn cảm chưa biết giá trị chúng ta cần đo;
Arduino out: là một chân ra của Arduino;
Arduino in pulseIn(): là một chân đầu vào của Arduino.
10uH: là ví dụ một cuộn cảm chưa biết giá trị chúng ta cần đo;
Arduino out là một chân ra của Arduino;
Arduino in pulseIn(): là một chân đầu vào của arduino;
Cuối cùng ta kết nối phần mạch bên trên với arduino như hình 8.
Trong đó chân D13 của arduino kết nối đến mạch giao động LC (nơi có cuộn cảm cần đo)
Chân A0 kết nối đến đầu ra của IC LM339.
Mở rộng vấn đề:
Nếu các bạn có một mạch điện LC và muốn đo tần số cộng hưởng của mạch đó chỉ cần bỏ hai con tụ ra khỏi mạch và đưa mạch LC vào vị trí này
Tần số cộng hưởng của mạch sẽ hiển thị ở đầu ra.
Chúng ra dễ dàng xem xét được mạch thiết kế cộng hưởng LC đã đạt tần số cộng hưởng hay chưa
Nếu chưa có thể điều chỉnh cuộn cảm hoặc tụ (thường các mạch cộng hưởng dùng cảm kháng hoặc tụ có vít chỉnh giá trị) để đạt yêu cầu thiết kế.
Hạn chế của mạch là khả năng đo đạc của vi điều khiển Atmega328 không đo được các tần số cộng hưởng quá cao khi mà chu kỳ xung chỉ còn vài uS.
5. Mã nguồn nạp vào Arduino
5.1. Mã nguồn căn bản để dễ hiểu
Mã nguồn này là khái niệm căn bản nhất để các bạn dễ hiểu vấn đề
Nó có những nhược điểm về sai số và tính tự động chọn dải đo là không có.
Các bạn muốn nhiều hơn hãy tham khảo mục 5.2. Mã nguồn nâng cao để biết thêm chi tiết:
double pulse, frequency, capacitance, inductance; void setup() { Serial.begin(115200); pinMode(A0, INPUT); pinMode(13, OUTPUT); Serial.println("Đo cuộn cảm!"); delay(200); } void loop() { digitalWrite(13, HIGH); delay(5);// digitalWrite(13, LOW); delayMicroseconds(100); pulse = pulseIn(11, HIGH, 5000); if (pulse > 0.1) { capacitance = 2.E-6; //Thay đổi giá trị tụ điện, giá trị theo thiết kế này là 2uF frequency = 1.E6 / (2 * pulse); inductance = 1. / (capacitance * frequency * frequency * 4.*3.14159 * 3.14159); inductance *= 1E6; Serial.print("Nửa chu kỳ uS:"); Serial.print( pulse ); Serial.print("\tTần số Hz:"); Serial.print( frequency ); Serial.print("\tĐiện cảm uH:"); Serial.println( inductance ); delay(20); } }
5.2. Mã nguồn nâng cao
Mã nguồn dưới đây hỗ trợ đồng thời cả hiển thị trên màn hình Serial của Arduino IDE
Hiển thị cả trên màn hình LCD 16×2 nếu các bạn có gắn theo sơ đồ.
Tự động thay đổi dải tầm đo và hiển thị đơn vị đo tùy thuộc vào cuộn cảm.
Mỗi giá trị đo đều được đo nhiều lần và lấy giá trị trung bình để giảm sai số đo.
#include <LiquidCrystal.h> #define input_pin A0 //Chân đọc xung vuông #define output_pin 13 //Chân xuất xung vuông const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2; LiquidCrystal lcd(rs, en, d4, d5, d6, d7); unsigned long delayforchange = 300; unsigned long delayforstable = 10; unsigned long timeout = 5000; String t_unit = "uS"; String l_unit = "uH"; String f_unit = " Hz"; unsigned int chu_ky = 0; float tan_so = 0; float dien_cam = 0; float T = 0.0; float F = 0.0; float L = 0.0; float cal_time = 0; byte cnt = 0; float pulsewidth = 0 ; bool continous = true; byte counter = 0; float pulse_in[20]; float total_time[10]; unsigned long calibrate[10]; byte pulse_in_size; byte total_time_size; byte calibrate_size; bool need_clear = true; void setup() { Serial.begin(115200); pulse_in_size = sizeof(pulse_in) / 4; total_time_size = sizeof(total_time) / 4; calibrate_size = sizeof(calibrate) / 4; pinMode(input_pin, INPUT_PULLUP); pinMode(output_pin, OUTPUT); digitalWrite(output_pin, LOW); lcd.begin(16, 2); } void loop() { clear_var(); if (autorange()) { read_value(); need_clear = true; } else { if (need_clear) { clear_lcd(); need_clear = false; } } } bool autorange() { delayforchange = 300; delayforstable = 10; timeout = 5000; cnt = 0; for (byte k = 0; k < calibrate_size ; k++) { digitalWrite(output_pin, HIGH); continous = true; counter = 0; pulsewidth = 0 ; delayMicroseconds(delayforchange); digitalWrite(output_pin, LOW); delayMicroseconds(delayforstable); do { byte tmp = counter % 2; if (tmp == 0) { pulsewidth = pulseIn(input_pin, HIGH, timeout); } else { pulsewidth = pulseIn(input_pin, LOW, timeout); } if (pulsewidth > 0 ) { pulse_in[counter] = pulsewidth; counter++; } else continous = false; } while (continous && counter <= 15); if (counter >= 7) { byte mid = counter / 2; total_time[0] = (pulse_in[mid - 3] + pulse_in[mid - 2] + pulse_in[mid - 1] + pulse_in[mid] + pulse_in[mid + 1] + pulse_in[mid + 2]) * 2 / 6; } else if (counter >= 3) { byte mid = counter / 2; total_time[0] = pulse_in[mid] + pulse_in[mid + 1] ; } else { total_time[0] = 0; } if (total_time[0] > 0) { calibrate[cnt] = total_time[0]; cal_time = cal_time + calibrate[cnt]; cnt++; delayforchange = total_time[0] * 2.5; delayforstable = total_time[0] * 2; timeout = total_time[0] * 4; } delay(20); } if (cal_time > 0 && cnt > 0) { cal_time = cal_time / cnt; delayforchange = cal_time * 2.5; delayforstable = cal_time * 2; timeout = cal_time * 4; } else { delayforchange = 300; delayforstable = 10; timeout = 5000; cal_time = 0; } if (cal_time > 0) return true; else return false; } void read_value() { cnt = 0; for (byte k = 1; k < total_time_size - 2; k++) { continous = true; counter = 0; digitalWrite(output_pin, HIGH); delayMicroseconds(delayforchange); digitalWrite(output_pin, LOW); delayMicroseconds(delayforstable); do { byte tmp = counter % 2; if (tmp == 0) { pulsewidth = pulseIn(input_pin, HIGH, timeout); } else { pulsewidth = pulseIn(input_pin, LOW, timeout); } if (pulsewidth > 0) { pulse_in[counter] = pulsewidth; counter++; } else continous = false; } while (continous && counter <= 15); if (counter >= 7) { byte mid = counter / 2; total_time[0] = (pulse_in[mid - 2] + pulse_in[mid - 1] + pulse_in[mid] + pulse_in[mid + 1] + pulse_in[mid + 2]) * 2 / 5; // total_time[0] = pulse_in[mid] + pulse_in[mid + 1] ; } else if (counter >= 3) { byte mid = counter / 2; total_time[0] = pulse_in[mid] + pulse_in[mid + 1] ; } else { total_time[0] = 0; } if (total_time[0] > 0) { cnt++; total_time[cnt] = total_time[0]; total_time[total_time_size - 1] = total_time[total_time_size - 1] + total_time[cnt]; } delay(20); } if (total_time[total_time_size - 1] > 0 && cnt > 0) { total_time[total_time_size - 1] = total_time[total_time_size - 1] / cnt; } else { delayforchange = 300; delayforstable = 10; timeout = 5000; total_time[total_time_size - 1] = 0; } /*****************************************************************/ /*********In ra LCD********/ /*****************************************************************/ if (total_time[total_time_size - 1] > 0) { T = total_time[total_time_size - 1]; F = 1000000 / T; L = 1000000 / (4 * PI * PI * F * F * 2.E-6); if (T > 999999) { chu_ky = uint16_t(T / 1000000); t_unit = " S"; } else if (T > 999) { chu_ky = uint16_t(T / 1000); t_unit = "mS"; } else { chu_ky = uint16_t(T); t_unit = "uS"; } if (L > 999999) { dien_cam = L / 1000000; l_unit = " H"; } else if (L > 999) { dien_cam = L / 1000; l_unit = "mH"; } else { dien_cam = L; l_unit = "uH"; } if (F > 999999) { tan_so = F / 1000000; f_unit = "MHz"; } else if (F > 999) { tan_so = F / 1000; f_unit = "kHz"; } else { tan_so = F ; f_unit = " Hz"; } /*************Hàng trên************************/ // lcd.clear(); lcd.setCursor(1, 0); lcd.print("L_"); lcd.setCursor(3, 0); lcd.print(l_unit); lcd.setCursor(4, 0); lcd.print("H"); lcd.setCursor(6, 0); lcd.print("T_"); lcd.setCursor(8, 0); lcd.print(t_unit); lcd.setCursor(10, 0); lcd.print(" F_"); lcd.setCursor(13, 0); lcd.print(f_unit); /*************Hàng dưới************************/ if (dien_cam < 10) { lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(2, 1); } else if (dien_cam < 100) { lcd.setCursor(0, 1); lcd.print(" "); lcd.setCursor(1, 1); } else lcd.setCursor(0, 1); lcd.print(dien_cam); lcd.setCursor(6, 1); lcd.print("|"); if (chu_ky < 10) { lcd.setCursor(7, 1); lcd.print(" "); lcd.setCursor(9, 1); } else if (chu_ky < 100) { lcd.setCursor(7, 1); lcd.print(" "); lcd.setCursor(8, 1); } else lcd.setCursor(7, 1); lcd.print(chu_ky); lcd.setCursor(10, 1); lcd.print("|"); if (tan_so < 10) { lcd.setCursor(11, 1); lcd.print(" "); lcd.setCursor(13, 1); } else if (tan_so < 100) { lcd.setCursor(11, 1); lcd.print(" "); lcd.setCursor(12, 1); } else lcd.setCursor(11, 1); lcd.print(tan_so); delay(20); need_clear = true; } else { if (need_clear) { clear_lcd(); need_clear = false; } } Serial.print("Tần số cộng hưởng: "); Serial.print(tan_so); Serial.println(f_unit); Serial.print("Chu kỳ: "); Serial.print(chu_ky); Serial.println(t_unit); Serial.print("Điện cảm: "); Serial.print(dien_cam); Serial.println(l_unit); } void clear_var() { for (byte i = 0; i < pulse_in_size; i++) { pulse_in[i] = 0; } for (byte i = 0; i < total_time_size; i++) { total_time[i] = 0; } for (byte i = 0; i < calibrate_size; i++) { calibrate[i] = 0; } } void clear_lcd() { lcd.clear(); lcd.print(" Do cuon cam"); }
6. Các lưu ý khác
Không đủ chính xác?
Nếu bạn nhìn vào phương trình và bạn sẽ thấy rằng dung sai của tụ điện là chìa khóa.
Mong đợi kết quả của bạn chính xác trong khoảng ~ 10% với tụ điện dung sai 10%.
Điều đó có nghĩa là gì?
Giả sử bạn đang sử dụng tụ điện có dung sai 10% và Arduino nhận ra rằng cuộn cảm là 1000uH.
Điều này có nghĩa là cuộn cảm nằm trong khoảng từ 900uH đến 1100uH.
Nếu bạn tìm hiểu các kết quả thống kê – hầu hết các tụ điện danh nghĩa có dung sai 10% thực tế sẽ có sai số dưới 10%.
Nếu bạn yêu cầu một phép đo rất chính xác cho một hệ thống chạy ở tần số rất cao, thì phương pháp này chắc chắn không dành cho bạn do điện dung ký sinh không được tính đến.
Phương pháp này sử dụng dòng điện thấp để đo độ tự cảm, vì vậy đặc tính bão hòa sẽ không tồn tại (các phép đo sẽ được thực hiện ở trạng thái không bão hòa.)
Đây sẽ không phải là vấn đề đối với hầu hết mọi người.
Có điều tuyệt vời này được gọi là khả năng thẩm thấu.
Làm đầy một cuộn cảm bằng một số vật liệu nhất định sẽ thay đổi độ tự cảm mà không làm thay đổi cuộn dây.
Điều này tương tự như hiện tượng tự cảm lẫn nhau trong máy biến áp.
Bạn có bao giờ để ý xem máy biến áp tần số cao được làm bằng ferit gần như không dẫn điện như thế nào và máy biến áp 60hz được làm bằng sắt / thép không?
Chúc các bạn thành công!
Ngôi sao lẻ loi viết
Chào ad, cho mình hỏi thêm với. Bạn có thể cho mình thông tin facebook được không ạ
admin viết
Đây bạn nhé:
https://www.facebook.com/machdienlythu/