ECE 476 Final Project

download ECE 476 Final Project

of 48

Transcript of ECE 476 Final Project

  • 8/7/2019 ECE 476 Final Project

    1/48

    ECE 476 Final Project: Wireless Keyboard

    Introduction:

    For our project, we designed a wireless keyboard that uses RF to transmit signals to thecomputer. In our design, we use a regular, 102 key ps/2 keyboard and connect it to ourtransmitter circuit. On the computers side, we connect our receiver circuit to the ps/2 port on theback of the computer. With this set up, we convert a cheap ordinary keyboard into a wirelesskeyboard.

    We had several motives for choosing this project. First of all, computers have lots ofwires and cables connected to them. These include the power cable, the monitor cable, theprinter cable, network cable, speaker wire, microphone input, modem lines, various USB device

    and the essential mouse and keyboard wires. These wires form an unsightly tangled mess in theback of all computers. We therefore chose to eliminate one of these wires by making a wirelesskeyboard. Second, the trend for making wireless devices continues to increase. These days, wehave wireless remote controls for TVs, VCRs, stereo systems, car alarms and garage dooropeners. Furthermore, we have wireless telephones, network connections and the now ubiquitouscell phones. We even have wireless remote controls for floor fans. Since wireless devices arebecoming so popular, we decided to make a wireless device so that we could learn more aboutsuch devices. Furthermore, we decided to make a wireless keyboard because current wirelesskeyboards are either too expensive or have a fairly short range. For example, most currentwireless keyboards use infrared for communication, which limits their range to about 6ft. Thesekeyboards cost about $40. Some newer keyboards that use RF have a longer range, but these

    keyboards often cost twice as much or more. Finally, we had a need for a cheap wirelesskeyboard with a long range: Sean enjoys playing movies on his computer but watching them onhis TV. To do this, he runs a long wire from his video card to the TV. However, if he wants topause or rewind the movie, he needs to get up and go to his computers keyboard and hit theappropriate buttons. Although he has an infrared wireless keyboard, the range is only about 6feet, which is too short a distance for him. So, being electrical engineers, we decided to make acheap wireless keyboard with a longer range.

    High Level Design:

    The wireless keyboard consists of a wired 102-key ps/2 keyboard, two Atmega32microcontrollers, one 433.92MHz transmitter and one 433.92MHz receiver from Radiotronix.

    Our design can be divided into two parts: the keyboard side and the computer side. Onthe keyboard side, we have one of the microcontrollers connected to the keyboard and to the

  • 8/7/2019 ECE 476 Final Project

    2/48

    transmitter. The keyboard communicates with the microcontroller and the microcontroller sendsdata out to the transmitter by using its built in UART. On the computer side, we have the othermicrocontroller connected to the computer and to the receiver. The computer communicateswith the microcontroller and the microcontroller gets data from the receiver through its build inUART. Note that we use the UART because they allow us to easily set the transmit and receive

    rate and they do all the transmitting and receiving in the background. Our setup is shown in thefigure below.

    Because we decided to use a ps/2 keyboard and connect to the ps/2 port on the computer, weneeded to implement the ps/2 protocol on the microcontrollers. A very good reference on theps/2 protocol is located on Adam Chapweskes webpage. The ps/2 protocol is a bi-directionalprotocol, which means that not only does the keyboard send data to the computer, but thecomputer sends data to the keyboard. For example, the computer can do such things as tell thekeyboard to reset or set the typematic delay and typematic rate, among other things. This meansthat in our wireless set up, not only should the keyboard be able to transmit to the computer, butthe computer should be able to transmit to the keyboard. However, due to budgetary constraints,we could only purchase one transmitter and one receiver. To overcome this obstacle, we had toprogram the microcontroller on the keyboard side so that it would pretend to be the computer andprogram the microcontroller on the computers side so that it would pretend to be the keyboard.

    On the keyboard side, this requires that the microcontroller sends the appropriate commands tothe keyboard when it boots up, and that it listens for the correct responses back from thekeyboard. Furthermore, on the computer side, this requires that the microcontroller respondscorrectly to all the commands that the computer sends to it.

    In addition, the ps/2 protocol specifies that data be sent at a maximum rate of 10kbps to16.6kbps. However, the transmitter/receiver pair can only transmit at a maximum of 4.8kbps.As a result, the microcontroller on the keyboard side needs to buffer the keyboard data so that itcan send it out at a much slower rate through the transmitter. We rely heavily on the fact that ahuman being can only type so fast, and that the typematic rate (the rate at which the keyboardresends a key that is held down) is well below the maximum. On the computer side, this also

    means that the microcontroller needs to buffer all the data that it slowly receives before passing italong to the computer at a faster rate.

  • 8/7/2019 ECE 476 Final Project

    3/48

    Program andHardware Design:

    First, a little background about the ps/2 protocol: The ps/2 protocol is a bi-directional

    protocol that uses a Clock line and a Data line. The clock is always generated by the keyboardand each clock cycle has to be between 60 and 100uSec long. When no data is being sent byeither the keyboard or the computer, both the Clock line and the Data line are pulled up to 5Vthrough pull up resistors on the keyboard side and the computer side. When the keyboard sendsdata, it generates clock pulses that go from 0V to 5V on the Clock line and it sends its data on theData line. If the computer wants to send a command to the keyboard, the computer pulls theClock line low to 0V for at least 100uSec. After the 100uSec elapse, the computer releases theClock line, places a start bit of 0V on the Data line and waits for the keyboard to start generatingclock pulses. At each clock pulse, another bit of data is placed on the Data line by the computer.Although the clock is generated by the keyboard, the computer has control over thecommunication. If the computer wants to stop the keyboard from sending data, it just pulls the

    Clock line low. The keyboard then has to wait for the Clock line to be released before it can startgenerating a clock and sending data. When the keyboard sends data to the computer, it sends atotal of 10 bits: A start bit (0V), 8 data bits, a parity bit and a stop bit (1V). When the computersends commands to the keyboard, it also sends a total of 10 bits: A start bit(0V), 8 data bits, aparity bit and a stop bit (1V). However, on the next clock cycle after the stop bit of thecommand is sent, the keyboard has to respond with an acknowledge bit (0V) on the data line.For more details on the ps/2 protocol, please see Adam Chapweskes webpage.

    Computer Side Hardware:

    The computer side hardware is shown in the figure below. The computer connects to themicrocontroller through a 6-pin min-DIN plug and provides power to run both themicrocontroller and the receiver, thus there is no need for any batteries. The

    specification for keyboards is that they should draw no more than 100mA, which is sufficient forour purposes. The Clock line connects to pin 5 of PORTA and the Data line connects to pin 4 ofPORTA on the microcontroller. These pins are always set to input with pull up resistors so thatthe Clock line and Data line are pulled high when the lines are idle. We use a 510 Ohm resistorto connect the Clock line to pin 7 of PORTA and another 510 Ohm resistor to connect the Dataline to pin 6 of PORTA. We use these resistors so that we can pull the Clock and Data lines low

    using pins 7 and 6 respectively without shorting pins 5 and 4 to ground and burning out the portpins. The microcontroller receives data from the wireless keyboard using the Radiotronixreceiver (RCR-433-RP). The data output of the receiver is passed to the RXD pin of themicrocontroller. As a result, the UART handles all the signal reception in the background forus. Like for the transmitter, we use a dipole antenna made from a piece of wire that is about 2feet long.

  • 8/7/2019 ECE 476 Final Project

    4/48

  • 8/7/2019 ECE 476 Final Project

    5/48

    Computer Side Software

    The software on the computer side has two main tasks. First, it listens for incoming

    data on the UART, determining which bytes correspond to keyboard codes. Second, it echoesthese codes to the computer.

    Every byte sent to the receiver is in the following format. There is an initial stream ofbytes which are all 0xAA. These allow the Adaptive Gain Control on the receiver to properlyhandle the incoming signal. Then, 0xFF is sent. This indicates that the next byte will be a validdata byte. Finally, a data byte is sent. Since the microcontroller uses the UART to receive datafrom the receiver, it polls the UART regularly to see if it has received any bytes. Themicrocontroller decodes the sequence of bytes it receives using the state machine shown. Asbytes are read from the UART they are added to a queue to be sent on the PS/2 bus.

    In addition to polling the UART, the microcontroller polls the state of the PS/2

    connection. When the connection is idle, and there is data to send, the microcontroller setsseveral state variables. These state variables cause an interrupt to generate a clock signal on thePS/2 port and to place data on the PS/2 data line. This interrupt occurs four times for every clockcycle, writing the data, stop, start and parity bits to the PS/2 connection.

  • 8/7/2019 ECE 476 Final Project

    6/48

    Keyboard Side Hardware:

    The keyboard side hardware setup is shown in the figure below. The keyboard connects

    to the microcontroller through a 6-pin mini-DIN socket. The Data line of the keyboard isconnected to pin 7 of PORTD and the Clock line of the keyboard is connected to pin 17, which isexternal interrupt 1 of the microcontroller. On the falling edges of the Clock line, themicrocontrollers interrupt triggers and either a bit of data is read in or one bit of data is sent outto the keyboard. The data that is to be transmitted to the computer is on the TXD pin of theUART. This pin connects to the data input of the Radiotronix transmitter (RCT-433-AS) and istransmitted. For the transmitters antenna, we use a dipole antenna made from a piece of wirethat is approximately 2 feet long.

    One of the problems that we experienced involved one of the external interrupts.Originally, we used interrupt 2, which is an asynchronous edge triggered interrupt. When using

    this interrupt, our code refused to work. After days of work, we finally realized that the interruptwould get triggered at the incorrect times. In some cases, small noise spikes would trigger theinterrupt and in other cases it would trigger for no apparent reason. Once we changed our codeto use external interrupt 1, we didnt encounter any of these errors. Based on our experience, itappears that the external interrupt is very sensitive to external noise and isnt suited to our use.

  • 8/7/2019 ECE 476 Final Project

    7/48

  • 8/7/2019 ECE 476 Final Project

    8/48

    Keyboard Side Software:

    The software on the keyboard side has two main tasks: It listens to the data coming from

    the keyboard and it sends it out to the transmitter through the UART. The keyboard generates aclock on the Clock line and sends its data on the Data line. Whenever the clock is goes low, 1 bitof data is present on the Data line and the microcontroller reads it. To read the data line at theappropriate times, we use edge triggered external interrupt 2 to trigger on each falling edge.When the interrupt executes, one data bit is shifted into a register. Since the ps/2 protocol sendsa start bit, followed by 8 data bits, then a parity and a stop bit, we only shift in the data bits into aregister. Once we have the 8 data bits, we place the byte into a queue. To make sure that theAGC on the receiver end can read the data bytes correctly, we place a stream of eleven bytes thatare all 0xAA and then the byte 0xFF into the queue before each data byte. The 0xFF byteindicates that the next byte is a data byte and should not be ignored. Furthermore, we maintaintimer2 to keep track of how long it has been since we transmitted some data. If more than

    approximately 25mSec has elapsed, we transmit a stream of 0xAA, followed by one 0xFF andone 0xAA. This keeps the AGC on the receiver end properly set to receive data. The ps2protocol also allows the computer to talk to the keyboard. To do this, we also use the externaledge triggered interrupt to place a data bit on the DATA line at the appropriate times so that thekeyboard can get it. Although the interrupt code appears quite long, there is only a piece of itthat is executed every time the interrupt is taken. The rest of the time, the program is inside themain while loop where we are constantly checking if the queue is empty and if the UART is freeto send data. If there is data in the queue and the UART is available, we transmit the data bytesfound in the queue.

    Results of the Design

    The wireless keyboard we constructed can successfully transmit keys to the keyboard.However, there are several issues in its performance. Its reaction speed is slightly slower than anormal keyboard. In addition, it occasionally drops a key or inserts a duplicate key. Overall, Ibelieve that the transmission accuracy would need to be improved slightly before it could beused. This could be accomplished by tuning the baud rate and preamble length more finely,implementing an error correcting code, or combining multiple codes from the keyboard so that

    they use a single preamble. The more significant issue with using our keyboard is that thecomputer which we tested it on would not boot properly with the keyboard attached. This meansthat a normal keyboard must be attached to the computer before turning it on, and then replacedwith ours. We had difficulty trouble shooting this problem because the oscilloscope could notlock on to the commands sent by the computer to the keyboard. Therefore we couldnt see thesignals and see what exactly we were doing wrong. We were unable to locate the problemwithin the time constraints of this project.

  • 8/7/2019 ECE 476 Final Project

    9/48

    The other problem which can cause our keyboard to fail is interference with otherhardware transmitting at the same frequency. This causes both our keyboard and the otherhardware (everyone in the class working with RF uses the same frequency) to have trouble. Thedecoding scheme used by the receiver will keep most of this interference from being passed on tothe computer, but the interference will prevent our signal from being transmitted as well.

    This system is no more dangerous than a keyboard, or a cell phone. People might getcarpal tunnel syndrome from using our keyboard (like other keyboard). In addition, some studiesmight show that exposure to radio waves slightly increases the risk of cancer. However, thepower output of the circuit is quite low, so the dangers are not particularly excessive.

    Conclusions

    Performance

    We had hoped that our keyboard would be able to handle the boot sequence from thecomputer. The biggest difficulty in getting this to work is that it is difficult to capture what ishappening on the ps/2 port during this period. We also hoped that our keyboard would have abetter error rate and drop fewer characters. Given more time, we could have implemented anerror correcting code to lower the number of errors.

    Intellectual Properties

    Some portions of our code were loosely based upon code found at the Micrel website.Their website has sample information showing how to construct a wireless keyboard using theirtransmitters and Microchip PIC microprocessors. The overall organization of our code differsfrom theirs (ours is interrupt based and theirs is delay based).

    Ethical Considerations

    Below we address several points of the IEEE Code of Ethics.

    1. It is our belief that the power level at which we transmit will not cause any harm topeople, or the environment. However, it is possible that this signal could interferewith other hardware which is using this frequency.

  • 8/7/2019 ECE 476 Final Project

    10/48

    2. We state the capabilities of our system, though we have not measured exact bit errorrates or performance statistics. It is not ready for manufacturing or sales, and we areclear that this is the case.

    3. On several occasions we resisted the urge to pay the TAs off for a good grade in thisclass, not that they would have accepted.

    5. We acknowledge the fact that it is possible for anyone listening on the frequency weare transmitting on could easily determine what is being typed on our wirelesskeyboard. No encryption of any kind is used.

    6. As college students, this project was quite educational and clearly helped to improveour technical competence.

    7. We have acknowledged all of the sources which we drew upon. The largest of whichbeing Micrels wireless keyboard page.

    COMPUTER SIDE CODE

    /******************************************

    * 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

    *

  • 8/7/2019 ECE 476 Final Project

    11/48

    * C - Debugging LEDs

    */

    #include

    #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

  • 8/7/2019 ECE 476 Final Project

    12/48

    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

  • 8/7/2019 ECE 476 Final Project

    13/48

    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/7/2019 ECE 476 Final Project

    14/48

    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);

    }

  • 8/7/2019 ECE 476 Final Project

    15/48

    //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)

    {

  • 8/7/2019 ECE 476 Final Project

    16/48

    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

  • 8/7/2019 ECE 476 Final Project

    17/48

    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)

    {

  • 8/7/2019 ECE 476 Final Project

    18/48

    TCNT1=0;

    if(transmitting)

    {

    if(clockState==HIGH)//write data out here

    {

    if(position==0)//start bit

    {

    DATA_OUT=0;

    }

    else if(position>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

  • 8/7/2019 ECE 476 Final Project

    19/48

    {

    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;

    }

    }

  • 8/7/2019 ECE 476 Final Project

    20/48

    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;

  • 8/7/2019 ECE 476 Final Project

    21/48

    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)

    {

  • 8/7/2019 ECE 476 Final Project

    22/48

    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;

    }

    }

  • 8/7/2019 ECE 476 Final Project

    23/48

    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);

    }

    }

    }

    }

  • 8/7/2019 ECE 476 Final Project

    24/48

    KEYBOARD SIDE CODE

    /******************************************

    * Wireless Keyboard - Hejnar, Leventhal

    * Keyboard Side Code

    */

    #include

    //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)

  • 8/7/2019 ECE 476 Final Project

    25/48

    char countIn; //count how many Low CLK pulses we have seen as we receive data fromkeyboard

    char countOut; //count how many Low CLK pulses we have seen as we transmitt data tokeyboard

    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

  • 8/7/2019 ECE 476 Final Project

    26/48

    //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;

  • 8/7/2019 ECE 476 Final Project

    27/48

    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=2 to 9, then seeing data bits 0 to 7

  • 8/7/2019 ECE 476 Final Project

    28/48

    //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 comparematch interrupt;

    TIFR=TIFR&0xFD; //make bit1=0 to clear the timer0 comp matchflag (just in case its set)

    }

    else if ((countIn>1) && (countIn>1;//shift data right by 1

  • 8/7/2019 ECE 476 Final Project

    29/48

    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 matchflag (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

  • 8/7/2019 ECE 476 Final Project

    30/48

    TIMSK=TIMSK&0xFD; //set bit1=0 to disable timer0 interrupt

    TIFR=TIFR&0xFD; //set bit1=0 to clear the timer0 compmatch flag just in case

    //don't pass along responses to RF that are meant only for themicrocontroller 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);

  • 8/7/2019 ECE 476 Final Project

    31/48

    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 inhibitcommunication

    //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 inhibitcommunication

  • 8/7/2019 ECE 476 Final Project

    32/48

    {

    //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 clockspeed (16MHz)

    TCNT1=0; //reset timer1 to 0

    OCR1A=2240; //140uSec*16MHz=2240cycles

    TIMSK=(TIMSK&0xEF)|0x10; //set bit4=1 to 1 to enableOutput 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 comparematch interrupt;

    TIFR=TIFR&0xFD; //set bit1=0 to clear the timer0 comp matchflag (just in case its set)

    parityOut=0; //reset parity

    txDone=FALSE; //transmitting not done(just starting)

    }

    else if (countOut>1 &&countOut

  • 8/7/2019 ECE 476 Final Project

    33/48

    TCNT0=0; //reset timer0 since saw a clock signal

    TIFR=TIFR&0xFD; //set bit1=0 to clear the timer0 comp matchflag just in case

    if (dataOut&0x01)//if lowest bit is a 1

    {

    wDAT=1; //write out a 1 to thekeyboard

    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 matchflag (just in case its set)

    if(parityOut&0x01) //if parity is odd

    wDAT=0; //write out a 0 to the keyboard

    else

  • 8/7/2019 ECE 476 Final Project

    34/48

    wDAT=1; //write out a 1 to the keyboard tomake 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 matchflag (just in case its set)

    wDAT=1; //write the stop bit (when change DDR, this willalso activate the pullups)

    DDRD=0x00; //make DAT line input, CLK input already. Do thisso 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 matchinterrupt

    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

  • 8/7/2019 ECE 476 Final Project

    35/48

    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 ortransmitting 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 caseits set)

  • 8/7/2019 ECE 476 Final Project

    36/48

    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)

  • 8/7/2019 ECE 476 Final Project

    37/48

    {

    //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

    }

  • 8/7/2019 ECE 476 Final Project

    38/48

    }

    //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

  • 8/7/2019 ECE 476 Final Project

    39/48

    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

  • 8/7/2019 ECE 476 Final Project

    40/48

    #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 itonly 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

    ;

  • 8/7/2019 ECE 476 Final Project

    41/48

    //------------------------

    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 (cmdmight 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

  • 8/7/2019 ECE 476 Final Project

    42/48

    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

  • 8/7/2019 ECE 476 Final Project

    43/48

    while(1)

    {

    if((!queueEmpty) && (UCSRA&0x20)) //if queue not empty and UART isavailable

    {

    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

    }

    }

    }

  • 8/7/2019 ECE 476 Final Project

    44/48

    Schematics:

    Keyboard Side

  • 8/7/2019 ECE 476 Final Project

    45/48

    Computer Side

  • 8/7/2019 ECE 476 Final Project

    46/48

    References

    Websites:

    The PS/2 Mouse/Keyboard Protocol, Adam Chapweske,http://panda.cs.ndsu.nodak.edu/~achapwes/PICmicro/PS2/ps2.htm

    Micrels Wireless Keyboard Site, http://www.micrel.com/product-info/qr/qwiklink-2k.shtml

    Vendors:

    Radiotronix: http://www.radiotronix.com/

    Data Sheets:

    ATMega32: http://www.atmel.com/dyn/resources/prod_documents/doc2503.pdf

    RCR-433-RP: www.radiotronix.com/datasheets/rcr433rp.pdf

    RCT-433-AS: www.radiotronix.com/datasheets/rct433as.pdf

  • 8/7/2019 ECE 476 Final Project

    47/48

    PICTURES

    This is the circuit that we built. The white keyboard is connected to a PS/2 socket, which connects to the

    STK 500 board. The transmitter that we are using is located on the small yellow circuit board that is

    connected to the white prototype board. The actual transmitter chip is on the other side of the yellow

    circuit board. The receiver is located on the small green circuit board that is connected to the stand

    alone prototype board that we build. The prototype board has the ATmega32 processor located on it

    along with the necessary supporting components. The ATmega32 connects to the computer through a

    PS/2 socket. (The multi colored wire leads to the PS/2 socket at the back of the computer).

  • 8/7/2019 ECE 476 Final Project

    48/48

    On the left is Luke Hejnar and on the right is Sean Leventhal. In this picture, we are using the wireless

    keyboard.

    http://courses.cit.cornell.edu/ee476/FinalProjects/s2003/lph2/WirelessKybd/index.html