/******************************************
* Wireless Keyboard - Hejnar, Leventhal
* Keyboard Side Code
*/
#include <Mega32.h>
//connect the DAT line to B.0 which is pin 1 on the
chip (Yellow)
//connect the CLK line to B.2 which is pin 3 on the
chip (Blue)
#define rDAT PIND.7
#define rCLK PIND.3
#define wDAT PORTD.7
#define wCLK PORTD.3
#define TRUE 1
#define FALSE 0
#define QUEUELEN 200
char receive; //indicate
that int2 interrupt should work as reciever (if 1) or tranmsitter (if 0)
char countIn; //count
how many Low CLK pulses we have seen as we receive data from keyboard
char countOut; //count
how many Low CLK pulses we have seen as we transmitt data to keyboard
unsigned char dataIn; //will
store the data bits coming in from the keyboard
unsigned char dataOut; //will
store the data bits we are sending out to the keyboard
char parityIn; //will
store the calculated parity of data coming in from the keyboard
char parityOut; //will
store the calculated parity of data we are sending out to the keyboard
char pError; //will
store if there was a parity error in data sent by keyboard
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 rxDone; //indicate
done receiving frame
char txDone; //indicate
done transmitting frame
char t2visits; //times
gone into timer2 interrupt without any resets of the counter
void initialize(void); //initialize
mcu
void initializeKyBd(void);//initialize keyboard
char queuePut(char d); //put
data into queue
char queueGet(void); //get
data from queue
void TXtoKyBd(char d); //send
command to keyboard
void RXfromKyBd(void); //receive
data from keyboard
//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
}
//on every falling clock edge generated by the keyboard,
either receives or sends data
interrupt [EXT_INT1] void external_int1(void)
{
//when
receiving data
if(receive==TRUE)
{
countIn++; //count how many
clock pulses we have seen
//if countIn=1, then seeing the
start bit
//if countIn=
//if countIn=10, then seeing the
parity bit
//if countIn=11, then seeing the
stop bit
if (countIn==1)//seeing start
bit
{
dataIn=0;
rxDone=FALSE; //receiving not done (just
starting)
//set
up timer0 to check for no clock transition in 200uSec
TCNT0=0; //reset timer0
TCCR0=0x0B;
//put timer0 into compare match
mode, prescaler of 64;
TIMSK=(TIMSK&0xFD)|0x02;
//make bit1=1 to enable compare match interrupt;
TIFR=TIFR&0xFD;
//make bit1=0 to clear the timer0 comp match flag (just in case its set)
}
else if ((countIn>1) &&
(countIn<10)) //data bits being sent
{
TCNT0=0;
//reset timer0 since saw a
clock signal
TIFR=TIFR&0xFD;//make
bit1=0 to clear the timer0 comp match flag (just in case its set)
dataIn=dataIn>>1;//shift
data right by 1
if
(rDAT==1) //if DAT line is 1
{
dataIn=dataIn|0x80; //shift in a received bit of 1. (0
shifted in automatically)
parityIn++; //update
the parity
}
}
else if (countIn==10) //parity
bit being sent
{
TCNT0=0;
//reset timer0 since saw a
clock signal
TIFR=TIFR&0xFD;
//set bit1=0 to clear the timer0 comp match flag (just in case its set)
//partiy
should be odd
if
((parityIn+rDAT)&0x01) //if (calculated
parity+ rDAT) is odd,
pError=FALSE; //then
no parity error
else
pError=TRUE; //otherewise there
was a parity error
}
else if (countIn==11) //stop bit being sent
{
TCCR0=0x00; //stop timer0 since seen last clock
TCNT0=0; //reset timer0
TIMSK=TIMSK&0xFD; //set bit1=0 to disable timer0 interrupt
TIFR=TIFR&0xFD; //set bit1=0 to clear the timer0
comp match flag just in case
//don't
pass along responses to RF that are meant only for the microcontroller or if
there was a parity error
//
parityError BAT successful Ack BAT error
if(!pError
&& (dataIn!=0xAA) && (dataIn!=0xFA) && (dataIn!=0xFC))
{
//AGC
set up and syncronization
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xFF);
queuePut(dataIn);
//insert data into queue
}
rxDone=TRUE; //indicate that we have received a frame
countIn=0; //reset count since have seen the
end of frame
parityIn=0; //clear parity for next time
}
}
//when
sending data, writing stuff onto the DAT line when clock is low so
//that
the data is valid when clock goes high and the keyboard reads it
else
{
countOut++; //coutn how many clock pulses we have
seen
//if countOut=1, then seeing
ourselves pulling line low to inhibit communication
//if countOut=2 to 9 then we
will be sending data bits 0 to 7
//if countOut=10, then we will
be sending out the parity bit
//if countOut=11, then we will
be sending out the stop bit
//if countOut=12, then seeing
the "ack" bit
if (countOut==1) //seeing
ourslves pulling the line low to inhibit communication
{
//set
up timer so that we keep CLK low for at least 100uSec
TCCR1A=0x00; //normal waveform generation
TCCR1B=0x01; //normal waveform generation and full clock
speed (16MHz)
TCNT1=0; //reset timer1 to 0
OCR1A=2240; //140uSec*16MHz=2240cycles
TIMSK=(TIMSK&0xEF)|0x10; //set bit4=1 to 1 to enable Output
Compare A match interrupt
//set
up timer0 to check for no clock transition in 200uSec
TCNT0=0; //reset timer0
TCCR0=0x0B;
//put timer0 into compare match
mode, prescaler of 64;
TIMSK=(TIMSK&0xFD)|0x02;
//set bit1=1 to enable compare match interrupt;
TIFR=TIFR&0xFD;
//set bit1=0 to clear the timer0 comp match flag (just in case its set)
parityOut=0; //reset parity
txDone=FALSE; //transmitting not done(just starting)
}
else if (countOut>1
&&countOut<10) //data bits being sent
{
TCNT0=0;
//reset timer0 since saw a clock signal
TIFR=TIFR&0xFD;
//set bit1=0 to clear the timer0 comp match flag just in case
if
(dataOut&0x01)//if lowest bit is a 1
{
wDAT=1; //write
out a 1 to the keyboard
parityOut++; //calculate the parity
}
else
wDAT=0; //write out a 0 to the keybard
dataOut=dataOut>>1;//shift
data right by 1 to get next bit next time
}
else if (countOut==10)//send
parity bit
{
TCNT0=0;
//reset timer0 since saw a clock signal
TIFR=TIFR&0xFD;
//set bit1=0 to clear the timer0 comp match flag (just in case its set)
if(parityOut&0x01)
//if parity is odd
wDAT=0; //write out a 0 to the keyboard
else
wDAT=1; //write out a 1 to the keyboard to make it odd parity
}
else if (countOut==11)//sending
out the stop bit
{
TCNT0=0;
//reset timer0 since saw a clock signal
TIFR=TIFR&0xFD;
//set bit1=0 to clear the timer0 comp match flag (just in case its set)
wDAT=1; //write the stop bit (when change
DDR, this will also activate the pullups)
DDRD=0x00;
//make DAT line input, CLK input already.
Do this so kybd can send ack bit
}
else if (countOut==12)//getting
the ack bit of 0 on DAT
{
TCCR0=0x00;
//turn off timer0 since seen last
clock
TIMSK=TIMSK&0xFD; //set bit1=0 to turn of timer0 comp match
interrupt
TIFR=TIFR&0xFD; //set bit1=0 to clear timer0 comp
match flag (just in case its set)
txDone=TRUE;//transmitting
done
countOut=0; //reset countOut for next time
parityOut=0;//reset
parity for next time
}
}
GIFR=0;
}
//used to make CLK low for at least 100uSec so can send
stuff to keyboard
interrupt [TIM1_COMPA] timer1_compA(void)
{
TIMSK=TIMSK&0xEF; //set
bit4=0 to turn off interrupt
TCCR1B=0x00; //turn off timer (saves power)
DDRD=0x80; //make
CLK an input, keep DAT as output
wCLK=1; //write 1 to B.2 so pullup turn
on
wDAT=0; //write 0 to DAT, this is the
start bit...kybd will start generating a clock any moment now
}
//if this executes, then it has been at least 200uSec
between clk pulses while receiving or transmitting data to keyboard
interrupt [TIM0_COMP] timer0_comp(void)
{
TIMSK=TIMSK&0xFD; //set bit1=0 to turn off timer0 comp match
interrupt
TCCR0=0x00;
//turn off timer0
TIFR=TIFR&0xFD; //set bit1=0 to clear timer0 comp
match flag (just in case its set)
countIn=0; //reset
counters
countOut=0;
parityIn=0;
//reset parity calculations
parityOut=0;
txDone=TRUE; //there was some error, but pretend you are
done
rxDone=TRUE;
receive=TRUE; //put system into receive mode (just a
default option)
wDAT=1;
//turn on pull ups
wCLK=1;
DDRD=0x00; //set DAT and CLK to input
}
//used to make sure we send something approximately every 25msec
interrupt [TIM2_OVF] timer2_overflow(void)
{
t2visits++;
//after
visit this interrupt without reseting 6 times, then about 25msec
//elapsed
since last time we sent something
if (t2visits==15)
{
//send some stuff for AGC
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xAA);
queuePut(0xFF);
queuePut(0xAA);
t2visits=0;//reset number of
visits
}
}
//initialize the mcu
void initialize(void)
{
DDRD=0x00; //make PORTD pin D.3 and D.7 input for
CLK and DAT
PORTD=0x88; //write 1 to B.7 and B.3 so pullups on
for wCLK and wDAT
MCUCR=0x08;
//int1 triggered on falling edge
GICR=0x80; //int1 enable
//Timer0
set up. The rest will be done inside the
external interupt
OCR0=50;
//Timer0 Outoput compare when 50 (decimal)....1/(16Mhz/64)*50=200uSec.
//Timer2
set up.
TCCR2=0x06; //prescal by 256
TIMSK=(TIMSK&0xBF)|0x40;
//set bit6=1 to enable overflow interrupt
//UART
UCSRB=0x08;
//enable transmitter only
UCSRC=0xB6;
//Asynchronous mode, 8bit words, 1 stop bit ,odd parity
UBRRH =
(int)300>>8;
UBRRL =
(int)300 & 0xFF ; //need to change this 416 for 2400, 207 for 4800
DDRC=0xff; //for testing, set portc to output
PORTC=0xff; //for testing,set LEDs off
DDRA=0xff; //for testing set porta.0 to output
PORTA=0x00; //for testing,set to 0
receive=TRUE; //put int1 interupt into recieve mode
countIn=0; //no low clock pulses seen yet
countOut=0;
parityIn=0; //calculated parity at 0
parityOut=0;
//set
up queue
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
rxDone=FALSE; //haven't finished receiving
txDone=FALSE; //haven't finished transmitting
#asm
sei
#endasm
}
void initializeKyBd(void)
{
//------------------------
dataIn=0;
countIn=0;
RXfromKyBd(); //put into receive mode
while(!rxDone) //wait
until get 0xAA (por sucessfull) from kybd (get it only when turn
; //power
on and off. Not when you reset microcontroller
//------------------------
TXtoKyBd(0xFF);
//put int tranmsit mode, tell kybd to reset itself
while(!txDone) //wait until transmitting done
;
//------------------------
RXfromKyBd(); //put into receive mode
while(!rxDone) //wait until get 0xFA (ack) from kybd that
it got the command
;
//------------------------
RXfromKyBd(); //put into receive mode
while(!rxDone) //wait until get 0xAA (reset sucesfull) from
kybd
;
//------------------------
TXtoKyBd(0xF4); //put into transmit mode, tell
kybd to enable all keys (cmd might not be needed)
while(!txDone) //wait until transmitting done
;
//------------------------
RXfromKyBd(); //put into receive mode
while(!rxDone) //wait until get 0xFA (ack) from kybd that
it got the command
;
//------------------------
//kybd
will now remain in receive mode unless we change it
}
//set interrupt to be in receive mode
void RXfromKyBd(void)
{
receive=TRUE; //set int2 to receive mode
rxDone=FALSE; //reset
wDAT=1; //pull
ups on
wCLK=1; //pull
ups on
DDRD=0x00; //set DAT and CLK to input
countIn=0;
}
//sets interrupt to be in transmit mode
void TXtoKyBd(char d)
{
receive=FALSE; //set int2 into transmit mode
txDone=FALSE; //reset
dataOut=d; //the data to transmit
DDRD=0x88; //set DAT and CLK to output
wDAT=1; //keey
DAT high
wCLK=0; //pull
CLK low to signal that you want to communicate.
Int2 will trigger right away
}
void main(void)
{
initialize(); //initialize mcu
initializeKyBd();
//initialize keyboard
while(1)
{
if((!queueEmpty)
&& (UCSRA&0x20)) //if queue not empty and UART is available
{
t2visits=0; //reset timer2 count value
TCNT2=0; //reset
timer2
TIFR=TIFR&0xBF; //set bit6=0 to reset overflow
flag (just in case its set)
UDR=queueGet(); //send data out
}
}
}