|
|
View previous topic :: View next topic |
Author |
Message |
Arlof
Joined: 31 May 2006 Posts: 2
|
ADCless POT reading using a 16F628 |
Posted: Wed May 31, 2006 9:57 pm |
|
|
Hello,
Long time lurker first time poster.....
I've been using higher end pics in the past, and now I'm playing with a MELABS x3 board. I've gotten everything to work except for the pot measurement. It appears to use the RC time constant to measure the change of resistence.
Circuit is a 5K pot in series with a .1 uF capacitor.
I've read in Myke Predko's book how to do it, but my code doesn't seem to work at all. The PIC basic hex file works, using the POT command so I know the hardware is fine.
Code: |
#case // case sensitive turned on
#include <16F628.h> // Include device header file
#use delay(clock = 4000000)// Make compiler aware of osc frequency 4 @ MHz External
#fuses XT,NOLVP, NOWDT, // Pre Directive of: External Oscil, No Low Voltage, No Watch Dog
#use rs232(baud = 9600, xmit = PIN_B2, rcv = PIN_B1) // Setup the on boards USART
#byte port_b = 0x06 // Register For Bit Level Port_B
#byte port_a = 0x05 // Register For Bit Level Port_A
#byte LCD_DATA = 0x05
#bit BUTSTAT = port_b.7 // Port_B PIN_B7 aka Push Botton
#bit POTPIN = port_b.0 // Port_B PIN_B0 aka POT
// Function Prototype
int pot_read(void);
int potval;
void main(void)
{
//int CharPresent;
port_b_pullups(TRUE);
set_tris_a(0x00);
set_tris_b(0b10000010);
// set led's off
BUTSTAT = 1;
output_low(LED1);
output_low(LED2);
printf("TEST RS232\r\n");
lcd_init();
//enable_interrupts(INT_RB); // Enable Status Chang on B Interrupt
//enable_interrupts(GLOBAL); // Enable Interrupts to be used.
for (;;)
{
output_high(LED1);
delay_ms(250);
output_low(LED1);
output_high(LED2);
delay_ms(250);
output_high(LED1);
delay_ms(500);
output_low(LED1);
output_low(LED2);
delay_ms(500);
potval = pot_read();
printf(putc_lcd,"%x",potval);
}
}
int pot_read (void)
{
int i = 0;
output_low(LED1);
output_low(LED2);
port_b_pullups(FALSE);
output_high(POT);
delay_us(5);
set_tris_b(0b10000011); // Set port b0 to input.
//output_low(POT);
while (POTPIN == 1)
i++;
printf("Pot Val = %x",i);
return (i);
}
|
So basically it just hangs in the while loop I assume. Now that I look at the code is it because I don't have a roll over for my int i? I thought it would automatically roll over....
Anyway, the way I coded the pot_read() function was that it put out a high on the B0 pin and delay 5 us for charging of the cap. Then I change my tris to make it an input, the capacitor should start to discharge to ground, then wait for the trigger point on the high to low transition. approx 2.5 or 1.5 V.
Any ideas? I'm sorta stumped.
Regards,
David. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed May 31, 2006 11:16 pm |
|
|
Look at the schematic for your board:
http://www.melabs.com/downloads/labx3sch.pdf
The trimpot and capacitor are in the top center of the schematic.
Note the values.
Now go to this explanation of the POT command, on the Piclist website:
http://www.piclist.com/techref/microchip/seepicsrc/psbpix/pot.htm
Near the top of the article, they explain how they calculate the
charging time for the capacitor. Compare the amount of time that
they charge the capacitor to the amount of time that you're using.
Plug the values of the cap and trimpot from the labx3 schematic
into their equation. What time value do you get ?
Also, do you have the trimpot set at some reasonable value ?
Make sure it's not set at 0. Initially, it's best to set it at max resistance.
Besides that problem, the rest of your pot_read() routine doesn't work
the way the Pot command does in PicBasic. If you want to translate
the PicBasic Pot command to C, one good way to do it is to compile
a Picbasic program which uses that command, and then look at the .LST
file. They put comments in there which explain what the ASM code is
doing. You may not understand all of it, but I think you should be
able to get the idea of how they do the measurement. Example:
Code: |
POT
call CONVPIN ; Convert pin to FSR and bit mask
POTT
movwf RM1 ; Save bit mask
call HIGHT ; Set pin high to charge cap
movlw 10 ; Charge cap for 10ms
call PAUSE
movf RM1, W ; Get bit mask
iorwf INDF, F ; Set pin to input
bcf FSR, 7 ; Point to port
xorwf INDF, F ; Flip bit to low
clrf R0 ; Zero counter
clrf R0 + 1
potloop
bsf FSR, 7 ; Point to TRIS
movf RM1, W ; Get bit mask
xorwf INDF, F ; Set pin to output
; Discharge a little (& clear Watchdog timer)
clrwdt
nop ; Short delay
nop
xorwf INDF, F ; Set pin back to input
bcf FSR, 7 ; Point back to port
andwf INDF, W ; Read pin
btfsc STATUS, Z ; Still high?
goto potdone ; No
movf R2, W ; Get scale factor
addwf R0, F ; Increase count by scale
btfsc STATUS, C ; Check for roll to high
incfsz R0 + 1, F
goto potloop ; Do some more
decf R0 + 1, F ; Overflow so set to max
potdone
movf R0 + 1, W ; Get result to W
DONE |
|
|
|
Arlof
Joined: 31 May 2006 Posts: 2
|
|
Posted: Sat Jun 03, 2006 12:58 pm |
|
|
Hey, Great help thanks. Apprently the guy in the that wrote that book forgot to mention you needed to discharge the capacitor.
So if anyone else has this question the coded solution was:
Now I've got another question I did a delay_ms(2.5) ; And it put a delay of about 9.28 seconds. Whats the deal with that is that a bug or something? I've got compiler 3.42.
Thanks,
David
Code: |
int pot_read (void) // instruction = 1uS
{
int i = 0;
output_high(POT);
delay_ms(3); // Charge time 5x.1e-6x5k = 2.5 mS
set_tris_b(0b10000011); // Set port b0 to input.
while (POTPIN == 1) // Do loop will the storge charge is more than 2.5 Vdc
{
i++; // Increment Counter 0hms = 01 hex
output_low(POT); // Set ouput to discharge cap a bit
set_tris_b(0b10000010); // set the i/o port to output
delay_us(10); // wait a bit for it to discharge some.
set_tris_b(0b10000011); // I/O to input to check for the switch point
}
set_tris_b(0b10000010); // Set the i/o to output
return (i); // return time it took to pull the RC to a 0.
}
|
|
|
|
Leef_me
Joined: 14 Mar 2006 Posts: 45
|
|
Posted: Sat Jun 03, 2006 2:29 pm |
|
|
>>Arlof said:
>>Now I've got another question I did a delay_ms(2.5) ; And it put a >>delay of about 9.28 seconds. Whats the deal with that is that a bug or >>something? I've got compiler 3.42.
>>Thanks,
>>David
Hmm, according to the "Compiler Updates" webpage the latest versions are Version 3.249 & Version 3.236 . Perhaps you have a typo.
Check the parameter value for delay_ms() again; 2.5 is not within the allowed parameter ranges.
I did try 2.1, 2.2 ... 3.5 and only 2.5, 3 and 3.5 gave any ASM result.
I did not try to decipher the resulting delay. The values 2.1 and others caused the compiler to not generate any code.
------------------------------------------------------------------------------
Quoting from the help file:
Syntax:
delay_ms (time)
Parameters:
time - a variable 0-255 or a constant 0-65535
HTH,
Leef_me
Code: | #include "C:\Documents and Settings\Lee\My Documents\rc_signal\rc.h"
void main()
{
delay_ms(100);
output_float (PIN_A3);
delay_ms(2.5);
output_float (PIN_A3);
}
|
|
|
|
Ttelmah Guest
|
|
Posted: Sat Jun 03, 2006 2:29 pm |
|
|
The 'delay' functions, accept _integer_ values only. My guess would be that 2.5, gets encoded by the compiler to a float, and then the first two bytes of this get taken and treated as an integer. This would be '0x2080', allowing for the byte order used in the float, which ought to give 8.32 seconds. However the behaviour with a float is completely undefined, so this is only a guess.
If you want to delay for 2.5mSec, then code this as delay_us(2500).
Best Wishes |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|