You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
147 lines
3.6 KiB
C
147 lines
3.6 KiB
C
/*
|
|
* ----------------------------------------------------------------------------
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
* Joerg Wunsch wrote this file. As long as you retain this notice you
|
|
* can do whatever you want with this stuff. If we meet some day, and you think
|
|
* this stuff is worth it, you can buy me a beer in return. Joerg Wunsch
|
|
* ----------------------------------------------------------------------------
|
|
*
|
|
* Demo combining C and assembly source files.
|
|
*
|
|
* This demo implements an RC model type PWM decoder. The incoming
|
|
* PWM signal consists of a pulse sequence with a pulse width of 920
|
|
* microseconds up to 2120 microseconds (1520 microseconds being the
|
|
* neutral point). Depending on the value of the decoded incoming
|
|
* PWM, an outgoing PWM is controlled between 0 and 100 %.
|
|
*
|
|
* The project is intented to be run on an ATtiny13 that has only one
|
|
* timer channel (timer 0), so both the incoming signal discrimination
|
|
* as well as the outgoing PWM need to run on the same timer.
|
|
*
|
|
* For verification purposes, the same project can also be run on an
|
|
* ATtiny25/45/85, where timer 1 can be used to evaluate the incoming
|
|
* PWM signal, and timer 0 to generate the outgoing PWM. In that
|
|
* case, no additional assembly code is needed.
|
|
*
|
|
* $Id$
|
|
*/
|
|
|
|
/*
|
|
* This is the main C source file for the demo.
|
|
*/
|
|
#include <avr/interrupt.h>
|
|
#include <avr/io.h>
|
|
#include <avr/sleep.h>
|
|
|
|
#include "project.h"
|
|
|
|
volatile uint16_t pwm_incoming;
|
|
volatile struct
|
|
{
|
|
uint8_t pwm_received: 1;
|
|
}
|
|
intbits;
|
|
|
|
void
|
|
ioinit(void)
|
|
{
|
|
counter_hi = 0;
|
|
flags = 0;
|
|
|
|
/*
|
|
* Timer 0 runs as phase-correct PWM at full clock, OC0B connects to
|
|
* the PWM engine.
|
|
*/
|
|
TCCR0A = (1 << COM0B1) | (1 << WGM00);
|
|
TCCR0B = (1 << CS00);
|
|
OCR0A = 255;
|
|
|
|
#if defined(__AVR_ATtiny13__)
|
|
TIMSK0 = (1 << TOIE0) | (1 << OCIE0A);
|
|
|
|
# define F_CPU 1200000ul
|
|
/* Minimal PWM pulse width is 920 us. */
|
|
# define MIN_PWM_VAL ((920ul * F_CPU) / 1000000ul)
|
|
/* Maximal PWM pulse width is 2120 us */
|
|
# define MAX_PWM_VAL ((2120ul * F_CPU) / 1000000ul)
|
|
|
|
#elif defined(__AVR_ATtiny25__) ||\
|
|
defined(__AVR_ATtiny45__) ||\
|
|
defined(__AVR_ATtiny85__)
|
|
|
|
# define F_CPU 1000000ul
|
|
/*
|
|
* We use a prescaler of 16 here to avoid the 32-bit calculations
|
|
* below.
|
|
*/
|
|
/* Minimal PWM pulse width is 920 us. */
|
|
# define MIN_PWM_VAL ((920ul * F_CPU) / 16 / 1000000ul)
|
|
/* Maximal PWM pulse width is 2120 us */
|
|
# define MAX_PWM_VAL ((2120ul * F_CPU) / 16 / 1000000ul)
|
|
|
|
#else
|
|
# error "Don't know how to run on your MCU_TYPE."
|
|
#endif
|
|
|
|
PCMSK = (1 << 4);
|
|
GIFR = (1 << PCIF);
|
|
GIMSK = (1 << PCIE);
|
|
|
|
DDRB = (1 << PB1);
|
|
PORTB = 0;
|
|
|
|
sei();
|
|
}
|
|
|
|
#if defined(__AVR_ATtiny25__) ||\
|
|
defined(__AVR_ATtiny45__) ||\
|
|
defined(__AVR_ATtiny85__)
|
|
ISR(PCINT0_vect)
|
|
{
|
|
uint8_t tcnt1;
|
|
|
|
if (PINB & (1 << 4))
|
|
{
|
|
/* Start timer 1 with a prescaler of 16. */
|
|
TCNT1 = 0;
|
|
TCCR1 = (1 << CS12) | (1 << CS10);
|
|
return;
|
|
}
|
|
|
|
/* Stop timer 1, current value is pulse width. */
|
|
tcnt1 = TCNT1;
|
|
TCCR1 = 0;
|
|
GIMSK &= ~(1 << PCIE);
|
|
|
|
pwm_incoming = tcnt1;
|
|
intbits.pwm_received = 1;
|
|
}
|
|
#endif /* ATtinyX5 */
|
|
|
|
int
|
|
main(void)
|
|
{
|
|
|
|
ioinit();
|
|
|
|
for (;;)
|
|
{
|
|
if (intbits.pwm_received)
|
|
{
|
|
intbits.pwm_received = 0;
|
|
#if defined(__AVR_ATtiny13__)
|
|
if (pwm_incoming < MIN_PWM_VAL)
|
|
pwm_incoming = MIN_PWM_VAL;
|
|
else if (pwm_incoming > MAX_PWM_VAL)
|
|
pwm_incoming = MAX_PWM_VAL;
|
|
OCR0B = (pwm_incoming - MIN_PWM_VAL) * 255ul / (MAX_PWM_VAL - MIN_PWM_VAL);
|
|
#else
|
|
OCR0B = (pwm_incoming - MIN_PWM_VAL) * 255u / (MAX_PWM_VAL - MIN_PWM_VAL);
|
|
#endif
|
|
GIFR = (1 << PCIF);
|
|
GIMSK |= (1 << PCIE);
|
|
}
|
|
sleep_mode();
|
|
}
|
|
}
|