Created
December 14, 2016 01:08
-
-
Save yellowcrescent/1d62cfdd4b59e48e623edc110eced203 to your computer and use it in GitHub Desktop.
helloavr
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
blink.c - blinky test! first C prog for AVR target | |
TARGET: AVR ATmega32-U16 (PDIP-40 package) | |
Jacob Hipps - http://jacobhipps.info/ | |
Started: 08 Dec 2011 | |
Updated: 15 Dec 2011 | |
*/ | |
#define F_CPU 1000000UL // osc speed (1 MHz) | |
#include <avr/io.h> | |
#include <avr/interrupt.h> | |
#include <string.h> | |
#define LED_OFF 0 | |
#define LED_RED 1 | |
#define LED_GRN 2 | |
#define CYC_1MS 16 // timer cycles in 1ms (approx) | |
#define CYC_1S 15624 // timer cycles in 1s | |
/* | |
Bitmap array which contains a representation of each | |
character that should be displayed on the 7-seg display. | |
The hex value maps to a bitmask which is outputted to | |
the pins on PORTC. Note that PC5 is used by the dot | |
and is not one of the 7 segments. | |
*/ | |
#define CGMAX 0x14 | |
unsigned char sevseg_bmp[] = { | |
0xDB, // 00 - '0' | |
0x50, // 01 - '1' | |
0xC7, // 02 - '2' | |
0xD5, // 03 - '3' | |
0x5C, // 04 - '4' | |
0x9D, // 05 - '5' | |
0x9F, // 06 - '6' | |
0xD0, // 07 - '7' | |
0xDF, // 08 - '8' | |
0xDC, // 09 - '9' | |
0xDE, // 0A - 'A' | |
0x1F, // 0B - 'b' | |
0x07, // 0C - 'c' | |
0x57, // 0D - 'd' | |
0x8F, // 0E - 'E' | |
0x8E, // 0F - 'F' | |
0x00, // 10 - (null) | |
0x53, // 11 - 'J' | |
0x01, // 12 - '_' (underscore) | |
0x85, // 13 - (triple bars) | |
0x80 // 14 - (overscore) | |
}; | |
uint8_t xmit_mode = 0; // 0 = no comms, 1 = recv, 2 = send | |
uint8_t req_status = 0; | |
uint8_t req_rep = 0; | |
char xmitbuf[8]; | |
char lastmsg[8]; | |
uint8_t lastmsg_len = 0; | |
uint8_t xbyte = 0; // current byte | |
uint8_t xbit = 0; // current bit | |
uint8_t tx_len = 0; // transmit size in bytes | |
unsigned char sevseg = 0xFF; // initialize sevseg to all filled | |
uint8_t ss_cnt = 0; | |
uint8_t ssc_enable = 0; | |
uint8_t ssc_index = 0; | |
uint8_t ssc_inc = 0; | |
// set the state of bicolor LED between pins 1 and 2 | |
void set_led(uint8_t lstate) { | |
if(!lstate) { | |
// off | |
PORTB &= ~(1<<PB0); | |
PORTB &= ~(1<<PB1); | |
} else if(lstate & LED_RED) { | |
// red | |
PORTB &= ~(1<<PB0); | |
PORTB |= 1<<PB1; | |
} else if(lstate & LED_GRN) { | |
// green | |
PORTB |= 1<<PB0; | |
PORTB &= ~(1<<PB1); | |
} | |
} | |
void toggle_led() { | |
PORTB ^= ((1<<PB0) | (1<<PB1)); | |
} | |
void sevseg_set(uint8_t setval) { | |
PORTC &= ~(sevseg_bmp[8]); // clear out the 7 segments (not the dot) | |
// light the bitmap! | |
if(setval > CGMAX) PORTC |= sevseg_bmp[CGMAX]; | |
else PORTC |= sevseg_bmp[setval]; | |
} | |
int main(void) { | |
// perform setup and initialization | |
// Disable JTAG on Port C | |
MCUCSR |= (1<<JTD); | |
MCUCSR |= (1<<JTD); // must be "written twice within 4 cycles" | |
// according to the datasheet | |
// set Data Direction Registers | |
DDRB |= 1<<PB0; // set PB0 to output | |
DDRB |= 1<<PB1; // set PB1 to output | |
DDRA |= 15; // set PA0-PA3 to output | |
DDRC = 0xFF; // set Port C to all output (SevSeg LED driver) | |
// init LED red and relay output off/open | |
set_led(LED_RED); | |
PORTA &= ~(1<<PA0); | |
PORTC = 0xFF; | |
// enable timer overflow interrupt | |
TIMSK |= 1 << TOIE1; // Timer1 - used for LED clocker (16-bit) | |
TIMSK |= 1 << TOIE0; // Timer0 - used for SegSev delay clocker (8-bit) | |
// enable external interrupts INT0 and INT1 | |
// for serial bit-bang | |
GICR |= ((1 << INT1) | (1 << INT0)); // enable INT1 and INT0 external interrupts | |
MCUCR |= ((1 << ISC00) | (1 << ISC01)); // INT0 rising edge trigger | |
MCUCR |= ((1 << ISC11) | (1 << ISC10)); // INT1 rising edge trigger | |
DDRD |= 1<<PD4; // data out (pin 18) | |
DDRD &= ~(1<<PD5); // data in (pin 19) | |
// setup 16-bit timer for F_CPU/64 sync operation | |
TCCR1B |= ((1 << CS10) | (1 << CS11)); | |
// setup 8-bit timer for F_CPU/1024 sync operation | |
TCCR0 |= ((1 << CS02) | (1 << CS00)); | |
// clear the SevSeg | |
sevseg_set(0x10); | |
// enable global interrupts | |
sei(); | |
// main loop | |
while(1) { | |
if(!ssc_enable && TCNT1 > 1600 && TCNT1 < 2000) { | |
PORTC &= ~(1<<PC5); | |
//PORTD &= ~(1<<PD4); // XXX - test | |
} else if(ssc_enable && TCNT0 > 120 && TCNT0 < 160) { | |
PORTC &= ~(1<<PC5); | |
} | |
} | |
return 0; | |
} | |
void rx_reply(uint8_t bsize) { | |
// increment bsize to get actual size | |
// (since it is not incremented for the last byte) | |
bsize++; | |
// for now, let's just echo what's recieved by to host | |
//tx_len = bsize; | |
xmitbuf[0] = 'J'; | |
xmitbuf[1] = 'M'; | |
xmitbuf[2] = 'H'; | |
tx_len = 3; | |
} | |
// interrupt vector for TCNT1 overflow | |
ISR(TIMER1_OVF_vect) { | |
//set_led(LED_GRN); | |
//toggle_led(); | |
// toggle relay output | |
//PORTA ^= (1<<PA0); | |
// change sevseg display & inc counter | |
//sevseg_set(ss_cnt); | |
//ss_cnt++; | |
//if(ss_cnt > CGMAX) ss_cnt = 0; // reset the counter if out o' charmaps | |
// pulse the sevseg dot | |
if(!ssc_enable) { | |
PORTC |= (1<<PC5); | |
} | |
toggle_led(); | |
// XXX - test of PD4 output (pin 18) | |
//PORTD |= (1<<PD4); | |
} | |
// interrupt vector for TCNT0 overflow | |
// Loop through and display lastmsg[] as hex on the SegSev. | |
// Underscore (_) seperates values and triple-bars signifies EOT. | |
ISR(TIMER0_OVF_vect) { | |
unsigned char cc; | |
uint8_t nib; | |
if(ssc_enable) { | |
set_led(LED_GRN); | |
PORTC |= (1<<PC5); | |
if(ssc_index < lastmsg_len) { | |
cc = lastmsg[ssc_index]; | |
if(!ssc_inc) { | |
nib = cc >> 4; | |
sevseg_set(nib); | |
ssc_inc++; | |
} else if(ssc_inc == 1) { | |
nib = cc & 0x0F; | |
sevseg_set(nib); | |
ssc_inc++; | |
} else { | |
sevseg_set(0x12); | |
ssc_inc = 0; | |
ssc_index++; | |
} | |
} else if(ssc_index == lastmsg_len) { | |
sevseg_set(0x13); | |
ssc_index = 0; | |
} | |
} | |
} | |
// INT0 handler (pin 16) | |
// This interrupt is used to signal the beginning | |
// of a byte if pulsed once, and beginning of | |
// a request of pulsed twice | |
ISR(INT0_vect) { | |
req_rep++; | |
if(req_rep > 2) req_rep = 2; | |
if(xmit_mode == 1 && req_rep == 2) rx_reply(xbyte); | |
} | |
// INT1 handler (pin 17) | |
// Clock pulse | |
ISR(INT1_vect) { | |
//toggle_led(); | |
if(!xmit_mode && req_rep == 2) { | |
// rx begin | |
ssc_enable = 0; // disable msg display | |
xmit_mode = 1; // xmit_mode is now RX | |
req_rep = 0; // reset req_rep | |
xbit = 0; // reset bit counter | |
xbyte = 0; // reset byte counter | |
} else if(xmit_mode == 1 && req_rep == 2) { | |
// tx begin | |
lastmsg_len = xbyte + 1; // copy recv'd message for later | |
memcpy(lastmsg,xmitbuf,lastmsg_len); | |
xmit_mode = 2; // xmit_mode is now TX | |
req_rep = 0; // reset req_rep | |
xbit = 0; // reset bit counter | |
xbyte = 0; // reset byte counter | |
} else if(req_rep == 1) { | |
// rx/tx continue - next byte | |
req_rep = 0; // reset req_rep | |
xbit = 0; // reset bit counter | |
xbyte++; // inc byte counter | |
if(xbyte > tx_len) { | |
// transmission complete! | |
xmit_mode = 0; // xmit_mode is now NONE | |
xbyte = 0; // reset byte counter | |
tx_len = 0; // reset tx length counter | |
sevseg_set(0x10); | |
ssc_enable = 1; | |
return; | |
} | |
} else if(!xmit_mode) { | |
return; | |
} | |
sevseg_set(xmit_mode); | |
// RX mode | |
if(xmit_mode == 1) { | |
// detect next bit | |
if(PORTD & (1<<PD5)) xmitbuf[xbyte] |= (1 << xbit); // 1 - high pulse | |
else xmitbuf[xbyte] &= ~(1 << xbit); // 0 - low pulse | |
xbit++; | |
// TX mode | |
} else if(xmit_mode == 2) { | |
// if last byte - signal all 1s (0xFF) - to signify EOT | |
if(xbyte == tx_len) PORTD |= (1 << PD4); | |
// otherwise, signal next bit | |
else if(xmitbuf[xbyte] & (1 << xbit)) PORTD |= (1 << PD4); | |
else PORTD &= ~(1 << PD4); | |
} | |
return; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment