Vôn kế Bluetooth dựa trên arduino. Vôn kế bí mật trong Arduino - đo điện áp pin bằng vi điều khiển

Với một số bổ sung.

Một tính năng ít được biết đến của Arduino và nhiều chip AVR khác là khả năng đo điện áp tham chiếu 1,1 V bên trong. Tính năng này có thể được sử dụng cho tăng độ chính xác Chức năng Arduino - analogRead sử dụngđiện áp tham chiếu tiêu chuẩn 5 V (trên nền tảng có điện áp cung cấp 5 V) hoặc 3,3 V (trên nền tảng có điện áp cung cấp 3,3 V).Cô ấy cũng có thể dùng để đo Vcc áp dụng cho chip, cung cấp phương tiện kiểm soát điện áp pin không sử dụng chân analog quý giá.

Động lực

Có ít nhất ít nhất hai lý dođể đo Cung cấp hiệu điện thế Arduino của chúng tôi (Vcc). Một trong số đó là dự án chạy bằng pin của chúng tôi nếu chúng tôi muốn theo dõi mức điện áp của pin. Ngoài ra, khi nguồn pin (Vcc) không thể là 5,0 volt (ví dụ: nguồn điện 3 cell 1,5 V) và chúng tôi muốn thực hiện các phép đo tương tự chính xác hơn - chúng tôi phải sử dụng tham chiếu 1,1 V bên trong hoặc nguồn bên ngoàiđiện áp tham chiếu. Tại sao?

Giả định thông thường khi sử dụng analogRead() là điện áp tương tự Nguồn điện của bộ điều khiển là 5,0 volt, trong khi trên thực tế, điều này có thể không xảy ra (ví dụ: nguồn điện từ 3 phần tử 1,5 V). Tài liệu chính thức của Arduino thậm chí có thể dẫn chúng ta đến giả định không chính xác này. Thực tế là nguồn điện không nhất thiết phải là 5,0 volt, bất kể mức hiện tại như thế nào, nguồn điện này đều được cung cấp cho Vcc của chip. Nếu nguồn điện của chúng ta không ổn định hoặc nếu chúng ta đang chạy bằng nguồn pin, điện áp này có thể thay đổi một chút. Đây là một ví dụ mã minh họa vấn đề này:

Vcc kép = 5,0; // không nhất thiết phải đúng int value = analogRead(0); / đọc số đọc từ A0 double volt = (giá trị / 1023.0) * Vcc; // chỉ đúng nếu Vcc = 5,0 volt. Để đo điện áp chính xác, cần có điện áp tham chiếu chính xác. Hầu hết các chip AVR đều cung cấp ba tham chiếu điện áp:

  • 1,1 inch từ nguồn nội bộ, trong tài liệu, nó chuyển dưới dạng tham chiếu băng thông (một số trong số chúng là 2,56 V, ví dụ ATMega 2560). Việc lựa chọn được thực hiện bởi hàm analogReference() với tham số INTERNAL: analogReference(INTERNAL) ;
  • nguồn điện áp tham chiếu bên ngoài, được dán nhãn AREF trên arduino. Chọn: analogReference(EXTERNAL);
  • Vcc là nguồn điện của bộ điều khiển. Chọn: analogReference(DEFAULT).

Trong Arduino, bạn không thể kết nối trực tiếp Vcc với chân analog - theo mặc định, AREF được kết nối với Vcc và bạn sẽ luôn nhận được giá trị tối đa là 1023, bất kể bạn được cấp nguồn từ điện áp nào. Kết nối với ISF một nguồn điện áp đã biết trước đó, điện áp ổn định, nhưng điều này - yếu tố phụ trong sơ đồ.

Bạn cũng có thể kết nối Vcc với ISF thông qua điốt: Độ sụt áp trên diode đã được biết trước nên việc tính toán Vcc không khó. Tuy nhiên, với mạch như vậy thông qua một diode dòng điện chạy liên tục, rút ​​ngắn tuổi thọ pin, điều này cũng không tốt lắm.

Tham chiếu điện áp bên ngoài là chính xác nhất nhưng cần có phần cứng bổ sung. ION bên trong ổn định nhưng độ lệch không chính xác +/- 10%. Vcc hoàn toàn không đáng tin cậy trong hầu hết các trường hợp. Việc chọn tham chiếu điện áp bên trong không tốn kém và ổn định, nhưng hầu hết chúng ta muốn đo điện áp lớn hơn 1,1V, vì vậy sử dụng Vcc là cách thực tế nhất nhưng có khả năng kém chính xác nhất. Trong một số trường hợp, nó có thể rất không đáng tin cậy!

Làm thế nào để làm nó

Nhiều chip AVR bao gồm dòng ATmega và ATtiny cung cấp phương tiện đo điện áp tham chiếu bên trong. Tại sao điều này là cần thiết? Lý do rất đơn giản - bằng cách đo điện áp bên trong, chúng ta có thể xác định giá trị của Vcc. Đây là cách thực hiện:

  1. Đặt tham chiếu điện áp mặc định: analogReference(DEFAULT); . Chúng tôi sử dụng Vcc làm nguồn.
  2. Lấy số đọc ADC cho nguồn 1,1 V bên trong.
  3. Tính giá trị Vcc dựa trên phép đo 1,1 V bằng công thức:

Vcc * (đọc ADC) / 1023 = 1,1 V

Những gì sau đây:

Vcc = 1,1 V * 1023 / (đọc ADC)

Đặt mọi thứ lại với nhau và chúng tôi nhận được mã:

long readVcc() ( // Đọc tham chiếu 1.1V đối với AVcc // đặt tham chiếu thành Vcc và phép đo thành tham chiếu 1.1V bên trong #if được xác định(__AVR_ATmega32U4__) || được xác định(__AVR_ATmega1280__) || được xác định(__AVR_ATmega2560__) ADMUX = _BV (REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); #elif được xác định (__AVR_ATtiny24__) || được xác định(__AVR_ATtiny44__) || được xác định(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV (MUX0); #elif được xác định (__AVR_ATtiny25__) || được xác định(__AVR_ATtiny45__) || được xác định(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV( MUX2) | _BV(MUX1); #endif độ trễ (75); // Chờ Vref giải quyết ADCSRA |= _BV(ADSC); // Bắt đầu chuyển đổi while (bit_is_set(ADCSRA,ADSC)); // đo uint8_t low = ADCL; // phải đọc ADCL trước - sau đó khóa ADCH uint8_t high = ADCH; // mở khóa cả kết quả dài = (cao<<8) | low; result = 1125300L / result; // Calculate Vcc (in mV); 1125300 = 1.1*1023*1000 return result; // Vcc in millivolts }

Cách sử dụng

Kiểm tra Vcc hoặc điện áp pin

Bạn có thể gọi hàm này là readVcc() nếu bạn muốn theo dõi Vcc. Một ví dụ sẽ là kiểm tra mức sạc pin. Bạn cũng có thể sử dụng nó để xác định xem bạn đang kết nối với nguồn điện hay đang chạy bằng nguồn pin.

Đo Vcc cho điện áp tham chiếu

Bạn cũng có thể sử dụng nó để lấy giá trị Vcc chính xác để sử dụng với analogRead() khi bạn đang sử dụng điện áp tham chiếu (Vcc). Trừ khi bạn sử dụng nguồn điện được điều chỉnh, bạn không thể chắc chắn rằng Vcc = 5,0 volt. Chức năng này cho phép bạn nhận được giá trị chính xác. Tuy nhiên có một lưu ý...

Trong một bài viết, tôi đã tuyên bố rằng chức năng này có thể được sử dụng để cải thiện độ chính xác của các phép đo tương tự trong trường hợp Vcc không quá 5,0 volt. Thật không may, thủ tục này sẽ không cho kết quả chính xác. Tại sao? Điều này phụ thuộc vào độ chính xác của điện áp tham chiếu bên trong. Thông số kỹ thuật đưa ra điện áp danh định là 1,1 volt, nhưng cho biết nó có thể thay đổi tới 10%. Các phép đo như vậy có thể kém chính xác hơn so với nguồn điện Arduino của chúng tôi!

Tăng độ chính xác

Mặc dù dung sai lớn của nguồn điện 1.1V bên trong hạn chế đáng kể độ chính xác của phép đo khi sử dụng trong sản xuất hàng loạt, nhưng chúng tôi có thể đạt được độ chính xác cao hơn cho các dự án tùy chỉnh. Điều này có thể dễ dàng thực hiện bằng cách đo Vcc bằng vôn kế và hàm readVcc() của chúng tôi. Tiếp theo, thay thế hằng số 1125300L bằng một biến mới:

tỉ lệ_constant = nội bộ1.1Ref * 1023 * 1000

nội bộ1.1Ref = 1,1 * Vcc1 (voltmeter_readings) / Vcc2 (readVcc_function_readings)

Giá trị hiệu chỉnh này sẽ là chỉ báo tốt cho phép đo chip AVR, nhưng có thể bị ảnh hưởng bởi sự thay đổi nhiệt độ. Hãy thử nghiệm với các phép đo của riêng bạn.

Phần kết luận

Có rất nhiều thứ bạn có thể làm với tính năng nhỏ này. Bạn có thể sử dụng điện áp tham chiếu ổn định gần 5.0V mà không thực sự có 5.0V trên Vcc. Bạn có thể đo điện áp pin hoặc thậm chí xem bạn đang chạy bằng nguồn pin hay nguồn điện cố định.

Cuối cùng, mã sẽ hỗ trợ tất cả Arduinos, bao gồm cả Leonardo mới, cũng như các chip dòng ATtinyX4 và ATtinyX5.

Các tổ hợp Arduino đa chức năng được nhiều người hâm mộ các thiết bị lập trình điện tử tự chế quan tâm, cho phép họ biến những ý tưởng thú vị thành hiện thực.

Ưu điểm chính của mạch Arduino làm sẵn là nguyên tắc mô-đun khối độc đáo: mỗi bo mạch có thể được thêm các giao diện bổ sung, mở rộng không ngừng khả năng tạo các dự án khác nhau.

mô-đun Arduinođược xây dựng trên một bộ vi điều khiển đa năng với bộ tải khởi động riêng, giúp bạn dễ dàng flash nó bằng mã chương trình cần thiết mà không cần sử dụng các thiết bị bổ sung. Lập trình được thực hiện bằng ngôn ngữ C++ tiêu chuẩn.

Một trong những ví dụ đơn giản nhất về việc sử dụng Arduino có thể là việc triển khai, dựa trên tổ hợp này, một vôn kế DC có độ chính xác cao với phạm vi đo từ 0 đến 30 V.

Đầu vào tương tự Arduino được thiết kế cho điện áp không đổi không quá 5 volt, do đó, có thể sử dụng chúng ở điện áp vượt quá giá trị này bằng bộ chia điện áp.


Sơ đồ kết nối Areduino qua bộ chia điện áp

Một bộ chia điện áp gồm hai điện trở mắc nối tiếp. Nó được tính bằng công thức:

Đầu nối USB ngoài trong đài phát thanh xe hơi

Dữ liệu ban đầu và sửa đổi

Vì vậy, tại thời điểm này chúng ta có một vôn kế có điện áp không đổi với giới hạn 0,20V (xem phần trước). Bây giờ chúng tôi thêm một ampe kế 0,5a vào nó. Để làm điều này, chúng tôi sửa đổi một chút mạch - nó sẽ trở thành một mạch truyền qua, nghĩa là nó có cả đầu vào và đầu ra.

Tôi đã loại bỏ phần liên quan đến màn hình trên LCD - nó sẽ không thay đổi. Về nguyên tắc, thành phần mới chính là shunt Rx 0,1 Ohm. Chuỗi R1-C1-VD1 dùng để bảo vệ đầu vào analog. Sẽ rất hợp lý khi cài đặt tương tự ở đầu vào A0. Vì chúng tôi giả sử dòng điện khá lớn nên có các yêu cầu lắp đặt - đường dây điện phải được làm bằng dây khá dày và được kết nối trực tiếp với các cực shunt (nói cách khác là hàn), nếu không các kết quả đọc sẽ khác xa thực tế. Ngoài ra còn có một lưu ý về dòng điện - về nguyên tắc, điện áp tham chiếu 1,1V cho phép bạn đăng ký nó trên shunt Dòng điện 0,1 Ohm lên tới 11 ampe với độ chính xác kém hơn 0,01a một chút, nhưng khi điện áp như vậy giảm trên Rx, công suất giải phóng sẽ vượt quá 10 W, điều này không thú vị chút nào. Để giải quyết vấn đề, bạn có thể sử dụng bộ khuếch đại có mức tăng 11 sử dụng op-amp chất lượng cao và shunt 10 mOhm (0,01 Ohm). Nhưng hiện tại, chúng tôi sẽ không làm phức tạp cuộc sống của mình và chỉ giới hạn dòng điện ở mức 5A (trong trường hợp này, công suất Rx có thể được chọn ở mức 3-5 W).

Ở giai đoạn này, một điều bất ngờ đang chờ đợi tôi - hóa ra ADC của bộ điều khiển có độ lệch 0 khá lớn - khoảng -3mV. Nghĩa là, ADC đơn giản là không nhìn thấy các tín hiệu nhỏ hơn 3 mV và có thể nhìn thấy các tín hiệu ở mức cao hơn một chút với độ chính xác đặc trưng là -3 mV, điều này làm hỏng tính tuyến tính ở đầu phạm vi. Một tìm kiếm nhanh không đưa ra bất kỳ tài liệu tham khảo rõ ràng nào về một vấn đề như vậy (độ lệch bằng 0 là bình thường, nhưng nó sẽ nhỏ hơn đáng kể), vì vậy rất có thể đây là sự cố với một phiên bản Atmega 328 cụ thể. Giải pháp tôi chọn là gấp đôi - về điện áp - một bước phần mềm ở đầu phạm vi (màn hình bắt đầu ở 0,06 volt), đối với dòng điện - điện trở kéo lên bus 5V. Điện trở được biểu thị bằng một đường chấm chấm.

Nguồn

Bạn có thể tải xuống phiên bản đầy đủ của đồng hồ đo volt-ampe này (trong phiên bản I2C) từ liên kết ở cuối bài viết. Tiếp theo tôi sẽ hiển thị những thay đổi đối với mã nguồn. Đã thêm số đọc đầu vào tương tự A1 với giá trị trung bình tương tự như đối với vôn kế. Về bản chất, đây là cùng một vôn kế, chỉ không có bộ chia và chúng ta nhận được ampe bằng công thức Ohm: I = U/Rx (ví dụ: nếu điện áp rơi trên Rx = 0,01 V thì dòng điện là 0,1A). Tôi cũng giới thiệu hằng số khuếch đại hiện tại AmpMult - cho tương lai. Hằng số AmpRx với điện trở shunt có thể sẽ phải được khớp để tính đến độ thiếu chính xác của điện trở shunt. Chà, vì đây đã là đồng hồ đo volt-ampe và vẫn còn chỗ trống trên màn hình 1602, nên nó vẫn hiển thị mức tiêu thụ điện năng hiện tại tính bằng watt, có được chức năng bổ sung đơn giản.

.... // Đầu vào tương tự #define PIN_VOLT A0 #define PIN_AMP A1 // Điện áp tham chiếu bên trong (chọn) const float VRef = 1.10; // Hệ số chia điện trở đầu vào (Rh + Rl) / Rl. TRONG 0,2) Vôn += 3; // Chuyển đổi sang volt (In: 0..1023 -> (0..VRef) được chia tỷ lệ theo Mult) float Volt = InVolt * VoltMult * VRef / 1023; float Amp = InAmp * VRef / AmpMult / AmpRx / 1023 ; // Để tính đến sự sụt giảm trên shunt, hãy bỏ ghi chú 2 dòng //float RxVolt = InAmp * VRef / 1023 / AmpMult; // Vôn -= RxVolt; phao Watt = Volt * Amp; // Dữ liệu đầu ra lcd.setCursor (8, 0); lcd.print(Watt); lcd.print("W "); lcd.setCursor(0, 1); lcd.print(Volt); lcd.print("V "); lcd.setCursor(8, 1); lcd.print(Amp); lcd.print("A "); )

Liên kết

  • Thư viện LiquidCrystal_I2C, cho phép bạn thiết lập sơ đồ chân

Một sơ đồ hữu ích được trình bày cho những ai thích thử nghiệm với Arduino. Đây là một vôn kế kỹ thuật số đơn giản có thể đo điện áp DC một cách đáng tin cậy trong phạm vi 0 - 30V. Bo mạch Arduino, như thường lệ, có thể được cấp nguồn bằng pin 9V.

Như bạn có thể biết, đầu vào analog của Arduino có thể được sử dụng để đo điện áp DC trong phạm vi 0 - 5V và phạm vi này có thể tăng lên,
dùng hai điện trở làm bộ chia điện áp. Bộ chia sẽ giảm điện áp đo được xuống mức đầu vào tương tự Arduino. Sau đó chương trình sẽ tính giá trị điện áp thực tế.

Cảm biến analog trên bo mạch Arduino phát hiện sự hiện diện của điện áp ở đầu vào analog và chuyển đổi nó thành dạng kỹ thuật số để vi điều khiển xử lý thêm. Trong hình, điện áp được cung cấp cho đầu vào analog (A0) thông qua một bộ chia điện áp đơn giản bao gồm các điện trở R1 (100 kOhm) và R2 (10 kOhm).

Với các giá trị chia này, bo mạch Arduino có thể được cung cấp điện áp từ 0 đến
55V. Ở đầu vào A0, chúng ta có điện áp đo được chia cho 11, tức là 55V / 11=5V. Nói cách khác, khi đo 55V ở đầu vào Arduino, ta có giá trị tối đa cho phép là 5V. Trong thực tế, tốt hơn là viết phạm vi “0 - ​​​​30V” trên vôn kế này để nó vẫn giữ nguyên
Biên độ an toàn!

Ghi chú

Nếu số đọc trên màn hình không trùng với số đọc của vôn kế công nghiệp (phòng thí nghiệm), thì cần đo giá trị của điện trở R1 và R2 bằng một dụng cụ chính xác và chèn các giá trị này thay vì R1=100000.0 và R2=10000.0 trong mã chương trình. Sau đó, bạn nên đo điện áp thực giữa chân 5V và chân “Nối đất” của bo mạch Arduino bằng vôn kế trong phòng thí nghiệm. Kết quả sẽ là giá trị nhỏ hơn 5V, ví dụ sẽ là 4,95V. Giá trị thực này phải được chèn vào dòng mã
vout = (giá trị * 5.0)/1024.0 thay vì 5.0.
Ngoài ra, hãy thử sử dụng điện trở chính xác với dung sai 1%.

Các điện trở R1 và R2 cung cấp một số biện pháp bảo vệ chống lại việc tăng điện áp đầu vào. Tuy nhiên, hãy nhớ rằng bất kỳ điện áp nào trên 55V đều có thể làm hỏng bo mạch Arduino. Ngoài ra, thiết kế này không cung cấp các loại bảo vệ khác (chống tăng điện áp, đảo cực hoặc quá điện áp).

Chương trình vôn kế kỹ thuật số

/*
Vôn kế DC
Một Arduino DVM dựa trên khái niệm bộ chia điện áp
T.K.Hareendran
*/
#bao gồm
LCD LiquidCrystal(7, 8, 9, 10, 11, 12);
int analogInput = 0;
float vout = 0,0;
float vin = 0,0;
phao R1 = 100000.0; // điện trở của R1 (100K) -xem văn bản!
phao R2 = 10000,0; // điện trở của R2 (10K) – xem văn bản!
giá trị int = 0;
thiết lập void())(
pinMode(analogInput, INPUT);
lcd.begin(16, 2);
lcd.print(“Vôn kế DC”);
}
vòng lặp trống()
// đọc giá trị ở đầu vào analog
giá trị = analogRead(analogInput);
vout = (giá trị * 5.0) / 1024.0; // xem văn bản
vin = vout / (R2/(R1+R2));
nếu (vin<0.09) {
vin=0.0;//câu lệnh để loại bỏ việc đọc không mong muốn !
}
lcd.setCursor(0, 1);
lcd.print(“INPUT V= “);
lcd.print(vin);
độ trễ (500);
}

Sơ đồ nguyên lý của vôn kế Arduino

Danh sách các thành phần

Bo mạch Arduino Uno
Điện trở 100 kOhm
Điện trở 10 kOhm
điện trở 100 ohm
Điện trở cắt 10kOhm
Màn hình LCD 16?2 (Hitachi HD44780)

Đầu vào tương tự của bo mạch Arduino.

Bảng mạch Arduino UNO chứa 6 đầu vào analog được thiết kế để đo tín hiệu điện áp. Sẽ đúng hơn nếu nói rằng 6 chân của bo mạch có thể hoạt động ở cả chế độ đầu ra rời rạc và đầu vào analog.

Các chân này được đánh số từ 14 đến 19. Ban đầu chúng được cấu hình làm đầu vào tương tự và có thể được truy cập bằng tên A0-A5. Chúng có thể được cấu hình ở chế độ đầu ra riêng biệt bất cứ lúc nào.

pinMode(A3, OUTPUT); // cài đặt chế độ đầu ra rời rạc cho A3
digitalWrite(A3, THẤP); // cài đặt đầu ra A3 ở mức thấp

Để quay lại chế độ đầu vào analog:

pinMode(A3, INPUT); // cài đặt chế độ đầu vào analog cho A3

Đầu vào analog và điện trở kéo lên.

Điện trở kéo lên được kết nối với các chân đầu vào tương tự cũng như với các chân rời rạc. Các điện trở này được bật bằng lệnh

digitalWrite(A3, CAO); // bật điện trở kéo lên đầu vào A3

Lệnh phải được áp dụng cho chân được cấu hình ở chế độ đầu vào.

Cần phải nhớ rằng điện trở có thể ảnh hưởng đến mức tín hiệu đầu vào analog. Dòng điện từ nguồn điện 5V đi qua điện trở kéo lên sẽ gây ra hiện tượng sụt áp trên điện trở trong của nguồn tín hiệu. Vì vậy tốt hơn hết là ngắt kết nối điện trở.

Bộ chuyển đổi analog sang digital của bo mạch Arduino.

Việc đo điện áp thực tế ở các đầu vào được thực hiện bằng bộ chuyển đổi tương tự sang số (ADC) có công tắc cho 6 kênh. ADC có độ phân giải 10 bit, tương ứng với mã ở đầu ra của bộ chuyển đổi 0...1023. Sai số đo không quá 2 đơn vị chữ số có nghĩa nhỏ nhất.

Để duy trì độ chính xác tối đa (10 bit), điện trở trong của nguồn tín hiệu không vượt quá 10 kOhm. Yêu cầu này đặc biệt quan trọng khi sử dụng các bộ chia điện trở nối với đầu vào analog của bo mạch. Điện trở của các điện trở chia không thể quá cao.

Chức năng phần mềm đầu vào tương tự.

int analogRead(port)

Đọc giá trị điện áp ở đầu vào analog được chỉ định. Điện áp đầu vào nằm trong khoảng từ 0 đến mức điện áp tham chiếu (thường là 5 V) chuyển đổi thành mã từ 0 đến 1023.

Với điện áp tham chiếu là 5 V thì độ phân giải là 5 V/1024 = 4,88 mV.

Quá trình chuyển đổi mất khoảng 100 μs.

int inputCod; // mã điện áp đầu vào
đầu vào floatĐiện áp; // điện áp đầu vào trong V

inputCod= analogRead(A3); // đọc điện áp ở đầu vào A3
inputVoltage= ((float)inputCod * 5. / 1024.); // chuyển đổi mã thành điện áp (V)

void analogReference(type)

Đặt điện áp tham chiếu cho ADC. Nó xác định điện áp đầu vào tương tự tối đa mà ADC có thể chuyển đổi chính xác. Giá trị của điện áp tham chiếu cũng xác định hệ số chuyển đổi mã thành điện áp:

Điện áp đầu vào = mã ADC * điện áp tham chiếu/1024.

Đối số kiểu có thể nhận các giá trị sau:

  • MẶC ĐỊNH – điện áp tham chiếu bằng điện áp nguồn của bộ điều khiển (5 V hoặc 3,3 V). Đối với Arduino UNO R3 – 5V.
  • NỘI BỘ – điện áp tham chiếu bên trong 1,1 V cho bo mạch có bộ điều khiển ATmega168 và ATmega328, cho ATmega8 – 2,56 V.
  • INTERNAL1V1 – điện áp tham chiếu 1,1 V bên trong cho bộ điều khiển Arduino Mega.
  • INTERNAL2V56 – điện áp tham chiếu 2,56 V bên trong cho bộ điều khiển Arduino Mega.
  • BÊN NGOÀI – nguồn điện áp tham chiếu bên ngoài, được kết nối với đầu vào ISF.

analogReference(NỘI BỘ); // điện áp tham chiếu là 1,1 V

Vôn kế hai kênh trên Arduino.

Để làm ví dụ về việc sử dụng các hàm đầu vào tương tự, hãy tạo một dự án cho một vôn kế kỹ thuật số đơn giản trên Arduino. Thiết bị phải đo điện áp ở 2 đầu vào analog của bo mạch, đồng thời truyền giá trị đo được về máy tính qua cổng nối tiếp. Lấy dự án này làm ví dụ, tôi sẽ trình bày các nguyên tắc tạo ra các hệ thống thu thập thông tin và đo lường đơn giản.

Hãy quyết định rằng vôn kế phải đo điện áp trong phạm vi ít nhất 0...20 V và phát triển mạch kết nối các đầu vào vôn kế với bo mạch Arduino UNO.

Nếu chúng ta đặt điện áp tham chiếu thành 5 V thì đầu vào analog của bo mạch sẽ đo điện áp trong khoảng 0...5 V. Và chúng ta cần ít nhất 0...20 V. Điều này có nghĩa là chúng ta cần sử dụng một bộ chia điện áp.

Điện áp ở đầu vào và đầu ra của bộ chia có liên hệ với nhau bởi hệ thức:

Uoutput = (Uinput / (R1 + R2)) * R2

Tỷ số truyền:

K = Uoutput / Uinput = R2 / (R1 + R2)

Chúng ta cần tỷ số truyền là 1/4 (20 V * 1/4 = 5 V).

Để duy trì độ chính xác tối đa (10 bit), điện trở trong của nguồn tín hiệu không vượt quá 10 kOhm. Vì vậy ta chọn điện trở R2 bằng 4,22 kOhm. Ta tính điện trở của điện trở R1.

0,25 = 4,22 / (R1 + 4,22)
R1 = 4,22 / 0,25 – 4,22 = 12,66 kOhm

Tôi tìm thấy điện trở có điện trở 15 kOhm có giá trị gần nhất. Với điện trở R1 = 15 kOhm và R2 = 4,22:

5 / (4,22 / (15 + 4,22)) = 22,77 V.

Mạch vôn kế dựa trên Arduino sẽ trông như thế này.

Hai bộ chia điện áp được kết nối với đầu vào analog A0 và A1. Các tụ điện C1 và C2, cùng với các điện trở phân chia, tạo thành các bộ lọc thông thấp giúp loại bỏ nhiễu tần số cao khỏi tín hiệu.

Tôi lắp ráp mạch này trên một bảng mạch.

Tôi kết nối đầu vào đầu tiên của vôn kế với nguồn điện được điều chỉnh và đầu vào thứ hai với nguồn điện 3,3 V của bo mạch Arduino. Để theo dõi điện áp, tôi nối một vôn kế với đầu vào đầu tiên. Tất cả những gì còn lại là viết chương trình.

Một chương trình đo điện áp bằng bảng Arduino.

Thuật toán rất đơn giản. Cần thiết:

  • đọc mã ADC hai lần mỗi giây;
  • chuyển đổi nó thành điện áp;
  • gửi giá trị đo được qua cổng nối tiếp tới máy tính;
  • chương trình giám sát cổng Arduino IDE hiển thị các giá trị điện áp thu được trên màn hình máy tính.

Tôi sẽ cung cấp cho bạn bản phác thảo hoàn chỉnh của chương trình ngay lập tức.

// chương trình đo điện áp
// trên đầu vào analog A0 và A1

#bao gồm

khoảng thời gian đo
#define R1 15. // điện trở R1
#define R2 4.22 // điện trở R2


thả nổi u1, u2; // đo điện áp

thiết lập void() (
Serial.begin(9600); //

MsTimer2::start(); // kích hoạt ngắt
}

vòng lặp trống() (

// khoảng thời gian 500 mili giây
if (timeCount >= MEASURE_PERIOD) (
timeCount= 0;

//

// đọc mã kênh 2 và chuyển đổi thành điện áp
u2= ((float)analogRead(A1)) * 5. / 1024. / R2 * (R1 + R2);

// truyền dữ liệu qua cổng nối tiếp
Serial.print("U1 = "); Serial.print(u1, 2);
Serial.print(" U2 = "); Serial.println(u2, 2);
}
}

// xử lý ngắt 1 ms
void hẹn giờInterrupt() (
thời gianCount++;
}

Hãy để tôi giải thích dòng mã ADC được chuyển đổi thành điện áp:

// đọc mã kênh 1 và chuyển đổi thành điện áp
u1= ((float)analogRead(A0)) * 5. / 1024. / R2 * (R1 + R2);

  • Mã ADC được đọc: analogRead(A0) .
  • Được chuyển đổi rõ ràng sang định dạng dấu phẩy động: (float) .
  • Chuyển đổi thành điện áp ở đầu vào analog: * 5. / 1024. Dấu chấm ở cuối các số cho biết đây là số dấu phẩy động.
  • Hệ số truyền của bộ chia được tính đến: /R2*(R1 + R2).

Hãy tải chương trình vào bo mạch và khởi chạy màn hình cổng nối tiếp.

Hai thanh chạy hiển thị giá trị của điện áp đo được. Mọi thứ đang hoạt động.

Đo giá trị tín hiệu trung bình.

Hãy kết nối kênh đầu tiên của vôn kế của chúng ta với nguồn điện áp có mức gợn sóng cao. Chúng ta sẽ thấy hình ảnh này trên màn hình.

Các giá trị điện áp của kênh đầu tiên trên màn hình điều khiển liên tục co giật và nhảy vọt. Và số đọc của vôn kế điều khiển khá ổn định. Điều này là do vôn kế tham chiếu đo giá trị trung bình của tín hiệu, trong khi bo mạch Arduino đọc các mẫu riêng lẻ cứ sau 500 ms. Đương nhiên, thời điểm ADC đọc rơi vào các điểm khác nhau trong tín hiệu. Và ở mức xung cao, biên độ tại các điểm này sẽ khác nhau.

Ngoài ra, nếu tín hiệu được đọc trong các mẫu thưa thớt riêng biệt thì bất kỳ nhiễu xung nào cũng có thể gây ra sai số đáng kể trong phép đo.

Giải pháp là lấy một số mẫu thường xuyên và lấy giá trị trung bình đo được. Đối với điều này:

  • trong trình xử lý ngắt, chúng tôi đọc mã ADC và tính tổng nó với các mẫu trước đó;
  • đếm thời gian lấy trung bình (số lượng mẫu lấy trung bình);
  • khi đạt đến số lượng mẫu được chỉ định, chúng tôi lưu tổng giá trị của mã ADC;
  • Để có được giá trị trung bình, chia tổng mã ADC cho số lượng mẫu trung bình.

Bài toán trong sách giáo khoa toán lớp 8. Đây là bản phác thảo của chương trình, một vôn kế có giá trị trung bình hai kênh.

// chương trình đo trung thế
// trên đầu vào analog A0 và A1

#bao gồm

#define MEASURE_PERIOD 500 // khoảng thời gian đo
#define R1 15. // điện trở R1
#define R2 4.22 // điện trở R2

int timeCount; // bộ đếm thời gian
tổng dàiU1, tổngU2; // các biến để tính tổng mã ADC
avarageU1 dài, avarageU2; // tổng mã ADC (giá trị trung bình * 500)
cờ booleanSẵn sàng; // chỉ báo mức độ sẵn sàng của dữ liệu đo lường

thiết lập void() (
Serial.begin(9600); // khởi tạo cổng, tốc độ 9600
MsTimer2::set(1, timeInterupt); // ngắt hẹn giờ, khoảng thời gian 1 ms
MsTimer2::start(); // kích hoạt ngắt
}

vòng lặp trống() (

if (flagReady == true) (
flagReady= sai;
// chuyển đổi thành điện áp và truyền vào máy tính
Serial.print("U1 = ");
Serial.print((float)avarageU1 / 500. * 5. / 1024. / R2 * (R1 + R2), 2);
Serial.print(" U2 = ");
Serial.println((float)avarageU2 / 500. * 5. / 1024. / R2 * (R1 + R2), 2);
}
}

// xử lý ngắt 1 ms
void hẹn giờInterrupt() (

thời gianCount++; // +1 bộ đếm mẫu trung bình
sumU1+= analogRead(A0); // tổng hợp mã ADC
sumU2+= analogRead(A1); // tổng hợp mã ADC

// kiểm tra số lượng mẫu trung bình
if (timeCount >= MEASURE_PERIOD) (
timeCount= 0;
avarageU1= sumU1; // quá tải giá trị trung bình
avarageU2= sumU2; // quá tải giá trị trung bình
tổngU1= 0;
tổngU2= 0;
flagReady= đúng; // kết quả đo dấu hiệu đã sẵn sàng
}
}

Trong công thức chuyển đổi mã ADC thành điện áp, /500 đã được thêm vào - số lượng mẫu. Tải, khởi chạy trình giám sát cổng (Cntr+Shift+M).

Bây giờ, ngay cả với mức độ xung đáng kể, số đọc vẫn thay đổi hàng phần trăm. Nguyên nhân là do điện áp không ổn định.

Số lượng mẫu phải được chọn có tính đến:

  • số lượng mẫu quyết định thời gian đo;
  • Làm sao số lớn hơn mẫu thì ảnh hưởng của nhiễu sẽ càng ít.

Nguồn gây nhiễu chính trong tín hiệu tương tự là mạng 50 Hz. Do đó, nên chọn thời gian trung bình là bội số của 10 ms – thời gian nửa chu kỳ của mạng 50 Hz.

Tối ưu hóa tính toán.

Tính toán dấu phẩy động chỉ đơn giản là tiêu tốn tài nguyên của bộ vi điều khiển 8 bit. Bất kỳ phép toán dấu phẩy động nào đều yêu cầu không chuẩn hóa mantissa, phép toán điểm cố định, chuẩn hóa mantissa, hiệu chỉnh thứ tự... Và tất cả các phép toán với 32 số chữ số. Vì vậy, cần hạn chế tối đa việc sử dụng các phép tính dấu phẩy động. Tôi sẽ cho bạn biết cách thực hiện điều này trong các bài học sau, nhưng ít nhất hãy tối ưu hóa các phép tính của chúng ta. Hiệu quả sẽ rất đáng kể.

Trong chương trình của chúng tôi, việc chuyển đổi mã ADC thành điện áp được viết như sau:

(float)trung bìnhU1 / 500. * 5. / 1024. / R2 * (R1 + R2)

Có rất nhiều phép tính ở đây, tất cả đều có dấu phẩy động. Nhưng hầu hết các phép tính đều là các phép tính với hằng số. Một phần của dòng:

/ 500. * 5. / 1024. / R2 * (R1 + R2)

(phao)trung bìnhU1 * 0,00004447756

Bản thân các trình biên dịch thông minh nhận dạng các phép tính bằng hằng số và tính toán chúng ở giai đoạn biên dịch. Tôi có câu hỏi về trình biên dịch của Andruino thông minh đến mức nào. Tôi đã quyết định kiểm tra nó.

Tôi đã viết một chương trình ngắn. Nó thực hiện một chu kỳ 10.000 lượt và sau đó truyền thời gian thực hiện của 10.000 chu kỳ đó đến máy tính. Những thứ kia. nó cho phép bạn xem thời gian thực hiện của các thao tác được đặt trong phần thân vòng lặp.

// kiểm tra tối ưu hóa tính toán

int x= 876;
thả nổi y;
số int không dấu;
không dấu thời gian dài Hiện tại, timePrev;

thiết lập void() (
Serial.begin(9600);
}

vòng lặp trống() (
đếm++;
// y= (float)x / 500. * 5. / 1024. / 4.22 * (15. + 4.22);
// y= (float)x * 0,00004447756 ;

nếu (đếm >= 10000) (
đếm= 0;
timeCurrent= millis();
Serial.println(timeCurrent - timePrev);
timePrev= thời gian hiện tại;
}
}

Trong tùy chọn đầu tiên, khi các thao tác dấu phẩy động trong vòng lặp được nhận xét và không được thực thi, chương trình tạo ra kết quả là 34 mili giây.

Những thứ kia. 10.000 vòng lặp trống được hoàn thành trong 34 mili giây.

Sau đó tôi mở dòng:

y= (float)x / 500. * 5. / 1024. / 4.22 * (15. + 4.22);

lặp lại tính toán của chúng tôi Kết quả của 10.000 lần vượt qua trong 922 mili giây hoặc

(922 – 34) / 10.000 = 88,8 µs.

Những thứ kia. dòng tính toán dấu phẩy động này mất 89 µs để hoàn thành. Tôi nghĩ sẽ có nhiều hơn nữa.

Bây giờ tôi đóng dòng này bằng một nhận xét và mở dòng tiếp theo, nhân với hằng số được tính toán trước:

y= (float)x * 0,00004447756 ;

Kết quả của 10.000 lần vượt qua trong 166 mili giây hoặc

(166 – 34) / 10.000 = 13,2 µs.

Kết quả đáng kinh ngạc. Chúng tôi đã tiết kiệm được 75,6 μs trên mỗi dòng. Chúng tôi đã hoàn thành nó nhanh hơn gần 7 lần. Chúng tôi có 2 dòng như vậy, nhưng có thể có nhiều dòng hơn trong chương trình.

Kết luận - việc tính toán với các hằng số phải được thực hiện độc lập trên máy tính và sử dụng trong các chương trình dưới dạng hệ số có sẵn. Trình biên dịch Arduino sẽ không tính toán chúng ở giai đoạn biên dịch. Trong trường hợp của chúng tôi, chúng tôi nên làm điều này:

#define ADC_U_COEFF 0,00004447756 // hệ số chuyển đổi mã ADC thành điện áp

Serial.print((float)avarageU1 * ADC_U_COEFF, 2);

Tùy chọn tối ưu cho hiệu suất là chuyển mã ADC vào máy tính và cùng với đó là tất cả các phép tính dấu phẩy động. Trong trường hợp này, máy tính phải nhận dữ liệu chương trình chuyên ngành. Trình giám sát cổng từ Arduino IDE sẽ không hoạt động.

Tôi sẽ nói về những cách khác để tối ưu hóa chương trình Arduino trong các bài học sau nếu cần. Nhưng không giải quyết được vấn đề này thì không thể phát triển được chương trình phức tạp trên vi điều khiển 8 bit.

Một bài học khác đã xuất hiện trên trang web (