PDA

View Full Version : Math question relating to AD input on PIC12F675



rfetech
- 27th October 2010, 18:08
Hello all,

This is my first PIC code in several years. Even back then, I only wrote a few simple programs and that will be obvious when you read my question. :)

I think that I'm OK with all the circuitry, and the main code isn't yet finished, but I would like for someone to help guide me with the math.

Let's assume that I have all the configurations correct.:rolleyes:

I'll have a pot connected to AN2, which is configured for 8 bits. This should give me a value of 1 - 255 at AN2. I want to convert that range of numbers (1 - 255) into seconds and then use the new value in a variable for the PAUSE command. The code, I believe, should give me a range of 1 - 63 seconds. I just don't know how the decimal places will be handled and if the PAUSE command accepts non-whole numbers.

Thanks and regards,
Mitch




delayloop:
ADCIN 2, adval ' read in value at AN2.
IF adval <4 THEN ' make lowest value to be 4 which would equate
adval = 4 ' to a 1 second pause.
delay = adval /4 * 1000 ' convert AD value of 1 - 255 into 1 - 63 second pause.
ENDIF
PAUSE delay ' pause from 1 - 63 seconds.

LinkMTech
- 27th October 2010, 18:31
Welcome Mitch,
I don't think you have to worry about the division remainders since it will be "rounded down".
But your code needs a little change to work as you want otherwise it won't give you a variable "Pause". So assuming this is just a snippet:


delayloop:
ADCIN 2, adval ' read in value at AN2.
IF adval <4 THEN adval = 4 ' make lowest value to be 4 which would equate to a 1 second pause.
delay = (adval /4) * 1000 ' convert AD value of 1 - 255 into 1 - 63 second pause.

PAUSE delay ' pause from 1 - 63 seconds.

aratti
- 27th October 2010, 18:44
delay = adval * 250 will give a better linerity, unless you prefer increments of one second.

Al.

rfetech
- 28th October 2010, 01:10
Thanks Louie and Al.

Louie: Yes, I do need to use parenthesis. That was an oversight. I hope you are correct about the division remainders. That is one of my concerns.

Al: It's not critical, either way, to my application but what you suggest makes good sense. I will probably test it each way.

I've tentatively completed the code for my project if either of you, or anyone else, would care to critique it for me. I could really use your more experienced opinions. I hope to breadboard it tomorrow.

Thanks again,
Mitch



'************************************************* ***************
'* Name : Train_Autoreverser.pbp *
'* Author : *
'* Notice : Copyright (c) 2010 *
'* : All Rights Reserved *
'* Date : 10/27/2010 *
'* Version : 1.0 *
'* Notes : Model train autoreversing circuit using *
'* : a PIC12F675 and reed switch sensors. *
'************************************************* ***************

' ---------Configuration--------

' PICBasic Pro v2.6a default configuration for PIC12F675
' __config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _CP_OFF


' ---------Constants/Defines-------

DEFINE OSCCAL_1K 1 ' Calibrate internal oscillator

DEFINE ADC_BITS 8 ' Set number of bits in result
DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time in uS

SW1 CON 0 ' Reed switch 1 to GPIO.0
SW2 CON 1 ' Reed switch 2 to GPIO.1
RY1 CON 4 ' Relay 1 (Power) to GPIO.4
RY2 CON 5 ' Relay 2 (Voltage reversing) to GPIO.5


' ---------Variables---------

adval VAR BYTE ' Store result of each A/D conversion.
delay VAR BYTE ' Store result of math conversion to seconds.


' ---------Initialization--------

ANSEL = %00000100 ' Set AN2 analog, all others digital.
CMCON = 7 ' Turn off analog comparators.


' ---------Main Code---------

PAUSE 2000 ' Let everything stabalize for 2 seconds.
LOW RY2 ' Make sure RY2 is off for forward movement.

mainloop:
HIGH RY1 ' Turn on Power relay to start forward movement.

IF SW1 = 0 THEN ' Keep moving in the forward direction until
LOW RY1 ' SW1 reed switch is closed. Then turn off
ELSE ' RY1 power relay to stop movement.
HIGH RY1
ENDIF

GOTO delayloop ' Keep stopped for x number of seconds.(1-63)

HIGH RY2 ' Turn on reversing relay for reverse movement.
HIGH RY1 ' Turn on power relay to start reverse movement.

IF SW2 = 0 THEN ' Keep moving in the reverse direction until
LOW RY1 ' SW2 reed switch is closed. Then turn off
ELSE ' RY1 power relay to stop movement.
HIGH RY1
ENDIF

LOW RY2 ' Get RY2 ready for next forward movement.

GOTO delayloop ' Keep stopped for x number of seconds.(1-63)

GOTO mainloop ' Keep repeating until user terminated.

END


delayloop:
ADCIN 2, adval ' Read A/D channel 2 into adval variable.
IF adval <4 THEN ' Make 1 second the shortest time delay.
adval = 4
delay = (adval /4) * 1000 ' Divide adval value (1-255) by 4 and multiply
ENDIF ' by 1000 to get millisecond value for PAUSE
PAUSE delay ' command. Place this value in delay variable.

