Как настроить вход АЦП Arduino на A0 вместо использования по умолчанию?
Я пытаюсь построить этот измеритель переменного тока постоянного тока, исходный код по умолчанию использовал A3 в качестве входных данных, как изменить входные данные на A0? ссылка: https://simple-circuit.com/arduino-autoranging-ac-dc-voltmeter-with-trms/
Спасибо за помощь Адам
/**************************************************************************
*
* Arduino autoranging AC/DC voltmeter.
* Voltage and frequency are printed on 1602 LCD screen.
* This is a free software with NO WARRANTY - Use it at your own risk!
* https://simple-circuit.com/
*
*************************************************************************/
#include <LiquidCrystal.h> // include Arduino LCD library
// LCD module connections (RS, E, D4, D5, D6, D7)
LiquidCrystal lcd(8, 9, 10, 11, 12, 13);
// define autoranging channel pins
#define CH0 2
#define CH1 3
#define CH2 4
#define CH3 5
const uint16_t Time_Out = 50000, // time out in microseconds
Periods = 10; // number of periods of measurement (for AC voltage only)
// variables
byte ch_number;
const uint16_t res_table[4] = {2444, 244, 94, 47}, // voltage divider resistances in tenths kOhms
total_res = 22444; // total resistance in tenths kOhms
uint16_t current_res;
volatile byte per;
void setup(void)
{
pinMode(CH0, OUTPUT);
pinMode(CH1, OUTPUT);
pinMode(CH2, OUTPUT);
pinMode(CH3, OUTPUT);
lcd.begin(16, 2); // set up the LCD's number of columns and rows
lcd.setCursor(1, 0);
lcd.print("Voltage:");
ch_number = 0;
ch_select(ch_number);
// ADC and analog comparator configuration
ADMUX = 0x03;
ADCSRA = 0x87;
ADCSRB = (0 << ACME); // select AIN1 as comparator negative input
ACSR = 0x13; // turn on analog comparator
}
// analog comparator ISR
ISR (ANALOG_COMP_vect)
{
byte count = 0;
for(byte i = 0; i < 50; i++) {
if ( ACSR & 0x20 )
count++;
}
if(count > 48)
per++;
}
// main loop
void loop()
{
bool dc_flag = 0; // DC voltage flag bit
int32_t sum = 0; // sum of all readings
uint16_t n = 0; // number of readings (samples)
ACSR = (1 << ACI); // clear analog comparator interrupt flag
ACSR = (1 << ACIE); // enable analog comparator interrupt
uint32_t current_m = micros(); // save current millis
byte current_per = per; // save current period number
while ( (current_per == per) && (micros() - current_m < Time_Out) ) ;
if( micros() - current_m >= Time_Out ) { // if there's time out event ==> voltage signal is DC
dc_flag = 1;
for (byte i = 0; i < 200; i++) {
ADCSRA |= 1 << ADSC; // start conversion
while(ADCSRA & 0x40); // wait for conversion complete
int16_t an = (int16_t)(ADCL | (uint16_t)ADCH << 8) - 511;
sum += an;
n++; // increment number of readings
delay(1);
}
}
else { // here, voltage signal is AC
current_m = micros(); // save current millis()
per = 0;
while ( (per < Periods) && (micros() - current_m < (uint32_t)Time_Out * Periods) ) {
ADCSRA |= 1 << ADSC; // start conversion
while(ADCSRA & 0x40); // wait for conversion complete
int32_t an = (int16_t)(ADCL | (uint16_t)ADCH << 8) - 511;
sum += sq(an); // sq: square
n++; // increment number of readings
}
}
ACSR = (0 << ACIE); // disable analog comparator interrupt
uint32_t total_time = micros() - current_m; // used to claculate frequency
// voltage calculation
float v;
if(dc_flag) // if voltage signal is DC
v = (4 * sum)/n; // calculate Arduino analog channel DC voltage in milli-Volts
else // here voltage signal is AC
v = 4 * sqrt(sum/n); // calculate Arduino analog channel RMS voltage in milli-Volts
// claculate actual (input) voltage in milli-Volts (apply voltage divider equation)
v = v * (float)total_res/current_res;
v /= 1000; // get voltage in Volts
uint16_t v_abs = abs(int16_t(v));
if( (v_abs >= 10 && ch_number == 0) || (v_abs >= 100 && ch_number == 1) || (v_abs >= 250 && ch_number == 2) ) {
ch_number++;
ch_select(ch_number);
delay(10);
return;
}
if( (v_abs < 220 && ch_number == 3) || (v_abs < 80 && ch_number == 2) || (v_abs < 8 && ch_number == 1) ) {
ch_number--;
ch_select(ch_number);
delay(10);
return;
}
char _buffer[8];
lcd.setCursor(0, 1);
if( v < 0)
lcd.print('-');
else
lcd.print(' ');
if(v_abs < 10)
sprintf( _buffer, "%01u.%02u", v_abs, abs((int16_t)(v * 100)) % 100 );
else if( v_abs < 100)
sprintf( _buffer, "%02u.%01u", v_abs, abs((int16_t)(v * 10)) % 10 );
else
sprintf( _buffer, "%03u ", v_abs );
lcd.print(_buffer);
if(dc_flag)
lcd.print("VDC ");
else {
lcd.print("VAC ");
// calculate signal frequency in Hz
uint32_t period_time = total_time/Periods;
float freq = 1000000.0/period_time;
sprintf( _buffer, "%02u.%02uHz", (uint16_t)freq % 100, (uint16_t)(freq * 100) % 100 );
lcd.print(_buffer);
}
delay(500); // wait half a second
}
void ch_select(byte n) {
switch(n) {
case 0:
digitalWrite(CH0, HIGH);
digitalWrite(CH1, LOW);
digitalWrite(CH2, LOW);
digitalWrite(CH3, LOW);
break;
case 1:
digitalWrite(CH0, LOW);
digitalWrite(CH1, HIGH);
digitalWrite(CH2, LOW);
digitalWrite(CH3, LOW);
break;
case 2:
digitalWrite(CH0, LOW);
digitalWrite(CH1, LOW);
digitalWrite(CH2, HIGH);
digitalWrite(CH3, LOW);
break;
case 3:
digitalWrite(CH0, LOW);
digitalWrite(CH1, LOW);
digitalWrite(CH2, LOW);
digitalWrite(CH3, HIGH);
}
current_res = res_table[n];
}
// end of code.
@oldbin, 👍1
2 ответа
Ваш код трудно прочитать, это просто большой объем символов на экране, но у вас есть красивая картинка arduino. Измените свой код, чтобы использовать A0 вместо A3. Измените свое физическое соединение с A3 на A0, и все готово. Я скучаю по прочитанному вами коду.
Это сложная схема, и он сделал все регистры напрямую, что сделало ее чрезвычайно сложной для понимания. Я недостаточно хорошо знаю набор регистров, чтобы говорить со знанием дела о том, что он делает. Оптроны замыкают части входной сети делителя, которую он выбирает в своем коде. Вот как он делает ранжирование. Оптроны нарисованы в обратном порядке, выход слева, а вход справа. Попробуйте перейти по этой ссылке на сайт Ника Гэммона: https://www.gammon.com.au/adc Также попробуйте вот это: https://www.arduino.cc/en/Reference/PortManipulation
Вход для АЦП выбирается четырьмя наименее значимыми битами
“Регистра выбора мультиплексора АЦП”, он же ADMUX
. Он устанавливается на
аналоговый вход 3 с помощью этой строки кода:
ADMUX = 0x03;
Измените эту строку на ADMUX = 0;
и АЦП будет считывать вывод A0.
- Как найти пиковое значение аналогового сигнала?
- Создание синусоидальной волны с помощью ЦАП и ее обратная передача
- Как преобразовать эту программу в сборку из c++
- Хранение данных в SDRAM Arduino Portenta H7
- Как проверить, установлен ли пин?
- Несколько кнопок на один вход
- Как закодировать Arduino для выполнения определенного кода с помощью ползункового переключателя
- Если я использую схему смещения для сигнала, поступающего на аналоговый вход, повлияет ли это на работу АЦП?
Спасибо. Можете ли вы сказать, как лучше разместить код? В коде нет A3, причина этого-по умолчанию. вот почему я не знаю, как измениться., @oldbin
Я никогда этого не делал, поэтому на данный момент я не буду пытаться это объяснить. Есть много других, которые справляются с работой лучше, чем я. ADMUX = 0x03; Я считаю, что вам нужно изменить одно из утверждений на ADMUX = 0x00; Сообщите нам, как вы это сделали? Я прогнал схему обратно к простым схемам, где кто-то задал тот же вопрос. Там ответ был близок к моему. "Если вам нужно изменить A3 на A0, вы должны изменить определение аналогового контакта в коде"., @Gil
идеально! заряжено ADMUX = 0x03 как ADMUX = 0x00, это работает. Спасибо., @oldbin
На самом деле, заряженный ADMUX = 0x03 как ADMUX = 0x02, A2 в качестве входных данных; но заряженный ADMUX = 0x03 как ADMUX = 0x01, A1-A7 не работает в качестве входных данных! ПОЧЕМУ?, @oldbin
Вы переместили соединение на A0? Также проверьте любые ссылки на ADMUX., @Gil
Да, я переместил ввод на относительный контакт и проверил приведенные выше результаты. Я больше ничего не менял, не знаю, как проверить ссылки на ADMUX?, @oldbin
`Оптроны замыкают части сети входного делителя " ... Э-э... нет. Они выбирают различные отводы в сети делителя для считывания напряжения., @Majenko
Спасибо. Я использовал это решение для MEGA2560, получил тот же результат, но как определить A5,A6,A8 на MEGA2560? Я попробовал какой-то номер, например 0100, 0110, но ничего не вышло., @oldbin
@oldbin вы должны прочитать спецификацию чипа. Он сообщает вам, что представляют собой все регистры и что означают разные значения., @Majenko