Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.

Re: Ok, more programming help........

cashman04 wrote:Wow,

Code: Select all | TOGGLE FULL SIZE
`value1 = (analogRead(sensePin1) / 150) + 1;`

Ya, I'd say thats a bit more elegant.

My only question on that though is this-

Ok, so lets go through the math of that code-

sensePin1=150

150/150 =1

1+1=2

value1 = 2

Now that does get me the number I want=2. But I don't know how to out put the number 2 directly to the 7- segment display.

I have to output B01110011 so it will display the number 2.
Now finally my question-
How can I do my -
Code: Select all | TOGGLE FULL SIZE
`shiftOut(dataPin, clockPin,MSBFIRST,  value1);`

shift out code so that it knows to output B01110011 when value1 = 2 ?

Two things:

First, I'm taking advantage of integer division in Arduino. 150/150 = 1, but 149/150 = 0 in integer division. It always rounds down, (they actually just call it decimal truncation, but tomato tomahto.)

Second, now that you've got your number, THAT's when you reference your font_table variable, going to font_table[2], so you call:

Code: Select all | TOGGLE FULL SIZE
`shiftOut(dataPin, clockPin,MSBFIRST,  font_table[value1]);`
Red M&M, Blue M&M: They all wind up the same color

stinkbutt

Posts: 593
Joined: Wed Feb 17, 2010 2:40 am

Re: Ok, more programming help........

oPossum wrote:Why should it be a global?

It doesn't have to be, but if it's a constant, you'll need to re-declare it every time you want to assign it. Since it's being called in a loop, that's a waste of resources, constantly allocating and then de-allocating a variable at the beginning & end of the loop. Better to be global at least with respect to the loop, if not totally global.

My philosophy is that if the variable references a global thing, like the value of a pin, it should be global. If it is a temporary value to be discarded later it shouldn't be. But sure, it doesn't absolutely need to be global. It's just more elegant from my personal programming philosophy (yes, I know global variables are bad, but this ain't Java or some real OO language.)

Plus, it's much easier for me to make clearer to cashman the difference between declaration and assignment if I do it in different code blocks. This also means I don't have to explain scope to the guy who is new to programming. We can work our way to that later. For now I'm just worried about explaining variables, and improving his code.

Ultimately, though, no, it's doesn't have to be global. You're absolutely right.
Red M&M, Blue M&M: They all wind up the same color

stinkbutt

Posts: 593
Joined: Wed Feb 17, 2010 2:40 am

Re: Ok, more programming help........

Complete code....

Code: Select all | TOGGLE FULL SIZE
`//2 7-segment displays multiplexed run through a tilt shift register//input from pot displaying from 0-9 on display1//input from photoresistor displaying 0-9 on display 2const int sensePin1 = 0; // analog input from potconst int sensePin2 = 1; // analog input from photoresistorconst int dataPin = 2;const int clockPin = 3;const int latchPin = 4;const int gnd1 = 12;const int gnd2 = 13;const int timer = 500;void setup() {  pinMode(sensePin1, INPUT);  pinMode(sensePin2, INPUT);  pinMode(latchPin, OUTPUT);  pinMode(clockPin, OUTPUT);  pinMode(dataPin, OUTPUT);  pinMode(gnd1, OUTPUT);  pinMode(gnd2, OUTPUT);  Serial.begin(9600);}byte map_analog(const int an){    static const byte font_table[] =    {        B10111011,        B00001010,        B01110011,        B01011011,        B11001010,        B11011001,        B11111000,        B00001011,        B11111011,        B11011011,    };    const int n = (an + 149) / 150;    if((n < 0) || (n >= (sizeof(font_table) / sizeof(font_table[0]))) return 0;    return font_table[n];}void loop() {  for (int i=0; i<timer; i++){     digitalWrite(latchPin, LOW);    shiftOut(dataPin, clockPin, MSBFIRST, map_analog(analogRead(sensePin1)));    digitalWrite(latchPin, HIGH);    digitalWrite(gnd1, LOW);    delay(1);    digitalWrite(gnd1, HIGH);         digitalWrite(latchPin, LOW);    shiftOut(dataPin, clockPin, MSBFIRST, map_analog(analogRead(sensePin2)));    digitalWrite(latchPin, HIGH);    digitalWrite(gnd2, LOW);    delay(1);    digitalWrite(gnd2, HIGH);  }}`
Last edited by oPossum on Sun Nov 28, 2010 6:28 pm, edited 2 times in total.
I am the Possum, and I approve of this message. Sent from MacBook Wheel Sorry for my bad German.
oPossum

Posts: 636
Joined: Fri Oct 26, 2007 12:42 am
Location: Michigan, USA

Re: Ok, more programming help........

Get rid of the superfluous comma at the end of font_table
Red M&M, Blue M&M: They all wind up the same color

stinkbutt

Posts: 593
Joined: Wed Feb 17, 2010 2:40 am

Re: Ok, more programming help........

Ya, I read through the link you gave on variables. For me, it seems simpler just to make variables global for now. When it came to declaring them in the scope of the loop, or even in the setup, it just seemed to make it more complicated to me.
cashman04

Posts: 25
Joined: Fri Nov 19, 2010 7:04 pm

Re: Ok, more programming help........

That's pretty much why I didn't worry about it. Strictly speaking Possum's right that you should keep your variables as local as you can, but you do what you have to.
Red M&M, Blue M&M: They all wind up the same color

stinkbutt

Posts: 593
Joined: Wed Feb 17, 2010 2:40 am

Re: Ok, more programming help........

OK, wow, so that works perfectly.

But now, I am a bit confused of what exactly is happening, lol.

Code: Select all | TOGGLE FULL SIZE
`byte map_analog(const int an) {   const int n = (an + 149) / 150;   if((n < 0) || (n >= (sizeof(font_table) / sizeof(font_table[0])))) return 0;   return font_table[n];`

Mainly this I think is a bit beyond me still. its basically solving for n. Then putting it in font_table[n] to call to the binary of the number correct?
What is the (sizeof(font_table) doing exactly? Thats where this really confuses me. Also, and I see where you declare "an" as a variable, but where is it getting its value from. To me it would make sense if an equaled the analog input, but I don't see how it is going about that.

Thanks again for all the help. Im just trying to understand it better, so I can go about doing something else even harder with it, lol. All for learning.
cashman04

Posts: 25
Joined: Fri Nov 19, 2010 7:04 pm

Re: Ok, more programming help........

Code: Select all | TOGGLE FULL SIZE
`//2 7-segment displays multiplexed run through a tilt shift register//input from pot displaying from 0-9 on display1//input from photoresistor displaying 0-9 on display 2// Declare pin usage// Must not change, so declared constconst int sensePin1 = 0; // analog input from potconst int sensePin2 = 1; // analog input from photoresistorconst int dataPin = 2;const int clockPin = 3;const int latchPin = 4;const int gnd1 = 12;const int gnd2 = 13;const int timer = 500;void setup() {  Serial.begin(9600);  pinMode(sensePin1, INPUT);  pinMode(sensePin2, INPUT);  pinMode(latchPin, OUTPUT);  pinMode(clockPin, OUTPUT);  pinMode(dataPin, OUTPUT);  pinMode(gnd1, OUTPUT);  pinMode(gnd2, OUTPUT);}// Convert an analog value to a 7 segment digitbyte map_analog(const int an){   // Table of 7 segment charaters   // This must never be changed by the program, so it is declated const   // This can be retained between calls, so it is declared static    static const byte font_table[] =    {        B10111011,   // 0        B00001010,   // 1        B01110011,   // 2        B01011011,   // 3        B11001010,   // 4        B11011001,   // 5        B11111000,   // 6        B00001011,   // 7        B11111011,   // 8        B11011011,   // 9    };   // Caculate a font table index   // 0 -> 0   // 1 to 150 -> 1   // 151 to 300 -> 2   // etc...    const int n = (an + 149) / 150;   // Limit to the size of the font table   // Return zero if out of bounds    if((n < 0) || (n >= (sizeof(font_table) / sizeof(font_table[0]))) return 0;   // Return the 7 segment digit    return font_table[n];}// Read the analog pin, convert to 7 segment digit, and shift outvoid show_analog_digit(int analog_pin, int ground_pin){    digitalWrite(latchPin, LOW);    shiftOut(dataPin, clockPin, MSBFIRST, map_analog(analogRead(analog_pin)));    digitalWrite(latchPin, HIGH);    digitalWrite(ground_pin, LOW);    delay(1);    digitalWrite(ground_pin, HIGH); }void loop() {  int i = timer;  while(i--) {    show_analog_digit(sensePin1, gnd1);    show_analog_digit(sensePin2, gnd2);  }}`
Last edited by oPossum on Sun Nov 28, 2010 7:22 pm, edited 2 times in total.
I am the Possum, and I approve of this message. Sent from MacBook Wheel Sorry for my bad German.
oPossum

Posts: 636
Joined: Fri Oct 26, 2007 12:42 am
Location: Michigan, USA

Re: Ok, more programming help........

cashman04 wrote:OK, wow, so that works perfectly.

But now, I am a bit confused of what exactly is happening, lol.

Code: Select all | TOGGLE FULL SIZE
`byte map_analog(const int an) {   const int n = (an + 149) / 150;   if((n < 0) || (n >= (sizeof(font_table) / sizeof(font_table[0])))) return 0;   return font_table[n];`

Mainly this I think is a bit beyond me still. its basically solving for n. Then putting it in font_table[n] to call to the binary of the number correct?
What is the (sizeof(font_table) doing exactly?

sizeof(font_table) is the number of bytes in the table
sizeof(font_table[0]) is the size of each entry
so, sizeof(font_table) / sizeof(font_table[0]) will be the number of entries in font_table

The array index in the variable n is compared to the number of entires to make sure it is not too large, to prevent accessing an array element that does not exist. That can cause a program to crash or behave strangely. The function will return immediately if it is too large or below zero.

It it is within range, then it is used as an index into the font_table array. If n is 3, the the fourth entry will be returned. C is a zero based language, so an index of 0 would return the first element, 1 the second, etc...

Also, and I see where you declare "an" as a variable, but where is it getting its value from. To me it would make sense if an equaled the analog input, but I don't see how it is going about that.

It is passed to the function.

So this line...

will call analogRead() and the returned value will be passed to map_analog() in the variable an.
The value must not be changed (once it is read), so it is declared const.
I am the Possum, and I approve of this message. Sent from MacBook Wheel Sorry for my bad German.
oPossum

Posts: 636
Joined: Fri Oct 26, 2007 12:42 am
Location: Michigan, USA

Re: Ok, more programming help........

AHHHHHHH.

Ok, I see what you did now. I didn't get the whole font table index thing. Wow, that a clever way to do it. Completely different than I was going about it. But no surprise there. Wow, thanks for teaching all that to me guys!

Now, time to play with it some more to figure out all the code exactly.. Then, time to make it more difficult somehow. I'm thinking I'll just throw another multiplexed digit on there, and find something else to display on it....... any suggestions?

Thanks a bunch for helping me understand this all.

Edit: you posted more as I was typing this. I completely get the size of table now. I was getting a blank display when doing up to high on the potentiometer, So i just mapped the values to 0-1000. And then adjusted the +149 and /150 a little bit so that It won't go over the numbers in the table. Now i get a smooth 0-9 for each of the imputs low to high.
cashman04

Posts: 25
Joined: Fri Nov 19, 2010 7:04 pm

Re: Ok, more programming help........

Ok, another question.

I had a thought on a different way to try and do it all.

Since it is right now just taking a number from 0-1024, and dividing to take it down to a single digit between 0-9, and then taking the result and outputting the declared binary for 0-9, then why can't I just map the 2 inputs from 0-1024, to 0-9 with the map function.

Code: Select all | TOGGLE FULL SIZE
`byte map_analog(const int an) {      if((an < 0) || (an >= (sizeof(font_table) / sizeof(font_table[1])))) return 0;   return font_table[an]; }  void loop() {  int pot = (analogRead(sensePin1));  map(pot, 0, 1023, 0, 9);  int photo = (analogRead(sensePin2));  map(photo, 10, 1023, 0, 9);   Serial.println(pot);  Serial.println(photo);      for (int i=0; i<timer; i++){    digitalWrite(latchPin, LOW);    shiftOut(dataPin, clockPin, MSBFIRST, map_analog(pot));    digitalWrite(latchPin, HIGH);    digitalWrite(gnd1, LOW);    delay(1);    digitalWrite(gnd1, HIGH);       digitalWrite(latchPin, LOW);    shiftOut(dataPin, clockPin, MSBFIRST, map_analog(photo));    digitalWrite(latchPin, HIGH);    digitalWrite(gnd2, LOW);    delay(1);    digitalWrite(gnd2, HIGH);  }}`

Above is what I changed. Yet for some reason on the serial print, it is still displaying 0-1024. The way I though the map worked is it would convert 0-1024 to 0-9 automatically.
My only thought on why it isn't working is cause the map values are being declared in the loop() and not above. I tried putting it up there also, but still didn't work.

Any thoughts on why this isn't working. Or maybe I just don't understand the map thing correctly.
cashman04

Posts: 25
Joined: Fri Nov 19, 2010 7:04 pm

Re: Ok, more programming help........

You're doing everything right.

EXCEPT you're ignoring the return value of the map() function.

Try this:

Code: Select all | TOGGLE FULL SIZE
`void loop() {  int pot = (analogRead(sensePin1));  pot = map(pot, 0, 1023, 0, 9);  int photo = (analogRead(sensePin2));  photo = map(photo, 10, 1023, 0, 9);  Serial.println(pot);  ...`

The map() function does not actually change the value of the variable passed to it. It RETURNS the mapped value. You can see that here, in the appendix of the function definition page.

What your original code was doing was calling the map() function, but then just throwing away the value it returned. Oh, and as an homage to oPossum, here's the same code using constants:

Code: Select all | TOGGLE FULL SIZE
`void loop() {  const int pot = map( analogRead(sensePin1), 0, 1023, 0, 9 );  const int photo = map( analogRead(sensePin2), 10, 1023, 0, 9);  Serial.println(pot);  ...`

As a general rule, you will rarely find functions that attempt to change the value of the variables passed into them. Instead, they will usually just return the new value. For example, you could take a number and divide it by two like this:

Code: Select all | TOGGLE FULL SIZE
`void divide_by_two( int numerator ){  numerator /= 2;}`

or like this:

Code: Select all | TOGGLE FULL SIZE
`int divide_by_two( int numerator ){  return numerator/2;}`

In the first case you're modifying the passed in number, in the second you're just returning the value of the argument (numerator) divided by 2 and leaving it to the programmer to decide what the hell to do with it.

There are a variety of reasons to do it the second way. The first is just convention - If every function just returns the answer, then people who use and re-use existing code know how the function is going to behave. More importantly, in order to implement the function the first way, you need to pass variables by reference. C doesn't normally do that. See, there are two ways to handle passing a variable as an argument to a function. You can pass by value, or pass by reference. When you pass by value you just make a copy of the value of the variable, essentially creating a new variable with the same value, and send it to the function. When you pass by reference you copy a pointer to the memory location of the variable into the function to allow that function to modify the variable directly.

Not only does C not normally pass by reference, but it's bad programming practice to do so: It's too easy to fuck it up and end up with non-deterministic results, because the decision to change a variable should lie at the level of code where the variable is being actually written and re-written, not nested inside some function that you may not have ever written to begin with. Remember a lot of this code is intended to be re-used by other people, (like you in the case of the map() function,) and modifying a variable inside the function would seem like hoodoo if you didn't expect it.

Frankly, I'm not even sure if Arduino can pass by reference. And if it did, it'd probably require pointers. I'm not going to tell you what pointers are. All I'm going to tell you is STAY THE FUCK AWAY FROM POINTERS. Pointers are the most arcane, intimidating, confusing piles of shit you'll ever encounter when you program. Pointers are not for the faint of heart, they're not for beginners. Pointers are like lawyers; We tolerate them only because it's impossible to live without them, but we'd be much happier if the world didn't need them. Pointers make the Baby Jesus cry.
Red M&M, Blue M&M: They all wind up the same color

stinkbutt

Posts: 593
Joined: Wed Feb 17, 2010 2:40 am

Re: Ok, more programming help........

I see what you mean there. Cool.

I had to read this a few times till it finally sank in.
t's too easy to fuck it up and end up with non-deterministic results, because the decision to change a variable should lie at the level of code where the variable is being actually written and re-written, not nested inside some function that you may not have ever written to begin with.

I'll try and remember that, cause right now, that pretty much what I have been doing. Just going from one thing to another, reusing code I had used before.

Thanks for the lesson.

Oh and it worked, of course. I had just been thinking about trying to find different ways to do thing and though that one seemed kinda like the most obvious choice.
cashman04

Posts: 25
Joined: Fri Nov 19, 2010 7:04 pm

Re: Ok, more programming help........

OK, I think I may have missed a HUGE one along the way somewhere.
So I multiplexed in a 3rd display, and have a temp sensor going to it. All I get returned is 0 though. I think I know why. When defining my pins I have this.

Code: Select all | TOGGLE FULL SIZE
`const int sensePin1 = 0; // analog input from potconst int sensePin2 = 1; // analog input from photoresistorconst int sensePin3 = 2; // analog input form temp sensorconst int dataPin = 2;const int clockPin = 3;const int latchPin = 4;const int gnd1 = 12;const int gnd2 = 13;const int gnd3 = 11;`

Now, I am using analog pin 2, AND digital pin 2. How do I define the difference? Or is it as simple as when using an analog pin, I can't use the same digital pin?
cashman04

Posts: 25
Joined: Fri Nov 19, 2010 7:04 pm

Re: Ok, more programming help........

I think we're going to need more code than that to determine what's wrong. A wiring diagram as well.

Plus, have you considered the possibility the problem is your temperature sensor's wired up backwards? Perhaps it's outputting a voltage for you, but in backwards it appears as a negative voltage which would cap out at zero.
Red M&M, Blue M&M: They all wind up the same color

stinkbutt

Posts: 593
Joined: Wed Feb 17, 2010 2:40 am