I looked all over the internet and couldn't find the code for a MiniPOV ATtiny2313 firmware which would allow text to always read FORWARDS when waving the miniPOV. A simple mercury switch ($2 at RadioShack, JayCar etc.) attached to the Sensor port (Pin 6) and GND, and oriented in the direction of waving, allows the miniPOV to detect direction and reverse the image on the reverse stroke. Here is my source code, modified from the original largeimage.c file.
Test it out! Either add "mercury.hex" lines in your miniPOV makefile, or just copy the contents above straight into an existing file

Have fun! Comments and suggestions welcome

Code: Select all
// mercury.c 13.08.2008 by Corwin Willys
// for LadyAda MiniPOV
//
// Modified version of largeimage.c to utilise a
// simple mercury switch to make the displayed
// text constantly FORWARD in two dimensions regardless
// of wave direction - no more backward text
// on the reverse swing wave!
//
// SETUP
// - Install a mercury switch on Sensor / Pin6 to GND
// - Line up mercury switch with the swing direction of your MiniPOV
// - Install this firmware and test:
// - If text is always backwards, adjust SETUP setting further down in
// this file!!
#include <avr/io.h> // this contains all the IO port definitions
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
void delay_ms( uint16_t milliseconds)
{
for( ; milliseconds > 0; milliseconds--)
{
_delay_ms( 1);
}
}
#define TIMER1_PRESCALE_1 1
#define TIMER1_PRESCALE_8 2
#define TIMER1_PRESCALE_64 3
#define TIMER1_PRESCALE_256 4
#define TIMER1_PRESCALE_1024 5
// We use these macros because binary constants arent always supported. ugh.
#define HEX__(n) 0x##n##UL
#define B8__(x) ((x&0x0000000FLU)?1:0) \
+((x&0x000000F0LU)?2:0) \
+((x&0x00000F00LU)?4:0) \
+((x&0x0000F000LU)?8:0) \
+((x&0x000F0000LU)?16:0) \
+((x&0x00F00000LU)?32:0) \
+((x&0x0F000000LU)?64:0) \
+((x&0xF0000000LU)?128:0)
#define B8(d) ((unsigned char)B8__(HEX__(d)))
// store all the image data in program memory (ROM)
// instead of RAM (the default)
// START OF IMAGE DATA
const uint8_t large_image[] PROGMEM = {
B8(00000000),
B8(00000000),
B8(00000000),
B8(00000000),
B8(00000000),
B8(01111100),
B8(10000010),
B8(10000010),
B8(10000010),
B8(01000110),
B8(00000000),
B8(00000000),
B8(01110000),
B8(10001000),
B8(10001000),
B8(10001000),
B8(01110000),
B8(00000000),
B8(00000000),
B8(10001000),
B8(11111000),
B8(10010000),
B8(10001000),
B8(00001000),
B8(00000000),
B8(00001000),
B8(01111000),
B8(10001000),
B8(01100000),
B8(10001000),
B8(01111000),
B8(00001000),
B8(00000000),
B8(10001000),
B8(10001000),
B8(11111010),
B8(10000000),
B8(10000000),
B8(00000000),
B8(10001000),
B8(11111000),
B8(10010000),
B8(00001000),
B8(10001000),
B8(11110000),
B8(10000000),
B8(00000000),
B8(00000000),
B8(00000000),
B8(00000000),
B8(00000000),
B8(00000000),
};
// END OF IMAGE DATA
// special pointer for reading from ROM memory
PGM_P largeimage_p PROGMEM = large_image;
#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))
int imagesize = NUM_ELEM(large_image);
// this function is called when timer1 compare matches OCR1A
uint8_t j = 0;
int k = 0;
SIGNAL( SIG_TIMER1_COMPA ) {
if (j >= imagesize)
{
if (bit_is_clear(PIND, 2)) // going one direction
k = 0;
else
k = 1; // going in the other direction
j = 0;
}
// read the image data from ROM
if (k >= 1) // if k=1 then the switch is either open or not present
// --------SETUP---------
//
// Just swap the two PORTB lines below depending on how
// the PCB mercury switch is mounted - you should aim to get
// all text forwards and not all backwards
PORTB = pgm_read_byte(largeimage_p + imagesize - j - 1); // reversing the image
else // if k=0 the switch is present and closed to ground
PORTB = pgm_read_byte(largeimage_p + j); // normal direction
j++;
}
int main(void) {
DDRB = 0xFF; // set all 8 pins on port B to outputs
DDRD = 0xFB; // one input on pin D2, this pin reads Corwins Mercury
PORTD = 0x04; // turn on pullup on pin D2
/*
the frequency of the interrupt overflow is determined by the
prescaler and overflow value.
freq = clock_frequency / ( 2 * prescaler * overflow_val)
where prescaler can be 1, 8, 64, 256, or 1024
clock_freq is 8MHz
and overflow_val is 16bit
the overflow value is placed in OCR1A, the prescale is set in TCCR1B
so for example:
A good POV frequency is around 400Hz
desired freq = 400Hz
clock freq = 8MHz
8MHz / (400Hz * 2) = 10000
since 10000 is less than 655536 (largest 16 bit number)
OCR1A = 10000 and the prescale is 1
*/
TCCR1B = (1 << WGM12) | TIMER1_PRESCALE_1;
OCR1A = (uint16_t)10000; //MODIFIED BY CORWIN TO UP SPEED AFTER MERCURY CHANGES
TIMSK |= 1 << OCIE1A; // Output Compare Interrupt Enable (timer 1, OCR1A)
sei(); // Set Enable Interrupts
while (1);
}