Skip to content

Instantly share code, notes, and snippets.

@SyncChannel
Last active May 3, 2018 03:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save SyncChannel/839ff3d346a632fc8910 to your computer and use it in GitHub Desktop.
Save SyncChannel/839ff3d346a632fc8910 to your computer and use it in GitHub Desktop.
/*
* REF-0 Standalone Operation
* Device: Atmel ATTINY841
* Written in Atmel Studio 6
* Created: 8/11/2015 8:56:28 AM
* Author: Dan Watson
*
* Pinout:
* PB1 (pin 3): PPS input
* PA1 (pin 12): Serial out to REF-0 (has to go through an inverter)
* PA6 (pin 7): Pulses high during PPS (for an LED)
*/
// CPU running at 16 MHz (External TCXO)
#define F_CPU 16000000UL
// Defines for USART setup
#define USART_BAUDRATE 9600
#define BAUD_PRESCALE ((F_CPU / (USART_BAUDRATE * 16UL)) - 1)a
// Four includes are needed for this program
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <util/delay.h>
// Motorola Oncore messages
// If you add more code and run out of RAM, store these in PROGMEM instead
uint8_t Ea[76] = { 0x40, 0x40, 0x45, 0x61, 0x01, 0x01, 0x07, 0xCE, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x08,
0x02, 0x08, 0xFF, 0x82, 0x04, 0x08, 0xFF, 0x82, 0x06, 0x08,
0xFF, 0x82, 0x08, 0x08, 0xFF, 0x82, 0x0A, 0x08, 0xFF, 0x82,
0x0C, 0x08, 0xFF, 0x82, 0x0E, 0x08, 0xFF, 0x82, 0x10, 0x08,
0xFF, 0x82, 0x20, 0xDF, 0x0D, 0x0A };
uint8_t En[69] ={ 0x40, 0x40, 0x45, 0x6E, 0x01, 0x01, 0x00, 0xC0, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00,
0x00, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00,
0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0xFA, 0x0D, 0x0A };
uint8_t Bb[92] = { 0x40, 0x40, 0x42, 0x62, 0x0A, 0x02, 0x00, 0x00, 0x5A, 0x00,
0x00, 0x00, 0x04, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x06,
0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x5A,
0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00,
0x0C, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
0x5A, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x5A, 0x00, 0x00,
0x00, 0x12, 0x00, 0x00, 0x5A, 0x00, 0x00, 0x00, 0x14, 0x00,
0x00, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C,
0x0D, 0x0A };
uint8_t Ap[25] = { 0x40, 0x40, 0x41, 0x70, 0x32, 0x61, 0x52, 0x99, 0x00, 0x81,
0x01, 0x2A, 0x0F, 0x54, 0xEB, 0x8B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x0D, 0x0A };
uint8_t Aw[8] = { 0x40, 0x40, 0x41, 0x77, 0x00, 0x36, 0x0D, 0x0A };
uint8_t Bj[8] = { 0x40, 0x40, 0x42, 0x6A, 0x00, 0x28, 0x0D, 0x0A };
uint8_t Az[11] = { 0x40, 0x40, 0x41, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x3B, 0x0D,
0x0A };
uint8_t At[8] = { 0x40, 0x40, 0x41, 0x74, 0x01, 0x34, 0x0D, 0x0A };
uint8_t Bo[8] = { 0x40, 0x40, 0x42, 0x6F, 0x00, 0x2D, 0x0D, 0x0A };
uint8_t Ag[8] = { 0x40, 0x40, 0x41, 0x67, 0x0A, 0x2C, 0x0D, 0x0A };
//Misc variables
volatile uint8_t gotPPS = 0;
uint8_t messageRotation = 0;
// Declare functions
void sendByte(uint8_t val);
void advanceSecond();
void sendMessages();
int main(void)
{
DDRA = 0b01000000; // Set Data Direction Register A, Pin A6 output
DDRB = 0b00000000; // Set Data Direction Register B
// Set up INT0 interrupt, on Pin B1
MCUCR |= (1 << ISC01) | (1 << ISC00); // Interrupt on INT0 rising edge
GIMSK |= (1 << INT0); // Enable INT0
// Set up USART 0
UCSR0C = (1 << UCSZ00) | (1 << UCSZ01); // Set 8 bit characters for USART 0
UBRR0H = (BAUD_PRESCALE >> 8); // Set baud rate on USART 0
UBRR0L = BAUD_PRESCALE;
UCSR0B = (1 << TXEN0) | (1 << RXEN0); // Enable Tx and Rx on USART 0
sei(); // Enable interrupts
while(1)
{
if (gotPPS == 1)
{
PORTA |= (1 << PINA6);
_delay_ms(75);
advanceSecond();
sendMessages();
PORTA ^= (1 << PINA6);
gotPPS = 0;
}
}
return 0;
}
ISR(INT0_vect)
{
gotPPS = 1;
}
void sendByte(uint8_t val)
{
UDR0 = val;
while ((UCSR0A & (1 << UDRE0)) == 0) {}; // Wait for Tx to complete
}
void advanceSecond()
{
Ea[73] = Ea[73] ^ Ea[10]; // XOR the seconds out of the check character
Ea[10]++; // Increment seconds
if (Ea[10] == 60) // If we reached 59 seconds, XOR the minute out
{ // of the check character and increment
Ea[10] = 0;
Ea[73] = Ea[73] ^ Ea[9];
Ea[9]++;
if (Ea[9] == 60) // If we reached 59 minutes, XOR the hour out
{ // of the check character and increment
Ea[9] = 0;
Ea[73] = Ea[73] ^ Ea[8];
Ea[8]++;
if (Ea[8] == 24) // If it's midnight, set hours to zero
{
Ea[8] = 0;
}
Ea[73] = Ea[73] ^ Ea[8]; // XOR the new hours back in to the check character
}
Ea[73] = Ea[73] ^ Ea[9]; // XOR the new minutes back into the check character
}
Ea[73] = Ea[73] ^ Ea[10]; // XOR the new seconds back into the check character
}
void sendMessages()
{
for (int j = 0; j < 76; j++) sendByte(Ea[j]);
for (int j = 0; j < 69; j++) sendByte(En[j]);
messageRotation++; // Cycle message rotation
if (messageRotation >= 30) messageRotation = 0;
if (messageRotation % 2 == 0) // Send @@Bb every two seconds
{
for (int i = 0; i < 92; i++) sendByte(Bb[i]);
}
if (messageRotation % 5 == 0) // Send @@Ap every five seconds
{
for (int i = 0; i < 25; i++) sendByte(Ap[i]);
}
if (messageRotation % 20 == 0) // Send @@Aw every 20 seconds
{
for (int i = 0; i < 8; i++) sendByte(Aw[i]);
}
switch(messageRotation) { // Distribute the other messages throughout
case 8: // the 30 second period of rotation
for (int i = 0; i < 8; i++) sendByte(Bj[i]); // I chose seconds arbitrarily...
break;
case 13:
for (int i = 0; i < 11; i++) sendByte(Az[i]);
break;
case 17:
for (int i = 0; i < 8; i++) sendByte(At[i]);
break;
case 23:
for (int i = 0; i < 8; i++) sendByte(Bo[i]);
break;
case 27:
for (int i = 0; i < 8; i++) sendByte(Ag[i]);
break;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment