I am try to build this AC-DC meter, the code original used default A3 as input, how can change the input on A0? the link: https://simple-circuit.com/arduino-autoranging-ac-dc-voltmeter-with-trms/
Thanks for help Adam
/**************************************************************************
*
* 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.
2 Answers 2
The input to the ADC is selected by the four least-significant bits of
the "ADC Multiplexer Selection Register", aka ADMUX
. It is set to
analog input 3 by this line of code:
ADMUX = 0x03;
Change this line to ADMUX = 0;
and the ADC will read pin A0.
Your code is to hard to read, it is just a blob of characters on my screen but you have a pretty picture of the arduino. Change your code to use A0 instead of A3. Change your physical connection from A3 to A0 and you are all set. I miss read the code you posted.
It is a tricky circuit and he did all of the the registers directly, making it extremely hard to follow. I do not know the register set well enough to speak knowledgeable about what he is doing. The Optocouplers short out parts of the input divider network which he selects in his code. This is how he does the ranging. The optocouplers are drawn in reverse with the output on the left and the input on the right. Try this link to Nick Gammon's site: https://www.gammon.com.au/adc Also try this one: https://www.arduino.cc/en/Reference/PortManipulation
-
Thanks. Can you tell how to post a code better? There is not a A3, in the code, cause of it is default. that's why I don't how to change.oldbin– oldbin2021年07月25日 00:46:25 +00:00Commented Jul 25, 2021 at 0:46
-
I have never done so at this point I will not try to explain it. There are many others that do a better job then I can. ADMUX = 0x03; Is one of the statements I believe you need to change it to ADMUX = 0x00; Let us know how you did? I chased the circuit back to simple circuits where somebody asked the same question. There answer was close to mine. " If you need to change A3 to A0 you must change the analog pin definition in the code"Gil– Gil2021年07月25日 00:59:46 +00:00Commented Jul 25, 2021 at 0:59
-
perfect ! charged ADMUX = 0x03 as ADMUX = 0x00, it works. Thank you.oldbin– oldbin2021年07月25日 01:18:19 +00:00Commented Jul 25, 2021 at 1:18
-
Actually, charged ADMUX = 0x03 as ADMUX = 0x02, A2 as input; but charged ADMUX = 0x03 as ADMUX = 0x01, A1-A7 non of as input works! WHY?oldbin– oldbin2021年07月25日 01:33:23 +00:00Commented Jul 25, 2021 at 1:33
-
Did you move the connection to A0? Also check any references to ADMUX.Gil– Gil2021年07月25日 01:35:21 +00:00Commented Jul 25, 2021 at 1:35
Explore related questions
See similar questions with these tags.