Author Topic: Duty Cycle detection  (Read 12922 times)

0 Members and 1 Guest are viewing this topic.

Offline 84750ErikTopic starter

  • Contributor
  • Posts: 41
  • Country: be
    • My Safety
Re: Duty Cycle detection
« Reply #50 on: October 25, 2017, 09:13:02 pm »
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?
AVR 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: [Select]
/*
 * 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 150kHz
TCNT0 = 0;
TCCR0A = 0;
TCCR0B = _BV(CS01) | _BV(CS00);

// Prepare PB3 and PB4
DDRB = _BV(DDB4);
PORTB = 0;

// Set up PCINT on PB3
GIFR |= _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
};
Fantastic! 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!
 

Offline technix

  • Super Contributor
  • ***
  • Posts: 3508
  • Country: cn
  • From Shanghai With Love
    • My Untitled Blog
Re: Duty Cycle detection
« Reply #51 on: October 25, 2017, 09:19:32 pm »
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?
AVR 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: [Select]
/*
 * 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 150kHz
TCNT0 = 0;
TCCR0A = 0;
TCCR0B = _BV(CS01) | _BV(CS00);

// Prepare PB3 and PB4
DDRB = _BV(DDB4);
PORTB = 0;

// Set up PCINT on PB3
GIFR |= _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
};
Fantastic! 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!
I 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.)
 

Offline 84750ErikTopic starter

  • Contributor
  • Posts: 41
  • Country: be
    • My Safety
Re: Duty Cycle detection
« Reply #52 on: October 25, 2017, 09:29:02 pm »
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?
AVR 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: [Select]
/*
 * 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 150kHz
TCNT0 = 0;
TCCR0A = 0;
TCCR0B = _BV(CS01) | _BV(CS00);

// Prepare PB3 and PB4
DDRB = _BV(DDB4);
PORTB = 0;

// Set up PCINT on PB3
GIFR |= _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
};
Fantastic! 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!
I 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.)
Impressive!
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?

 

Offline technix

  • Super Contributor
  • ***
  • Posts: 3508
  • Country: cn
  • From Shanghai With Love
    • My Untitled Blog
Re: Duty Cycle detection
« Reply #53 on: October 26, 2017, 04:15:48 am »
Impressive!
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?
You may want to make use of micros() on Arduino in the PCINT. Also make sure you are using the correct PCINT.
 

Offline 84750ErikTopic starter

  • Contributor
  • Posts: 41
  • Country: be
    • My Safety
Re: Duty Cycle detection
« Reply #54 on: October 26, 2017, 06:28:57 am »
You may want to make use of micros() on Arduino in the PCINT. Also make sure you are using the correct PCINT.
Hi 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!!
 

Offline 84750ErikTopic starter

  • Contributor
  • Posts: 41
  • Country: be
    • My Safety
Re: Duty Cycle detection
« Reply #55 on: October 28, 2017, 07:24:05 am »
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- ?

 

Offline technix

  • Super Contributor
  • ***
  • Posts: 3508
  • Country: cn
  • From Shanghai With Love
    • My Untitled Blog
Re: Duty Cycle detection
« Reply #56 on: October 28, 2017, 10:51:35 am »
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- ?
It will work on ATtiny85 if you adjusted the CPU frequency (that does include adjusting the fuse bits) and the clock prescaler.
 

Offline 84750ErikTopic starter

  • Contributor
  • Posts: 41
  • Country: be
    • My Safety
Re: Duty Cycle detection
« Reply #57 on: October 28, 2017, 11:40:10 am »

It will work on ATtiny85 if you adjusted the CPU frequency (that does include adjusting the fuse bits) and the clock prescaler.
Ok, 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
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf