o_0
Member level 3
The attached Codevision code is for an Atmega32a-based accelerometer mouse that interfaces to the computer via PS/2 protocol. (Notice this is not PlayStation2, it's this: **broken link removed**)
I have been able to show that the ADC portion works, which is dataFromMouse(), however I'm still not getting any mouse movement. All the outputs of the uC remain at +5V (idle state) all the time.
I honestly don't have a clue where to start debugging this huge program, other than putting LED lighting commands in strategic places. If anyone has any prior experience with this, I would greatly appreciate any suggestions on how to approach this.
Thanks in advance.
I've attached the file with the code, as well as the schematic.
Some differences in my setup:
* Instead of a crystal, I'm using int.RC 8 MHz.
* Not using the buffers.
* AREF has a 100nF capacitor to GND
Also I should mention I don't have an LCD, though there's code for it.
I have been able to show that the ADC portion works, which is dataFromMouse(), however I'm still not getting any mouse movement. All the outputs of the uC remain at +5V (idle state) all the time.
I honestly don't have a clue where to start debugging this huge program, other than putting LED lighting commands in strategic places. If anyone has any prior experience with this, I would greatly appreciate any suggestions on how to approach this.
Thanks in advance.
I've attached the file with the code, as well as the schematic.
Some differences in my setup:
* Instead of a crystal, I'm using int.RC 8 MHz.
* Not using the buffers.
* AREF has a 100nF capacitor to GND
Also I should mention I don't have an LCD, though there's code for it.
Code:
#include <Mega32.h>
#include <stdio.h> // sprintf
#include <delay.h>
//used LCD when debugging
/*#asm
.equ __lcd_port=0x15
#endasm
#include <lcd.h> // LCD driver routines
*/
#define CLK_TIME 250
#define RESPOND_WAIT 700
//define PS/2 data line states
#define IDLE 0
#define INHIBIT 1
#define BUSY 2
#define REQUEST 3
#define POWEROFF 4
/******************************************
*
*Ports:
* D - Input/Output to Computer
* D.1 - Output Clock
* D.2 - Input Clock
* D.6 - Output Data
* D.7 - Input Data
*
* B - Status LEDs
*
* C - Buttons
********************************************/
//define some useful maps to bits
#define CLK_OUT PORTD.1
#define DATA_OUT PORTD.6
#define CLK_IN PIND.2
#define DATA_IN PIND.7
#define VCC_IN PIND.4
//state of the data line
char transmitting, receiving, waiting;
//conuters in tim1
int count, count1, count2;
unsigned char lastClkIn, ClkIn, dataIn;
unsigned char myState;
unsigned char rcvBit, rcvByte;
//variables for writing to PS/2 port
unsigned char PS2byte, lastPS2byte;
unsigned char position, PS2parity;
char clockState, nextClockState, nextCLK_OUT;
unsigned char packetCount;
void initChip(void);
//define clock states
#define HIGH 0
#define FALLING 1
#define LOW 2
#define RISING 3
/////////////////////////////MOUSE
//Reaction timer states
#define NoPush 11
#define MaybePush 12
#define Pushed 13
#define MaybeNoPush 14
#define LCDwidth 16
void initialize(void); //all the usual mcu stuff
void displayAxis(unsigned char,unsigned char, unsigned char); //display first the accel for each axis
//void displayAxis(float, float, float);
unsigned char led; //light states
unsigned char lcddelay; //timing variable for lcd
unsigned char btndelay; //timing variable for button push
unsigned char btn1holddelay, btn2holddelay; //timing variable for button hold
//unsigned char ReactState;
float tempthresh, temperature; //the threshold tSemperture to turn the fan on.
//the button push states and flags.
unsigned char PushState1, PushState2, PushFlag1, PushFlag2, lastPushFlag1, lastPushFlag2;
//record the voltage of x,y,z coordinate
unsigned char xADC, yADC, zADC;
//calibration variables
unsigned char xCal, yCal, zCal;
bit scaling;
unsigned char lcdPosCount0,lcdPosCount1;
unsigned char PushState[5];
unsigned char PushFlag[5];
enum{BTN_LEFT=0, BTN_RIGHT, BTN_MIDDLE, BTN_FREEZE, BTN_DOUBLE};
enum{POSS_SCROLL=0, POSS_BEGIN_SCROLL, BEGIN_SCROLL, POSS_UP_SCROLL, POSS_DOWN_SCROLL, REAL_UP_SCROLL, REAL_DOWN_SCROLL};
enum{BTN_PACKET=0, X_PACKET, Y_PACKET, Z_PACKET};
enum{X_AXIS=0, Y_AXIS, Z_AXIS};
void debounce(unsigned char* PushFlag, unsigned char* PushState, unsigned char button);
void dataFromMouse(void);
void posConvert(void);
void getMovement(void);
void packetGen(void);
//define queue values
#define QUEUELEN 20
#define TRUE 1
#define FALSE 0
unsigned char queue[QUEUELEN]; //queue of data sent by keyboard. (first in, first out)
unsigned char queueFull; //indicates if queue is full
unsigned char queueEmpty;//indicates if queue is empty
unsigned char queueIn; //indicates where to put data into queue
unsigned char queueOut; //indicates where to take data out of queue
unsigned char queuePut(unsigned char d); //put data into queue
unsigned char queueGet(void); //get data from
unsigned char packetGenFlag, resendFlag;
unsigned char inhibited;
//////////////////////////////TESTUING
bit outInhibit;
bit forceDelay;
unsigned char powerOffSend;
//////////Record positions
//the current position of x y z
char curPosition[3];
char lastPosition[3];
char movement[3];
////////////Processes Command variables
unsigned char lastlastSampleRate, lastSampleRate, sampleRate, deviceID;
bit transmitMode, setResolutionFlag, settingSampleRateFlag;
//set when the mouse have significent movemenet
bit realMoveFlag, realBtnFlag, realScrollFlag;
bit transmitFlag;
////////////Process scroll motions
unsigned char scrollMotion[5];
char scrollCount, falseStateCount;
unsigned char scrollIndex;
unsigned char scrollState;
char resolution;
//****************************
//PS/2 Host Command set.
#define ERROR 0xFC
#define RESET 0xFF
#define RESEND 0xFE
#define SET_DEFAULT 0xF6
#define DIS_DATA_REPORT 0xF5
#define EN_DATA_REPORT 0xF4
#define SET_SAMPLE_RATE 0xF3
#define GET_DEVICE_ID 0xF2
#define SET_REMOTE_MODE 0xF0
#define SET_WRAP_MODE 0xEE
#define RESET_WRAP_MODE 0xEC
#define READ_DATA OxEB
#define SET_STREAM_MODE 0xEA
#define STATUS_REQ 0xE9
#define SET_RES 0xE8
#define SET_SCALING21 0xE7
#define SET_SCALING11 0xE6
#define ACK 0xFA
#define INIT_SUCC 0xAA
#define INIT_SUCC_1 0x00
#define SCALING21 0x02
//float voltage;
unsigned char Ain;
int clock;
int ticked = 0;
//LCD buffer used for debugging
//unsigned char ledbuf[17];
//*****************************
//Push button state machine variables
unsigned char mousekill, but_state, butinfo;
bit leftBtn, rightBtn, middleBtn, lastLeftBtn, lastRightBtn, lastMiddleBtn;
unsigned char test0;
unsigned int debounceTimer;
#define STATE_READY 0
#define STATE_ALMOST_READY 1
#define STATE_BTN_PRESS 2
#define STATE_BTN_RELEASE1 3
#define STATE_BTN_RELEASE2 4
//#define but_press 2
//#define but_release1 3
//#define but_release2 4
void debounceBtn(void)
{
unsigned char PINCval;
debounceTimer = 0;
PINCval = PINC&0x0f;
//Debounce State machine for the button pushes
switch(but_state)
{
//No button push state
case(STATE_READY):
if(~(PINCval) != 0)
{
butinfo = PINCval;
but_state = STATE_ALMOST_READY;
}
else
{
test0 = 0;
but_state = STATE_READY;
}
break;
//Maybe-button push detected
case(STATE_ALMOST_READY):
if(PINCval == butinfo)
but_state = STATE_BTN_PRESS;
else
but_state = STATE_READY;
break;
//Button push definately detected
case STATE_BTN_PRESS:
if(PINCval == butinfo)
{
if(~PINC.1 == 0x01) //Left mouse click
leftBtn = 1;
else if (~PINC.2 == 0x01) //Middle mouse click
middleBtn = 1;
else if (~PINC.3 == 0x01) //Right mouse click
rightBtn = 1;
but_state = STATE_BTN_PRESS;
}
else
but_state = STATE_BTN_RELEASE1;
break;
//Maybe Button is released
case STATE_BTN_RELEASE1:
if(PINCval== butinfo)
but_state = STATE_BTN_PRESS;
else
but_state = STATE_BTN_RELEASE2;
break;
//Last check if button is released
case STATE_BTN_RELEASE2:
if(PINCval == butinfo)
but_state = STATE_BTN_RELEASE1;
else
{
//reaset all the button state
but_state = STATE_READY;
leftBtn = 0;
rightBtn = 0;
middleBtn =0;
butinfo = 0;
test0 = 0;
}
break;
}
}
/////Debounce an array of buttons
void debounce(unsigned char* PushFlag, unsigned char* PushState, unsigned char button)
{
unsigned char btn_mask;
switch(button)
{
case BTN_LEFT:
btn_mask = 0x01;
break;
case BTN_RIGHT:
btn_mask = 0x02;
break;
case BTN_FREEZE:
btn_mask = 0x04;
break;
case BTN_DOUBLE:
btn_mask = 0x08;
break;
}
switch (PushState[button])
{
case NoPush:
if (~PIND == btn_mask) PushState[button]=MaybePush;
else PushState[button]=NoPush;
break;
case MaybePush:
if (~PIND == btn_mask)
{
PushState[button]=Pushed;
PushFlag[button]=1;
}
else PushState[button]=NoPush;
break;
case Pushed:
if (~PIND == btn_mask) PushState[button]=Pushed;
else PushState[button]=MaybeNoPush;
break;
case MaybeNoPush:
if (~PIND == btn_mask) PushState[button]=Pushed;
else
{
PushState[button]=NoPush;
PushFlag[button]=0;
}
break;
}
}
//insert data into queue. Return 1 if queue full, or 0 if inserted data sucessfully
char queuePut(char d)
{
if (queueFull==TRUE) //check if queue is full
return(TRUE);
queue[queueIn]=d; //insert d into queue
queueIn++; //increment where to stick in the next d value
queueEmpty=FALSE; //indicate queue isnt' empty anymore
if (queueIn==QUEUELEN) //if reached the end of the queue
queueIn=0; //wrap around to the beginning
if (queueIn==queueOut) //if queueIn caught up to queueOut
queueFull=TRUE; //indicate queue is full
return(0);
}
//get data out of queue. Return 0 if queue empty or the actual data if not empty
char queueGet(void)
{
char d;
if(resendFlag == TRUE)
{
resendFlag=FALSE;
return lastPS2byte;
}
if (queueEmpty==TRUE) //check if queue is empty
return(0);
d=queue[queueOut]; //get data out of queue
queueOut++; //increment location where to get next d value
queueFull=FALSE; //indicate queue isn't full anymore
if (queueOut==QUEUELEN) //if reached the end of the queue
queueOut=0; //wrap around to the beginning
if (queueOut==queueIn) //if queueOut caught up to queueIn
queueEmpty=TRUE; //indicate queue is empty
if(d==0xAA)
delay_ms(375);
lastPS2byte = d;
return(d); //return the data from queue
}
///Generate a standard 4 byte Microsoft IntelliMouse: left, middle, right, x, y, z packet.
void packetGen(void)
{
unsigned char btnPacket=0x08;
//the first byte is at least 0x08, because the third bit is always 1
char scroll;
//check if the y-axis is a negative move | check if the x-axis is a negative move | middle button click | right button click | left button click
//when there is only button click
if(realBtnFlag && realMoveFlag==FALSE)
{
btnPacket = btnPacket | ((middleBtn&0x1) <<2) | ((rightBtn&0x1)<<1) | (leftBtn&0x1);
queuePut(btnPacket);
queuePut(0x00);
queuePut(0x00);
queuePut(0x00);
}
else if(!realBtnFlag && realScrollFlag)//&& !realMoveFlag
{
btnPacket = btnPacket | ((middleBtn&0x1) <<2) | ((rightBtn&0x1)<<1) | (leftBtn&0x1);
queuePut(btnPacket);
queuePut(0x00);
queuePut(0x00);
scroll = movement[Z_AXIS] - zCal;
if(scrollState == REAL_UP_SCROLL)
{
queuePut(0x03);
}
else if(scrollState == REAL_DOWN_SCROLL)
{
queuePut(0xFD);
}
scrollState = POSS_SCROLL;
}
else if(realMoveFlag == TRUE)
{
btnPacket = btnPacket | (((movement[Y_AXIS]>>7)&0x1)<<5) | (((movement[X_AXIS]>>7)&0x1)<<4) | ((middleBtn&0x1) <<2) | ((rightBtn&0x1)<<1) | (leftBtn&0x1);
queuePut(btnPacket);
queuePut(movement[X_AXIS] << resolution);
queuePut(movement[Y_AXIS] << resolution);
queuePut(0x00);
//queuePut((movement[Z_AXIS]<2 && movement[Z_AXIS]>-2)?0:movement[Z_AXIS]&0x0f);
}
/*
if(packetCount < 20)
{
queuePut(0x8);
queuePut(0x8);
queuePut(0x8);
queuePut(0x0);
}
else
{
queuePut(0x8 | 0x30);
queuePut(0xF3);
queuePut(0xF3);
queuePut(0x0);
}
packetCount++;
*/
}
//Obtain x, y, z movements.
void getMovement(void)
{
unsigned char i=0;
//position conversion formula.
// xxxxxxxOLD (int)(voltage - first voltage(when not moving) * 100)
// ADC reading - init adc reading(calibrating data)
curPosition[X_AXIS] = (signed char)(xADC - xCal);
curPosition[Y_AXIS] = (signed char)(yADC - yCal);
curPosition[Z_AXIS] = (signed char)(zADC - zCal);
//only when the mouse has significent movement we generate a packet
//get the difference between the previous position and current position
for(i=0;i<3;i++)
{
movement[i] = curPosition[i];// - lastPosition[i] ;
//only check x and y movements
if(i<2)
{
if(!(movement[i] < 3 || movement[i] > -3))
realMoveFlag = TRUE;
/*
if(movement[i] > 3 || movement[i] < -3)
realMoveFlag = TRUE;
*/
}
}
}
/*
//////////FAILED ATTEMPT: TRYING THE CALCULATE THE SLOPE.
void detectScroll(void)
{
signed char slope, slopePrev;
signed char scrollPos;
scrollPos = (signed char)movement[Z_AXIS];
switch (scrollState)
{
case POSS_SCROLL:
if(scrollPos < 10 && scrollPos > -10)
{
PORTB = ~0x80;
scrollState = BEGIN_SCROLL;
}
else
{
PORTB = ~0x40;
scrollState = POSS_SCROLL;
}
//PORTB = ~0x00;
scrollMotion[1]=scrollPos;
break;
case POSS_BEGIN_SCROLL:
if(scrollPos < 10 || scrollPos > -10)
{
//PORTB = ~0xa0;
scrollState = BEGIN_SCROLL;
scrollMotion[1]=scrollPos;
}
else
{
//PORTB = ~0x40;
scrollState = POSS_SCROLL;
}
PORTB = ~0x00;
break;
case BEGIN_SCROLL:
//PORTB = ~0x80;
if(scrollPos < 12 && scrollPos > -12)
{
scrollMotion[1] = scrollPos;
scrollState = POSS_SCROLL;
}
else
{
PORTB = ~0x0f;
scrollMotion[2] = scrollPos;
slopePrev = (scrollMotion[1]-scrollMotion[0]);
slope = (scrollMotion[2]-scrollMotion[1]);
if(slope > 0 )//&& slopePrev > 0)
{
PORTB = ~0xFF;
scrollState = POSS_UP_SCROLL;
}
else
scrollState = POSS_SCROLL;
}
break;
case POSS_UP_SCROLL:
scrollMotion[3] = scrollPos;
slope = (scrollMotion[3]-scrollMotion[2]);
if(slope > 0)
scrollState = REAL_UP_SCROLL;
else
scrollState = POSS_SCROLL;
break;
case REAL_UP_SCROLL:
scrollMotion[4] = scrollPos;
slope = (char)(scrollMotion[4]-scrollMotion[3]);
if(slope > 0)
scrollState = REAL_UP_SCROLL;
else
scrollState = POSS_UP_SCROLL;
break;
case POSS_DOWN_SCROLL:
scrollState = POSS_SCROLL;
break;
case REAL_DOWN_SCROLL:
scrollState = POSS_SCROLL;
break;
}
}
*/
void detectScroll(void)
{
signed char slope, slopePrev;
signed char scrollPos;
scrollPos = (signed char)movement[Z_AXIS];
switch (scrollState)
{
case POSS_SCROLL:
if(scrollPos < 10 && scrollPos > -10)
{
PORTB = ~0x80;
scrollState = POSS_SCROLL;
}
else
{
PORTB = ~0x40;
scrollState = BEGIN_SCROLL;
}
//PORTB = ~0x00;
scrollMotion[1]=scrollPos;
break;
case BEGIN_SCROLL:
//PORTB = ~0x80;
if(scrollPos <= 15 && scrollPos >= -15)
{
//scrollMotion[1] = scrollPos;
scrollState = POSS_SCROLL;
}
else
{
PORTB = ~0x0f;
scrollMotion[2] = scrollPos;
//slopePrev = (scrollMotion[1]-scrollMotion[0]);
//slope = (scrollMotion[2]-scrollMotion[1]);
if(scrollPos > 15 )//&& slopePrev > 0)
{
PORTB = ~0xFF;
scrollState = POSS_UP_SCROLL;
}
else if(scrollPos < -15)
{
scrollState = POSS_DOWN_SCROLL;
PORTB = ~0xF0;
}
}
break;
case POSS_UP_SCROLL:
scrollMotion[3] = scrollPos;
//slope = (scrollMotion[3]-scrollMotion[2]);
if(scrollPos <= 10 && scrollPos >= -10)
scrollState = POSS_SCROLL;
PORTB = ~0x00;
if(scrollPos < -20)
scrollState = REAL_UP_SCROLL;
else
scrollState = POSS_UP_SCROLL;
break;
case REAL_UP_SCROLL:
scrollMotion[4] = scrollPos;
//slope = (char)(scrollMotion[4]-scrollMotion[3]);
//if(slope > 0)
scrollState = REAL_UP_SCROLL;
//else
// scrollState = POSS_UP_SCROLL;
break;
case POSS_DOWN_SCROLL:
scrollMotion[3] = scrollPos;
//slope = (scrollMotion[3]-scrollMotion[2]);
if(scrollPos <= 10 && scrollPos >= -10)
scrollState = POSS_SCROLL;
if(scrollPos > 20)
{
PORTB = ~0x01;
scrollState = REAL_DOWN_SCROLL;
}
else
scrollState = POSS_DOWN_SCROLL;
break;
case REAL_DOWN_SCROLL:
scrollState = REAL_DOWN_SCROLL;
break;
}
}
void dataFromMouse(void)
{
/////////////////// X /////////////////////
ADMUX = 0b01100000; //read voltage on A.0 for x axis
ADCSRA.6 = 1;
//ADCSRA.6 bit will be clear after the conversion is done.
while(ADCSRA.6 == 1){}
xADC = ADCH; //read the ADC value
/////////////////// Y /////////////////////
ADMUX = 0b01100001; //read voltage on A.1 for y axis
ADCSRA.6 = 1;
//ADCSRA.6 bit will be clear after the conversion is done.
while(ADCSRA.6 == 1){}
yADC = ADCH; //read the ADC value
/////////////////// Z /////////////////////
ADMUX = 0b01100010; //read voltage on A.2 for z axis
ADCSRA.6 = 1;
//ADCSRA.6 bit will be clear after the conversion is done.
while(ADCSRA.6 == 1){}
zADC = ADCH; //read the ADC value
//We need to record the init reading of ADC for computing relative position
//the initial position of the mouse should be positioned on a flat surface.
if(xCal == 0)
{
xCal = xADC;
yCal = yADC;
zCal = zADC;
}
//displayAxis(xADC, yADC, zADC);
}
//Process a command received from the host. Reply appropriate feedback to
//the computer.
void processCommand(unsigned char hostCommand) {
delay_us(50);
if (hostCommand == RESET)
{
queueIn = 0;
queueOut=0;
queueEmpty = TRUE;
queueFull = FALSE;
delay_us(500);
}
//always acknowledge the incoming request
queuePut(ACK);
if(setResolutionFlag) {
setResolutionFlag = 0;
if(hostCommand >= 0 && hostCommand <= 3)
resolution = hostCommand;
if(hostCommand < 0 || hostCommand > 3) { //send an error
queuePut(ERROR);
return;
} else {
resolution = hostCommand;
return;
}
return;
}
if(settingSampleRateFlag) {
settingSampleRateFlag = 0;
if(hostCommand >= 10 && hostCommand <= 200) {
lastlastSampleRate = lastSampleRate;
lastSampleRate = sampleRate;
sampleRate = hostCommand;
if((lastlastSampleRate == 200) && (lastSampleRate == 100) && (sampleRate == 80)) {
deviceID = 0x03; // enter MS intellimouse mode
}
if(deviceID == 0x03 && lastlastSampleRate == 200 && lastSampleRate == 200 && sampleRate == 80) {
deviceID = 0x03; // enter MS 5-button mouse mode
}
} else { // bad sample rate, output an error
queuePut(ERROR);
}
return;
}
switch (hostCommand) {
case RESEND:
resendFlag = TRUE;
break;
case RESET: //reset RESP: 0xAA, 0x00
//putsf(" Rset\r\n");
/* forceDelay = TRUE;
delay_ms(1000);
forceDelay = FALSE;
*/
deviceID = 0x00;
queuePut(INIT_SUCC);
queuePut(deviceID);
//queuePut(INIT_SUCC_1);
transmitMode = 0;
sampleRate = 100;
break;
case EN_DATA_REPORT: //enable transmit
//putsf("rp +\r\n");
transmitMode = 1;
break;
case 0xE6: //set scaling 1:1
scaling = 0;
break;
case 0xE7: //set scaling 2:
scaling = 1;
break;
case GET_DEVICE_ID: //get device ID
//printf("ID=0x%x\r\n",deviceID);
//delay_ms(1);
queuePut(deviceID);
//transmitMode = 1;
break;
case SET_RES: //E8: set resolution
//putsf(" Setres\r\n");
setResolutionFlag = 1;
break;
case STATUS_REQ: //status request respond 0xFA, 0x00, 0x02, 0x64
//putsf(" Sreq\r\n");
// queuePut(ACK);
queuePut(0x00);
queuePut(resolution);
queuePut(sampleRate);
break;
// case 0xEA: //set stream mode
// case 0xEB: //read data (for Remote Mode)
// case 0xEC: //reset wrap mode
// case 0xEE: //set wrap mode
// case 0xF0: //set remote mode
case SET_SAMPLE_RATE: //F3: set sample rate
//putsf(" set srate\r\n");
settingSampleRateFlag = 1;
break;
case DIS_DATA_REPORT: //disable data reporting
//putsf(" rep-\r\n");
transmitMode = 0;
break;
case SET_DEFAULT: //set defaults
//putsf(" dflts\r\n");
transmitMode = 0;
sampleRate = 100;
resolution = 4;
break;
default: //all other commands
break;
}
}
/*//Display the current axis.
void displayInput(unsigned char from, unsigned char inFromHost)
{
//1 = host and 0 = device
if(from && lcdPosCount0 == 0 || from && lcdPosCount0 > 14)
{
lcdPosCount0 = 2;
//lcd_clear();
lcd_gotoxy(0,0);
lcd_putsf("H:");
lcd_gotoxy(2,0);
sprintf(ledbuf, "%2x", inFromHost);
lcd_puts(ledbuf);
}
else if(from)
{
lcd_gotoxy(lcdPosCount0,0);
sprintf(ledbuf, "%2x", inFromHost);
lcd_puts(ledbuf);
lcdPosCount0 = lcdPosCount0 + 2;
}
////DEVICE print out
if(!from && lcdPosCount1 == 0 || !from && lcdPosCount1 > 14)
{
lcdPosCount1 = 2;
//lcd_clear();
lcd_gotoxy(0,1);
lcd_putsf("D:");
lcd_gotoxy(2,1);
sprintf(ledbuf, "%2x", inFromHost);
lcd_puts(ledbuf);
}
else if(!from)
{
lcd_gotoxy(lcdPosCount1,1);
sprintf(ledbuf, "%2x", inFromHost);
lcd_puts(ledbuf);
lcdPosCount1 = lcdPosCount1 + 2;
}
}
void displayAxis(unsigned char xAxis, unsigned char yAxis, unsigned char zAxis)
{
lcd_clear();
lcd_gotoxy(0,0);
lcd_putsf("x=");
lcd_gotoxy(2,0);
sprintf(ledbuf, "%d", xAxis);
lcd_puts(ledbuf);
lcd_gotoxy(7,0);
lcd_putsf("y=");
lcd_gotoxy(10,0);
sprintf(ledbuf, "%d", yAxis);
lcd_puts(ledbuf);
lcd_gotoxy(0,1);
lcd_putsf("z=");
lcd_gotoxy(2,1);
sprintf(ledbuf, "%d", zAxis);
lcd_puts(ledbuf);
}
*/
//***********************************************************************
//Compute the odd parity of a character. If the character has even numbers
//of 1, the parity bit will be 1, otherwise it will be 0.
unsigned char parity(unsigned char x)//calculate the parity of a character
{
unsigned char temp, i;
temp=1;
for(i=0;i<8;i++)
{
temp=temp^(x&1);
x>>=1;
}
return temp;
}
//***********************************************************************
void clockStateNow(void)
{
switch (myState)
{
case BUSY:
//if the clock being hold low when the clock should've been high.
//Transition to inhibit state
if ((clockState == HIGH || clockState == RISING) && CLK_IN == 0)
{
inhibited = TRUE;
myState = INHIBIT;
clockState = LOW;
transmitting = 0;
receiving = 0;
count2 = 0;
}
else if ( !(transmitting || receiving) ) //if not doing anything, then we go back to idle
myState = IDLE;
else myState = BUSY;
break;
case IDLE:
//if the clock being hold low when the clock should've been high.
//Transition to inhibit state
if ((clockState == HIGH || clockState == RISING) && CLK_IN == 0)
{
inhibited = TRUE;
myState = INHIBIT;
clockState = LOW;
transmitting = 0;
receiving = 0;
count2 = 0;
}
//if there is data in the queue waiting to be sent
//transition to BUSY state
else if(queueEmpty == FALSE)
{
myState = BUSY;
transmitting=1;
nextClockState=RISING;
position = 0;
}
else
{
myState = IDLE;
}
break;
case INHIBIT:
//if the computer inhibit before we finishing sending the byte
//we need to resend the byte
if(position != 0 && position < 10)
{
resendFlag = TRUE;
}
position = 0;
//right after the clock get out of inhibit state
//we need to check if the computer have hold down the data.
//If the computer pulls low the data line, then the mouse goes into
//REQUEST state.
if (outInhibit == TRUE)
{
if(DATA_IN == 0)
{
//The computer is request to send some data to the mouse
myState = REQUEST;
clockState = RISING;
}
else
{
//If the data line wasn't low.
//then the computer must have put the mouse into inhibit
//for processing data.
myState = IDLE;
clockState = RISING;
}
outInhibit = FALSE;
}
//if the clock high, meaning the computer has released clock line
if(CLK_IN == 1)
{
outInhibit = TRUE;
}
else
{
inhibited = TRUE;
myState = INHIBIT;
transmitting = 0;
clockState = LOW;
receiving = 0;
outInhibit = FALSE;
}
break;
case REQUEST:
position = 0;
receiving = 1;
nextClockState = FALLING;
//if the clock being hold low when the clock should've been high.
//Transition to inhibit state
if ((clockState == HIGH || clockState == RISING) && CLK_IN == 0)
{
inhibited = TRUE;
myState = INHIBIT;
clockState = LOW;
transmitting = 0;
receiving = 0;
count2 = 0;
}
else if ( transmitting || receiving)
myState = BUSY;
else
myState = REQUEST;
break;
}//end switch
}
//interrupt for clock generation, byte receive and transmition
//This interrupted get triggered every 20us
interrupt [TIM1_COMPA] void clockGenNrecvNtrans(void)
{
lcddelay++;
if (queueEmpty == TRUE)
count++;
count2++;
if(debounceTimer <= 480)
debounceTimer++;
else
debounceBtn();
if (count >= 500)
{
packetGenFlag = TRUE;
count = 0;
}
lastClkIn = ClkIn;
ClkIn = CLK_IN;
dataIn = DATA_IN;
//transmitting flag is set.
if(transmitting)
{
clockState = nextClockState;
if(clockState==HIGH)//write data out here
{
if(position==0)//start bit
{
DATA_OUT=0;
}
else if(position<9)//data bits
{
DATA_OUT=PS2byte&0x01;
PS2byte = PS2byte>>1;
}
else if(position==9)//parity bit
{
DATA_OUT=PS2parity;
}
else if (position == 10)
{
DATA_OUT =1;
}
//increment the position after trasmitting one bit
position++;
nextClockState = FALLING;
}//end clockState == HIGH
else if(clockState==FALLING)
{
CLK_OUT=0;
nextClockState = LOW;
}
else if(clockState==LOW)
{
nextClockState=RISING;
}
else //clockstate == rising
{
if (position == 0)//read input from queue
{
//check if there is a packet needed to be sent in the queue
if (queueEmpty == FALSE)
{
//get the packet from the queue
PS2byte = queueGet();
PS2parity = parity(PS2byte);
if(queueEmpty == TRUE)
transmitFlag = TRUE;
//delay 150us before transmitting.
delay_us(150);
}
}
if (position == 11) //stop the transmittion
{
transmitting=0;
position = 0;
}
CLK_OUT=1;
nextClockState=HIGH;
}
}//end if transmitting
//RECEIVING from the computer host
if(receiving)
{
clockState = nextClockState;
if(clockState==HIGH)//write data out here
{
if(position==11)
{
DATA_OUT=1; //ACK bit
//display is used for debugging.
//displayInput(1, rcvByte);
receiving = 0;
position = 0;
//process the received byte from the computer and provide proper feedback.
processCommand(rcvByte);
rcvByte = 0;
rcvBit = 0;
}
if (position == 10)
{
DATA_OUT = 0;
}
nextClockState = FALLING;
}
else if (clockState ==FALLING)
{
CLK_OUT = 0;
nextClockState = LOW;
}
else if (clockState ==LOW)
{
nextClockState = RISING;
}
else //clockState == RISING
{
CLK_OUT = 1;
if (position >=0 && position < 8)
{
//fatch a bit from the computer
rcvBit = DATA_IN;
//if pos < 11 then receive bits from host
rcvByte = ((rcvBit & 0x01) << position) | rcvByte;
}
//if we are still in recveiving mode then increament the position counter.
if (position < 11)
{
nextClockState = HIGH;
position++;
}
}
}
//transition to the correct state after finishing receiving or trasmitting.
clockStateNow();
}
//The entry point of the software.
void main(void)
{
unsigned char lastSpos, currSpos;
unsigned char upS, downS, lastUpS, lastDownS;
char scroll;
//initialize the trasmission part of the code
initChip();
//initialize the part of code handles the mouse movement
initialize();
//tell the computer that the mouse is ready and alive.
queuePut(0xAA);
queuePut(0x00);
while(1)
{
//BLINK corresponding status LED.
if(myState==IDLE)
{
//PORTB = ~0x20;
}
else if ( myState == INHIBIT)
{
//PORTB = ~0x80;
CLK_OUT = 1;
DATA_OUT = 1;
}
else if (myState == REQUEST)
{
//PORTB = ~0x40;
}
else if (myState == BUSY)
{
/* if (transmitting == 1)
PORTB = ~0x10;
if (receiving == 1)
PORTB = ~0x08;
*/
}
else //error state
{
//PORTB = ~0x01;
}
//timer1 sets this flag every 500*20us
if(packetGenFlag == TRUE)
{
scrollCount++;
if(scrollCount >0)
{
//scroll state machine, detect if there is a scroll.
detectScroll();
scrollCount =0;
}
//if the scroll state never changes back to POSS_SCROLL state
//we need to reset its state to POSS_SCROLL after 20*20us
if(scrollState != POSS_SCROLL)
{
falseStateCount ++;
}
else if(scrollState == POSS_SCROLL ||scrollState == BEGIN_SCROLL )
falseStateCount = 0;
if(falseStateCount > 20)
{
falseStateCount = 0;
scrollState = POSS_SCROLL;
}
if(scrollState == REAL_UP_SCROLL || scrollState == REAL_DOWN_SCROLL)
{
realScrollFlag = TRUE;
//there should be a pause between scroll
//we pause 20*20us
scrollCount = -20;
}
//get the position data from accelerometers
dataFromMouse();
//convert position into relative position movement
getMovement();
//if any of the button is pushed then we need to generate a packet to represent it
if(leftBtn ==1 || middleBtn ==1 || rightBtn ==1)
realBtnFlag = TRUE;
//if any of the button has changed to unpushed state, we also need to send a packet to indicate the change
if(lastLeftBtn != leftBtn || lastMiddleBtn != middleBtn || lastRightBtn != rightBtn )
realBtnFlag = TRUE;
//detetect if there is a scroll
/* scroll = movement[Z_AXIS];
if(!(scroll > -10 && scroll < 10))
realScrollFlag = TRUE;
*/
//keep the previous button state
lastLeftBtn = leftBtn;
lastMiddleBtn = middleBtn;
lastRightBtn = rightBtn;
if(transmitMode ==1 && (realMoveFlag==TRUE || realBtnFlag==TRUE || realScrollFlag==TRUE))
packetGen();
packetGenFlag = FALSE;
realBtnFlag = FALSE;
realMoveFlag = FALSE;
realScrollFlag = FALSE;
}
}
}
void initChip(void)
{
count = 0;
TIMSK = 0x10 ; //Set the compare A interrupt
PS2byte = 0xFA;
rcvByte = 0x00;
rcvBit = 0x00;
ClkIn = 1;
lastClkIn = 1;
outInhibit = FALSE;
forceDelay = FALSE;
position = 0;
clockState = HIGH;
nextClockState = HIGH;
myState = IDLE;
//timer 1 setup: running at 12.5 kHz
TCCR1A = 0;
TCCR1B = 8 + 3; //CTC mode, prescalar = 1024
OCR1A = 4;
DDRD = 0b01000010; //set data direction (see initial wiriing comments)
PORTD = 0b01000010; //initialize outputs to high
DDRB = 0xFF; //set LEDs to all output
PORTB = ~0x00; //set all LED's to off
CLK_OUT = 1;
DATA_OUT = 1;
}
//**********************************************************
//Set up all variables that's not releated to clock generation
void initialize(void)
{
unsigned char i;
//make c as input
DDRC = 0x00;
//init the buttons
debounceTimer =0;
but_state = STATE_READY;
butinfo =0;
leftBtn =0;
rightBtn =0;
middleBtn =0;
lastLeftBtn = 0;
lastRightBtn = 0;
lastMiddleBtn = 0;
//init current position and previous position
for(i=0;i<3; i++)
{
curPosition[i] = 0;
lastPosition[i] = 0;
movement[i] = 0;
}
//init calibration variables
xCal = 0;
yCal = 0;
zCal = 0;
scrollCount = 0;
scrollIndex = 0;
scrollState = POSS_SCROLL;
packetGenFlag = FALSE;
queueEmpty = TRUE;
queueFull = FALSE;
queueIn = 0;
queueOut =0;
transmitMode = FALSE;
realMoveFlag = FALSE;
realScrollFlag = FALSE;
realBtnFlag = FALSE;
//init the LCD
//used for debugging purposes only
/* lcd_init(LCDwidth); //initialize the display
lcd_clear(); //clear the display
lcdPosCount0 = 0;
lcdPosCount1 = 0;
*/
//read voltage on A.0
ADMUX = 0b01100000;
//ADC on
ADCSRA = 0b11000111;
//enable sleep mode
MCUCR = 0b10000000;
//carnk up the ISRs
#asm
sei
#endasm
}
Attachments
Last edited: