Duty Cycle detection - Page 1
Forum section: electronics / projects

author: 84750Erik
author_rank: Contributor
timestamp: October 12, 2017, 08:10:58 am
content: I need to detect whether the duty cycle from a circuit drops below a certain value.Frequency: 2kHzAmplitude: TTL (0 to 5V)Step response: an hour or more (it is a very slow system)Requirement: detect whether the duty cycle is lower then a adjustable value, most likely less then around 70%.Hysteresis is required, say about 5 to 10%.When the duty cycle drops below the preset value a TTL output needs to be triggered. When the duty cycle recovers above the preset value+hysteresis the TTL output needs to be reset. Changes in duty cycle take several hours. However measurements take place once an hour only, during a time adjustable between say 5 seconds and 30 seconds.A circuit with a flipflop and 2 comparators is my preference. And I want a hardware solution, no software with microcontroller: the circuit has to be universally used without need for software. at a later stage this circuit wil be used in a controller for further processing.

author: Benta
author_rank: Super Contributor
timestamp: October 12, 2017, 08:32:35 am
content: Some kind of monostable, where decision point is if the monostable or your PWM pulse times out first. A 4538 might do it, but a counter/timer would be more stable.

author: Rerouter
author_rank: Super Contributor
timestamp: October 12, 2017, 08:36:01 am
content: the circuit your describing is a missing pulse detector, e.g. using the good old 555 timer,

author: danadak
author_rank: Super Contributor
timestamp: October 12, 2017, 09:23:19 am
content: QuoteA controller can "appear" as a universal part with proper software and HW design.This can be easily done with a PSOC or for that matter just about most low end controllers. Solutionwould be 1 chip.What is the accuracy and resolution of the duty cycle measurement/decision you want to male ?Regards, Dana.

author: mikerj
author_rank: Super Contributor
timestamp: October 12, 2017, 10:59:06 am
content: Low pass filter the PWM and use a conventional comparator with feedback for hysteresis?

author: David Hess
author_rank: Super Contributor
timestamp: October 12, 2017, 01:40:02 pm
content: Quote from: mikerj on October 12, 2017, 10:59:06 amIf the frequency is not stable then this is what I would do. The input levels to the filter and the comparator need to either be stable or ratiometric which means truing up the TTL signal. Note that TTL is *not* 0 to 5 volts.

author: 84750Erik
author_rank: Contributor
timestamp: October 12, 2017, 06:12:23 pm
content: Hi Mike, it is not pwm but you come closest to what I need.555 is out because trigger points cannot be set (resistors are internal); I received a circuit to be tested in LTSpice, could not get duty cycle detection at a higher then 50% trigger point. I need to detect from 80% downward.A 1st degree low pass into the negative of a comparator (339 or 393), and on the positive the reference voltage. Hysteresis with resistor in positive feedback. And a buffer (I use a spare CD4093 lying around) before the LP filter.Just tested it out, works perfect for my needs.

author: 84750Erik
author_rank: Contributor
timestamp: October 12, 2017, 06:14:18 pm
content: 555: unable to set trigger point beyond 50% duty cycle. I may miss something, but I tested a circuit on LTspice. Maybe you have a better schematic?

author: 84750Erik
author_rank: Contributor
timestamp: October 12, 2017, 06:16:24 pm
content: Quote from: danadak on October 12, 2017, 09:23:19 amNo controller and I mean it: hardware solution is cheaper, faster, less current consumption and I can connect my circuit to any kind of controller later on to process the result.

author: fcb
author_rank: Super Contributor
timestamp: October 12, 2017, 06:19:20 pm
content: +1 for MikerJJust use a low pass filter and a comparator.

author: 84750Erik
author_rank: Contributor
timestamp: October 12, 2017, 06:19:52 pm
content: Quote from: David Hess on October 12, 2017, 01:40:02 pmFully agree, I am sorry, I should have specificied: 0 to 5V. Filter and comparator fed by buffer (I used spare CD4093 lying around), just been testing, works perfect: I can adjust trigger point from 90% down to 40% (duty cycle does not go lower), hysteresis adjustable. I did not know/realise how valuable you all are! Thank you very much!!

author: 84750Erik
author_rank: Contributor
timestamp: October 12, 2017, 06:25:14 pm
content: Quote from: danadak on October 12, 2017, 09:23:19 amAccuracy and resolution do not matter much, repeatability does.The actual duty cycle may vary due to hardware tolerances, and variations in duty cycle will be less then 10% per day max, in a one way direction: down. Very slowly. I plan on doing measurements once an hour, get a DC voltage or even simpler: either on or off, and process that further in a controller.

author: danadak
author_rank: Super Contributor
timestamp: October 13, 2017, 12:19:01 pm
content: w/o using an external xtal a PSOCs main osc is +/- 2%, so thatwould govern its timing accuracy and repeat-ability in a duty cyclemeasurement.That's PSOC 4 the low end part. This could b e done completely in HWand toggle a pin. Only code needed would be to start the componentsinside PSOC. Or use code to do measurement with PSOC via ISR orb oth.Regards, Dana.

author: Zero999
author_rank: Super Contributor
timestamp: October 13, 2017, 06:14:21 pm
content: Quote from: David Hess on October 12, 2017, 01:40:02 pmYes, I agree. use a comparator to get the TTL voltage to a known level, low pass filter it and use another comparator to compare it to a fixed reference voltage.See attached.U1 converts the signal to a definite 5V square wave. The threshold is 2V with 50mV of hysteresis. This is low pass filtered by R6 and C1. U2 compares it against 70% of the supply voltage, around 3.5V, with around 180mV of hysteresis (about 5%).Note that this circuit might benefit from a comparator with a higher common mode input range or run of a higher supply voltage, which might require changing the values of R1 to R4. The LM393 is only specified to 1.5V below the positive rail, yet this circuit takes the inputs on U2 to nearly 3.6V.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 13, 2017, 06:29:34 pm
content: Is the frequency stable and guaranteed 2kHz +/- (margin proportional to the duty cycle threshold margin)?If so, a missing pulse detector is a fine solution. It's also the fastest possible solution (latency of ~1 cycle on average).If not, an LPF + comparator is pretty good, minding that the LPF needs to roll off considerably lower than whatever the true minimum frequency is. This of course isn't a problem over the requested duration (sub 1 hour).Don't forget hysteresis on the comparator, to prevent false triggers from the LPF's leftover ripple when it's borderline near the threshold.You will want to use an active filter, to keep component size and cost down. Although if the 220k + 4.7uF shown above is acceptable, that's not too bad. Try to avoid using electrolytic capacitors here. Film caps are very large, but good. Tantalum is actually quite reasonable (okay leakage, stable value, no danger of shorting out a supply!).If very low supply consumption is desirable, you can choose some nice slow CMOS op-amps and comparators. A comparator with response time in the 5us range sips little enough current that it can run from a battery for months, maybe even years on end. They perform quite well, when you don't need screaming speed.Tim

author: 84750Erik
author_rank: Contributor
timestamp: October 13, 2017, 07:50:09 pm
content: Quote from: T3sl4co1l on October 13, 2017, 06:29:34 pmThe pulses being detected my miss here and there, the frequency is within 5%, so I would say good enough for a comparator solution. And yes, very low power consumption is preferred (battery operation), so your information is most helpful!

author: 84750Erik
author_rank: Contributor
timestamp: October 13, 2017, 07:51:13 pm
content: Quote from: Hero999 on October 13, 2017, 06:14:21 pmThis is it!!!Thanks, will be built and fine-tuned.

author: 84750Erik
author_rank: Contributor
timestamp: October 13, 2017, 07:53:36 pm
content: Quote from: Hero999 on October 13, 2017, 06:14:21 pmCan you suggest a comparator per your latest sentence please?

author: newbrain
author_rank: Super Contributor
timestamp: October 13, 2017, 09:45:10 pm
content: Quote from: 84750Erik on October 12, 2017, 06:16:24 pmTo each their own, I won't try to convince you otherwise, but I would like to understand the reasoning behind this choice.Cheaper:Thesmallest PIC (SOT23-6)with an analogue comparator costs on Digikey almost exactly asone LM393(in single quantity). Even assuming the passives as free, it's more expensive unless a large number of unit is produced.Faster:With the LPF solution (very nice one, Hero999!), not really. In any case, it would not seem to be an important point, given the times at play.Less current:The resistive dividers to set the thresholds in the analogue solution draw by themselves more than the MCU, even without using sleep modes.Connectivity:No special advantage for either solution. The PIC might be more versatile (though not much, given its limitation).The above without taking into account a more complex layout and an increased BOM.Of course, a negative side is that one needs to write the firmware.

author: Someone
author_rank: Super Contributor
timestamp: October 14, 2017, 12:24:45 am
content: Quote from: newbrain on October 13, 2017, 09:45:10 pmI agree this seems like an ideal job for a microcontroller and a small part with appropriate sleep modes and power gating would have vanishingly tiny power consumption (the fun of having all the power gating configurable inside the chip). Microcontrollers can be used as universal type chips for all sorts of functions and delivered as a black box, the interfaces in and out would be simply TTL/CMOS here. The requirement for me that jumped out and screamed embedded micro was this one:Quote from: 84750Erik on October 12, 2017, 08:10:58 amBut that seems to have been poorly explained and the OP has made it clear they're not going to think about microcontrollers.

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 01:54:48 am
content: Quote from: newbrain on October 13, 2017, 09:45:10 pmYou convinced me.I know AVR controllers (Atmega328, Arduino,..) and I have a bit of C++ experience.Please give me some input o how to tackle this?

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 02:10:21 am
content: Quote from: Someone on October 14, 2017, 12:24:45 amI am truly sorry, I hope to be able to explain better: please let me know what it is that was not explained well?And after both of the previous posts here I have been convinced to at least try and experiment with a microcontroller solution.I had thought it would not be possible to get a digital controller to verify duty cycle from a frequency that is stable within 10% (worst case) and where the pulses do get missed from time to time, and where the drift in duty cycle is downward over a perios of days/weeks and an upward correction takes hours. And most likely my hardware schooling made me prejudiced. So, I listen to you: please let me know what and how this can be done with a controller.

author: Someone
author_rank: Super Contributor
timestamp: October 14, 2017, 04:27:47 am
content: Quote from: 84750Erik on October 12, 2017, 08:10:58 amThis is confusing, measurement of what is once per hour? How is that timed/triggered/decided? A small microcontroller can stay in a low power mode and wake up as often as needed, then this is a simple design:Start a timer and set an interrupt to occur on the edges of the signal being measured.In the interrupt store the timer value and the polarity of the signal (add debouncing here if needed to clean up the edges).Once you have 3 edges then you can calculate the duty cycle, make a decision, turn everything to low power and go back to sleep (repeat and filter if you want to reduce noise or cover missing pulses).Some controllers will even have timer capture hardware that can do this with more determinism than a simple interrupt, but thats more accuracy than you've suggested you need. A timer at only 1MHz has 0.2% resolution for the duty cycle of a 2kHz signal. By measuring the duty cycle and the period you are now only concerned with the short term stability of the clock source and not its accuracy so the onboard low power oscillator will likely be sufficient. Even the larger Atmel parts you are already familiar with will wait in low power modes of a few uA, so lower power consumption is going to be hard to achieve with a comparator, reference, and biasing.

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 04:34:42 am
content: Quote from: Someone on October 14, 2017, 04:27:47 amThe purpose is to have a reading once an hour of the duty cycle of a sensor output. Since this sensor too has to be woken up and since it may take several seconds to stabilise then the reading of a stable and reliable measurement may take several seconds. But once the sensor output (the duty cycle) has stabilised then the reading may go ahead, say for example 5 readings are taken and then the average calculated.The sensor output may also be passed through a low pass filter: then we just have to read an analog value.

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 04:42:09 am
content: Quote from: Someone on October 14, 2017, 04:27:47 amI am not familiar yet with interrupts. But there would be a DS3231 RTC module present.The whole module consists of 1. the sensor module with duty cycle output 2. hard- or software to convert this duty cycle value to an analog value (or convert straight using a microcontroller) 3. a microcontroller to process this value for transmission 4. DS3231 RTC module to control the wake-up timings of the microcontroller for transmissions 5. a 464MHz HC12 transmission module 6. 6V battery, LDO voltage regulator and solar panel.So if the duty cycle measurement can be done by this same microcontroller I am open for suggestions as you did, but please maybe a little more detailed because my programming knowledge is still lacking a lot?

author: newbrain
author_rank: Super Contributor
timestamp: October 14, 2017, 10:42:02 am
content: Quote from: 84750Erik on October 14, 2017, 01:54:48 amOh drat! I now have to be helpful rather than snarkyQuote from: 84750Erik on October 14, 2017, 04:42:09 amSome programming will be needed for sure: your system already includes both I2C (for the RTC) and UART (for the RF module) interfaces, plus something else to wake up the sensor when it's time for a measurement.A controller able to handle those will for sure have enough power to measure the duty cycle at 2kHz.An ATmega would be I think OK: there'sAtmel Application Note 135that fits very well with what you're after, and other examples can be found on the web.If you're familiar with Arduino it might even be possible to use its framework for the communications and sensor control, while resorting to direct register programming for duty cycle measurements.I have more experience with STM32s, so mypersonalpreference would be to use an el-cheapoSTM32F103 boardor a (more expensive) Nucleo and exploit the timer PWM input capture mode (see chapter 14.3.7 in thereference manual) to get period and on/off times. As those cheapies come with a 32kHz crystal, I would probably do away with the separate RTC module, unless the better accuracy or other time keeping functions of DS3231 are needed.Of course, the way forward depends also on other constraints, e.g. time available vs. platform knowledge, single project or small/large volume product etc. etc...

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 11:56:25 am
content: Quote from: newbrain on October 14, 2017, 10:42:02 amDirect register programming: out of my league.Time constraints: not applicableWillingness to learn: fullyRTC module: necessary because the module needs to be able to remain accurate within about a minute over a half year periodSo unless I may receive some guidance I can just as well use the hardware solution. But I am willing to take up the challenge given the input I already received here.

author: David Hess
author_rank: Super Contributor
timestamp: October 14, 2017, 11:58:09 am
content: If I did not want to tie up or use the timer/counters or any external logic, then I might use an I2C or SPI port as a 1 bit clocked ADC. Count the number of 1s and 0s to get the duty cycle and do so over multiple cycles to get greater resolution if needed. Or use any general purpose I/O pin to do the same thing in a software loop.

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 12:09:03 pm
content: Quote from: David Hess on October 14, 2017, 11:58:09 amWhy should I have to give up I2C just to count 1s and 0's? Can this not be done in a digital input? During a short fixed amount of time read digital values from the sensor, summation of both and compare the amount of high versus low?

author: David Hess
author_rank: Super Contributor
timestamp: October 14, 2017, 01:25:56 pm
content: Quote from: 84750Erik on October 14, 2017, 12:09:03 pmSure it can be done with a general purpose digital input which I said. The advantage of using an I2C or SPI port is that a much higher sample rate may be attained for greater resolution.

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 03:03:05 pm
content: What digital input is the SPI port on an Arduino?I don't think to need the SPI port, programming will be over hardware serial.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 14, 2017, 05:27:57 pm
content: Note that a digital input pin is a 1-bit ADC (with a shitty threshold). You can realize precisely the same functions that have been suggested here in analog terms, as digital structures. Upside: counters are free, and numerical division is mere microseconds, so it's even more accessible to do the full, frequency independent, duty cycle calculation (again, not that you need to).Considering your signal is more or less digital to begin with, there need not even be any quantization noise!You do have to worry about sample rate and all that, but since you want statistics rather than reproducible waveforms, you only need to sample at a rate suitable to give the desired confidence margin within the specified read-out time. The CPU could wake up every couple of minutes, burst a few samples, and sleep. Then every say 16 of those cycles, crank the samples through the statistics function and prepare a new result. This would then be polled (maybe filtered again, since you can afford it) at the hourly-ish rate, or whatever.Tim

author: Zero999
author_rank: Super Contributor
timestamp: October 14, 2017, 07:27:06 pm
content: Quote from: 84750Erik on October 13, 2017, 07:53:36 pmOn second thoughts, the LM393 will do, with some modifications to the circuit. R11 is added, to reduce the maximum voltage on C1 to 4.545V and change the values of the resistors around U2 to compensate.

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 08:50:02 pm
content: Quote from: T3sl4co1l on October 14, 2017, 05:27:57 pmHi, can you please help with something more specific? I have been reading here about SPI ports to be used, about interupts,.. I am a bit confused:1. does it matter which digital input on an Arduino to use? If so, why and which one?2. Your proposal sounds good but I would not even go that far; I would just take samples once an hour during 10 or so seconds after a 5 second warm-up and process the results (count number of LOW and HIGH readings and process). What is your take on that?3. Can you get me some flow chart or sample code or a link to where I can find more specific coding examples or hints?Thank you, Erik

author: 84750Erik
author_rank: Contributor
timestamp: October 14, 2017, 08:54:27 pm
content: Quote from: Hero999 on October 14, 2017, 07:27:06 pmok, thanks; I have the hardware and the software route to experiment with: I will investigate both solutions, since time is not an issue -reliability is- I can afford it.

author: Zero999
author_rank: Super Contributor
timestamp: October 14, 2017, 10:24:13 pm
content: Personally I'd choose the software/digital solution. It should be trivial with a microcontroler and will be more accurate than an analogue solution.

author: newbrain
author_rank: Super Contributor
timestamp: October 14, 2017, 10:34:19 pm
content: Quote from: 84750Erik on October 14, 2017, 08:50:02 pmUsing the SPI might be possible, but I don't see the advantage with respect to using one of the timers in the ATmega, it's a bit of a kludge and then one would have to count ones and zeros inside the received byte stream.1. If you use a digital input, any unused digital (also analogue) pin of the Arduino would do, if you intend to use the comparator the choice is more limited: only one pin can the positive input, but the negative one can be assigned to any of the ADC inputs, if the ADC is disabled.2. If that fits your precision and accuracy needs, I don't see any problem with your solution (but I'm not T3sl4co1l!).3. As I pointed before the code associated with AN135 might be a good start: it's interrupt based, but well commented, and the AN explains the used algorithms.It can be foundhere.Using a SW only solution eschewing the timer peripheral and interrupts is also possible, just sampling the input in a tight loop and accumulating the zero and one results during your sampling time.One must be careful, though:Interrupts should be disabled, not to disturb the sampling. Not using Arduino myself I don't know if that's acceptable (but possibly yes, if no function relying on intterupts are used in the loop).the code path for counting zeros and ones should be the same, otherwise results would be skewed.Something like this:Code:// Untested code, just an incomplete sketch - pun partially intended// Variables 32 bit wide should be more than enough:// I would expect the sample rate to be quite less than 4MHz, giving// 1000 seconds as the longest possible sample window for a 32 bit// unsigned integer.uint32_t count = 0; // Counter for 0s + 1suint32_t ones = 0; // Counter for 1anoInterrupts(); // Disable interrupts// Thw LOOPS_IN_5S constant should be tuned for the loop to last// about 5s, or whatever sampling time is neededwhile(count < LOOPS_IN_5S){// Note that no "if" is used, the path for 0s and 1s is the same// To have an efficient loop, I would never use digitalRead(),// it should be changed to a simple register read.ones += digitalRead(inutPin);count++;}interrupts(); // Re-enables interrupts.// Calculate the duty cycle in %. If more precision is needed// *1000 could be used, or floating point.uint16_t dutyPer100 = (ones*100)/count;Hope this helps!

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 14, 2017, 11:08:43 pm
content: Quote from: 84750Erik on October 14, 2017, 08:50:02 pmI don't know Arduino boards specifically, but the basic ATmega has options. You're simply reading a digital pin state. SPI can do that, USART can do that, GPIO can do that.Serial might be less convenient, because you get bytes out, whereas you might want a unary bit stream. You need to unpack the bytes to get a high-and-low count (which is kind of annoying to write out in C).The basic operation might be this:Code:// initializationuint16_t mark = 0, period = 0;while (read_pin == 0);// pin just turned to 1, count 'on' durationwhile (read_pin == 1) {mark++; period++;delay(SAMPLE_TIME);}// pin just turned to 0, count 'off' durationwhile (read_pin == 1) {period++;delay(SAMPLE_TIME);}Repeat this a few times, sum up the marks and periods, and get duty_cycle = (uint16_t)((1 << 16) * mark / period) (for a 0.16 fixed point result).Note that the above code hangs until an edge is received, and skips through rapidly if edges are much more common than expected. This is a good example of fragile code. Better to use for() to make a fixed duration loop -- it might be 10 second window you mentioned -- and count the occurrence of 1 conditionally.The DSP method is similar, using accumulator variables that count up the input, but instead of doing a final division, the pin value is added (unconditionally) to the variable, then the variable's value is reduced proportionally each iteration. That is, multiplied by a number slightly less than 1.0 -- the effect is to have a "leaky" accumulator, so that a constant stream of '1's will not make the accumulator eventually overflow, but instead it rises and levels off exponentially, just like the voltage on a capacitor.Such a loop looks like,Code:uint32_t accumulator = 0;const uint32_t GAIN_FACTOR = (1 << 16) * (;for (NUM_SAMPLES) {accumulator += read_pin * (1 << 16); // read_pin should return 1 if true, 0 if false (e.g., (PORTA & (1 << PA3)) >> PA3) )accumulator = (accumulator * GAIN_FACTOR) >> 16; // the first multiplication technically has a 64-bit result.delay(SAMPLE_TIME); // Check the assembler output if it's doing the right thing} // or not, and add typecasts as needed. My C is rusty.Using interrupts, you'd have a counter running in the background (could be a hardware timer-counter) and sample it when an input edge occurs. This gives you the mark and period counts without any extra thinking.Make sure to filter the input, and prevent additional interrupt events from firing while the interrupt is being serviced (otherwise a nearby RF field will crash the MCU).Using the timer-counter hardware, I believe you can use the input capture / gating pin to enable or trigger the counter, doing the same thing with almost no CPU involvement at all.Obviously, the first two options chew CPU constantly, so if you don't need to do anything else, and you can interrupt this process to do other things (like serial or GPIO when reading out the data), that's fine. The latter options can be tacked onto an existing build, assuming that build is, itself, not critical on timing (i.e. it can spare a few clock cycles to service the interrupts), and has the timer(s) and pins free.The latter options are probably on the advanced side for someone only experienced with Arduino. I would worry about the buginess of the Arduino libraries, as far as being able to support these kinds of functions, too. At that point you might be better off with C in AVR Studio -- less buggy, much steeper learning curve.Tim

author: newbrain
author_rank: Super Contributor
timestamp: October 14, 2017, 11:34:30 pm
content: This is another good way of counting, period by period.Quote from: T3sl4co1l on October 14, 2017, 11:08:43 pmBut to have a fair measurement, the code path for counting zeros must not have a different length from the one counting ones, the code here would favour zeroes, as I fear that SAMPLE_TIME cannot be so great to swamp the increment time, if any precision is needed.Adding a "space++; " in the last loop would make them even. Make sure to use all the variables, or make them volatile, otherwise unused ones will be thrown away by the compiler.Quote from: T3sl4co1l on October 14, 2017, 11:08:43 pmQFT(I think some piece is missing in GAIN_FACTOR, and (1>>16) is 0)But style points for using a const uint32_t: I mostly program in C, and tend to forget that Arduino is actually C++.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: October 14, 2017, 11:42:44 pm
content: Quote from: newbrain on October 14, 2017, 11:34:30 pmFixed. Obviously I meant to shift the whole result, not multiplyI even forget if const is in C or not... in any case, the intent is to use a constant or macro parameter there, which is also emphasized by the tradition of CAPITALS_AND_UNDERSCORES.The use of int_t types is certainly intentional, giving explicit instruction that these variables are of the size they say they are. I don't know if Arduino has an improved "int", but the idea of using "int" alone definitely feels wrong when an ATmega "int" might be 16 bits while an STM32 "int" might be 32 bits. (On that note, 32 bits is fine for the 16 bit case, but the opposite is clearly not the case: that FIR filter needs the 16.16 fixed point to operate!)Tim

author: 84750Erik
author_rank: Contributor
timestamp: October 15, 2017, 01:59:23 am
content: Quote from: Hero999 on October 14, 2017, 10:24:13 pmI will pursue that path, I am convinced.I wish to thank T3sl4co1l and newbrain for their contributions here in their last 4 posts. Since yesterday I am on vacation for a week with limited internet access and no way of doing any testing, and I will have to study in depth all of yours last four posts, so it may take a few days before I will be able to give any meaningfull response.

author: Ian.M
author_rank: Super Contributor
timestamp: October 15, 2017, 03:17:10 am
content: IMHO its well worth putting in the effort to off load as much as possible of the duty cycle measurement to on-chip peripheral modules, especially capturing edge times.Quote from: newbrain on October 14, 2017, 10:42:02 amA.N. AVR135 sourcecode:http://www.atmel.com/images/AVR135.zipIt supports the ATmega328PB MCU, can be compiled with GCC and a quick inspection doesn't appear to have any serious conflicts with the Arduino framework - it doesn't use Timer 0, and the pins needed to link the two timers for the test version are available (PB3 - the test PWM out, is Arduino Uno digital pin 11 and PB0 - the capture input is digital pin 8 ) , so an Arduino ATmega328P port shouldn't be too difficult to put together and test.Edit: added a space so pin 8 doesn't become a smiley

author: ebclr
author_rank: Super Contributor
timestamp: October 15, 2017, 06:10:08 am
content: A double RC and a comparator with hysteresis is a simple an pure analog solutionDuty cycle AVG voltage proportional do duty cicle for fixed 2KhZ

author: 84750Erik
author_rank: Contributor
timestamp: October 25, 2017, 07:47:28 pm
content: Quote from: T3sl4co1l on October 14, 2017, 11:08:43 pmHi, here we are back after a week vacation, I took some time studying your proposals and ideas but to be honest it seems a bit above my capacities currently.For sure, I will pursue the software path using an MCU to count 1's and 0's in the duty cycle. I would need a precision and repeatability of measurements of better than 1% but that should be attainable when using fast direct register readings. Using the analog approach will not cut this.However, I feel lost when trying to understand your code proposals, and this has to do with my lack of knowledge, and nothing with your educational skills which are excellent.Basically I would propose to connect the signal containing the duty cycle to be measured to a digital input of an Arduino (no I2C since I need that, not to ISP due to correct previous reasoning against its use). Then on wake-up, once an hour, I would wait for a rising edge, count the length of time for the edge to rise again, calculate the period (which will be approx. 420 microseconds or a frequency of about 2.4kHz, and simultaneously count the number of 1's (or 0's) in that period. Repeat this a few hundred times (or tens of times) and calculate the averages, and from there the duty cycle.The hard part for me is to translate this routine in C++ as well as using direct register addressing for that purpose.Luckily the microcontroller does not have to do anything else in the meantime. All that is needed is1. wakeup after a call from a DS3231 RTC2. wait a shirt while for the sensor to settle (5 seconds?)3. do the measurements at the digital input4. convert this value to a string5. transmit this string through hardware serial to a HC-12 434MHz transceiver.6. go back to extended sleepNow after studying for a few hours the code in saw in the posts since my last writing 10 days ago I realise my head is turning in circles. The application note AVR135 I read, however not in detail, is indeed right on the mark, but here too I get lost for the time being in its technical prowess.I will delve in detail in that note the coming days, but any additional help will be very much appreciated!!Thanks,Erik

author: 84750Erik
author_rank: Contributor
timestamp: October 25, 2017, 07:49:11 pm
content: Quote from: ebclr on October 15, 2017, 06:10:08 amThanks ebclr but I decided to pursue the software route: the precision and repeatability of measurements will be a leap better.

author: 84750Erik
author_rank: Contributor
timestamp: October 25, 2017, 07:53:31 pm
content: Quote from: newbrain on October 14, 2017, 11:34:30 pmHi newbrain, can you please elaborate on the use of "space++; "?I also think that counting, period by period, will be the best solution. But why would that previous code favour zeroes?And I also do not understand the use of "GAIN_FACTOR", and of "1>>16)"Thank you for any further help!!Erik

author: technix
author_rank: Super Contributor
timestamp: October 25, 2017, 07:58:55 pm
content: This seem to me like a perfect job for the less-than-15-cents-in-quantity-of-10 STC15W100... Although the method below can work on any chip that supports either triggering interrupts on both edges, or have two interrupt lines that can be tied together and configured into triggering on either edge.Set a free-running timer at 30MHz, and interrupt on both edges of the signal. Now you can determine how many counts the timer have went through for each high and low period.

author: 84750Erik
author_rank: Contributor
timestamp: October 25, 2017, 08:13:05 pm
content: Hi Technix, nice to read, except: I have no idea how to program the STC15W100: if possible I would prefer to stay with Atmel chips, I already have a steep learning curve on those.Would it be possible to help with somewhat more precise coding examples or hints, preferably for Atmel AVR?

author: 84750Erik
author_rank: Contributor
timestamp: October 25, 2017, 08:38:49 pm
content: Quote from: Ian.M on October 15, 2017, 03:17:10 amI downloaded AVR135, if I understand you well this should do on a Atmega328P, with pin 8 as digital input capture?I already have a 2.4kHz signal with variable duty cycle. I tried to compile the code for Arduino Uno but I get an error, missing inavr.h, and stdio.h, amongst others. Now I will try and find these libraries.

