Designing a Time Delayed Relay

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
Kris got both me and John (and perhaps many others) started using PICs. If I could, I would thank him profusely for it postmortem. A few years ago I wanted to get involved again with microprocessors and thought the Texas Instruments MSP430 series would be the way to go. I still like the TI Von Neumann architecture because it is so similar to the Intel 8080/8085 micros I "grew up" with, but in the early years of its release the cost to develop was prohibitive. I still have a few TI USB dongles with application-specific integrated circuits added to an MSP430 controller, but haven't done much with them yet. Free trade-show souvenirs for now, along with a box full of SMD parts (op-amps, voltage regulators, and the like), also picked up gratis at trade shows.

Here is a somewhat dated Instructable that provides an overview of most of the microprocessors available today. I have nothing against micros that come with "proprietary" code that allows rank beginners to become familiar with microprocessors. Heck, I wish those had been available in the 1970s when I was writing BASIC programs interpreted by a time-sharing main-frame computer. Try doing real-time I/O with one of those when the only connection is a 110 baud serial data link. But before the end of that decade... voila! Microprocessors everywhere! The Picaxe, Arduino, and Basic Stamp all get the ball rolling for the hobbyist of today. There may be others.

What floats my boat is getting down to the hardware level, manipulating bits and bytes that directly connect to the real world. The more abstract the connection is, the less I am interested in pursuing it. That is a job for professional programmers, coders, and analysts who can work with, and actually enjoy, abstractions. I like to bite into things that will bite you back if you're not careful. Code that fails by "throwing an exception" doesn't qualify. Just my own opinion, your mileage (or kilometers) may (will) vary.

It's nice to see John is moving forward on this project. With that inspiration, I might even resurrect the LED flashlight project, for which Kris started developing a solution. :D
 
Last edited:

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
After a little bit of thinking and toying with some code, I have some thoughts, clarifications and perceived problems for discussion. I hope the section below will allow all to follow along without having to review the last 300+ posts or outside documents!

To clarify where I am:
  • I need to receive an analog signal from two separate sources into the PIC12F675 - it only has one ADC so they will have to take turns being sensed. The signal will be used to turn on the relay on the board which controls the dust collector.
  • My ADC input will be oscillating at 60Hz - a sine wave fluctuating above and below a baseline of ~+2.5VDC
  • I need to sample this waveform ~720x sec or more to accurately detect when the wave is above (and below, as a secondary precautionary check against noise) 2.5VDC by a certain threshold amount.
  • I need to store the results of ADC input and then compare them against my threshold setpoints.
  • The chip will allow 1023 divisions of the input so we have resolution of about 4.88mV (5v/1023) and the thresholds for each sensor are different - one at 2.75VDC and the other at 2.9VDC
  • Clock frequency of 4MHz with instruction cycle of four oscillations or approximately 1μs
Some problems that came along:
  • Since I am using C initially to get this going, I am unware of the code's time cost - i.e. - how long do the instructions take to cycle? Is there a way to determine this through MPLAB's software? Since the time period to execute is unknown, I think for now it is safer to execute at clock speed with no delays, such that we can be assured of getting at least 720 samples per second or greater.
  • Since there is only one multiplexed ADC, will writing the code for one analog channel followed by code for the other be sufficiently quick enough to switch between the two inputs?
  • As you can see in the code below, I have only gotten up to the point of testing the code to turn the light on, there is no further code at this point to pick up the next state, which is power down with shut off routine. I am having trouble visualizing how to setup up the next part of the algorithm - specifically, how to code for turn off device after it has been initially turned on.
Code:
#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON       // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF        // Data Code Protection bit (Data memory code protection is disabled)

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>


#define _XTAL_FREQ 4000000                          // Setting internal clock to 4MHz

int main(void)

{
  // SET UP
  int AN3_AD_IN_110;                         // variable to hold value of A/D input from U2 Allegro chip, 110v line.
  int AN2_AD_IN_220;                         // " from U3 Allegro chip, 220v line.
                                            // This signal is baseline of 2.5VDC with a 0-2.5VAC signal riding on top.  
  int max, min, max1, min1;                    // variables for min/max comparisons  
  ADCON0 = 0b0001001;                               // AN2 is analog, turning on analog channel and starting converter
  TRISIO = 0b001100;                                // Only AN2 and AN3/MCLR are inputs all else outputs.


 while (1)
 {          
    ADCON0 = 0b0001101;                             // AN3 is analog, turning on analog channel and starting converter
    ANSEL =  0b0111100;                             // AN2 and AN3 set to Analog, other 2 pins are digital, 011 on left side indicates FRC for timing
    ADCON0bits.GO_DONE = 1;                         // do A/D measurement
       
    while (ADCON0bits.GO_DONE == 1)                 // wait until bit = 0 measurement completed        
         AN3_AD_IN_110 = ADRESL + (ADRESH << 8);    // 1024 bit resolution 5v/1023 = 4.88mV per bit
            if (AN3_AD_IN_110 >= 562)                 // check for voltage greater than 2.75 threshold
                max == AN3_AD_IN_110;               // set variable max to 562 or greater
            if (AN3_AD_IN_110 <= 1)                   // check for V less than 4.88mV, can't scale to negative values?
                min == AN3_AD_IN_110;               // set var. min to 1 or less
   
    if ((max >= 562) && (min <=1))                       // if threshold is achieved in either direction
        GPIO = 0b000001;                            // set GP0 high to turn on relay
        GPIO = 0b100000;  //REMOVE ONLY FOR TESTING // this is to check code on dev. board - GP5 outermost LED to corner should light
                 
    ADCON0 = 0b0001001;                             // AN2 is analog, turning on analog channel and starting converter
    ADCON0bits.GO_DONE = 1;                         // do A/D measurement
   
    while (ADCON0bits.GO_DONE == 1)                 // wait until bit = 0 measurement completed        
         AN2_AD_IN_220 = ADRESL + (ADRESH << 8);    // 1024 bit resolution 5v/1023 = 4.88mV per bit
            if (AN2_AD_IN_220 >= 562)                // check for voltage greater than 2.75 threshold
                max1 == AN2_AD_IN_220;              // set variable max to 562 or greater
            if (AN2_AD_IN_220 <= 1)                   // check for V less than 4.88mV, can't scale to negative values?
                min1 == AN2_AD_IN_220;              // set var. min to 1 or less
   
    while ((max1 >= 562) && (min1 <=1))                // if threshold is achieved in either direction
        GPIO = 0b000001;                            // set GP0 high to turn on relay
        GPIO = 0b010000;  //REMOVE ONLY FOR TESTING // this is to check code on dev. board - GP4 should light when active
   
           
 }
   

}
 
Last edited:

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
Something about your max and min routine doesn't look right. On the first iteration you should compare max against a value greater than, or equal to, half of full-scale and compare min against a value less than, or equal to, half of full-scale. Since this is an un-signed ten-bit integer from the ADC, all measured values will be in the range 0x000 to 0x3FF inclusively. Half of full scale would be 0x1FF or decimal 511.

Each time through the comparison loop, the value you test against will be different because the initial value 511 will be replaced with a new max value for the >= compare and the initial value 511 will be replaced with a new min value for <= compare. Subsequent comparisons may or may not replace min and max, depending on where on the sine wave the ADC measurement is made. The max values will range from 1FF to 3FF and the min values will range from 0x000 to 0x1FF. Therefore, you need your compare statements to be between two variables: the changing ADC output and the changing min and max values. So, instead of comparing against a constant, do the comparison against max and min values that were updated as a result of previous comparisons. Eventually, if the AC waveform is stable, the max and min values will quit changing.

Each time through the loop, you must check to see if the current ADC output is either greater than previous max or less than previous min values. If both conditions are true for successive ADC conversions, then you are done and the difference between max and min represents the peak-to-peak value of the input.

Probably the easiest way to determine when the loop is done is to compute and store the difference between max and min after each pair of comparisons in the loop and then determine when this difference quits increasing by a significant amount. So, create a variable called peak and after doing the two comparisons and possible replacement of min or max for the current ADC conversion, compute temp_peak = max - min for current comparison against a previously stored value for peak. If the difference between the current difference between min and max is less than the previous difference stored in peak, plus or minus say two least significant bits, then you are done. The value stored in peak is what your current limit will be compared against. If the difference is greater than plus or minus two least significant bits, replace peak with temp_peak and repeat the ADC loop until the peak is found.

As I mentioned earlier, the min/max test will converge rather quickly to min and max values that are nearly the peak-to-peak value, but it could take awhile for the least significant bits to reach their true values. You may want to try limiting the number of iterations to, say 128 or 256 with a counter if the peak isn't being found in a reasonable period of time.

I would set an LED output on either when the peak is found or the maximum iteration count is reached, and then reset the loop variables with a push-button switch for test purposes. You could also use another ADC channel to digitize a DC voltage from a potentiometer so you can set the level that the peak will be compared against.

You can nest the two ADC loops. Digitize one input and store the max, min, and peak values and then digitize the other input and store its max, min, and peak values. Set a flag bit in a variable to indicate when a loop has found its peak and then skip that inner loop. When both flags are set, the ADC min, max, and peak values can used in your program and later be re-initialized for the next time you want to measure the peak-to-peak value of the inputs.

All of this will be much easier if you get it working for just one ADC channel and then later duplicate for the second channel. Well, I would also add a small routine to read the potentiometer voltage and store the result as an integer to compare with peak. You only have to do this once, each time you re-initialize the max/min routine.

Don't worry about timing. Let the C code execute as fast as it can without worrying about how fast that actually is. If you have a "spare" output available, you can set it when you start each ADC cycle, clearing it each time at the end of the max/min loop, and use your DSO to see how fast the ADC conversions are occurring. You might even see some useful timing information by just monitoring the ADC input pins with your DSO... worth a try and you might learn something, but whatever "glitches" you see will be buried in the much larger DC-biased AC input signal. Might need a high-pass RC filter in front of your o'scope probe to get rid of that so you can see high-speed stuff. Use AC o'scope input coupling so you can crank the sensitivity up, although a high-pass filter should already take care of that. Setting and clearing a bit on an output port is soooo much easier, and it won't slow things down much to add that to your code.

Code this in bite-sized steps. Get the ADC max/min routines working, with an LED to indicate when the peak value is found. Use an ADC channel to digitize 0 to 5 V DC from a potentiometer and store this digitized value to compare against the peak value the max/min routine finds. Use a push-button switch to extinguish the LED and re-initialize max/min variables when pressed. When the switch is released, let the code rip and try to estimate how long it takes to find the peak value. Experiment with different pot settings from 0 to +5 V DC to make sure the peak is found for various output levels from your Allegro simulator. Write down the results in your journal.

Extra points if you give up on C and code this in assembly. :D
 

CDRIVE

Hauling 10' pipe on a Trek Shift3
May 8, 2012
4,960
Joined
May 8, 2012
Messages
4,960
John, I'll admit that I'm very late to the party but this thread is just too long to read all of it to see just how we got here. I did read the first page though. For the life of me the logic at this point is over complicated.

I'd want only two things from my dust collector:

(1) Turn ON at a predetermined time after the chips and dust generating
machine is turned on.
(2) Turn OFF at a predetermined time after the dust generating machine is turned OFF .

Number (1) is good practice to reduce wear and tear on your breakers and also lower peak instantaneous demand that many power utilities monitor and charge for.
Number (2) is primarily used to ensure that the debris has cleared out from the dust collector ducts and the impeller.

If I were doing this project I'd be using a ACS712 or a Toroidal Current Transformer to sense ON current for the wood working machine. I wouldn't care a hoot about where in the phase of a 60 Hz cycle this occurs. All I'd care about is developing a High or Low control voltage to feed the PIC. For this reason I doubt that I'd use an ADC input either. After that the PIC would only have to wait the 'delay' period before providing a High or Low output to drive a FET or BJT controlled relay coil. After that the program needs a similar OFF delay before shutting down the dust collector after you shut off the chip and dust maker.

In short, I see nothing that demands attention to phase angles, or more specifically measurements in nS, uS or mS, for that matter.

Chris
 

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
... In short, I see nothing that demands attention to phase angles, or more specifically measurements in nS, uS or mS, for that matter. ...
Chris, the thread is getting a bit long in the tooth, but it is an interesting chronicle of the journey John has made from newbie to accomplished PIC artist. @KrisBlueNZ provided lots of guidance and feedback before he passed, but John took it to completion by designing and populating a commercially-manufactured circuit board. The final circuit is quite simple: an Allegro Hall-Effect current sensor, a PIC, and a relay to turn the dust collector on and off. The only thing remaining is to write the control software.

The Allegro produces a faithful analog voltage copy of the current passing through its input terminals, including both DC as well as AC currents. To do this with a mono-polar power supply connection, the output analog signal is offset by half the supply voltage when zero current is present. No signal equals +2.5 V DC. Positive currents give a signal from +2.5 V to +5 V. Negative currents give a signal from +2.5 V to 0 V. Alternating current gives a signal that oscillates above and below +2.5 V DC, but in the range of 0 to +5 V DC depending on amplitude.

So, yeah, John could just look at the ADC output and use a "trip" level above +2.5 V DC to turn on his dust collector. Sooner or later (probably within a few cycles) the ADC will produce an output that indicates something is drawing current above the selected level and he can turn the dust collector on. And then he just looks for an ADC output near +2.5 V DC, plus or minus a few counts to allow for noise, to determine when to start the turn-off delay for the dust collector. There is a potential problem with that because the AC current goes through zero 120 times per second whether the tool is running or not. With the tool running, if one of those zero-crossings happened to get digitized, it could signal a erroneous delayed shut-down. Plenty of software ways to guard against that, but since it is just software I suggested that John program to discover a true peak-to-peak amplitude of the incoming AC current signal, and use the discovered peak-to-peak value for his threshold comparison.

The advantage of this approach is manly the learning experience, but it could come in handy later for digital processing of other alternating current signals. Once the code is developed it can be used over and over again without further expense.

So, here is the problem: the Allegro current sensor with an AC input produces symmetrical sinusoidal outputs centered about a DC voltage that is half of Vcc. How can John measure the peak-to-peak value of those outputs? Bear in mind that the output DC bias changes with changes in Vcc, and the Allegro itself may "drift" about the DC offset as a result of temperature changes and (perhaps) other factors. However, the transduction "gain" or the relation between changes in output voltage as a function of changes in input current remains relatively constant. So all that is needed is to subtract the negative-going peak value from the positive-going peak value to find a peak-to-peak value that will be insensitive to changes in the DC bias point.

Finding the positive-going peak value and the negative-going peak value are non-trivial digital tasks because the ADC conversion can occur anywhere within the AC cycle. The conversions are asynchronous to the incoming waveform. Sure, you could just look for an ADC output that exceeded some "trip" level, but that isn't the problem we are trying to solve. We want an accurate trip level that can be measured and adjusted to any level desired, either in software or with an external control. This ain't kids; this is real programming!

The max/min list-sorting routine is taught to every entry-level programmer. To find the max value you just compare the current max value against the previous max value. If the current max value is greater than the previous max value, the previous max value is replaced with the current max value. Similar reasoning to find the min value. Wash rinse and repeat until the max and min values (or, more explicitly, their difference) is no longer changing. For sufficiently fast sampling, say twenty or so samples per cycle or 1200 samples per second, the max and min values should be found within just a few cycles of the AC waveform. There are subtleties related to ADC resolution and the rate of change of the waveform near its peak values that I won't bore you with, but the basic algorithm is very efficient at finding max and min values that are "gud enuf" to work with.

John is also aware that there is an analog solution: cut the connection between Allegro output and ADC input. Insert capacitor (to block the DC bias), rectifier, and low-pass filter network. Now you have an analog DC signal proportional to AC input current. But why do that when a few bytes of code will accomplish the same thing? Maybe the next project will be to "teach" the PIC how to use a floating-point library to convert an arbitrary AC signal to a "true-rms" measurement. Might need a bigger PIC for that one.

Just to bring everyone up to speed on where John is with this project, below is the "final" schematic with power supply, two Allegro chips, a PIC, and a relay. And below that are two images of the finished product. You can find all this on page 17 of this thread, post #340 for the schematic and post #334 for the photos. No need to read the entire thread.

upload_2015-1-4_23-56-16-png.17967


0012_zps421d344a.jpg


0022_zps13dee2b3.jpg


As Kris said in his post #334, "just" add some software to control it. :cool:
 

CDRIVE

Hauling 10' pipe on a Trek Shift3
May 8, 2012
4,960
Joined
May 8, 2012
Messages
4,960
You're correct Hop. I wasn't aware that John was that far along (completely loaded PCB) with his project. That fact changes things greatly. Admittedly I would have taken an analog / digital (uC) approach. The only thing I'd have the Pic doing is On and Off delays. I wouldn't have even used an ADC input to the Pic.

Being a woodworker myself I'm quite familiar with both basic and elaborate dust collector systems. Some even have automatic duct gates.

I'm surprised that John had the patience to wait as long as he has to get this project done but as you pointed out John started his EP membership with this topic when he was as green as a Sapling. Now look at him...Astounding progress and accomplishment!! ;)

Chris
 

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
... I'm surprised that John had the patience to wait as long as he has to get this project done ...
The hardware was essentially complete as of January 3, 2015. John has been learning how to program PICs since then. I offered to do the programming, but he refused to accept my offer. How is the man going to learn anything if someone else hands him a canned solution? IMHO, it was a good decision on John's part to do his own programming. The power tools and dust collection system still have on/off switches John can manually operate, so it's not like completion of this project is a pressing priority.

One problem might be he is uncomfortable with assembly language, preferring C. Compared to C, Microchip ASM is rather arcane and very specific to a particular piece of hardware. It takes careful reading of the datasheet to learn how to "bit bang" various bits in various registers to get the PIC to do what you want it to do. It isn't necessary here, but John has not yet had to operate against timing constraints and satisfy real-time response to events signaled by hardware interrupts. I suppose it is possible to do those things in C with an optimizing compiler and careful attention to the code generated by the compiler, but I wouldn't attempt it. For this project, C seems to be an acceptable higher-level programming language. I sometimes wish I were more comfortable using it.

John and I correspond frequently, Chris. I got involved with this thread only peripherally, since John and Kris were doing so well working together. After Kris unexpectedly died, I continued technical exchanges with John on this and other projects.

John is a much better woodworker than I ever hope to be. Hell, I am a wood butcher, not a woodworker. My "dust collection" system is to use the Sears Shop Vac once a year or so to "clean up" my woodworking shop. He and I have exchanged photos of some of the work we have done, mostly small projects for the house, and I value his advise and expertise with regard to home maintenance repairs. Were it not for John and Kris, I would probably still be puttering around with Arduino Uno boards, wondering how I am going to fit ten pounds of electronics into a thimble.

Even the tiny 6-pin SMD PICs can do things we used to use TTL for back in the 1960s, before microprocessors came along. Of course you can now buy single-function TTL and CMOS parts in SMD packages, so you can sprinkle a gate or two here and there on a circuit board if that is necessary. Glue logic. The PIC is no speed-demon compared to discrete logic, but it packs a ton of functionality. What I might have done with analog circuitry, especially for timing purposes, is now dirt-cheap, simple, and easy with a PIC requiring no external timing components. But I am preaching to the choir here.

I try not to offer complete solutions here in this forum because I believe people should learn as much as possible on their own to effectively pursue this hobby. If a poster is looking to learn, I will help. If a poster is looking for easy answers, someone else can help them. I love to encourage newbies. Forums like this did not exist when I was kid poking around inside radios and TV sets in the 1950s. But you don't learn much if someone just gives you the solution without any effort on your part. John is willing to put forth the effort, so all I have to do is provide some guidance here and there from time-to-time. It's up to him to decide what to do.

