Fade a LED according to ADC conversion.
This can also be used to drive a servo (brown->ground, red->+6V, yellow->pwm). In that case, it is recommended to use a separated power supply for the servo as an USB RS232 module may not provide enough current.
#include BOARD_H
#define COUNTER counter1
#define COUNTER_CLK_DIV 8
#if HW_BITS(COUNTER)==16
# define PWM_PERIOD 0.02
# define PWM_TMIN 0
# define PWM_TMAX PWM_PERIOD
#else
# define PWM_PERIOD 0.0002
# define PWM_TMIN 0
# define PWM_TMAX PWM_PERIOD
#endif
#define ADC_CLK_DIV 128
#define count_t hw_uint_t(HW_BITS(COUNTER))
#define COUNT_TOP (uint32_t)(HW_SYSHZ*PWM_PERIOD/COUNTER_CLK_DIV)
#define COMPARE_MIN (count_t)(PWM_TMIN*HW_SYSHZ/COUNTER_CLK_DIV)
#define COMPARE_MAX (count_t)(PWM_TMAX*HW_SYSHZ/COUNTER_CLK_DIV)
#if defined HW_DEVICE_ATTINYX5
# define TOP_OBJ compare2
#else
# define TOP_OBJ compare0
#endif
#if HW_ADDRESS((pin,avcc)) == -1
# define VREF vcc
#else
# define VREF (pin,avcc)
#endif
static volatile count_t duty ;
HW_ISR( (adc0,irq), interruptible )
{
uint16_t adc =
hw( read, adc0 );
const uint8_t ns = 32 ;
static uint16_t lpfsum ;
lpfsum = lpfsum - (lpfsum + ns/2)/ns + adc ;
uint32_t tmp32 = lpfsum ;
tmp32 = (tmp32 * (COMPARE_MAX-COMPARE_MIN) + ns*1023/2) / (ns*1023) + COMPARE_MIN ;
count_t tmp = tmp32 ;
if ( sizeof(count_t) > 1 ) {
hw( disable, interrupts );
duty = tmp ;
hw( enable, interrupts );
}
else
duty = tmp ;
}
HW_ISR( (COUNTER,irq,overflow), non_interruptible )
{
if ( duty ) {
if ( duty < COUNT_TOP ) {
hw( write, (COUNTER,compare1), duty );
hw( enable, (COUNTER,compare1,irq) );
}
else
hw( disable, (COUNTER,compare1,irq) );
}
else {
hw( disable, (COUNTER,compare1,irq) );
}
}
#if HW_ADDRESS((PIN_LED,port,port)) < 0x40
HW_ISR( (COUNTER,compare1,irq), naked )
{
}
#else
{
}
#endif
int main ( )
{
sleep, enabled,
sleep_mode, idle );
mode, digital_output );
mode, analog_input_pullup );
if ( COUNT_TOP > ((1UL<<
HW_BITS(COUNTER))-1) )
HWA_E(
"PWM_COUNTER can not afford PWM_PERIOD.") ;
hwa( configure, (COUNTER,prescaler),
clock, ioclk );
clock, ioclk / COUNTER_CLK_DIV,
direction, up_loop,
bottom, 0,
top, TOP_OBJ );
hwa( write, (COUNTER,TOP_OBJ), COUNT_TOP );
hwa( enable, (COUNTER,irq,overflow) );
clock, ioclk / ADC_CLK_DIV,
trigger, manual,
vref, VREF,
align, right,
hwa( enable, (adc0,irq) );
hw( enable, interrupts );
for(;;)
return 0 ;
}