Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

4 Analog inputs on Atmega328p

Status
Not open for further replies.

johnny78

Full Member level 4
Joined
Jun 28, 2017
Messages
209
Helped
1
Reputation
2
Reaction score
4
Trophy points
18
Activity points
1,724
hi Guys

i was working on a project based on Atmega328p now im in the final part of it & i need to use 4 Analog inputs of it
1 : read push buttons
2 : read 2 Ntc's
3 : read the mains Voltage
& im using the internal 8Mhz oscillator
is that ok ?
can i read all of this inputs ?


thanks Guys
 

Hi,

I guess it´s O.K.
Guess, because we don´t know your requirements about sampling rate and accuracy, precision, resolution.
Guess, because I don´t have the complete datasheet in mind. I recommend you read it first and tell us what´s unclear.

1) usually I don´t need an analog input for reading push buttons. Why do you?
2) requirements?
3) mains is AC. What information of this "AC" do you want to measure? Requirements?

Klaus
 

Hi,

I guess it´s O.K.
Guess, because we don´t know your requirements about sampling rate and accuracy, precision, resolution.
Guess, because I don´t have the complete datasheet in mind. I recommend you read it first and tell us what´s unclear.

1) usually I don´t need an analog input for reading push buttons. Why do you?
2) requirements?
3) mains is AC. What information of this "AC" do you want to measure? Requirements?

Klaus
im using the analog input to read 5 buttons & i want to read the Ac mains through the transformer i can supply 12vdc throught a voltage devider to measure high & low mains voltage

thanks for reply
Johnny
 

Read 5 buttons on 1 pin -


1665402102913.png


OR this approach :

1665402193251.png


You have to work out the tolerances to set the code V range for each button.



Regards, Dana.
 
Read 5 buttons on 1 pin -


View attachment 179000

OR this approach :

View attachment 179001

You have to work out the tolerances to set the code V range for each button.



Regards, Dana.
thanks Dana you already have guided me to use this method of reading buttons & it works for me

regards
Johnny
 

Your question read all the inputs, yes, notwithstanding signal conditioning to use
A/D onboard to its full dynamic range where needed. This of course depends on
what you want from sensors, precision or just gross values.


Regards, Dana.
--- Updated ---

One way of doing the reads and tests :

1665406004035.png


This is mBlock, it converts your code blocks to Arduino code.


Regards, Dana.
 

thanks
i will test it

regards
Johnny
Your question read all the inputs, yes, notwithstanding signal conditioning to use
A/D onboard to its full dynamic range where needed. This of course depends on
what you want from sensors, precision or just gross values.


Regards, Dana.
--- Updated ---

One way of doing the reads and tests :

View attachment 179007

This is mBlock, it converts your code blocks to Arduino code.


Regards, Dana.
 

My error, the initialization of variables should occur as shown, not the
way I had it prior. Keep in mind the button test values I show are for
reference only, your design for the button and resistor values will
determine what you should use to generate the A/D values that you
will read and test against.

Same is true for the NCT1 & NCT2 readings, I show no actions
on therm once read. Thats where you do additional block code
or call a block subroutine to handle.
1665574570247.png



Regards, Dana.
--- Updated ---

This is how you would do a subroutine :

1665579988080.png


Regards, Dana.
--- Updated ---

Error in above, cannot edit because of auto merge, so here is correct config :

1665580200612.png



Regards, Dana.
 
Last edited:

My error, the initialization of variables should occur as shown, not the
way I had it prior. Keep in mind the button test values I show are for
reference only, your design for the button and resistor values will
determine what you should use to generate the A/D values that you
will read and test against.

Same is true for the NCT1 & NCT2 readings, I show no actions
on therm once read. Thats where you do additional block code
or call a block subroutine to handle.
View attachment 179066


Regards, Dana.
--- Updated ---

This is how you would do a subroutine :

View attachment 179067

Regards, Dana.
--- Updated ---

Error in above, cannot edit because of auto merge, so here is correct config :

View attachment 179068


Regards, Dana.
hi Dana
im still working on the Arduino IDE & i get some errors with push buttons
Sometimes the button gives the result of something else

is there any capacitor inside the Analog input of the MCU ?
because sometimes when i release a button it activates another action
so do you suggest to use delays or something to hardware?

regards
Johnny
 

Hi,

reading pushbuttons this style needs a bit "tolerant" software.
The input of the ADC is analog, it is not ON and OFF.

Errors:
* the resistors are not perfect, thus the expected voltage is not perfect.
* the ADC is not perfect it adds GAIN and OFFSET erros.
Your software needs to be "tolerant" to this erros.
Example:
Let´s say you expect a gain error of +/-2% and an offset error of +/-10 LSB
If you expect an ideal ADC value of 234 for a key, then you should care for 2% gain error = 5 (4.7) LSB and the offset error of 10 LSB: so the key should be valid for ADC values of "219 ... 249)

Also:
* there is a timing problem:
When you press or release a key the analog voltage at the ADC is not in zero time at the expected voltage. It needs some time to settle. Also key do bounce, this means they switch a couple of time until they are stable. This takes some milliseconds.

Example:
* when you press a key the voltage goes from one voltage (let´s expect it to represent 0 LSB) to another voltage (let´s say 234 LSB). So if you theretically do extremely fast conversions you get all values from: stable 0, 1, 2, 3, ... 233, stable 234.
Realistically you do a conversion at random time. And there is a little chance that you just do the conversion when the voltage travels from one (key) value to another. Then you get a false value. If you don´t validate it, then you may process code for the wrong key.

So my idea: Do the key press in an interrupt every 20ms (this usually covers all timing problems). And set the "key" valid when two consecutive conversions show the same key:
when the ADC values show: no_key, no_key, no_key, key1, key3, key3, key3...
* dismiss when the value changes from: no_key to key1
* dismiss when the value changes from: key1 to key3
* use "key3" after you see no change from key3 to key3

Klaus
 

    johnny78

    Points: 2
    Helpful Answer Positive Rating
Post your schematic and your code.

Normally one bounces the button in, then bounces it out, then acts
on the fact it was pressed. That should be the logical flow in your code.
Some designs that need a constant press of a button to effect an operation
would bounce in, do operation, then bounce out.

Bounce test times most folks do it around 50 - 100 mS. I have had switches
need > 500 mS they were so bad. Bounce caused by switch inertia and beam
flex and springs and.....

There is, on most embedded A/Ds, a sample and hold at the input of the ADC.
Essentially a cap that is charged by pin V and then "effectively" disconnected from
pin while conversion is in process. But it is relatively small C, pF range, so that
should not be an issue in your application.

All that being said what are the values of the R's in your button R ladder ? If they
are too high you could be experiencing crosstalk/noise pickup. Something in the
range of 1 - 10K appropriate.

ADC precautions in datasheet :

1665660805716.png


Note the caution of other processes inside ATMEGA generating noise. Effective technique
is to temporarily turn off those, such as PWM, driving leds from ports and other loads,.......
timers......

The ADC is 10 bits, depending on what you use for Vref each LSB is ~ a few mV. Look at
your supply rail using a DSO if you have one, on infinite persistence, bet you will see a
few 100's of mV of noise. So bypassing crucial. The following shows effective esr of various
C technologies :

1665661239354.png


OSCON in this chart are polymer tantalums, best bulk caps for bypassing after MLC's.


Regards, Dana.
 
Last edited:

    johnny78

    Points: 2
    Helpful Answer Positive Rating
hi Guys

i've added some delays to my code & its 99% ok with no problems
any suggestions for improvement of this code ?

Code:
void ButtonDelay() {
  ButtonsDelay ++;
  if ((ButtonsDelay) == 1500) {
    ButtonsBusy = 0;
    ButtonsDelay = 0;
  }
}

void loop() {

  int sensorValue = analogRead(A5);
 
  ///////////////////////////////////////////////////////////////
  if ((sensorValue) > 1000) { // && (ButtonsBusy) == 0) { //1023
    ButtonsBusy = 1;
    ButtonDelay();
    if ((sensorValue) > 1000 && (ButtonsBusy) == 0) { //1023
      NoButton = 0;
      PowerButton = 1;
      LedsDis = PowerLed;
    }
  }
  if ((sensorValue) > 930 && (sensorValue) < 940 ) {//848
    ButtonsBusy = 1;
    ButtonDelay();
    if ((sensorValue) > 930 && (sensorValue) < 940 && (ButtonsBusy) == 0) {//848
      NoButton = 0;
      SfButton = 1;
      LedsDis = SfLed;
    }
  }
  if ((sensorValue) > 730 && (sensorValue) < 745 ) {//649
    ButtonsBusy = 1;
    ButtonDelay();
    if ((sensorValue) > 730 && (sensorValue) < 745 && (ButtonsBusy) == 0) {//649
      NoButton = 0;
      AlarmButton = 1;
      LedsDis = AlarmLed;
    }
  }
  if ((sensorValue) > 785 && (sensorValue) < 799 ) {//689
    ButtonsBusy = 1;
    ButtonDelay();
    if ((sensorValue) > 785 && (sensorValue) < 799 && (ButtonsBusy) == 0) {//689
      NoButton = 0;
      DownButton = 1;
      LedsDis = DownLed;
    }
  }
  if ((sensorValue) > 855 && (sensorValue) < 865 ) {//749
    ButtonsBusy = 1;
    ButtonDelay();
    if ((sensorValue) > 855 && (sensorValue) < 865 && (ButtonsBusy) == 0) {//749
      NoButton = 0;
      UpButton = 1;
      LedsDis = UpLed;
    }
  }
  if ((sensorValue) < 460) {
    ButtonsDelay = 0;
    if ((sensorValue) < 460) {
      NoButton = 1;
      LedsDis = B00000000;
      InitializeButton();
    }
  }
  ///////////////////////////////////////////////////////////////

& i've used this schematic with 10k for each button & 100k pull down resistor


1665402193251.png


best regards
Johnny
--- Updated ---

Post your schematic and your code.

Normally one bounces the button in, then bounces it out, then acts
on the fact it was pressed. That should be the logical flow in your code.
Some designs that need a constant press of a button to effect an operation
would bounce in, do operation, then bounce out.

Bounce test times most folks do it around 50 - 100 mS. I have had switches
need > 500 mS they were so bad. Bounce caused by switch inertia and beam
flex and springs and.....

There is, on most embedded A/Ds, a sample and hold at the input of the ADC.
Essentially a cap that is charged by pin V and then "effectively" disconnected from
pin while conversion is in process. But it is relatively small C, pF range, so that
should not be an issue in your application.

All that being said what are the values of the R's in your button R ladder ? If they
are too high you could be experiencing crosstalk/noise pickup. Something in the
range of 1 - 10K appropriate.

ADC precautions in datasheet :

View attachment 179080

Note the caution of other processes inside ATMEGA generating noise. Effective technique
is to temporarily turn off those, such as PWM, driving leds from ports and other loads,.......
timers......

The ADC is 10 bits, depending on what you use for Vref each LSB is ~ a few mV. Look at
your supply rail using a DSO if you have one, on infinite persistence, bet you will see a
few 100's of mV of noise. So bypassing crucial. The following shows effective esr of various
C technologies :

View attachment 179081

OSCON in this chart are polymer tantalums, best bulk caps for bypassing after MLC's.


Regards, Dana.
im working on the hardware & thanks for mentioning about noise cancelling techniques

i've used A5,A4,A3 for reading NTC's with Pull up resistor
& A2 for reading Buttons's with pull down Resistor & A1 for sensing mains voltage from voltage devider resisrtors
Now A0 isnt connected on board i was thinking to set it as output & set it to low
is my setup ok ?

best regards
Johnny
 
Last edited:

Hi,

your solution
* uses more code than an interrupt one
* uses alot more processing power (I guess 1000 times)
* has big impact to the timing on the main loop
* needs to be sequentially start by the main loop
* covers just 99% of problems

Interrupt solution:
* write it once, test it, forget about it. (no need for sequentially starting it. Runs in background, and a runtime of maybe 10us every 20ms (0.05%) of processing power usually creates no timing problem in the main loop
* no need to sequentially start it from main loop. Just process the "button variable" at the code line you want to.
* reuse it in other projects

But every programmer has it´s own style. As long as it fits your needs it´s O.K.

Klaus
 
This basic code group should be made into a subroutine :




Code:
  if ((sensorValue) > 930 && (sensorValue) < 940 ) {//848
    ButtonsBusy = 1;
    ButtonDelay();
    if ((sensorValue) > 930 && (sensorValue) < 940 && (ButtonsBusy) == 0) {//848
      NoButton = 0;
      SfButton = 1;
      LedsDis = SfLed;
    }
  }

with a call like

Code:
SfButton = ChkKey(930, 940);

and a return if button number found. Note if you do use interrupts
dont forget to declare variables used in interrupt global and volatile.
Also the button test values should be >> a span of 10 due to A/D
error, R error. You need to worst case to determine those values.

Not clear to me if you are bouncing button out before you act on button.
You would do this if holding down button is not used to repeatedly
increment some machine variable or state.

Note normally you would :

Code:
void ButtonDelay() {
  ButtonsDelay ++;
  if ((ButtonsDelay) == 1500) {
    ButtonsBusy = 0;
    ButtonsDelay = 0;
  }
}

change the 1500 test to (especially if using interrupts)

void ButtonDelay() {
  ButtonsDelay ++;
  if ((ButtonsDelay) > 1500) {
    ButtonsBusy = 0;
    ButtonsDelay = 0;
  }
}

With regard interrupts, good programming style is to not
make f() calls within the interrupt because you get a lot of
stack thrashing and lose thruput due to that. Can wreak
havoc with real time processes. Simply set flags in the interrupt
and then process those in main().

Here is a discussion on interrupts, a different processor, but principles
the same.


Lastly your programming style lacks comments, a recipe for disaster.
Always take time to comment, functionality, what vars are used for......

Regards, Dana.
 
Last edited:

Hi,

with a call like

Code:

ChkKey(930, 940);

I´m far from being a good programmer, but I try to improve.
But more and more I use constants defined at the beginning instead of using fix numbers in code.
So one could decalare:
const uint16_t chkKeyLow[] = {1000, 930, 785, 745 and so on};
if you use a static counter variable (for keys 0..5) inside the ChkKey() function you even don´t need to pass a parameter.

***
Note if you do use interrupts
dont forget to declare variables used in interrupt global and volatile.
I like to go more into detail with this.
you need "volatile" only when both statements
* the variable is modified in the ISR
* the variable is read / used in MAIN or other ISRs
are true.

Klaus
 

I too try to improve -

One could use a computed variable to test for buttons, rather than constants,
and a cal routine to remove some of the error due to R's.

Use of volatile (including reasons, when and where to use it....) :



And of course enumeration for constants :


Almost forgot, turn the byte vars used for keys into bit variables to save memory,
so many choices, so many alternatives....write it all in ASM......



Regards, Dana.
 
Last edited:
i´m far from being a good programmer, but I try to improve.
But more and more I use constants defined at the beginning instead of using fix numbers in code.
So one could decalare:
Actually i cant work more than 3 hours at morning then my brain stops responding
& now its break time having fun with both of you Guys

you could help me with this
i use TimerOne library for Arduino sometimes
would you check this code for me ?
when timer starts it count seconds which i can see on serial monitor But when button is pressed the seconds counting goes X5 or more faster

Code:
setup(){
Timer1.initialize(125000);
  Timer1.attachInterrupt(callback);
  Timer1.stop();
  Serial.begin(9600);
}
void callback() {
  interrupter ++;
  halfSeconds = (interrupter / 4);
  seconds = (interrupter / 8);
  minutes = (seconds / 60);
}
void loop() {

  int sensorValue = analogRead(A5);
Serial.println(seconds);
  ///////////////////////////////////////////////////////////////
  if ((sensorValue) > 1000) { // && (ButtonsBusy) == 0) { //1023
    //ButtonsBusy = 1;
    Timer1.start();
    //ButtonDelay();
    if ((seconds) >= 15) {
      if ((sensorValue) > 1000 && (ButtonsBusy) == 0) { //1023
        NoButton = 0;
        PowerButton = 1;
        LedsDis = PowerLed;
        Timer1.stop();
        seconds = 0;
      }
    }
  }
code
& would you please check the hardware analog inputs setup in post13

thanks
Johnny
 

Hi,

what´s the idea behind timer1.stop?

Again code completely without comments. We need to spend a lot of time to find out what you want to do.
Don´t make it unnecessary difficult for us.

where is the variable declaration part?
Please show complete informations.

Klaus
 

Actually i cant work more than 3 hours at morning then my brain stops responding
& now its break time having fun with both of you Guys

you could help me with this
i use TimerOne library for Arduino sometimes
would you check this code for me ?
when timer starts it count seconds which i can see on serial monitor But when button is pressed the seconds counting goes X5 or more faster
here i ue TimerOne library for arduino
the start & stop are for Timer 1 counting start or stop
Code:
[/QUOTE]
[QUOTE="johnny78, post: 1742794, member: 596109"]
setup(){
Timer1.initialize(125000);                        // 1000000 = 1 second
  Timer1.attachInterrupt(callback);
  Timer1.stop(); //stops TimerOne counting
  Serial.begin(9600);
}
[/QUOTE]

[QUOTE="johnny78, post: 1742794, member: 596109"]

void callback() {// the isr of TimerOne library
  interrupter ++;                          //every 0.1.25 second
  halfSeconds = (interrupter / 4);
  seconds = (interrupter / 8);
  minutes = (seconds / 60);
}
void loop() {

  int sensorValue = analogRead(A5);
Serial.println(seconds);
  ///////////////////////////////////////////////////////////////
  if ((sensorValue) > 1000) { //1023 the power button
    Timer1.start(); // start run timerOne
    if ((seconds) >= 15) ;
      if ((sensorValue) > 1000) { //1023
        PowerButton = 1;
        LedsDis = PowerLed;   // display result on led declared at  the start (int PowerLed = B00010000);
        Timer1.stop(); stop count the timerOne
        seconds = 0; //Reset the seconds to 0 for new count
      }
    }
  }
code
& would you please check the hardware analog inputs setup in post13

thanks
Johnny
hi Klaus
im using TimerOne library which i've used in some projects long time ago
i will do some tests to check what kind of problem is that

But would you please check the Analog inputs for me ?
3 pins = A6,A5,A4 of the 6 inputs are Pulled up via 3k resistor to read the ntc's
1 pin = A3 is pulled down via voltage devider circuit to measure the +12v after the transformer
1 pin = A2 is the analog input of push buttons which its pulled down via 100k resistor
1 pin = A0 not connected (was thinking of setting it as output & set to low)

is that ok for analog inputs ?

thanks
Johnny
 
Last edited:

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top