It is easy to criticize a design with 20-20 hindsight. Most of this design came from Kris. John did the fine job on the board layout and component placement. The design of the delayed turn-off dust collector went through several iterations between Kris and John before it finally settled down to an Allegro Hall-Effect current sensor, a PIC, and a relay. Two Allegro sensors are used because John has 110 V AC as well as 220 V AC power tools on separate circuits. If you aren't fussy about not using a transformer for isolation, the whole thing (one tool only) could be fitted to the back side of a dual convenience outlet, one outlet for the tool and one for the dust collector. Might be a market for that if you could get UL approval and jump through a bunch of other hoops.

A lot of the conversation on this thread concerned the power supply and the use of "intrinsically safe transformers" to power same. If it were my project, I might have used an analog circuit to sense motor current and convey an on/off signal to the PIC. Or I might have foregone the use of a PIC entirely and used a timed delay-on-release relay (an expensive, large, COTS item) to control the dust collector. But the Allegro seems to be an ideal way to sense large AC currents using a very small "footprint" so I would probably have used it if I had known about it. And John had a size constraint he wanted to try to meet: fit the device inside a two-gang electrical box.

As you intimated, I probably would have just used an analog comparator (or a PIC with an analog comparator) to detect when the AC peak current exceeded a predetermined level. None of this max/min stuff, no analog-to-digital conversions. John could still program it that way if he wants to. No hardware changes required.

It is a real challenge doing any serious programming of small micros using high-level languages. I view micros as the hardware interface between the real world and the computing world, but the computer world is all about abstraction. The real world is all about specifics. It is all too easy to run out of memory or time or both when interfacing a microprocessor between the two worlds, so I tend to stick with assembly language programming. When the micros get big enough to incorporate operating systems, storage peripherals, and gigabytes of memory it is time (past time, actually) to switch to a high-level programming language. That may be why my Raspberry Pi has been gathering dust on my desk for several years now. I have the Linux OS on a thumb drive, but just can't seem to find the ambition to actually do something useful with the RPi.

Anyway, I am sure John will have the Delayed Turn-Off Dust Collector finished "real soon now" because Halloween is just around the corner and he has this spiffy project for his kids that involves that. But my lips are sealed until he posts about it. :D
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
@hevans1944 and @CDRIVE - you guys are too much :oops:;) I am still making my way through the electronics world and very aware that I am a rank novice still. I thank you both for the encouragement! I am very keen on learning enough to not only complete but continue on my electronics 'bucket' list of projects. I have some ideas that are mundane to quite interesting and want to be able to pursue them.

Getting on topic, I clearly don't understand my ADC input!

Based on the graph below, I was thinking that I would be looking for 2.75v and 2.9v as my switch signals.
The graph shows the output voltage of the ACS chip based on Vcc of 5v. If I want to switch at 2.5A and 4A, are 2.75 and 2.9v correct??

upload_2016-7-14_23-44-3.png

If the 1023 graduations are used to divide the sine wave from 0-5v, with 2.5v as the midrange at 511 - wouldn't 2.75 correspond to 563?

I see that my code is not sufficient to iterate properly. I will try to work on that if any time permits this week!

Hop, you will appreciate this: its the kids birthday soon and the one thing they both really wanted was a 3d printer, LOL. Of course the one they wanted is not sold assembled so we are all going to have an interesting time building this thing. Tomorrow should be fun! :cool::D And then off to watch the soccer match again :p:D:D - sorry, couldn't resist, got better seats for the same deal as last time :D
 

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
Lessee... 20 A corresponds to a voltage of 4.5 V and -20 A corresponds to a voltage of 0,5 V. So, you can write a linear equation for any output voltage a function of input current: Vout = 2.5 V + (4/40) (Iin). For Iin = 2,5 that means Vout = 2.5 + 0.1 (2.5) = 2.75 V. Check. For Iin = 4 A that means Vout = 2.5 + 0.1 (4) = 2.9 V. Check.

However, if 2.5 A and 4 A represent the rms motor current, you need to multiply rms by sqrt 2 or 1.414 to get the peak current. So, your threshold levels become (2.5)(1.414) = 3.535 A (peak) and (4)(1.414) = 5.657 A. (peak). That works out to 2.5 + 0.1 (3.535) = 2.854 V and 2.5 + 0.1 (5.657) = 3.066 V for your two thresholds.

Five volts into the ADC gives 0x3FF or 1023 decimal, so ADC output is Vin (1023//5.00). For 2.5 A rms motor current, peak output of ADC from Allegro will be 2.854 (1023/5) = 584, after rounding up to integer value, or 0x248. For 4 A rms motor current, peak output from Allegro will be 3.066 (1023/5) = 628, after rounding up to integer value, or 0x274.

If you do your ADC conversions and compare against 0x248 for 2.5 A motor current and against 0x274 for 4 A motor current you should get a "hit" (eventually) without doing the min/max calculations.
 
Last edited:

CDRIVE

Hauling 10' pipe on a Trek Shift3
May 8, 2012
4,960
Joined
May 8, 2012
Messages
4,960
John, this is a screen shot of a program I wrote for use with Picaxe ADC input. There's nothing revolutionary about it but it does reduce calculation tedium. After reading your last post it would appear to be applicable for use with blank PIC's too. If you'd like a copy I'll zip it up and post it.

Chris
upload_2016-7-15_9-44-33.png
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
Each time through the loop, you must check to see if the current ADC output is either greater than previous max or less than previous min values. If both conditions are true for successive ADC conversions, then you are done and the difference between max and min represents the peak-to-peak value of the input.
Post 363 should be all I need to complete the program, but I am stuck on this line in particular right now. You say that if both conditions are true, then you are done looking for the peak to peak. If both conditions are true, that means the ADC output is either greater than previous max or less than previous min value - wouldn't that indicate that the current is still changing?? If both higher highs and lower lows, that means the amplitude is growing, or the current is getting larger - wouldn't we want to come to a point where the previous max and min are equal?

I am a little lost on what you mean here. Can you please clarify for me?
Thanks!

Below is what I came up with to loop and check.
Essentially, I initialize max and min with a value, the first go around the ADC in is checked against these values, after that, they are subtracted from each other and if the difference is less than 20, we are within 100mV and we move forward to our check if max and min exceed our required threshold, if they do we turn on our relay (light for testing). I believe the adconbits.go_done part should be under the last if statement. Probably need to add a count = 0 after the adconbits to reinitialize the loop. Am I getting warmer?

Code:
while (1)
{        
    ADCON0 = 0b0001101;                             // AN3 is analog, turning on analog channel and starting converter
    ANSEL =  0b0111100;                             // AN2 and AN3 set to Analog, other 2 pins are digital, 011 on left side indicates FRC for timing
    ADCON0bits.GO_DONE = 1;                         // do A/D measurement
     
    while (ADCON0bits.GO_DONE == 1)                 // wait until bit = 0 measurement completed      
         AN3_AD_IN_110 = ADRESL + (ADRESH << 8);    // 1024 bit resolution 5v/1023 = 4.88mV per bit
            if (AN3_AD_IN_110 >= max)               // check for voltage greater than 2.75 threshold
                max == AN3_AD_IN_110;               // set variable max to 562 or greater
            if (AN3_AD_IN_110 <= min)               // check for V less than 4.88mV, can't scale to negative values?
                min == AN3_AD_IN_110;               // set var. min to 1 or less
            if (count < 128)  
                   temp_peak = max - min;
                   count = count + 1;
                   if (temp_peak <= 20)
                       if ((max >= 584) && (min <= 440)) // 0.354V above and below Vcc - 110v threshold
                           GPIO = 0b000001;         // set GP0 high to turn on relay
                           GPIO = 0b100000;  //REMOVE ONLY FOR TESTING // this is to check code on dev. board - GP5 outermost LED to corner should light
 
               
    ADCON0 = 0b0001001;                             // AN2 is analog, turning on analog channel and starting converter
    ADCON0bits.GO_DONE = 1;                         // do A/D measurement
 
Last edited:

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
Yikes! I almost missed that last post. Didn't show up in my alerts at first. Found it when I listed all the alerts to date.

I think I got it wrong as to when to exit the loop. When temp_peak = max - min quits changing it is time to exit the loop.

I'm a little busy right now, but I will try to look into this later. Finally got my basement workbench cleared off!
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
Finally got my basement workbench cleared off!
Nice!! That is exciting :D, does this mean you are prototyping or packing?

On second review today, I think I hit a stumbling block with the application of the logic in the code.

The idea to check for max and min and wait until they are stable by checking for little difference between the two would work if we are comparing voltages, but we are not simply adding +3v to -3v, (following the sine wave). In this case the values along the sine wave are being changed to a whole number - so if we are looking at a threshold of 0.354v above and below Vcc, we are reading into the ADC 2.854v or 584 on the positive side of the curve and on the negative side of the curve, 2.150v or 440. Subtracting those two numbers will never give us a small difference. We could retranslate the ADC numeric output into a decimal value, but I think we want to avoid floating point decimals if we can due to the large overhead involved.

It would seem that we are searching for a growing difference between the ADC input value, i.e. as the current grows, there would be a larger difference in the ADC value. At maximum input current, we would have a 2.5vac sitting on top of Vcc (2.5), so our max would be 5v and our min would be 0, creating a difference in ADC values of 1023. In contrast, when there is no current, we sit at 2.5, max and min or 511 for both, difference of zero. I will look at rewriting the code to reflect this discovery.

Let me know what you think when you are free. I will try to edit this post with the code when I finish it.

Thanks as always! :D
 

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
Subtracting those two numbers will never give us a small difference.
It is the difference that is changing. Compute (max - min) and store that value, say as PK_PK, before entering the max/min loop. If you initialize max = min = 0x200 or 0x1FF (half of the full-scale ADC output range) before you enter the max/min loop, then the initial value of (max - min) will be zero (so no computation necessary to initialize PK_PK; just set it to 0x00) and it will increase as the max/min loop is executed. At the end of each max/min loop iteration, retrieve PK_PK and subtract the current value of (max - min). If the difference is not zero, replace PK_PK with the current value of (max - min). If the difference is zero, exit the min/max loop with PK_PK now containing the peak-to-peak value of the input waveform.

Alternatively, since you update the values of both max and min each time you execute the max/min loop, you can just check to see if those values have changed from the previous iteration. Then exit the loop if both values are unchanged and compute PK_PK = (max - min).

Perhaps, if you have a Microsoft C compiler, you could code this up to execute on a PC with ADC input values accepted as keyboard number inputs. After each keyboard input, print the input value, PK_PK, max, and min all on one line. If the keyboard input value is 1024 or greater, re-initialize the max/min loop. See how fast it converges for some random integer inputs between zero and 1023.

does this mean you are prototyping or packing?
Prototyping!:D
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
Prototyping!:D
:DEnvious:D

This is what I have come up with previous to your post:
What I need to work on is rolling up the last statement that turns off the relay to be in one continuous loop with the rest of the program.
Code:
int main(void)

{
  // SET UP
  int AN3_AD_IN_110;                        // variable to hold value of A/D input from U2 Allegro chip, 110v line.
  int AN2_AD_IN_220;                        // " from U3 Allegro chip, 220v line.
                                            // This signal is baseline of 2.5VDC with a 0-2.5VAC signal riding on top.
  int max = 583, min = 441,
          max1 = 627, min1 = 627;           // variables for min/max comparisons on both channels 110/220
  int temp_value, temp_value1, peak, temp_peak;          
                                            // Hold temp values to compare ADC against
  int count = 0;
  ADCON0 = 0b0001001;                       // AN2 is analog, turning on analog channel and starting converter
  TRISIO = 0b001100;                        // Only AN2 and AN3/MCLR are inputs all else outputs.


while (1)
{        
    ADCON0 = 0b0001101;                         // AN3 is analog, turning on analog channel and starting converter
    ANSEL =  0b0111100;                         // AN2 and AN3 set to Analog, other 2 pins are digital, 011 on left side indicates FRC for timing
    //(ADCON0bits.GO_DONE == 1)                 // wait until bit = 0 measurement completed      
    AN3_AD_IN_110 = ADRESL + (ADRESH << 8);     // 1024 bit resolution 5v/1023 = 4.88mV per bit
      if (AN3_AD_IN_110 >= max)                 // check for 584 or greater
        {
          max = AN3_AD_IN_110;                 // set variable max to 584 or greater
        }
      if (AN3_AD_IN_110 <= min)                 // check for variable min to 440 or greater
        {
          min = AN3_AD_IN_110;                 // set var. min to 440 or less
        }
 
     temp_peak = max - min;              // temporary peak value established and used to compare later
 
     if (count < 128)                          // set counter to prevent infinite loop
        {
            count = count + 1;                  // incrementing counter
        }
      if ((temp_peak >= 144) && (count == 128)  // control statement - if peak value is above threshold and we iterated 129 times
           && (max >= 584) && (min <= 440))     // and if 0.354V above and below Vcc - 110v threshold then proceed
        {
          _delay(2);                            // 2 second delay before turning on
          GPIO = 0b000001;                      // set GP0 high to turn on relay
          GPIO = 0b100000;  //REMOVE ONLY FOR TESTING // this is to check code on dev. board - GP5 outermost LED to corner should light
          ADCON0bits.GO_DONE = 1;               // do A/D measurement
          count = 0;                            // reset count variable to zero for next go around
            
        }
        
}

    if ((temp_peak <= 130) && (max <= 560) && (min >= 490))
            {
               _delay(5);
               GPIO = 0b000000;
            }
 
Last edited:

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
Back to basics....

Perhaps, if you have a Microsoft C compiler, you could code this up to execute on a PC with ADC input values accepted as keyboard number inputs. After each keyboard input, print the input value, PK_PK, max, and min all on one line. If the keyboard input value is 1024 or greater, re-initialize the max/min loop. See how fast it converges for some random integer inputs between zero and 1023.

So that is just what I did, I was getting lost in the details, so this was quite helpful to get back on track, thanks!

The code seems to function, if you keep in mind the parameters of what should be entered - values along a sinusoidal wave. For instance, at Vcc 2.5v with a up to a 2.5VAC signal riding on top of it, 511 is the ADC's value at Vcc. With a current running through the sensors let's say we have 0.354VAC, or 73 units when converted by the ADC, our ADC value would vary between 438 and 584. That is the domain of valid entries when x amount of current is run through the circuit. At no current, we simply have Vcc or 511, no min/max. When run, enter the values and the program will look for a min and max and when detected, will subtract the two numbers and if the resultant is large enough, the light will turn on, when the value dips below a threshold, the light will turn off. The sampling size was reduced to 10 for testing purposes.

Code:
#include <stdio.h>
#include <stdlib.h>



int main(void)

{
  int AN3_AD_IN_110 = 0;             // variable to hold value of A/D input from U2 Allegro chip, 110v line.
  int max = 511, min = 511;          // variables for min/max comparisons on 110 channel 
  int temp_value, temp_peak = 0;            
                                     // Hold temp values to compare ADC against
  int count = 0;
  int input = 0;


 while (1)
 {          
   
    printf("Enter a value from 0 to 1023\n");
    scanf("%d", &input);    
    AN3_AD_IN_110 = input; 
      if (AN3_AD_IN_110 >= max)                 // check for 511 or greater
        { 
          max = AN3_AD_IN_110;                 // set variable max to 511 or greater
        }
      if (AN3_AD_IN_110 <= min)                 // check for variable min to 511 or greater
        { 
          min = AN3_AD_IN_110;                 // set var. min to 511 or less
        }
   
     temp_peak = max - min;              // temporary peak value established and used to compare later  
   
     if (count < 10)                          // set counter to prevent infinite loop
        {  
            count = count + 1;                  // incrementing counter
        } 
    printf("Max %d, Min %d, count %d, peak %d\n", max, min, count, temp_peak);
      if ((temp_peak >= 144) && (count == 10))  // control statement - if peak value is above threshold and we iterated 10 times
               
        { 
            printf("Light on \n");
            printf("Value of max is %d, min %d\n", max, min);   
            max = 511;
            min = 511;    
           count = 0;                            // reset count variable to zero for next go around
            printf("Max %d, Min %d, count %d, peak %d\n", max, min, count, temp_peak);
        }  
       if ((temp_peak <= 130) && (count == 10)) 
            {
                printf("Light off \n");
                printf("Value of max is %d, min %d\n", max, min);
               printf("Max %d, Min %d, count %d, peak %d\n", max, min, count, temp_peak);
                max = 511;
                min = 511;  
                count = 0;
            }          
         
           
 }
 }
 

hevans1944

Hop - AC8NS
Jun 21, 2012
4,968
Joined
Jun 21, 2012
Messages
4,968
:D:D:D:D Looks like you have nailed it! :D:D:D:D

I trust this will transfer (minus the I/O statements) to the PIC. Should be easy to test if you have bread-boarded the Allegro simulator. Use your spiffy digital storage oscilloscope to monitor the simulation waveform as you crank it up and down to make sure the trip points agree with the displayed sine waves. Don't forget to convert peak-to-peak measurements taken from the DSO screen back to rms to get trip points that are accurate with respect to Allegro AC current representations.

The current drawn by your shop equipment through the Allegro device will be your final test. If you can find a clamp-on ammeter to measure that current, you can relate it to the variable voltages produced by the Allegro simulator circuit, effectively calibrating it. Be careful probing around the Allegro after connecting the power tools to the circuit. Mains power is dangerous and it is only a few millimeters on the other side of the Allegro from you PIC. Temporarily connect whatever wires you need to make measurements of the Allegro outputs and use those wires for DSO and multimeter measurements. Apply AC to the power tools AFTER all test wires are in place. Make sure there is NO continuity from any of your measurement test wires (output 1, output 2, and common) to ANY of the AC current wiring. Remember, you are depending on those two Allegro chips to isolate your spiffy logic circuits from the real world!
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
Step 1, LOL, thanks Hop!!

I would love to probe the Allegro, but in reality, I think I will have to rely on good enough - the chip is a tiny soic and I really don't want to mess with trying to solder on test leads. If I must I will, but I think by going with the nameplate ratings, I should get to where I need to be without being dead on precise, I can always interface via the ICSP and upload any necessary changes or pop the chip as well. I will continue to work on the rest of the code and see how the loops fall together.

Thanks again for your continued support and direction :):D
 

chopnhack

Apr 28, 2014
1,576
Joined
Apr 28, 2014
Messages
1,576
Back on the hardware side of things, I successfully energized the circuit with no magic smoke! ;)

I was able to verify that the 7805 was doing its job via the J1 and J2 pins to a LED. LED lights when power is on. Only odd thing I noticed is that as soon as I powered up, the relay clicked... I didn't think that this was possible since Q1's base is currently not connected to anything since there is no pic chip in place. So after some sleuthing, it turns out the model I used in Eagle was an ECB instead of an EBC like the physical part I ordered.... :mad::mad::mad: and I thought I had cross checked all of my layout vs. physical components :oops:

Anybody know the part number or the fastest way to search for a ECB style 2N3904?
 

CDRIVE

Hauling 10' pipe on a Trek Shift3
May 8, 2012
4,960
Joined
May 8, 2012
Messages
4,960
Trevor, my Fairchild 2N3904 datasheet shows EBC for the TO-92 package only. The only other pin-outs shown apply to their SMD packages.
When I'm declared King of the world EBC pin-out will be one of my first decrees. :D

Chris
 
Top