Finalproc.c


#pragma regalloc-    //I allocate the registers myself
#pragma optsize-     //optimize for speed

#include 
#include  // sprintf
#include  // delay_ms
#include 
#include 
#include 
#include 
#include 

#define delayForw 15
#define delayBackw 15
#define delaySample 1
#define dend 20  // distance to end of pattern, for slowing down

unsigned char Ain, t; 		//raw A to D number
float voltage;		//scaled input voltage

int xmax=128, ymax=100;  // max distance on x,y axes (match tv screen size)
int zig=1;    // zig zag flag
int userReset=0;  // reset flag
unsigned char tvFlag=0, tvState=0;
int halfstep=0;  // motor half-stepping flag
int delayTemp;
extern unsigned char x_cycle, y_cycle; //position of the stepper motor (4 possibilities)
char key, ikey;  // key used to hold any button value; ikey to hold just scan mode button
unsigned char thres=0;
unsigned char white, black, nogo;
char go;
unsigned char samp1, samp2, samp3;
int x, y;  // loop variables
//-----------video----------------
//cycles = 63.625 * 16 Note NTSC is 63.55
//but this line duration makes each frame exactly 1/60 sec
//which is nice for keeping a realtime clock
#pragma regalloc+
extern char screen[1600];
char syncON, syncOFF;
extern int LineCount;
//----------functions--------------
void initialize(void);
void scanReset();
void checkTVpush();
void stop();
void sample();
void tv();
void tvclear();
//---------------------------------

void main(void)
{
	initialize();

	while(1)
	{
	   	scanReset();  // reset scanner
	   	tvclear();  // clear tv
	   	halfstep=0;  // initialize halfstep option

		// wait for the user to select a mode to start
		while (ikey!=0xdc && ikey!=0xec && ikey!=0xf4 && ikey != 0xbc)
			ikey=PINC & 0xfc;

		// if halfstep button pushed
		if (ikey == 0xbc){
			if (halfstep){ // half step -> full step
				PORTA.7 = 1; // turn off led
				halfstep=0;
			}
			else{ // full step -> half step
				PORTA.7 = 0; // turn on led
				halfstep=1;
			}
		}

		// wait for the user to select a mode to start
		while (ikey!=0xdc && ikey!=0xec && ikey!=0xf4 )
		   	ikey=PINC & 0xfc;

	   	// calibration: setting threshold value
	  	ADCSRA = 0b11000110;
		delay_ms(delaySample);
		white = ADCH;
		for(x=0; x< 25; x++)
       		x_forw(delayForw);
   		delay_ms(3);
	  	ADCSRA = 0b11000110;
		delay_ms(delaySample);
		black = ADCH;
		delay_ms(100);
		thres = ((white - black) / 2) + black;

	    // after calibration, set scanner to an initial position
		for(y=0; y< 20; y++)   {
			y_forw(delayForw);
			delay_ms(20);
		}
		for(x=0; x< 50; x++)  {
			x_backw(delayBackw);
			key = PINC & 0x01;
			if (key == 0 && x > 0)
				break;
		}
		delay_ms(200);

		/**** SCAN PROCESS ****/
		if (ikey == 0xdc) // (key 1) one direction mode: scan one way only (no zig zag)
		{
			// step y, scan x
			for (y=0; y=-50; x--){
					// slow down if near edges
					if (x>dend)
						delayTemp=delayBackw;
					else
						delayTemp=delayBackw*2;

			   		if (halfstep)
						x_backw_half(delayTemp);
					else
						x_backw(delayTemp);

					// detect if user resets
					key = PINC & 0xfc;
					if (key == 0xf8){
						userReset=1;
						break;
					}
					// detect if button pushed to display image to tv
					checkTVpush();
					if (tvFlag)
						tv();
					// if edge sensor is reached, stop moving backwards
					key = PINC & 0x01;
					if (key == 0)
						break;
				}
				if (userReset) break;
				if (halfstep)
					y_forw_half(delayForw);
				else
					y_forw(delayForw);
			}
		}
		else if (ikey == 0xec)// (key 2) zig zag mode: scanner slows at ends to try
		{                     //   to avoid shaking, also with software compensation
			zig=1;  // initialize zig flag
			// step y, scan x.  zigzag pattern.
			for (y=0; y=-50; x--){
				   		sample();
				   		if (x>=0) video_pt(x, y, Ain);
						// when x rod is nearing end, slow down
						if (x>dend)
							delayTemp=delayBackw;
						else
							delayTemp=delayBackw*2;

						if (halfstep)
							x_backw_half(delayTemp);
						else
							x_backw(delayTemp);

						// detect if user resets
						key = PINC & 0xfc;
						if (key == 0xf8){
							userReset=1;
							break;
						}
						// detect if button pushed to display image to tv
						checkTVpush();
						if (tvFlag)
							tv();
						// if reset sensor is reached, stop moving backwards
						key = PINC & 0x01;
						if (key == 0)
						{
							// fill in the rest of the screen line
							while (x>=0){
								video_pt(x,y, Ain);
								x--;
							}
							break;
						}
					}
				}
				if (userReset) break;
				zig=!zig;
				// slow down scanner when it's about to change directions
				delay_ms(20);
				if (halfstep)
					y_forw_half(delayForw);
				else
					y_forw(delayForw);
			}
		}
		else if (ikey == 0xf4)// (key3) normal zig zag mode with software compensation
		{
			zig=1;  // initialize zig flag
			// step y, scan x.  zigzag pattern.
			for (y=0; y=-50; x--){
				   		sample();
						if (x>=0) video_pt(x, y, Ain);

			   			if (halfstep)
			   				x_backw_half(delayBackw);
			   			else
			   				x_backw(delayBackw);
						// detect if user resets
						key = PINC & 0xfc;
						if (key == 0xf8){
							userReset=1;
							break;
						}
						// detect if button pushed to display image to tv
						checkTVpush();
						if (tvFlag)
							tv();
						// if reset sensor is reached, stop moving backwards
						key = PINC & 0x01;
						if (key == 0){
							while (x>=0){
								video_pt(x,y, Ain);
								x--;
							}
							break;
						}
					}
				}
				if (userReset) break;
				zig=!zig;
				if (halfstep)
					y_forw_half(delayForw);
				else
					y_forw(delayForw);
			}
		} // end if/else if/else if
		/**** END SCAN PROCESS ****/

		if (userReset)
			userReset=!userReset;
		else {
			tvFlag=1;
			tv();  // Display the scanned image to tv screen
		}
	}  // main program loop
}   //end of main


void initialize(void)
{
	//init the A to D converter
	//channel zero/ left adj /int Aref
	//Connected to internal 2,56V use 7..6 bits as 00 for Vref
	ADMUX = 0b00100000;
	//enable ADC and set prescaler to 1/64*8MHz=125,000
	//and set int enable
	ADCSRA = 0b10000110;

	// set ports
	DDRD=0xff;   // PORT D is output: pins 5, 6 to tv, pin 7 to half-step LED
	PORTD=0x00;
	DDRC=0x00;   // PORT C is input: reads the x and y reset sensors
	PORTC=0xfc;  // Turn pullups on pins 0, 1 for sensors, rest pulldown for buttons
	DDRB=0xff;   // PORT B is output: controls the motors
	PORTB=0x00;  // upper 4 bits for x motor, lower for y motor
	DDRA=0x80; // PORTA bit0 is adc and bit7 is output for led
	PORTA.7 = 1;
	// initialize variables
	x_cycle = 0;
	y_cycle = 0;
	key = 0x00;
	ikey = 0x00;
	tvFlag=0;
	tvState=0;
	halfstep=0;

	LineCount = 1;
	syncON = 0b00000000;
	syncOFF = 0b00100000;
 	MCUCR = 0b10000000;
	#asm
		sei
	#endasm
}

// reset the scanner to initial corner position
void scanReset()
{
	key = PINC & 0x03;
	// brink x back until sensor hit
	while(key == 0x01 || key == 0x03){
		x_backw(delayBackw);
		key = PINC & 0x03;
	}
	key = PINC & 0x03;
	// bring y back until sensor hit
	while(key == 0x02 || key == 0x03){
		y_backw(delayBackw);
		key = PINC & 0x03;
	}
	ikey = 0x00; // reset the scan mode
}

// tv display toggle and debounce
void checkTVpush()
{
	key=PINC & 0xf0;

	// no-button-push state
	if (key==0xf0)
		tvState=0;

	// enter button-pushed state, toggle flag for tv/no tv
	if (key == 0x70 && !tvFlag && tvState==0)  {
		tvState=1;
		tvFlag=1;
	}
	else if (key==0x70 && tvFlag && tvState==0) {
		tvState=1;
		tvFlag=0;
	}
}

// sample with the photo sensor through the ADC
void sample(){
	// take 3 samples, if 2 are black, final sample will be black
  	ADCSRA = 0b11000110;
	delay_ms(delaySample);
	samp1 = ADCH;
	if (samp1 > thres)
		samp1 = 1;
	else samp1 = 0;

  	ADCSRA = 0b11000110;
	delay_ms(delaySample);
	samp2 = ADCH;
	if (samp2 > thres)
		samp2 = 1;
	else samp2 = 0;

  	ADCSRA = 0b11000110;
	delay_ms(delaySample);
	samp3 = ADCH;
	if (samp2 > thres)
		samp3 = 1;
	else samp3 = 0;

	Ain = samp1 + samp2 *2 + samp3*4;

	if (Ain == 0 || Ain == 1 || Ain == 2 || Ain == 4)
		Ain = 0;
	else
		Ain = 1;
}

// display scanned image to tv
void tv(){
   	DDRD=0xff;	// Redefine PortD upper half output for TV
	PORTD=0x00;  //Lower half is pullup inputs for push buttons
	//init timer 1 to generate sync
	OCR1A = lineTime; 	//One NTSC line
	TCCR1B = 9; 		//full speed; clear-on-match
	TCCR1A = 0x00;	//turn off pwm and oc lines
	TIMSK = 0x10;		//enable interrupt T1 cmp
	go = 1;
	while(go)
	{
		//stall here until next line starts
		//sleep enable; mode=idle
		//use sleep to make entry into sync ISR uniform time
		#asm ("sleep");

		//The following code executes during the vertical blanking
		//Code here can be as long as
		//a total of 60 lines x 63.5 uSec/line x 8 cycles/uSec
		if (LineCount==231)
		{
			// exit tv on button push
			checkTVpush();
			if (!tvFlag)
				go=0;
		}  //line 231
	}  //while
	TIMSK = 0x00;  //disable interrupt
}

// clear the tv screen buffer
void tvclear()
{
	int a, b;
	for (a=0; a<=99; a++)
	{
		for (b=0; b<=127; b++)
			video_pt(b, a, 0);
	}
}