author: technix
author_rank: Super Contributor
timestamp: October 25, 2017, 09:02:53 pm
content: Quote from: 84750Erik on October 25, 2017, 08:13:05 pmAVR can be a lot more expensive than discrete solutions. STC15W100 is a 8051-core microcontroller, and super, super cheap.I am going to assume the target chip being ATtiny13, which tend to be a lot cheaper.Code:/** DutyRatio13.c** Created: 2017/10/26 4:21:58* Author : technix*/#define F_CPU 9600000#define THRESHOLD_LOW 75#define THRESHOLD_HIGH 80#include <avr/io.h>#include <avr/interrupt.h>/** Pin allocations:** PB3 = PWM input (PCINT3)* PB4 = triggered output*/uint8_t last_count = 0;uint8_t last_h = 0;uint8_t last_l = 0;int main(void){// Set up a free-running counter on Timer/Counter0 at 150kHzTCNT0 = 0;TCCR0A = 0;TCCR0B = _BV(CS01) | _BV(CS00);// Prepare PB3 and PB4DDRB = _BV(DDB4);PORTB = 0;// Set up PCINT on PB3GIFR |= _BV(PCIF);PCMSK |= _BV(PCINT3);GIMSK |= _BV(PCIE);sei();while (1){; // Do nothing. Maybe enter sleep mode?}}ISR(PCINT0_vect){uint8_t count = TCNT0;if (PINB & _BV(PINB3)){last_l = count - last_count;last_count = count;}else{last_h = count - last_count;last_count = count;}uint16_t last_cycle = (uint16_t)last_l + (uint16_t)last_h;if (last_cycle){uint16_t duty = (uint16_t)last_h * 100 / last_cycle;if ((PORTB & _BV(PORTB4)) && (duty < THRESHOLD_LOW))PORTB &= ~_BV(PORTB4);else if (!(PORTB & _BV(PORTB4)) && (duty >THRESHOLD_HIGH))PORTB |= _BV(PORTB4);}}FUSES ={.low = FUSE_SPIEN & FUSE_SUT0 & FUSE_CKSEL0, // 9.6MHz.high = FUSE_SELFPRGEN};

author: 84750Erik
author_rank: Contributor
timestamp: October 25, 2017, 09:13:02 pm
content: Quote from: technix on October 25, 2017, 09:02:53 pmFantastic! I have Attiny85 lying in my bin, I will test that tomorrow.Question: why do you set the frequency at 9.6MHz?..and did you really write that code between our conversations? I stand in awe!

author: technix
author_rank: Super Contributor
timestamp: October 25, 2017, 09:19:32 pm
content: Quote from: 84750Erik on October 25, 2017, 09:13:02 pmI set the clock to 9.6MHz using fuse bits, using the FUSES in the bottom. If you are using ATtiny85 you need to change the fuse bits and timer prescaler to adapt the code for a 16MHz core clock.And yes that is a 5-minute coding session. (I am a CS major instead of EE, and have a good grasp on the C language.)

author: 84750Erik
author_rank: Contributor
timestamp: October 25, 2017, 09:29:02 pm
content: Quote from: technix on October 25, 2017, 09:19:32 pmImpressive!Technix, I need the controller to drive a HC-12 transceiver using hardware TX & RX, so I think of using a Arduino Pro Mini, because I also need I2C for an RTC DS3231. What would I need to change in the code for it to work too on a ATMEGA168P?

author: technix
author_rank: Super Contributor
timestamp: October 26, 2017, 04:15:48 am
content: Quote from: 84750Erik on October 25, 2017, 09:29:02 pmYou may want to make use of micros() on Arduino in the PCINT. Also make sure you are using the correct PCINT.

author: 84750Erik
author_rank: Contributor
timestamp: October 26, 2017, 06:28:57 am
content: Quote from: technix on October 26, 2017, 04:15:48 amHi Technix, thank you for your input! Would it be possible to write an example code with micros() and using PCINT0 for example (this is the CLK for the SPI which I would not use)? I am total novice in writing code using direct register addressing. Thanks for your time!!

author: 84750Erik
author_rank: Contributor
timestamp: October 28, 2017, 07:24:05 am
content: Hi Technix, when compiling for ATtiny13 I get an error ".hig = FUSE_SELFPRGEN not declared".When compiling for ATtiny85 I get an error for #define F_CPU 960000 because I had selected an ATtiny85 with 8MHz internal clock so I will have to adjust that line.When compiling for Digispark 16MHz I get no error, but I will probaly still have to adjust the #define F_CPU line.Does this all mean it will work on ATtiny85or Digispark (which uses ATtiny85 too) -on condition I adjust the code setting for CPU frequency- ?

author: technix
author_rank: Super Contributor
timestamp: October 28, 2017, 10:51:35 am
content: Quote from: 84750Erik on October 28, 2017, 07:24:05 amIt will work on ATtiny85 if you adjusted the CPU frequency (that does include adjusting the fuse bits) and the clock prescaler.

author: 84750Erik
author_rank: Contributor
timestamp: October 28, 2017, 11:40:10 am
content: Quote from: technix on October 28, 2017, 10:51:35 amOk, will do. But now some more questions:1. I guess last_h, last_low and last_count contain values measured? If so, what do those values represent?2. How do I convert these values to the actual duty cycle?3. What is the meaning of ISR(PCINT_vect) ?4. Can this code be used in a Atmega328P (or Atmega168P)? If not, could I maybe ask you to do that for me (I am clueless at the moment on how to do that)?Thank you very much!Erik