1

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.

enter image description here

jsotola
1,5342 gold badges12 silver badges20 bronze badges
asked Jul 25, 2021 at 0:24

2 Answers 2

1

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.

answered Jul 25, 2021 at 9:17
-1

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

answered Jul 25, 2021 at 0:44
9
  • 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. Commented 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" Commented Jul 25, 2021 at 0:59
  • perfect ! charged ADMUX = 0x03 as ADMUX = 0x00, it works. Thank you. Commented 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? Commented Jul 25, 2021 at 1:33
  • Did you move the connection to A0? Also check any references to ADMUX. Commented Jul 25, 2021 at 1:35

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.