64 posts / 0 new

## Pages

Author
Message

Back in the day a very common trick to measure pots was with a VR method. I'm trying to accomplish this without a 555 timer using just a micro controller and cap. I'm thinking this may not work well because each lead (the out and the in) will be balanced at some point but I have had some success so far. Currently, what is getting in the way, is when I measure more then one pot. Pot 1 is fighting with 3? The Gameport pinout shows that x and y share the same +5 as do x2 and y2. In my design all for pots share the same power lead and I not sure but possibly I need to use at-lease two separate leads for that.

Hardware

C1=1200pf

VR 1-100k ohms

volts (powered from mcu)

IC atmega3289

a pc game port controller. (lots of schematics on line for this). It is just a 1-100k POT connected via two wires.

my time constant.

 Time constant ~120 microseconds Rise time from 20% to 80% 168 microseconds Rise time from 10% to 90% ~264 microseconds 3dB cutoff frequency ~1.326291 kilohertz

PORTD 0x80 is the lead I'm measuring from and has the Cap on it.

PORTC's 0-3 are my pots.

My thought is begin by bring one of the PORTC lines hi, waiting 1ms or so and then bring it low, then loop and discharge through the resister until PORTD 0x08 reads lo and return the value.

code example that does work but has the issue I mentioned above.  If I disconnect all pots but one of them, that pot read a perfect value.

unsigned char getvalue (POT)

{

unsigned char i=0;

DDRC = POT;//keep this line out at all times.
PORTC = 0;//bring the line lo ( and all other as they seem to be interfering).
for (;i<254;i++)//  now start the count (127us max)
{
if (!(PIND & 0x08 )) break;
}
PORTC = POT;//bring only the target pot lead hi
PORTD &= ~0x08;DDRD &= ~0x08;// set for read (I must hold this line lo or I get a strange result, I can explain if needed).
return i;

}

main()

{

getvalue ();

_delay_ms(1)

doStuff();

}

The pc joystick is 4 oneshots with a variable R and a fixed C. A write to the port triggers all 4 oneshots, and the driver/readtheoneshots subroutine hangs in a loop reading the 4 oneshot outputs, and remembering/saving the loops that each channel takes, which is the x or y position of that pot. Why don't you just hook the joystick up to two regular pots and read them with an a/d?

Imagecraft compiler user

This project is for using old game port controllers, modified them is not an option.

The pc joystick is 4 oneshots with a variable R and a fixed C.

Is that not what I listed above? Or are you saying I need to read from the PortC (I'm reading from the cap end).

Last Edited: Sat. Aug 20, 2016 - 02:36 AM

Sorry for the confusion, was trying to explain how I thought it worked.

Imagecraft compiler user

Or more simply, use a resistor to ground, say 10k and use the adc.

Or more simply, use a resistor to ground, say 10k and use the adc.

How would that work, I'm interested in this. A resistor on the trigger end or in series with the output?

Make a voltage divider.

ahhh, interesting thx.

Just a bit off the topic but on point with adc conversion. I have done this before many times with no issue. Though my ADC is freezing on me and for the life of me don't know why.  I'm sampling on PC1 and if the output is removed, lines is held lo, or line is held hi. My chip freezes on me. That or it is taking a very long time to complete and freezing the usb port.

{
_delay_us(150);
while ((ADCSRA & 0x10)==0);// Wait for complete
}

Last Edited: Sat. Aug 20, 2016 - 03:54 PM

Why bother with ADIF? (and why on earth aren't you doing it symbolically?)

Why bother with ADIF? (and why on earth aren't you doing it symbolically?)

I never learned another way to do the ADC, this example is all I have ever seen. I did some searing but I can't find anything on this "symbolically", not sure what you mean. Can you help me with this?

Ok I think you were referring to the fact that the code I sampled from is not using register names. ?I'm not sure why he did that but it worked for what I need then. So here is a break down of what I can figure from his code.

// ADEN: Set to turn on ADC , by default it is turned off
while (1)
{
}

Last Edited: Mon. Aug 22, 2016 - 12:59 AM

The ADC doesn't make sense to me.  I'm assuming a Mega32 since there is no Mega3289.

{
_delay_us(150);
while ((ADCSRA & 0x10)==0);// Wait for complete
}

Why the delay after writing to ADMUX?

Avoid 'magic numbers'.  If ADSC is bit 6 and it starts the conversion, use  ADCSRA |= (1 << ADSC);

ADSC stays high while the conversion is completing (13 ADC clock cycles), then it goes low.  Use:    while ( (ADCSRA & (1<<ADSC));   to detect when the conversion is finished.

At this point, ADSC is LOW and will start the next conversion when it is set HIGH.  ADCW must be compilier-specific term for the 10-bit ADC conversion result.

I'm just as confuse as you but after reading up on it it does in fact work now and make a lot more sense. Here is what I came up with.

{
//Start Single conversion
//Wait for conversion to complete
//Clear ADIF by writing one to it
}

Last Edited: Mon. Aug 22, 2016 - 01:09 AM

We've still got the magic 0x40!
Why all the guessing when you've got Atmel Studio to help you?
Nevertheless, have you got the joystick thingys to work?

No really, I'm trying to figure out why the exponential biased on one direction? When I move left I get %10 of my field of range but %80 when moving right. I though maybe it was my fixed resistor but that is clearly not it. So I'm guessing it has to do with my read_adc code.

S_K_U_N_X wrote:

The joystick pots could be log rather than linear

Yeah not sure this is helping with my sanity much...

Ok so on my volt meter from output PC1 to ground Oi get

at reset 4.82

right 4.81

left 4.85

quick and dirty schematic here.

PD3 ---\/\/\(VR1-100k)\/\/---PC1---\/\/\(10k)\/\/\---Ground

PD3 is out and Hi

PC1 is in and being used for ADC.

Why on earth Im getting 0-400 bit response on my ADC but only a .01 volts spread I have no idea. obviously ill continue to look this over but just wanted to comment on this so when I read it later I will know it was not a dream.

Last Edited: Tue. Aug 23, 2016 - 11:23 PM

Check the basics. You've got a multimeter so check your 10k is really 10k. Then check your joystick pot. Just tie the top of the joystick to vcc -rule out portd. Disconnect portc. Measure volts across 10k. Vary joystick. Observe volts changing. Then connect portc. Then portd.
I'd suggest adding a 100nF cap across the 10k. But that won't solve your immediate problem.

ok,

10k is really 10k ( 9.9 k)

POT is really 1-97k

from ground thru 10k to +5 I get 1.85

from ground thru VR to +5 I get the a non limier voltage.

So, is the voltage divider out, or is there a way to reduce the curve?

Last Edited: Wed. Aug 24, 2016 - 12:48 AM

Again, back to basics.
With the joystick at 1k we should get 10/11 times 5 which should be around 4.5V
At 100k should be 10/110 times 5 is around 0.5V

If you're not getting these values, then you need to look at your setup.
Now, the response curve of the pot may not be linear- considering pots are usually log or linear. You might be able to look at the pot - it might have 100kA or 100kC. Which one is what you can Google as i can't remember! If it is log, you can use a table in your code to linearise it.

With the joystick at 1k we should get 10/11 times 5 which should be around 4.5V
At 100k should be 10/110 times 5 is around 0.5V

Both conditions are about true, give or take a few tenths.

Hmm, a look up table? but I get 10 to 100  resolution from left to right?

(left) 1,2,3,4,5,6,7,8,9 (center) 1 thru 100 (right ), so the sensitivity will be much greater on the right side no?

but I guess I could change my resister and get better results.

maybe (left) 1 thru 100 (center) 1 thru 1024 (right )

then I could sort it out in a table.

Last Edited: Wed. Aug 24, 2016 - 01:38 AM

Ok, we've determined that the hardware side obeys Ohm's law. Let's convert the volts into ADC counts to see if that lines up:

0.5V =102

4.5V = 921

So that's around 800 counts end to end - that's over 9 bits of resolution.

Plot your readings versus pot angle and graph it - it doesn't need to be super accurate. This will show you the curve. You can then calc the anti-curve.

yeah its a bit of a mess. I did a quick

const unsigned char TABLE[2][512] PROGMEM =
{
1,0  ,
2,0  ,

.

.

.

999,354,

1000,254,

};

and it chewed up %4 of my program space but that will sure beat doing the math. I'll have to work out my anti curve function in excel but ill have it soon and test.

Last Edited: Thu. Aug 25, 2016 - 01:52 AM

You can trade table size for some code by using a interpolation table. Break the curve up into ,say,16 segments and interpolate on that.

999,354,

1000,254,

A pretty clever trick if you really *can* store those in a char array!!

(yes the 254 is OK, I mean the other 3).

I ended up with this.

const char TABLE[700] PROGMEM =
{
0  ,

.

.

.

254,

}

So I can just use the index as the input. That helped with code size. then I just do return(TABLE[ADCW] ); instead of return( ADCW ); So far it is doing the trick. going to play with it some more.

Last Edited: Fri. Aug 26, 2016 - 12:08 AM

The basic requirement for a subroutine is to do one thing and do it properly. Your adc function is now doing two things - adc and translation. Small point but can have a significant impact especially when debugging and testing.

ok, point taken.

I'm all set with my anti-curve but now since I see what I should be getting, I seen an imperfection and because of this it is very difficult to test. The controller jumps.  Watching under a debug with the values I see this

Holding at right it goes to 240 and 249 (249 is correct).

Holding at center it goes to 26 and 241 (141 is correct).

Holding at left it s always 0

There are also point in between but hard to pin point.

The strange thing is that the jumping favors the wrong values. I'm not sure what is causing the jumping and will continue to look for loose connection/grounding/etc. I though maybe it was the table but it looks good.

What is the adc value doing? Do you have a capacitor across the 10k to act as a filter?

I don't have a way to see the output of the ADC because my method of debug shows only one byte values. Though using an alternative table I can see it is jumping further apart the higher the resistance.  I put a 300pf across the resister, do I need something bigger, no effect from this?

--------------------------------------------------------------------------------------------------------------------------------------

So it turns out I have a code issue here? Ill cut down the array to post it in but it has 700 values.

extern const unsigned char TABLE[700] PROGMEM ;

in C file

const unsigned char TABLE[700] PROGMEM =
{
1,

2,

3,

}

use case.

It seem that the way I'm using it is returning random data. Is it define incorrectly?

The reason I say this is I did a test

So Y has my input and X has my output.  I can see the lower part of the number ( 0-254) and 90 for example gives me 26 but it should give me 128. 2 gives me 0 but should give me a 42 and 54 gives me 16 and should give 64.

At least I think its random? Is there something in common here.

Last Edited: Sat. Aug 27, 2016 - 02:28 AM

I think you need to read this:

https://www.avrfreaks.net/forum/t.... Part II tells you.

Most of us would just output the data via the usart by using printf(). I did suggest a 100nF cap earlier.

Aw right... and I knew about prg_read too, just been a while. I'll have to dig up a cap. The data is right now but still jumpy.

I did not need the cap, so it is currently not in place. The jumping was cause by the fact I though my ADC started at 38 and it was actually 38+255, I just didn't realize it because my output was a uchar.

currently my ADC is giving a high number something over 1100 that I'm trying to capture. I guess if the table does not extend to the length I ask it rolls over or returns 0.

Other that that the only issue I see it the resolution to the right is very low compared to the resolution to the left. This gives a very undesired result. I guess I coudl always change my fixed resister to get it right but then I have to length my array by a large amount. I may be forced to live with this.

So I'm getting pretty close to a usable joystick, thx to all involved.

Last Edited: Sat. Aug 27, 2016 - 10:47 PM

I'd suggest you put the cap in - it is going to give you a degree of ESD and EMI protection as well as some filtering.

I ordered a few, ill be trying that as well.  (sorry edited that previous post a bit).

Your debug method doesn't seem to be too effective. Only seeing uchars is a bit limiting. Something is suspect if your adc value is greater than 1023.

I found another debug method and see I'm looking at 283 - 1122 but this present a number of issue.

1) If I define static unsigned char TABLE[1122] = {} I'm out of Data: space

2) If I define const unsigned char TABLE[1122] = PROGRAM {} I'm out of program: space

3) If I use a table anything greater the [800] apparently it takes so long to look anything up that my usb device gives up on me. This one is suspicion but either way if my table size is greater then 800 the code freezes.

4) If I first bitshif my result 1 to the right I loose way too much precision.

At the moment I'm out of ideas on how to use such a large table and ironically I only need a byte (0-254).

My methods of debug are

1) out put data on the screen but only in a char. As I move the controller I see it count up to 254 4 times.

2) I drop a line low and loop for 1 us I do my loop x times and then bring it hi. I view this in my analyzer.  If I put a 100 in I get 150 us if I put in 500 I get 750. so I changed it to delay for .5 us and that seems to show the exact number I put in. my ADC seems to go up to 1.1 ms and that is 1100.

I suggested an interpolation table earlier. It's what fuel injection computers use (or at least they did). Divide your curve into 16 segments - get your ruler out and draw straight lines where the slope of the curve doesnt change much. Google for some code - my head is in heatmaps at the moment, so I'm solving my problems first!

You could use an Arduino board or similar and just use printf to output readable values. I'm writing an iPhone app at the moment and I'm using the same technique to dump out data.

Last Edited: Sun. Aug 28, 2016 - 02:56 AM

S_K_U_N_X (in post #6) wrote:

Or more simply, use a resistor to ground, say 10k and use the adc.

How would that work, I'm interested in this. A resistor on the trigger end or in series with the output?

I don't understand why you are using a look up table at all.

The joystick acts as a 100K ohm variable resistor with one end connected to +5V and the other end connected to the ADC input and to a 10K resistor to ground.

This will produce a voltage at the ADC input that follows the plot shown below:

Note that the above curve is independent of the taper of Rp.

Vx is the voltage connected to the ADC input.  Val_ADC is the digital output of the ADC.

Rp is the joystick potentiometer and Rg is the resistor to ground.

Vx = 5( Rg/(Rg + Rp) )        ==>       Rp = Rg(5 - Vx)/Vx

Translating this into C code:

uint32_t    R_pot;              // in ohms

uint32_t    R_g = 10000;   // in ohms (resistor to ground)

uint16_t    Vx;                   //  voltage in millivolts

R_pot = ( R_g * (5000UL - Vx) )/Vx;

Last Edited: Sun. Aug 28, 2016 - 06:05 AM

S_K_U_N_X wrote:
1) If I define static unsigned char TABLE[1122] = {} I'm out of Data: space

2) If I define const unsigned char TABLE[1122] = PROGRAM {} I'm out of program: space

(a) which C compiler accepts this curious "PROGRAM" syntax? Surely the directive to place it in flash should be on the left side of the = ? (in GCC is would be "PROGMEM")

(b) If 1K of data runs out of flash space isn't that telling you it's time to trade up to the next larger model of AVR?

a) its called a typo...

b) I use a atmage328, It's in production and I can not swap out at this time. the improvements are FM updates.  Normaly when I add a new device to work with the design it adds %5 code space. When I added a device that is similar to a supported devise its only a a or 2%. It goes in to beta then eventually pushes to stable. I'd very much like to add support for older game pads but a look up table that uses %15 is just nuts. I'm looking in to this interpolation table in hopes it will reduce the size.

Chuck99, I'm glad it works out on paper that way but it does not in the design. Maybe there is something about the design that is causing this? I can draw up how the pots interface with my schematic and maybe that will answer the mystery. Could it be the way I use my ADC? I really would love that graph to be a reality.

S_K_U_N_X wrote:

Chuck99, I'm glad it works out on paper that way but it does not in the design. ... I really would love that graph to be a reality.

That graph should be the reality.  If it isn't then there is something wrong.

You are using a look up table to cover up the problem, not fix it.

To troubleshoot your circuit and software, you really need to be able to send data to the PC (terminal emulation program) to view the raw ADC output.

You can use utoa() in <stdlib.h> to send the data as ASCII in binary, decimal, and hex.

If the USART in the uC isn't available, you can bit bang the serial on an i/o pin.

Use a USB to logic level serial adapter to interface to the PC.

I would start by using a fixed resistor as a substitute for the joystick pot (Rp).

A 10K resistor should give you Vx = 2.5 volts input to the ADC and the ADC output should be 511.

Use a voltmeter to verify that the input to the ADC is 2.5V, then check the ADC output.

Once that is working, test with a 1K, 20K, 50K, and 100K resistors.

Your data should match the graph.  Measure both Vx and ADC output.

Last Edited: Sun. Aug 28, 2016 - 11:25 PM

Ok i'll start testing. Hope to figure out what is causing this.

Last Edited: Sun. Aug 28, 2016 - 11:45 PM

Why do you do 255- ? Aren't you expecting a value 0..1023 from the adc?

Sorry Kartman, that entire post was all wrong, so I removed it.  But to answer that, the values I get from the adc are backwards and after I use the table they fit in 0-255 so I use that to flip it.

Though I really would prefer to hunt down the reason for the curve in the first place as Chuck pointed out.

Would you show us the routines for initializing and reading the ADC?

Also, what is the frequency that the ADC is running at?

What is the frequency that the uC is running at?

Last Edited: Mon. Aug 29, 2016 - 12:13 AM

When measuring my 10k fixed resistors in circuit they are all give strange results.

r1 is oen

r2 is open

r3 is 10k

r4 cause the meter to flicker 0.00 ( no idea what that means).

just bring all up and in?

PORTC=0xff;
DDRC=0;

{

}

My chip is at 12mhz

to read I must do this

DDRC = ~(1<<1);   _delay_us(500);//let things power up.

DDRC = ~(1<<3);   _delay_us(500);//let things power up.

DDRC = ~(1<<0);   _delay_us(500);//let things power up.

DDRC = ~(1<<2);   _delay_us(500);//let things power up.

Portc should be 0 - you don't want pullups enabled. Ddrc = 0 all inputs.
There is no need to touch ddrc past initialisation.
You've not shown us how you initialise the adc - this is critical.

sorry, here it is.