rfetech
- 28th October 2010, 04:49
Never mind looking over my code as I have found gross errors and will be attempting to correct them will I get time over the next couple days. I will re-post when I think that I have the problems resolved.

Thanks,
Mitch

rfetech
- 28th October 2010, 17:52
OK.... that was a long night!! :eek:

I've finished the code and tested the circuit on a breadboard. After getting my head on straight, I was able to revise the main code quite easily, even for me!!

The headache and long hours occurred when I just couldn't get the A/D working correctly. I spent hours going over the data sheet and dozens of forum messages, tried different combination's of Defines and register settings but never got it working... UNTIL... I saw that the PAUSE statement was expecting a 16 bit argument. At least that is the way that I understand it. So, based upon that, I changed my code from being setup for 8 bit resolution to 10 bit and everything purred like a kitten. Got to bed at 6am with a smile on my face!!:)

Bruce, if you happen to read this, I strongly believe that your proposed book would have saved me many hours of head-scratching by translating the data sheet into easier to understand terminology. So, don't give up on it.

Thanks to all who post on this forum for giving me the use of your knowledge and helping us all learn from your own trials and your successes.

My extremely complex, yet simple code is available for scrutiny. :o

p.s. Special thanks to Louie and Al for responding to my original post and helping me much more than they probably realize. THANKS!!!



'************************************************* ***************
'* Name : Train_Auto-Reverser.pbp *
'* Author : *
'* Notice : Copyright (c) 2010 *
'* : All Rights Reserved *
'* Date : 10/27/2010 *
'* Version : 1.0 *
'* Notes : Model train auto-reversing circuit using *
'* : a PIC12F675 and reed switch sensors. *
'************************************************* ***************


' ---------Configuration--------

' PICBasic Pro v2.6a default configuration for PIC12F675
' __config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _CP_OFF
' Changed MCLR function to Input Pin during programming of PIC.


' ---------Defines/Constants-------

DEFINE OSCCAL_1K 1 ' Calibrate internal oscillator

DEFINE ADC_BITS 10 ' Set number of bits in A/D result
DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time in uS

RY1 CON 4 ' Relay 1 (Power) to GPIO.4
RY2 CON 5 ' Relay 2 (Voltage reversing) to GPIO.5


' ---------Variables---------

SW1 VAR GPIO.0 ' Reed switch 1 to GPIO.0
SW2 VAR GPIO.1 ' Reed switch 2 to GPIO.1
adval VAR WORD ' Store result of each A/D conversion
delay VAR WORD ' Store result of math conversion


' ---------Initialization--------

ANSEL = %00000100 ' Set AN2 analog, all others digital
CMCON = 7 ' Turn off analog comparators
ADCON0.7 = 1 ' Right justify A/D conversion output


' ---------Main Code---------

PAUSE 2000 ' Let everything stabalize for 2 seconds.
LOW RY2 ' Make sure RY2 is off for forward movement.


mainloop:

HIGH RY1 ' Turn on Power relay to start forward movement.

WHILE SW1 = 1 ' Keep RY1 active until reed switch SW1
HIGH RY1 ' is closed.
WEND

LOW RY1 ' Removes power and stops movement.

GOSUB delayloop ' Keep stopped for x number of seconds.(0-63)

HIGH RY2 ' Prepare RY2 for reverse movement.
PAUSE 500 ' Let RY2 settle before activate RY1.
HIGH RY1 ' Turn on power relay to start reverse movement.

WHILE SW2 = 1 ' Keep RY1 active until reed switch SW2
HIGH RY1 ' is closed.
WEND

LOW RY1 ' Removes power and stops movement.
LOW RY2 ' Prepare RY2 for next forward movement.

GOSUB delayloop ' Keep stopped for x number of seconds.(0-63)

GOTO mainloop ' Keep repeating until user terminated.

END


delayloop:
ADCIN 2, adval ' Read A/D channel 2 into adval variable.
delay = adval * 60 ' Creates values for PAUSE command that
PAUSE delay ' allow delays from approx. 0 to 61 seconds.
RETURN

aratti
- 28th October 2010, 22:14
Hi rfetech, glad you got it working as you wanted!

If I may suggest you an improvement to increase the stability of your delay, just take more ADC reading instead of one. In the example given I take 10 reading and than multiply for 6 instead of 60, this will reduce by a factor of ten any difference in the ADC reading.

Cheers

Al.




A0 Var Byte

delayloop:
Delay = 0
For A0 = 1 to 10
ADCIN 2, adval ' Read A/D channel 2 into adval variable.
Delay = Delay + Adval
next A0
delay = delay * 6 ' Creates values for PAUSE command that
PAUSE delay ' allow delays from approx. 0 to 61 seconds.
RETURN

rfetech
- 29th October 2010, 15:02
Thanks Al. I'll add that to my code. The delay timing isn't critical but this extra code is good learning experience for me and I do appreciate it. FYI, this controller is for a small train that sits on a 12 ft shelf in the barber shop of a friend. He wants it to simply go back and forth to entertain the kids while they wait their turn to get a haircut. Who knows... some kid might be more curious about the controller, than the train, and become a PIC programmer. ;)

Thanks again!

Mitch

rfetech
- 4th November 2010, 13:02
I thought this might be a good starter project for someone so I have attached the schematic.

Mitch

aratti
- 4th November 2010, 16:59
Mitch, it is a good practice never leave inputs pins or reset floating. So I suggest you to pullup pin 4 with a 10K resistor. Apart from this well done.

Al.

tenaja
- 4th November 2010, 19:49
The biggest problem was not your 8 or 10 bit ad reading, or even the type of variable used for the pause command. (Pause will work with a byte.) In fact, the problem was the use of a byte var instead of a word in your calculation.... 255/4 *1000 = over 63,000... and that obviously does not fit within a byte

rfetech
- 5th November 2010, 02:04
Thanks for the input, Al. I build a PCB for my project today and that is when I discovered that I had left out resistors R6 and R7 from my schematic. I also realized that I had not done anything with pin 4. I went to the data sheet and, after reading, I decided to use pin 4 as MCLR. I also decided that I wanted POR active so I added the RC network that was suggested in the data sheet and then turned on those options in the PIC. I don't know the pros and cons of that decision but the MCLR and POR could be useful, in my opinion. I've updated my schematic and included it in the following attachment.

Tenaja, thank you for looking over the code and pointing out that PAUSE will work with a byte variable. Actually, I did realize that a BYTE was not large enough for my original calculation after I had struggled with it for a long while. :confused: Thanks again!

OK, here's the latest iteration of my circuit. This is the way I have built it onto a PCB today and it appears to be working great. Just have to experiment with the magnets under the train in order to get the spacing correct for the reed switches. I will post the final version of the code once I get a chance to update it and maybe try a couple little changes.

Regards,
Mitch

rfetech
- 9th November 2010, 03:35
OK, here is the final code, I hope, as I'm installing the controller for my friend sometime this week. I've incorporated the code suggestion from Al in the delay loop.

Again, thanks to you all for the helpful suggestions, etc.

Sincere regards,
Mitch





'************************************************* ***************
'* Name : Train_Auto-Reverser.pbp *
'* Author : *
'* Notice : Copyright (c) 2010 *
'* : All Rights Reserved *
'* Date : 10/27/2010 *
'* Version : 1.0 *
'* Notes : Model train auto-reversing circuit using *
'* : a PIC12F675 and reed switch sensors. *
'************************************************* ***************


' ---------Configuration--------

' Accepted PICBasic Pro v2.6a default configuration for PIC12F675
' __config _INTRC_OSC_NOCLKOUT & _WDT_ON & _MCLRE_ON & _CP_OFF
' Also enabled PWRT and BOD during programming of PIC.


' ---------Defines/Constants-------

DEFINE OSCCAL_1K 1 ' Calibrate internal oscillator

DEFINE ADC_BITS 10 ' Set number of bits in A/D result
DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 50 ' Set sampling time in uS

RY1 CON 4 ' Relay 1 (Power) to GPIO.4
RY2 CON 5 ' Relay 2 (Voltage reversing) to GPIO.5


' ---------Variables---------

SW1 VAR GPIO.0 ' Reed switch 1 to GPIO.0
SW2 VAR GPIO.1 ' Reed switch 2 to GPIO.1
adval VAR WORD ' Store result of each A/D conversion
delay VAR WORD ' Store result of math conversion
A0 VAR BYTE ' Index for measurement loop

' ---------Initialization--------

ANSEL = %00000100 ' Set AN2 analog, all others digital
CMCON = 7 ' Turn off analog comparators
ADCON0.7 = 1 ' Right justify A/D conversion output


' ---------Main Code---------

PAUSE 2000 ' Let everything stabalize for 2 seconds.
LOW RY2 ' Make sure RY2 is off for forward movement.


mainloop:
HIGH RY1 ' Turn on Power relay to start forward movement.

WHILE SW1 = 1 ' Keep RY1 active until reed switch SW1
HIGH RY1 ' is closed.
WEND

LOW RY1 ' Removes power and stops movement.

GOSUB delayloop ' Keep stopped for x number of seconds.(0-61)

HIGH RY2 ' Prepare RY2 for reverse movement.
PAUSE 500 ' Let RY2 settle before activate RY1.
HIGH RY1 ' Turn on power relay to start reverse movement.

WHILE SW2 = 1 ' Keep RY1 active until reed switch SW2
HIGH RY1 ' is closed.
WEND

LOW RY1 ' Removes power and stops movement.
LOW RY2 ' Prepare RY2 for next forward movement.

GOSUB delayloop ' Keep stopped for x number of seconds.(0-61)

GOTO mainloop ' Keep repeating until user terminated.

END


delayloop:
Delay = 0 ' Zero out variable
FOR A0 = 1 to 10 ' Take 10 readings
ADCIN 2, adval ' Read A/D channel 2 into adval variable.
Delay = Delay + adval
NEXT A0
delay = delay * 6 ' Creates values for PAUSE command that
PAUSE delay ' allow delays from approx. 0 to 61 seconds.

RETURN