1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
/*
* ----------------------------------------------------------------------------
* "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: asmdemo.c,v 1.1 2006/08/29 19:45:06 joerg_wunsch Exp $
*/
/*
* 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();
}
}
|