Skip to content

Instantly share code, notes, and snippets.

@anishathalye
Created November 30, 2016 17:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anishathalye/a2e7e2bb7718dc1c2a4ddbdcc317898a to your computer and use it in GitHub Desktop.
Save anishathalye/a2e7e2bb7718dc1c2a4ddbdcc317898a to your computer and use it in GitHub Desktop.
// blinking LED
//
// set lfuse to 0x5E for 20 MHz xtal
// 115200 baud serial
//
// Anish Athalye
//
// some code from http://academy.cba.mit.edu/classes/embedded_programming/hello.ftdi.44.echo.c
// license for that:
//
// Neil Gershenfeld
// 12/8/10
//
// (c) Massachusetts Institute of Technology 2010
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose. Copyright is
// retained and must be preserved. The work is provided
// as is; no warranty is provided, and users accept all
// liability.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#define LEDPORT (PORTA)
#define LEDDDR (DDRA)
#define LED_R (PA2)
#define LED_G (PA3)
#define LED_B (PA7)
#define SETB(byte, bit) (byte |= (1 << bit))
#define CLRB(byte, bit) (byte &= (~ (1 << bit)))
#define ASSIGNB(test, byte, bit) do { if (test) SETB(byte, bit); else CLRB(byte, bit); } while (0);
int pwm_ctr = 0;
int pwm_r = 0;
int pwm_g = 0;
int pwm_b = 0;
#define PWM_VALUES (20) // must be <= 0b00111111
// pwm_{color} values can go from [0, PWM_VALUES]
// 0 is off, and PWM_VALUES is full brightness
#define PWM_HZ (50)
#define PWM_TICKS (PWM_VALUES * PWM_HZ)
#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 8.5 // bit delay for 115200 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define char_delay() _delay_ms(10) // char delay
#define serial_port PORTA
#define serial_direction DDRA
#define serial_pins PINA
#define serial_pin_in (1 << PA0)
#define serial_pin_out (1 << PA1)
void get_char(volatile unsigned char *pins, unsigned char pin, unsigned char *rxbyte)
{
//
// read character into rxbyte on pins pin
// assumes line driver (inverts bits)
//
*rxbyte = 0;
while (pin_test(*pins,pin))
//
// wait for start bit
//
;
cli(); // disable interrupts
//
// delay to middle of first data bit
//
half_bit_delay();
bit_delay();
//
// unrolled loop to read data bits
//
if pin_test(*pins,pin)
*rxbyte |= (1 << 0);
else
*rxbyte |= (0 << 0);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 1);
else
*rxbyte |= (0 << 1);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 2);
else
*rxbyte |= (0 << 2);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 3);
else
*rxbyte |= (0 << 3);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 4);
else
*rxbyte |= (0 << 4);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 5);
else
*rxbyte |= (0 << 5);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 6);
else
*rxbyte |= (0 << 6);
bit_delay();
if pin_test(*pins,pin)
*rxbyte |= (1 << 7);
else
*rxbyte |= (0 << 7);
//
// wait for stop bit
//
bit_delay();
half_bit_delay();
sei(); // reenable interrupts
}
int main(void)
{
// set clock divider to /1
CLKPR = (1 << CLKPCE);
CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
// configure timer1 for CTC (clear timer on compare) mode
TCCR1B |= (1 << WGM12);
// enable the CTC interrupt
TIMSK1 |= (1 << OCIE1A);
// enable global interrupts
sei();
// start the timer at 20MHz / 1024
TCCR1B |= ((1 << CS10) | (1 << CS12));
// set the CTC compare value
// timer is incrementing at 20MHz / 1024 = 19531.25 Hz
// if want 100Hz pwm for example, the timer max count should be set to
// 19531.25 Hz / 100 Hz = 195
OCR1A = 19531.25 / PWM_TICKS;
// set to output port
LEDDDR |= (1 << LED_R | 1 << LED_G | 1 << LED_B);
// make everything off
SETB(LEDPORT, LED_G);
SETB(LEDPORT, LED_R);
SETB(LEDPORT, LED_B);
unsigned char input, color, value;
while (1)
{
get_char(&serial_pins, serial_pin_in, &input);
// protocol: c = CCVVVVVV
// where CC is the color channel
// and VV is the value
// CC: 0 = R, 1 = G, 2 = B, 3 = nothing
// VVVVVV: value from 0x00 to PWM_VALUES
color = input >> 6;
value = input & 0x3f;
if (0 <= value && value <= PWM_VALUES)
{
if (color == 0)
pwm_r = value;
if (color == 1)
pwm_g = value;
if (color == 2)
pwm_b = value;
}
};
}
ISR(TIM1_COMPA_vect)
{
if (pwm_ctr >= pwm_r)
{
SETB(LEDPORT, LED_R); // off
}
else
{
CLRB(LEDPORT, LED_R); // on
}
if (pwm_ctr >= pwm_g)
{
SETB(LEDPORT, LED_G); // off
}
else
{
CLRB(LEDPORT, LED_G); // on
}
if (pwm_ctr >= pwm_b)
{
SETB(LEDPORT, LED_B); // off
}
else
{
CLRB(LEDPORT, LED_B); // on
}
pwm_ctr++;
if (pwm_ctr >= PWM_VALUES)
{
pwm_ctr = 0;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment