I'm only just beginning to learn Arduino programming. And I'm wanting to move on quickly with a project. So, I'm hoping someone I can get some help, in some way.
Can someone please tell me whether it is possible to use a potentiometer to vary the analoge voltage to pin A0, and produce a result such that when the voltage rises there is a change in output pin. So, for instance, the input voltage is 0.5v, D4 pin turns on at 5v, when the voltage reaches 1v D4 goes to 0v but D5 turns on at 5v, then when 1.5v is reached D5 goes to 0v and D6 goes to 5v. Thank you.
Hi. Thanks for the heads up on this. I'll get to grips this week with my programming skills, and then maybe I'll post my code, especially if I get stuck with things. Rich
Correct me if I'm wrong, but I think this sets data pin 4 (D4) to write to, and reads from analogue pin A0. Not sure what >> 9 is doing, but I'll try to figure. Certainly two greater than signs.
digitalWrite(4, analogRead(A0) >> 9);
Unless it should be:
digitalWrite(4), analogRead(A0) >> 9);
EDIT: Just thinking about this:
digitalWrite(4, HIGH); would set D4 pin to 5v.
It looks then, that the second part (HIGH) has been replaced (as it were) with "analogRead(A0) >> 9);"
True, I think. But I would have thought that the code would be setting pin 4 to a voltage, not a pin selection. Unless ">> 9" is the key to pin selection. I read that ">>" is shifting bits to the right.
EDIT: In order to understand this, I think I need to be able to calculate, or see what is in ADCH and ADCL, when A0 is 2.5V
EDIT: Wait: If analogueRead returns a 10 bit value at 5V equivalent to 1023, then if A0 is at 2.5V, this function would return decimal 511.5 or 512. That is in binary 100000000. Shifted 9 bits to the right, that gives a binary value of 1. So, a voltage of 2,5V ends up as 0000000001 in the register.
readAnalog returns values from 0 to 1023. 0 for 0 V and 1023 for 5 V. for 2,25 V it is 512 (in theory).
512 is 1000000000 in binary. every number smaller then 512 has in binary zero at position 10th and every number greater then 511 has a 1 on 10th position. so shift to right by 9 position gives you HIGH (1) for 512 and more and LOW (zero) for every value smaller then 512. and remember? 512 is 2,25 V.
Juraj:
readAnalog returns values from 0 to 1023. 0 for 0 V and 1023 for 5 V. for 2,25 V it is 512 (in theory).
512 is 1000000000 in binary. every number smaller then 512 has in binary zero at position 10th and every number greater then 511 has a 1 on 10th position. so shift to right by 9 position gives you HIGH (1) for 512 and more and LOW (zero) for every value smaller then 512. and remember? 512 is 2,25 V.
The call to analogRead takes about 1700 instruction times to complete, worrying about shift v. comparison
is not relevant here. Code should be easy to understand, so that subtle bugs have nowhere to hide.
I seem to be at a stage where I've got an understanding that when the voltage at pin A0 is 2.5V and the result of ADC conversion is read (by way of analogueRead), then right shifted 9 bits, we get the equivalent of writing - analogueWrite(4, 1).
Assuming that - digitalWrite(digitalPin, analogRead(analogPin) >> 9); - is heading me towards a solution to my problem, then somehow I've got to discover more. Because that code on it's own is clearly insufficient.
This table is more or less correct, it shows the 10 bit conversion results for every voltage 0.5V voltage step on pin A0, from 0 - 5V.
0.0V 0000000000
0.5V 00001100110
1.0V 0011001100
1.5V 0100110010
2.0V 0110011010
2.5V 1000000000 pin D4 as OUTPUT
3.0V 1001100110 pin D5 as OUTPUT
3.5V 1011001100 pin D6 as OUTPUT
4.0V 1100110010 pin D7 as OUTPUT
4.5V 1110011000 pin D8 as OUTPUT
5.0V 1111111111
Using analogueRead(), has got to result in change of digital output pin as voltage increases in these discrete steps. That is, as the analogue voltage increases in steps on A0, output must go, from (say) D4, to D5. And D4 must go to LOW, as D5 sets to HIGH.
I think I need another hint, or code. Book I'm reading is Programming Arduino Getting Started with Sketches, by Monk.
You could use the bit version but you end up chopping the 5V in 8 steps, not 10 (8 = 2^3) if you would use the three most significant bits, or a 6-bit right-shift. That would result in steps of 0.625V.
So basically:
reading = analogRead(A0) >> 6;
case (reading) {
switch 0: // 0-0.625V
// Set outputs.
break;
switch 1: // 0.625 - 1.25V
// Set outputs.
break;
// etc.
switch 7: // 4.375 - 5V
// Set outputs.
break;
}
Where I say "set outputs" you set one high, but don't forget to set all others back to LOW.
If the voltage ranges fit, great. Otherwise, a more flexible way is as I first suggested, a range of if statements:
float voltage = analogRead(A0) * 5.0 / 1024;
if (voltage < 0.5) {
// set outputs for 0-0.5V.
}
else if (voltage < 1.0) {
// set outputs for 0.5-1V.
}
// etc.
else if (voltage < 4.5) {
// set outputs for 4-4.5V.
}
else {
// set outputs for 4.5-5V.
}
As you have to set everything else to LOW and only one HIGH, you best do the outputs in a function.
// Define this as global variables.
byte outputs[] = {3, 4, 5, 6, 7, 8}
byte nOuputs = 6;
// Use this in the if statements - probably somewhere in loop().
setOutput(5); // set pin 5 high, the others low.
// And this is the actual function that sets the pins as needed.
void setOutput(byte pin) {
for (byte i = 0; i < nOutputs, i++) {
if (outputs[i] == pin} {
digitalWrite(pin, HIGH);
}
else {
digitalWrite(outputs[i], LOW);
}
}
}
Thanks wvmarie. Very much appreciate the effort put in to this. I'll use what you wrote to to effect a solution to my problem. Also, will use it as a sort of tutorial in my effort to learn Arduino programming. I was last night beginning to think about the need for the program to start by "asking" IF voltage on pin A0 is, THEN..... But, it would have taken me ages to have finally solved the problem or task, at this stage in my knowledge.
Something to be aware of: in this example I'm using floating point math to get to the voltage. This is much less efficient than integer math, which in turn is less efficient than a bitwise operation. The last is however the least readable.
You will see a major reduction in sketch size (this matters a lot when your sketch gets big!) by not using floating point math, so instead of calculating the voltage, you calculate yourself what voltage level corresponds to which reading, and use that in your if statements:
int reading = analogRead(A0);
if (reading < 52) {
// set outputs for 0-0.5V.
}
else if (reading < 102) {
// set outputs for 0.5-1V.
}
// etc.
At this stage it probably doesn't matter much if at all, but it's good to know.
With switch and case a match must occur between the thing that is variable and the case statement. If we don't right shift, the case statements used would need to be:
case 0:
case 128:
case 256:
case 384:
case 512:
case 640
case 768:
case 896
case 1023
But right shifting 6 places, the case statements need to be:
case 0:
case 2
case 4:
case 5:
case 8:
case 10:
case 12:
case 14:
case 15:
switch (var) {
case label1:
// statements
break;
case label2:
// statements
break;
default:
// statements
}
OKay, I think I now get the BIT shifting method:
I'm not so sure.
6 is the same as divide by 64 so case 5 for 384 is wrong. It would be case 6
Integer math with the divisions provides the ranges and if you don't divide the analogRead()value, but just use integer values as the cases you will not pick up the ranges.
Anyway, a 7 place shift produces the following voltage range:
Voltage Range Right Shifted Result
0.000000V - 0.6201125V 0
0.625V - 1.2451125V 1
Etc. up to ............................... 7
In other words, right shifting has produced a range. Any voltage between 0 and 0.6201125V, will produce a binary 0. Any voltage between 0.625V and 1.245125V wil produce a binary 1. And so on up to 5V.
And of course these results are being used with the switch and case statements, as in:
reading = analogueRead (A0) >> 7:
switch (reading) {
Case 0:
digitalWrite (4, HIGH).
break:
I think that would make pin D4 HIGH, if voltage on A0, is between 0.000000V - 0.6201125V.
I take the bit shifting technique simply as a way of reducing the range 0-1023, into a range of 8. I will have to think whether this is good for my project, or not.
No, your voltage calculations are wrong as it goes exponential, not linear. You not only should shift bits, but also clear any higher bits. Bit shifts are not the way to go for this use - just forget about it.
Here is another way to think about turning on pins D4-D12 individually at .5v increments on A0.
int voltage = analogRead(A0);
for (int i = 1; i < 10; ++i) {
int vstep = i * 102;
if ((voltage >= vstep) && (voltage < vstep+102)) { //voltage is at or above current step and less than next
digitalWrite(i+3,HIGH);
} else {
digitalWrite(i+3,LOW);
}
}
Please read the first post in any forum entitled how to use this forum. http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.