📄 computer side.c
字号:
/******************************************
* Wireless Keyboard - Hejnar, Leventhal
* Computer Side Code
* Ports:
* A - Input/Output to Computer
* A.7 - Output Clock
* A.5 - Input Clock
* A.6 - Output Data
* A.4 - Input Data
*
* C - Debugging LEDs
*/
#include <Mega32.h>
#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 some useful maps to bits
#define UART_IN UCSRA.7
#define CLK_OUT PORTA.7
#define DATA_OUT PORTA.6
#define CLK_IN PINA.5
#define DATA_IN PINA.4
//state of the data line
char transmitting, receiving, waiting;
//receive state
//0 waiting for AA
//1 - waiting for FF
//2 - waiting for actual data
char RFState;
//variables for writing to PS/2 port
char position, PS2byte, PS2parity;
char clockState;
//define clock states
#define HIGH 0
#define FALLING 1
#define LOW 2
#define RISING 3
//define queue values
#define QUEUELEN 200
#define TRUE 1
#define FALSE 0
char queue[QUEUELEN]; //queue of data sent by keyboard. (first in, first out)
char queueFull; //indicates if queue is full
char queueEmpty;//indicates if queue is empty
char queueIn; //indicates where to put data into queue
char queueOut; //indicates where to take data out of queue
char queuePut(char d); //put data into queue
char queueGet(void); //get data from queue
//0 = waiting
//1 = received AA last
//2 = received FF last next in is good
char preamble_state;
//break code was received
char break_code;
char parity(char x)//calculate the parity of a character
{
char temp, i;
temp=1;
for(i=0;i<8;i++)
{
temp=temp^(x&1);
x>>=1;
}
return temp;
}
//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 (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
return(d); //return the data from queue
}
//determine the state of the data line
char clockStateNow(void)
{
if(transmitting || receiving || waiting)//I'm doing something
return(BUSY);
if(CLK_IN==0)//computer is inhibiting commmunication
return(INHIBIT);
if(DATA_IN==0)//computer wants to send something
return(REQUEST);
return(IDLE);//nothing happening
}
void initChip(void)
{
OCR1A = CLK_TIME; //compare match to drive the clock to PC
OCR1B = RESPOND_WAIT;
TCCR1B = 0x01; //Run counter at full speed
TCCR1A = 0x00; //nothing needed here, no output
TIMSK = 0x18; //Set the compare A interrupt and compare B interrupt
queueFull=FALSE;//queue is not full
queueEmpty=TRUE;//queue is empty
queueIn=0; //where to insert into queue
queueOut=0; //where to take out of queue
PORTA = 0xC0; //initialize outputs to high
DDRD = 0x00;
DDRB = 0x00;
DDRA = 0xC0; //set data direction (see initial wiriing comments)
DDRC = 0xFF; //set LEDs to all output
PORTC=0x00; //siet all LED's to off
UCSRB = 0x18 ; //enable only the receiver, no interrupts
UCSRC=0xB6; //odd parity, 8-bit data segments
UBRRH = (int)300>>8;
UBRRL = (int)300 & 0xFF ; //need to change this 416 for 2400, 207 for 4800
#asm
sei
#endasm
}
//this interrupt occurs four times per clock cycle on the ps/2 line
interrupt [TIM1_COMPA] void t1_cmpA(void)
{
TCNT1=0;
if(transmitting)
{
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)//stop bit
{
DATA_OUT=1;
}
else if(position==11)//end transmission, set up delay
{
transmitting=0;
waiting=1;
TCNT1=CLK_TIME+1;
}
position++;
clockState=FALLING;
}
else if(clockState==FALLING)
{
CLK_OUT=0;
clockState=LOW;
}
else if(clockState==LOW)
{
clockState=RISING;
}
else
{
CLK_OUT=1;
clockState=HIGH;
}
}
if(receiving)
{
//this was not working properly, removed to avoid bugs
}
PORTC=0x00;
}
//end delay step
interrupt [TIM1_COMPB] void t1_cmpB(void)
{
waiting=0;
TCNT1=0;
}
void main(void)
{
char inFromRF;
char myState;
initChip();//initialize chip
RFState = 0;
break_code=0;
while(1)
{
if(UART_IN)
{
//handle uart, make sure you receive the preamble before registering a symbol
inFromRF=UDR;
if(!UCSRA.2)
{
if(RFState==0)
{
if(inFromRF==0xAA)
RFState=1;
}
else if(RFState==1)
{
if(inFromRF==0xFF)
{
RFState=2;
}
}
else if(RFState==2)
{
if(inFromRF!=0xAA)//ignore this, the transmitter was just helping the AGC
{
if(inFromRF==0xF0)//keep break codes and their key codes together
{
PORTC=0xFF;
break_code=1;
}
else
{
if(break_code==1)
{
PORTC=0x00;
break_code=0;
queuePut(0xF0);
}
queuePut(inFromRF);
}
}
RFState=0;
}
PORTC=0x00;
}
}
myState=clockStateNow();//check if the line is idle
//never go to receive mode
/* if(myState==REQUEST)
{
receiving=1;
position=0;
}*/
if( (myState==IDLE) && !queueEmpty )//is it idle and is there something to send
{
//PORTC=0xFF;
PS2byte = queueGet();
if(PS2byte!=0)
{
transmitting=1;
position=0;
clockState=HIGH;
PS2parity = parity(PS2byte);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -