Hi all, it's the Ex-PIC virgin a.k.a. "newbie" (since I lost my virginity by completing a simple program that actually works!)
#1. Question on A2D use. Is it necessary to use the “#include a-d.h” when using the A2D channels? What is the purpose of this file and what are the advantages of using it or not?
#2. Does the readAD10 automatically dim the results as word? It suggests this in the help file.
Thanks, Ed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
1) Not required to use the #include <a-d.h>, as GCBasic picks thru the include/lowlevel header files when compiling. If you developed your own header say, and had it in the include folder (not lowlevel) then you would use:
#include <MyA-D.h>
The advantages of the ReadAD and ReadAD10 functions is a quick and easy read of an a-d input, scaled to 8 and 10 bits respectively, and referenced between Vdd and Vss. The unique functionality of the a-d.h is that it can be used across the broad spectrum of device selections (10f-18f). For more advanced functionality then you can set the sampling speed, V+ref, V-ref bits etc. as you see fit. Modify the a-d.h into MyA-D.h and have all kinds of fun!
Using header files just make your main code a lot cleaner, and easier to read.
2) The readAD10 handles the word value results, just be sure that any assigned variables are dimensioned as words, or you will think to yourself, why are my results stuck at 255?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Kent,
I am back fiddling with the A/D and low pin count 12F675 again. You kndly helped me before with this, but I ran out of time to check it all out. What I found when I can't store anything in the high order byte, is that maybe my loop is too fast for the A/D cap to charge properly, so I tried inserted delays in the loop. This changes the results. Here is my short test program:
#chip 12F675, 4
#config Osc = Int
dir GPIO.0 in
dim num as word
CheckAD:
num = ReadAD10(AN0)
wait 100 ms 'This makes a difference
EPWrite (0, num_H)
EPWrite (1, num)
Goto CheckAD
The "wait 100 ms" allows me to read a bigger number on my PicKit 2 proto board from the pot connected between the supply rails. The problem now is that I need to use this in a servo loop that cycles in 20 ms, so I can't use this longer delay. I tried various delay lengths and get different results each time, so the question is.....am I correct in assuming that the delay is in fact allowing the internal A/D cap to charge up properly? Is there another way around this? Thanks.
Keith R
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ussually AD conversion takes no more than 20 us, if the source impedance is very very hight then is possible to grow to 40 us... is recomended source impedance not higher than 5 Kohm.
I see GCBasic adc functions has acquisition delay and "wait for end of conversion" loop,..
Then it should read correctly without adding any delay... anyway when you add a delay afther the "ReadAD" function, the conversion is already done and the readed values are already passed to the register/s... that delay just waste time for nothing...
Regards.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Guy's, I tried using the eeprom numbers from 1 instead of 0, and it made no difference. Leaving out any delay, makes the high order bytes read FF and the low order read to a max of 3E. If I make the delay 10 ms, the eeprom mem reads 00 3E maximum. As soon as the delay is set over 84 mS, then it reads from 00 to 03 4E.
Just by the way, the feed to the AD input is via a 1K resistor that comes with the demo board. Any ideas??
Keith R
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Just another test for this......I used a 16F690 chip, and it does the same. If the A/D reads immediately or no more than 20 uS, then how come adding a delay makes a difference? Do I need to add something else like the sampling speed, V+ref, V-ref bits etc.? Thanks.
Keith R
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Keith... i had a look to the generated asm for your code, and may be there is a bug or something not working ok... i don't know if a compiler problem or a wrong use... or may be there is not problems and i am in a mistake...
Keith, O.K. see what you are saying now. The EEProm address at 0 or 1 shouldn't matter, as it seemed to be an effect of my test program. You definitely miss the some high bytes when the wait state goes below 20ms, at least with the on board 10k pot. Had me chasing my tail there, too. Must have had something else going on in previous programs so as not to notice that effect.
Change to the previously suggested 5k pot and you will not miss a beat. The impedance is even more critical for 18f's I believe, with a 2.5K suggested limit. You could test it with an off board pot too see for yourself.
If this is for your rc planes, then you probably won't be recording a reading every 20ms anyway, or else you will have to go with an off board eeprom to hold all the readings.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I only had higher resistance pot in my junk box, but I did try a 1K pot, and it reads exactly the same as the 10K. It will give a smooth reading from one extreme to the other, if I use a wait period of more than 84 mS.
I am using the PIC in my model plane for the electric motor control, so it has to have a frame rate of 20 mS, as per a normal model servo pulse ie. 1 to 2 mS pulse width and a frame rate of 20 mS.
First question: I read a voltage on the pin for te A/D input of 3.9 volts, but I read the eeprom as 03 4E or 846 decimal. How does this number relate to the input voltage?
2nd question: Is the problem due to the way the A/D conversion is done, or is it the way that the data is being written to the eeprom? How would I check this?
It sounds to me like there could be a problem in the ad read code. If I understood the assembler posted above, I could suggest a cure......but I don't, and that's why I'm playing with GC Basic.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
In the asm i can not see where ANSEL 0-2 bits are set to select channel as analog, may be i just cannot see... and my simulator does not support 16f675.
Suggestion:
Simulate the adread10 code and have a look to the ANSEL register...
Add a breakpoint at the begining of FN_READAD10.... then step by step...
The ANSEL 0-2 bits should set to 1 depending on the chanel to be redaded, in your case ANSEL,0 should be to 1 before ADC conversion is started.
Other cuestion:
There is a 20 us delay to ensure acquisition of the selected channel:
this means that the adc registers (ADRESL, ADRESH) are not readed until the conversion is correctly done, once this registers are readed any aditional delay should not do anything to the adc read... the conversion is already done and registers are already readed....
Greetings...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi, I presume that you are referring to the asm for the read a/d code in GC Basic? I unfortunately do not understand at this time, so Kent or Hugh could maybe comment on this. Maybe this code just cannot work for the smaller chips like the 12 and 16 series of PIC's.
Keith R
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok... you can try to configure ADC yourself instead of using gcbasic function.
This way you can know if the problem is in the gcbasic function or not.
This is an example to read adc channel 0 with 12f675 and 4 MHz clock.
To avoid problems with EPWrite:
A led attached to GPIO.1 (or any other you want) can be used as feedback, with 511 value in the "if num >...." the led will toggle just when pot is at 50%. you can try with other values to ensure led toggle at the desired Voltage. (don't forget led resistor)
Readed values go from 0 to 1023 -> 0 to 5V .
#chip 12F675, 4
#config Osc = Int
dir GPIO out 'Needed to attach the led
dir GPIO.0 in
wait 1 ms 'As this delay is outside the main loop it can be very long (just 20 us needed)
CheckAD:
set ADCON0.1 on '...................Start conversion
conv:
if ADCON0.1 on then goto conv '...Wait for conversion finished
num = ADRESL
num_H = ADRESH
if num > 511 then set GPIO.1 on 'you can connect a led to GPIO.1 to have feedback
if num < 511 then set GPIO.1 off 'Don't worry about num_H GCBasic does the work
EPWrite (0, num_H)
EPWrite (1, num)
Goto CheckAD
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Keith, if you are reading 03 4E or 846 decimal at 3.9, then that is the correct value. The math for ReadAD10 is 10 bits, with the max reading in hex 03 FF, or 1023 decimal, make sense?
So realizing that the default ReadAD10 (or ReadAD) function is set between Vdd (5V nominal) and Vss (0V). Then for the ReadAD10 and its 10 bits of resolution would equate to:
X / Vdd = 846 / 1023
My Pickit 2 Vdd is 4.86V though, probably because of a reverse polarity protection diode. Took an a-d reading of 03 4C, 844 decimal, from the EEProm, and with a DVM reading flopping from 4.00 to 4.02V.
X = 4.86 * 844 / 1023
X = 4.01 V ;Hurray!
It wouldn't hurt to read the a-d prior to Main once, and tossing it out, before reading again and storing it in EEProm.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I managed to get this first order filter code to work in two different PIC's (12F675 & 16F88). It is for filtering an input signal:
Regards, Ed.
'init on power up
set pulse off
dim Input as word
dim outputn as word
dim output as word
outputn = 0 'Intial condition
tp = 10 'time constant in seconds (ratio of tp/dt inthis case tp=1 dt=.1sec)
ready: 'Waiting for inputs
if trig on then 'must keep pulse on
set indicator on
gosub FirstLag
end if
wait 1 ms 'set sample rate to 1000Hz
goto ready
sub FirstLag 'reads input and computs output (set to +5V)
do
Input = readad10(an0) 'get new data
output = (input-outputn)/tp + outputn 'compute output
outputn = output 'set n-1 value of output
wait 100 ms 'set sample rate = dt
'diagnostic
if output >= 646 then set pulse on '1-e^-1 for a step input
end sub
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Bingo! Thanks so much to you guys for the help. I really appreciate it. I had a similar idea to "anonymous" (you should tell us your name) but did not know how to peek into the a/d registers. I used your program and just changed the LED output to suit my board's wiring. I tried various numbers to see how the AD was working and it works with the full range of the pot.
However......when I looked into the eeprom, then it only shows the low bytes...as before. So I tried putting a delay before the write eeprom function as you can see below:
if num > 511 then set GPIO.5 on 'you can connect a led to GPIO.1 to have feedback
if num < 511 then set GPIO.5 off 'Don't worry about num_H GCBasic does the work
wait 90 ms 'I added this and then EPWrite shows full number
EPWrite (0, num_H)
EPWrite (1, num)
Goto CheckAD
This worked fine, so I now see that it is nothing to do with the way that I'm reading the A/D, it means that writing to the eeprom needs more time than my loop is giving it. I also tried jumping out of the loop with one of the pushbuttons, and writing to the eeprom this way. This also works perfectly. This is so great, and now I can get on with my project.
Thanks again Kent for your regular help and for clearing up the math. This makes perfect sense to me now.
To Edward..........humble apologies for highjacking your thread! I hope that some of this helped you as well. Keep well.
Keith R
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
ED, Haven't done much digital filtering, although it would be useful for sure. Seems like the algorithm will do the trick, although the initial offset seems large, and takes a long while to get back to a mean? Haven't had time for a full study, or try.
Keith, can't argue with success, or being happy with an outcome. The extra wait state for EEPRom writes still seems unecessary. Now that you have tried anonymous's code, and you still have an unnecessary wait period, may suggest some corrupting hardware or setup problem. It's a mystery.
Using AN0 with the 10k pot, the very first EEProm write/read can "sometimes" give an erroneous (and usually low) result on initial startup. Using PWRTE=ON in config, is a definite benefit. One set of readings with a quick power on, power off, and no PWRTE, might look like:
00 03 AC 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1
10 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
20 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
...
...
...
Below is my last shot at trying to give an example, no external wait states.
#chip 12f675,4
#config _INTRC_OSC_NOCLKOUT '& _PWRTE_ON
dir GPIO.0 in 'Analog input from 10k pot connected to VDD
dir GPIO.1 out 'Set up output for led
dir GPIO.4 in 'Analog input of 5k or less
dim Volt as word
'#include <a-d_AVR.h>
EEPromCount = 0
Start:
Volt = ReadAD10(AN0) ;toggle between AN0 and AN3
'Volt = ReadAD10(AN3) ;to see the effect of less impedance
EPWrite(EEPromCount, Volt_H) ;lpc devices have byte size EEProm addr's
EEPromCount += 1 'increment counter/address
EPWrite(EEPromCount, Volt)
If EEPromCount = 15 Then goto blink ;Read 16 word values
EEPromCount += 1 'increment counter/address
goto Start
blink:
Do Loop
Set GPIO.1 On
wait 1 s
Set GPIO.1 Off
wait 1 s
nop
Loop
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks again Kent, I'll keep on playing with this thing, and I'll try your example as well. The pot that's on my board right now, is a 1K pot and this feeds AD0 via a 1K resistor. So far it works the same with the 10k, 5k, and 1k pots that I had. Maybe you are right, and there is some hardware hassle somewhere, but right now, I can at least carry with my model motor control project.
A friend of mine in Slovakia has his system working now that adds power on the uphills and backs off on the downhills. Remember that these are control-line aerobatic models, and we are not allowed to use any remote control of the throttle. He uses a model gyro and/or accelerometer to do the g-force sensing. He is an old hand at the PIC stuff, and mainly uses C to program, but I'm certain that I can do most of what I need in GCBasic. So far, I have amazed myself with what I have learned in such a short space of time....as a non-programmer. GCBasic has done this for me. I am really grateful to you guys.
Keith R
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Kent, This filter is identical to an r-c filter. The initial condition is equivalent to the starting charge on the capacitor. So you are correct it does take time to reach the mean. That is how it filters out high freqency effects.
Now that I have "mastered" the a-d command, I will work on something more useful: a PID controller. It will not be much more complex, but then I will have to learn how to use the PWM stuff.
I LOVE this stuff! Hugh has done a really great job. I really appreciate all you help.
Regards, Ed.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Keith:
I'm still unsure about the problem with adc and eeprom.
You tried with "adc manual configuration" in my code and the led is working as expected..
but... have yo tried ReadAD10(AN0) function with the led feedback and different trigger values?... if you could do it and tell us we can be totally sure about this issue.
It could be good when you exit the program by an external switch or save eeprom by an external switch.. or something like that, to be sure the eeprom write is not breaked just when a write operation is taking place.
You can try the following code with a write-eeprom function that should work for 12f675, if this code doesn't work properly without any delay then is very possible that there is a harware issue involved in the problem:
wait 1 ms 'As this delay is outside the main loop it can be very long (just 20 us needed)
CheckAD:
set ADCON0.1 on '...................Start conversion
conv:
if ADCON0.1 on then goto conv '...Wait for conversion finished
num = ADRESL
num_H = ADRESH
if num > 511 then set GPIO.1 on 'you can connect a led to GPIO.1 to have feedback
if num < 511 then set GPIO.1 off 'Don't worry about num_H GCBasic does the work
Sub my_EPWrite(epadr, value)
EEADR =epadr
EEDAT = value
set EECON1.WREN on
EECON2 = 85
EECON2 = 170
set EECON1.WR on
thisisaLoop1:
if EECON1.WR on then goto thisisaLoop1
set EECON1.WREN off
End Sub
Whta's the matter when input < outputn?
I think "word" is an unsiged variable, then -1=65536, -2=65535, -3=65534....
Interesting this filter, i'm managing some adc reads and need something like this... but i don't totally understand yet how it works... what i was doing is just: read=(read+previous_read+2ºprevious_read....+nºprevious_read1)/n; but your method looks simple... i will use it... when i can understand how it works .... :)
Greetings...
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It could be great when we can be sure that ReadAD10 function is working properly.
When i check the asm code generated by GCBasic i think it should not work properly because ANSEL register is not correctly set; but may be there are things i cannot see and i would like to know what's really happening...
I have not any 16f675 to try and cannot simulate that PIC.
Checking the ReadAD10 function with the led system is a try but is not totally clear.
The only thing that is totally clear is having a look to the ANSEL register... then i think that when you can be sure eeprom write is working properly you can add this line to your code (using ReadAD10 function):
EPWrite (2, ANSEL)
this way we can know what is really happening inside the PIC...
Good luck with your proyects!!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Santiago,
Thanks for giving us your name and registering. Thanks also for the extra suggestions. I did try the program with ReadAD10, and it works properly on the 12F675 and 16F690 as well. At the moment your suggestions work well for my program, and most of the time I don't have to write to the eeprom in my main loop of 20 mS to keep the motor running, so it's no problem.
When I see your's and Kent's programs, then I realise just how much I need to learn. All I need now is more time......!!
Keith R
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi all, here is a patch to the lag filter to correct the sign problem discussed in the PID thread.
This works both directions. Try to keep the ratio of tp/dt over 10, it helps stability.
Regards, Ed.
'A first order lag with PWM output
'Tested 02-22-09
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 in 'input test signal pin #17 (an0)
dir portB.4 out 'output testsignal pin #10
dir portB.0 out 'set pwm output pin 6
'name I/O
#define pulse portB.4
'init on power up
set pulse off
dim Input as word
dim outputn as word
dim output as word
dim PWMDC as word
FirstLag: 'reads input and computes output
Input = readad10(an0) 'get new data
If input >= outputn then
output = (input-outputn)/tp + outputn 'compute output
end if
if input < output then
output = outputn - (outputn - input)/tp
end if
outputn = output 'set n-1 value of output
PWMon 'Turn PWM on so we can see the internal calulations
PWMDC = output/4 'scale PWM
HPWM 1, 10, PWMDC 'output PWM
wait 100 ms 'set sample rate = dt
goto firstlag
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi all, it's the Ex-PIC virgin a.k.a. "newbie" (since I lost my virginity by completing a simple program that actually works!)
#1. Question on A2D use. Is it necessary to use the “#include a-d.h” when using the A2D channels? What is the purpose of this file and what are the advantages of using it or not?
#2. Does the readAD10 automatically dim the results as word? It suggests this in the help file.
Thanks, Ed.
1) Not required to use the #include <a-d.h>, as GCBasic picks thru the include/lowlevel header files when compiling. If you developed your own header say, and had it in the include folder (not lowlevel) then you would use:
#include <MyA-D.h>
The advantages of the ReadAD and ReadAD10 functions is a quick and easy read of an a-d input, scaled to 8 and 10 bits respectively, and referenced between Vdd and Vss. The unique functionality of the a-d.h is that it can be used across the broad spectrum of device selections (10f-18f). For more advanced functionality then you can set the sampling speed, V+ref, V-ref bits etc. as you see fit. Modify the a-d.h into MyA-D.h and have all kinds of fun!
Using header files just make your main code a lot cleaner, and easier to read.
2) The readAD10 handles the word value results, just be sure that any assigned variables are dimensioned as words, or you will think to yourself, why are my results stuck at 255?
Kent thanks, Ed.
Hi Kent,
I am back fiddling with the A/D and low pin count 12F675 again. You kndly helped me before with this, but I ran out of time to check it all out. What I found when I can't store anything in the high order byte, is that maybe my loop is too fast for the A/D cap to charge properly, so I tried inserted delays in the loop. This changes the results. Here is my short test program:
#chip 12F675, 4
#config Osc = Int
dir GPIO.0 in
dim num as word
CheckAD:
num = ReadAD10(AN0)
wait 100 ms 'This makes a difference
EPWrite (0, num_H)
EPWrite (1, num)
Goto CheckAD
The "wait 100 ms" allows me to read a bigger number on my PicKit 2 proto board from the pot connected between the supply rails. The problem now is that I need to use this in a servo loop that cycles in 20 ms, so I can't use this longer delay. I tried various delay lengths and get different results each time, so the question is.....am I correct in assuming that the delay is in fact allowing the internal A/D cap to charge up properly? Is there another way around this? Thanks.
Keith R
GCBasic doen't like the EPWrite (0, num_H), try the starting address at 1.
Ussually AD conversion takes no more than 20 us, if the source impedance is very very hight then is possible to grow to 40 us... is recomended source impedance not higher than 5 Kohm.
I see GCBasic adc functions has acquisition delay and "wait for end of conversion" loop,..
Then it should read correctly without adding any delay... anyway when you add a delay afther the "ReadAD" function, the conversion is already done and the readed values are already passed to the register/s... that delay just waste time for nothing...
Regards.
Hi Guy's, I tried using the eeprom numbers from 1 instead of 0, and it made no difference. Leaving out any delay, makes the high order bytes read FF and the low order read to a max of 3E. If I make the delay 10 ms, the eeprom mem reads 00 3E maximum. As soon as the delay is set over 84 mS, then it reads from 00 to 03 4E.
Just by the way, the feed to the AD input is via a 1K resistor that comes with the demo board. Any ideas??
Keith R
Just another test for this......I used a 16F690 chip, and it does the same. If the A/D reads immediately or no more than 20 uS, then how come adding a delay makes a difference? Do I need to add something else like the sampling speed, V+ref, V-ref bits etc.? Thanks.
Keith R
Hi Keith... i had a look to the generated asm for your code, and may be there is a bug or something not working ok... i don't know if a compiler problem or a wrong use... or may be there is not problems and i am in a mistake...
The asm code for the ReadAD10:
FN_READAD10
bsf ADCON0,ADFM
banksel ALLANSEL
clrf ALLANSEL ;..........<<<<---------- ANSEL = 0 (ALLANSEL = ANSEL)
banksel ADREADPORT
incf ADREADPORT,W
movwf ADTEMP
bsf STATUS,C
SysDoLoop_S1
banksel ALLANSEL
rlf ALLANSEL,F;........<<< rlf ANSEL when ANSEL=0 ?? missing bsf some bits..???
banksel ADTEMP
decfsz ADTEMP,F
goto SysDoLoop_S1
SysDoLoop_E1
banksel ANSEL
bcf ANSEL,ADCS1
bsf ANSEL,ADCS0
banksel ADCON0
bcf ADCON0,CHS0
bcf ADCON0,CHS1
btfsc ADREADPORT,0
bsf ADCON0,CHS0
btfsc ADREADPORT,1
bsf ADCON0,CHS1
bsf ADCON0,ADON
movlw 2
movwf SysWaitTemp10US
call Delay_10US
bsf ADCON0,GO_DONE
SysWaitLoop2
btfsc ADCON0,GO_DONE
goto SysWaitLoop2
bcf ADCON0,ADON
banksel ANSEL
clrf ANSEL
movf ADRESL,W
banksel READAD10
movwf READAD10
clrf READAD10_H
movf ADRESH,W
movwf READAD10_H
bcf ADCON0,ADFM
return
It looks like ANSEL,0-3 (analog select bits) will be always 0... then no inputs will be analog....
If this is right you're reading a digital input as analog.. unsected behaivor is sure .
Greetings..
Keith, O.K. see what you are saying now. The EEProm address at 0 or 1 shouldn't matter, as it seemed to be an effect of my test program. You definitely miss the some high bytes when the wait state goes below 20ms, at least with the on board 10k pot. Had me chasing my tail there, too. Must have had something else going on in previous programs so as not to notice that effect.
Change to the previously suggested 5k pot and you will not miss a beat. The impedance is even more critical for 18f's I believe, with a 2.5K suggested limit. You could test it with an off board pot too see for yourself.
If this is for your rc planes, then you probably won't be recording a reading every 20ms anyway, or else you will have to go with an off board eeprom to hold all the readings.
I only had higher resistance pot in my junk box, but I did try a 1K pot, and it reads exactly the same as the 10K. It will give a smooth reading from one extreme to the other, if I use a wait period of more than 84 mS.
I am using the PIC in my model plane for the electric motor control, so it has to have a frame rate of 20 mS, as per a normal model servo pulse ie. 1 to 2 mS pulse width and a frame rate of 20 mS.
First question: I read a voltage on the pin for te A/D input of 3.9 volts, but I read the eeprom as 03 4E or 846 decimal. How does this number relate to the input voltage?
2nd question: Is the problem due to the way the A/D conversion is done, or is it the way that the data is being written to the eeprom? How would I check this?
It sounds to me like there could be a problem in the ad read code. If I understood the assembler posted above, I could suggest a cure......but I don't, and that's why I'm playing with GC Basic.
In the asm i can not see where ANSEL 0-2 bits are set to select channel as analog, may be i just cannot see... and my simulator does not support 16f675.
Suggestion:
Simulate the adread10 code and have a look to the ANSEL register...
Add a breakpoint at the begining of FN_READAD10.... then step by step...
The ANSEL 0-2 bits should set to 1 depending on the chanel to be redaded, in your case ANSEL,0 should be to 1 before ADC conversion is started.
Other cuestion:
There is a 20 us delay to ensure acquisition of the selected channel:
bsf ADCON0,ADON
movlw 2
movwf SysWaitTemp10US
call Delay_10US
There is a loop to ensure that ADC cap is fully charged and conversion is correctly done:
SysWaitLoop2
btfsc ADCON0,GO_DONE
goto SysWaitLoop2
this means that the adc registers (ADRESL, ADRESH) are not readed until the conversion is correctly done, once this registers are readed any aditional delay should not do anything to the adc read... the conversion is already done and registers are already readed....
Greetings...
Hi, I presume that you are referring to the asm for the read a/d code in GC Basic? I unfortunately do not understand at this time, so Kent or Hugh could maybe comment on this. Maybe this code just cannot work for the smaller chips like the 12 and 16 series of PIC's.
Keith R
Ok... you can try to configure ADC yourself instead of using gcbasic function.
This way you can know if the problem is in the gcbasic function or not.
This is an example to read adc channel 0 with 12f675 and 4 MHz clock.
To avoid problems with EPWrite:
A led attached to GPIO.1 (or any other you want) can be used as feedback, with 511 value in the "if num >...." the led will toggle just when pot is at 50%. you can try with other values to ensure led toggle at the desired Voltage. (don't forget led resistor)
Readed values go from 0 to 1023 -> 0 to 5V .
#chip 12F675, 4
#config Osc = Int
dir GPIO out 'Needed to attach the led
dir GPIO.0 in
dim num as word
'Configure ADC to read channel 0 (10 bits) 4 MHz clock:
ANSEL = b'01010001
ADCON0 = b'10000001'
wait 1 ms 'As this delay is outside the main loop it can be very long (just 20 us needed)
CheckAD:
set ADCON0.1 on '...................Start conversion
conv:
if ADCON0.1 on then goto conv '...Wait for conversion finished
num = ADRESL
num_H = ADRESH
if num > 511 then set GPIO.1 on 'you can connect a led to GPIO.1 to have feedback
if num < 511 then set GPIO.1 off 'Don't worry about num_H GCBasic does the work
EPWrite (0, num_H)
EPWrite (1, num)
Goto CheckAD
Keith, if you are reading 03 4E or 846 decimal at 3.9, then that is the correct value. The math for ReadAD10 is 10 bits, with the max reading in hex 03 FF, or 1023 decimal, make sense?
So realizing that the default ReadAD10 (or ReadAD) function is set between Vdd (5V nominal) and Vss (0V). Then for the ReadAD10 and its 10 bits of resolution would equate to:
X / Vdd = 846 / 1023
My Pickit 2 Vdd is 4.86V though, probably because of a reverse polarity protection diode. Took an a-d reading of 03 4C, 844 decimal, from the EEProm, and with a DVM reading flopping from 4.00 to 4.02V.
X = 4.86 * 844 / 1023
X = 4.01 V ;Hurray!
It wouldn't hurt to read the a-d prior to Main once, and tossing it out, before reading again and storing it in EEProm.
Kent thanks for your help (yet again).
I managed to get this first order filter code to work in two different PIC's (12F675 & 16F88). It is for filtering an input signal:
Regards, Ed.
'init on power up
set pulse off
dim Input as word
dim outputn as word
dim output as word
outputn = 0 'Intial condition
tp = 10 'time constant in seconds (ratio of tp/dt inthis case tp=1 dt=.1sec)
ready: 'Waiting for inputs
if trig on then 'must keep pulse on
set indicator on
gosub FirstLag
end if
wait 1 ms 'set sample rate to 1000Hz
goto ready
sub FirstLag 'reads input and computs output (set to +5V)
do
Input = readad10(an0) 'get new data
output = (input-outputn)/tp + outputn 'compute output
outputn = output 'set n-1 value of output
wait 100 ms 'set sample rate = dt
'diagnostic
if output >= 646 then set pulse on '1-e^-1 for a step input
end sub
Bingo! Thanks so much to you guys for the help. I really appreciate it. I had a similar idea to "anonymous" (you should tell us your name) but did not know how to peek into the a/d registers. I used your program and just changed the LED output to suit my board's wiring. I tried various numbers to see how the AD was working and it works with the full range of the pot.
However......when I looked into the eeprom, then it only shows the low bytes...as before. So I tried putting a delay before the write eeprom function as you can see below:
if num > 511 then set GPIO.5 on 'you can connect a led to GPIO.1 to have feedback
if num < 511 then set GPIO.5 off 'Don't worry about num_H GCBasic does the work
wait 90 ms 'I added this and then EPWrite shows full number
EPWrite (0, num_H)
EPWrite (1, num)
Goto CheckAD
This worked fine, so I now see that it is nothing to do with the way that I'm reading the A/D, it means that writing to the eeprom needs more time than my loop is giving it. I also tried jumping out of the loop with one of the pushbuttons, and writing to the eeprom this way. This also works perfectly. This is so great, and now I can get on with my project.
Thanks again Kent for your regular help and for clearing up the math. This makes perfect sense to me now.
To Edward..........humble apologies for highjacking your thread! I hope that some of this helped you as well. Keep well.
Keith R
ED, Haven't done much digital filtering, although it would be useful for sure. Seems like the algorithm will do the trick, although the initial offset seems large, and takes a long while to get back to a mean? Haven't had time for a full study, or try.
Keith, can't argue with success, or being happy with an outcome. The extra wait state for EEPRom writes still seems unecessary. Now that you have tried anonymous's code, and you still have an unnecessary wait period, may suggest some corrupting hardware or setup problem. It's a mystery.
Using AN0 with the 10k pot, the very first EEProm write/read can "sometimes" give an erroneous (and usually low) result on initial startup. Using PWRTE=ON in config, is a definite benefit. One set of readings with a quick power on, power off, and no PWRTE, might look like:
00 03 AC 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1 03 E1
10 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
20 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
...
...
...
Below is my last shot at trying to give an example, no external wait states.
#chip 12f675,4
#config _INTRC_OSC_NOCLKOUT '& _PWRTE_ON
dir GPIO.0 in 'Analog input from 10k pot connected to VDD
dir GPIO.1 out 'Set up output for led
dir GPIO.4 in 'Analog input of 5k or less
dim Volt as word
'#include <a-d_AVR.h>
EEPromCount = 0
Start:
Volt = ReadAD10(AN0) ;toggle between AN0 and AN3
'Volt = ReadAD10(AN3) ;to see the effect of less impedance
EPWrite(EEPromCount, Volt_H) ;lpc devices have byte size EEProm addr's
EEPromCount += 1 'increment counter/address
EPWrite(EEPromCount, Volt)
If EEPromCount = 15 Then goto blink ;Read 16 word values
EEPromCount += 1 'increment counter/address
goto Start
blink:
Do Loop
Set GPIO.1 On
wait 1 s
Set GPIO.1 Off
wait 1 s
nop
Loop
Thanks again Kent, I'll keep on playing with this thing, and I'll try your example as well. The pot that's on my board right now, is a 1K pot and this feeds AD0 via a 1K resistor. So far it works the same with the 10k, 5k, and 1k pots that I had. Maybe you are right, and there is some hardware hassle somewhere, but right now, I can at least carry with my model motor control project.
A friend of mine in Slovakia has his system working now that adds power on the uphills and backs off on the downhills. Remember that these are control-line aerobatic models, and we are not allowed to use any remote control of the throttle. He uses a model gyro and/or accelerometer to do the g-force sensing. He is an old hand at the PIC stuff, and mainly uses C to program, but I'm certain that I can do most of what I need in GCBasic. So far, I have amazed myself with what I have learned in such a short space of time....as a non-programmer. GCBasic has done this for me. I am really grateful to you guys.
Keith R
Kent, This filter is identical to an r-c filter. The initial condition is equivalent to the starting charge on the capacitor. So you are correct it does take time to reach the mean. That is how it filters out high freqency effects.
Now that I have "mastered" the a-d command, I will work on something more useful: a PID controller. It will not be much more complex, but then I will have to learn how to use the PWM stuff.
I LOVE this stuff! Hugh has done a really great job. I really appreciate all you help.
Regards, Ed.
Hello Kent, Keith and Ed...
I'm anonymus... just too lazy to sign-up... :)
Keith:
I'm still unsure about the problem with adc and eeprom.
You tried with "adc manual configuration" in my code and the led is working as expected..
but... have yo tried ReadAD10(AN0) function with the led feedback and different trigger values?... if you could do it and tell us we can be totally sure about this issue.
It could be good when you exit the program by an external switch or save eeprom by an external switch.. or something like that, to be sure the eeprom write is not breaked just when a write operation is taking place.
You can try the following code with a write-eeprom function that should work for 12f675, if this code doesn't work properly without any delay then is very possible that there is a harware issue involved in the problem:
'******************************************************************************
'******************************************************************************
#chip 12F675, 4
#config Osc = Int
dir GPIO out 'Needed to attach the led
dir GPIO.0 in
dim num as word
'Configure ADC to read channel 0 (10 bits) 4 MHz clock:
ANSEL = b'01010001
ADCON0 = b'10000001'
wait 1 ms 'As this delay is outside the main loop it can be very long (just 20 us needed)
CheckAD:
set ADCON0.1 on '...................Start conversion
conv:
if ADCON0.1 on then goto conv '...Wait for conversion finished
num = ADRESL
num_H = ADRESH
if num > 511 then set GPIO.1 on 'you can connect a led to GPIO.1 to have feedback
if num < 511 then set GPIO.1 off 'Don't worry about num_H GCBasic does the work
my_EPWrite (0, num_H)
my_EPWrite (1, num)
Goto CheckAD
'_____ my_EPWrite subroutine _________________________________________________
Sub my_EPWrite(epadr, value)
EEADR =epadr
EEDAT = value
set EECON1.WREN on
EECON2 = 85
EECON2 = 170
set EECON1.WR on
thisisaLoop1:
if EECON1.WR on then goto thisisaLoop1
set EECON1.WREN off
End Sub
'******************************************************************************
'******************************************************************************
Ed:
Just a thought... in this line:
output = (input-outputn)/tp + outputn 'compute output
Whta's the matter when input < outputn?
I think "word" is an unsiged variable, then -1=65536, -2=65535, -3=65534....
Interesting this filter, i'm managing some adc reads and need something like this... but i don't totally understand yet how it works... what i was doing is just: read=(read+previous_read+2ºprevious_read....+nºprevious_read1)/n; but your method looks simple... i will use it... when i can understand how it works .... :)
Greetings...
Keith:
It could be great when we can be sure that ReadAD10 function is working properly.
When i check the asm code generated by GCBasic i think it should not work properly because ANSEL register is not correctly set; but may be there are things i cannot see and i would like to know what's really happening...
I have not any 16f675 to try and cannot simulate that PIC.
Checking the ReadAD10 function with the led system is a try but is not totally clear.
The only thing that is totally clear is having a look to the ANSEL register... then i think that when you can be sure eeprom write is working properly you can add this line to your code (using ReadAD10 function):
EPWrite (2, ANSEL)
this way we can know what is really happening inside the PIC...
Good luck with your proyects!!
Sorry... forget the idea of:
EPWrite (2, ANSEL)
It has no sense, when the ReadAD10 function is finished, ANSEL register is set to 0...
Hi Santiago,
Thanks for giving us your name and registering. Thanks also for the extra suggestions. I did try the program with ReadAD10, and it works properly on the 12F675 and 16F690 as well. At the moment your suggestions work well for my program, and most of the time I don't have to write to the eeprom in my main loop of 20 mS to keep the motor running, so it's no problem.
When I see your's and Kent's programs, then I realise just how much I need to learn. All I need now is more time......!!
Keith R
Hi all, here is a patch to the lag filter to correct the sign problem discussed in the PID thread.
This works both directions. Try to keep the ratio of tp/dt over 10, it helps stability.
Regards, Ed.
'A first order lag with PWM output
'Tested 02-22-09
'Chip model
#chip 16F88, 8
#config INTRC_IO
'Set the pin directions
dir portA.0 in 'input test signal pin #17 (an0)
dir portB.4 out 'output testsignal pin #10
dir portB.0 out 'set pwm output pin 6
'name I/O
#define pulse portB.4
'init on power up
set pulse off
dim Input as word
dim outputn as word
dim output as word
dim PWMDC as word
outputn = 0 'Initial condition
PWMDC = 0 'Initial condition
tp = 10 'time constant = tp in seconds (ratio of tp/dt )
FirstLag: 'reads input and computes output
Input = readad10(an0) 'get new data
If input >= outputn then
output = (input-outputn)/tp + outputn 'compute output
end if
if input < output then
output = outputn - (outputn - input)/tp
end if
outputn = output 'set n-1 value of output
PWMon 'Turn PWM on so we can see the internal calulations
PWMDC = output/4 'scale PWM
HPWM 1, 10, PWMDC 'output PWM
wait 100 ms 'set sample rate = dt
goto firstlag