Analog reading whit registers

Hey,

I have tried to read the analog input with register manipulation. But my problem is that when I try to read the values ​​with a potentiometer, I manage to turn the potentiometer only halfway when the reading has already reached 5 volts. But while I use the traditional analog reading command I get the voltage reading for the whole round and not just the first half of the round. What can cause this problem?

my hardware
arduino Uno
20k potentiometer

This is how I connected the potentiometer to arduino

potentiometer

Code what I use is from Electronoobs

void setup() {
  Serial.begin(9600); 
}  

void loop() {  
  //REFS1 AND REFS0 to 1 1 -> internal 1.1V refference
  ADMUX |= B11000000;   
  //We read A2 (MUX0)
  ADMUX |= B00000100;      
 
  // Start AD conversion
  ADCSRA |= B11000000;
  // Detect end-of-conversion
  while (bit_is_set(ADCSRA,ADSC));
  int val = ADCL | (ADCH << 8);
  float voltage = val * (5 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
}

My guess is the second assignment to ADMUX negates the first.

Its been a long time since I've done register manipulation so I can't provide code suggestions.

You are turning the 1.1V reference voltage on and you have wired to pot to 5V so yes you will get a full reading part way round the pot.

This open my mind i connetc 5v to Aref pin and chance code like this and it work.

void setup() {
  Serial.begin(9600); 
}  

void loop() {  
  //REFS1 AND REFS0 to 1 1 -> internal 1.1V refference
  //ADMUX |= B00000010;   
  //We read A1 (MUX0)
  ADMUX |= B00000010;      
 
  // Start AD conversion
  ADCSRA |= B11000000;
  // Detect end-of-conversion
  while (bit_is_set(ADCSRA,ADSC));
  int val = ADCL | (ADCH << 8);
  float voltage = val * (5 / 1023.0);
  // print out the value you read:
  Serial.println(voltage);
}

Guess (or look) again. Those are compound assignment operators. So same as

ADMUX = ADMUX | B11000000;
ADMUX = ADMUX | B0000100;

@penispena I see the second constant is only 7 bits, is the correct bit being set in the second assignment?

a7

Your correct, My programming skills are poor at best. I will keep to hardware advice :slight_smile:

No need to do that. Did you try it without?

By the way your use of the logic operators is wrong.
For example you use:-

Let's look at exactly what this will do.

what you have here is in effect
register = register, logic operation, mask
Where in this case register is ADMUX, logic operator is the bitwise OR, and the mask is B00000010.

What the bitwise OR operation will do is to SELECTIVELY set bits to one while leaving other bits unchanged.
So if you do
ADMUX |= B00000010; // set channel 2
and some time later
ADMUX |= B00000100; // set channel 4
Then the value in ADMUX is Bxxxxx11x where the x is the logic level of the bits that were already in the register to begin with. So assuming the least significant bit was a 0 to begin with you will have changed the input channel to channel 6 not 4 like you might think.

So the rule for a bitwise OR is that:-
A one in the mask sets the corresponding bit to a one in the result ( register ).
A zero in the mask leaves the corresponding bit in the register unchanged.

So suppose you actually want to set just the channel it will involve selectively setting some bits to one and other bits to zero, which you can't do with just the bitwise OR.

To selectively set bits to zero you need to use the bitwise AND operation. The rule for using that is
A zero in the mask sets the corresponding bit a zero in the result ( register ).
A one in the mask leaves the corresponding bit in the register unchanged.

So in order to set a channel to a value you need an AND operation to clear out the three bits that define the channel and then you need an OR operation to set to one the bits in the channel number that are one.

So setting a channel requires two operations
ADMUX &= B1111000; // clear out the channel select bits
ADMUX |= B00000010; // set the channel select to what you want.

But suppose your channel number is in a variable? You can still use this method. This is an example of how a grown up would do it using hexadecimal to describe the numbers involved. Suppose the channel you want is in a variable called chn

ADMUX &= 0xF8; // clear out the channel select bits
ADMUX |= chn; // set the channel select to what is in the variable

That way you won't be back asking why the channel is not being set correctly. :wink:

If you know what all the bits in a register need to be set to just use the = operation by itself, no need to use any logic operators.

Yes, THX @Grumpy_Mike for breaking this down.


Many times you will see that written like this

ADMUX &= ~B111; // clear out the channel select bits

which does the same and avoids a possible problem when variable lengths are different numbers of bits. No problem with either expression in this case.

And the belt and suspenders crowd might write the above as

ADMUX |= (chn &0x7);  // set the channel select

so chn can influence only the three bits it should. I guess the B&S ppl might even range check chn instead of crudely chopping it down to size…

a7