Tweet
Code :
The project described here is a digital implementation of “book cricket game” which Indian students normally use to play in their childhood time. The heart of the project is 8 bit MCU from AVR family called ATtiny85. ATtiny85 are small and cheap microcontrollers which are convenient for running simple programs with low footprint. The software used for programming the MCU is Ardunio which is a popular open source IDE.
The overall design is kept to a least for simplicity and ease to use. The main components used in the circuitry are 16X2 LCD which is used to display the characters in 2 lines with maximum of 16 characters in one line, a serial in parallel out shift register HEF4094, ATtiny85, 2 push buttons and 7805 voltage regulator which regulates the voltage supply to maximum of 5 volts. Shift register HEF4094 is used because normally when LCD is used it requires 7 connections to the pins on the display. But if shift register is used the number of connections to the MCU can be reduced to only 3 wires.
Figure 1 Circuit Diagram for the connection of LCD with HEF4094 IC
Figure 2 Circuit Diagram for MCU connection
WORKING
Before starting with the game some random numbers are required. These random numbers can be generated by keeping the ADC channel of the ATtiny85 floating, which means no connection the pin. So that noise is generated and by using the mod 10 value of the noise, integers from 0-9 are generated.
For displaying the data on the LCD, arduino 3 wire LCD libraries are used because it provides an easy way to write the characters on LCD.
2 push switches are used to handle the input from the user. One is RESET switch which is used to reset the MCU and the other is HIT switch through which all the calibration and playing is done.
Components
1x Breadboard
1x 16*2 LCD
1x 7805 regulator
2x Push Button
1x 47K ohm
1x 100 ohm
1x 470 ohm
1x HEF4094BP
1x Attiny 85V
STEPS TO PLAY THE GAME:
1. When the power switch is pressed, “Digital Book Cricket” will be displayed.
Figure 3 Step 1 Power on the supply
2. Using the HIT switch, number of wickets is set. Here a timer of 10 seconds is used to set the number of wickets. Also a timer of 10 seconds is used to set the number of over.
Figure 4 Step to set the number of wickets and over by using HIT switch
3. When all the basic set ups are over. Player 1 is supposed to bat first. He has to press the HIT button to score runs. He has to continuously press the HIT button until the innings are not over. At the end of the innings the scores are displayed on the screen.
Figure 5 Player 1 batting
Figure 6 Scores of player 1
4. After player 1 has finished its batting, player 2 gets to bat. The same procedure is followed until the end of the innings.
Figure 7 Batting of player 2
6. After the match is finished the Winner is declared.
//command bytes for LCD
#define CMD_CLR 0x01
#define CMD_RIGHT 0x1C
#define CMD_LEFT 0x18
#define CMD_HOME 0x02
// bitmasks for control bits on shift register
#define SHIFT_EN B00010000
#define SHIFT_RW B00100000
#define SHIFT_RS B01000000
int dat_pin=1;
int str_pin=2;
int clk_pin=0;
int lcd_lines=2;
const int buttonPin=4; // the pin that the pushbutton is attached to
int buttonState=0; // current state of the button
int lastButtonState=0; // previous state of the button
int data; //stores random value from ADC channel
char* startupmsg1=" Digital";
char* startupmsg2=" Book Cricket";
char* startupmsg3="Dev: Rahul Kar";
char *startupmsg4="yxrkt512@gmail";
int scoreboard[2]; //stores the total runs of 2 players
int overs_set,wickets_set; //stores the calibrated data
int wicket,balls;
void commandWrite(int value){
_pushByte(value, true);
delay(5);
}
//print the given character at the current cursor position. overwrites, doesn't insert.
void print(int value) {
_pushByte(value, false);
}
//print the given string to the LCD at the current cursor position. overwrites, doesn't insert.
//While I don't understand why this was named printIn (PRINT IN?) in the original LiquidCrystal library, I've preserved it here to maintain the interchangeability of the two libraries.
void printIn(char msg[]) {
unsigned int i;
for (i=0;i < strlen(msg);i++){
print(msg[i]);
}
}
void _pushByte(int value, bool command) {
int nibble = 0;
digitalWrite(str_pin,LOW); // set the strobe LOW
nibble = value >> 4; //send the first 4 databits (from 8)
_pushNibble(nibble, command);
delay(1);
nibble = value & 15; // set HByte to zero
_pushNibble(nibble, command);
}
// called twice by each _pushByte
void _pushNibble(int nibble, bool command) {
if (!command) {
nibble |= SHIFT_RS; // set DI HIGH
nibble &= ~SHIFT_RW; // set RW LOW
}
nibble &= ~SHIFT_EN; // set Enable LOW
_pushOut(nibble);
nibble |= SHIFT_EN; // Set Enable HIGH
_pushOut(nibble);
nibble &= ~SHIFT_EN; // set Enable LOW
_pushOut(nibble);
}
// push byte to shift register and on to LCD
void _pushOut(int value) {
shiftOut(dat_pin, clk_pin, LSBFIRST, value);
digitalWrite(str_pin, HIGH);
delayMicroseconds(10);
digitalWrite(str_pin, LOW);
}
//non-core stuff --------------------------------------
//send the clear screen command to the LCD
void clear(){
commandWrite(CMD_CLR);
}
//move the cursor to the given absolute position. line numbers start at 1.
//if this is not a 2-line LCD3Wire instance, will always position on first line.
void cursorTo(int line_num, int x){
//first, put cursor home
commandWrite(CMD_HOME);
//if we are on a 1-line display, set line_num to 1st line, regardless of given
if (lcd_lines==1){
line_num = 1;
}
//offset 40 chars in if second line requested
if (line_num == 2){
x += 40;
}
//advance the cursor to the right according to position. (second line starts at position 40).
for (int i=0; i<x; i++) {
commandWrite(0x14);
}
}
//scroll whole display to left
void leftScroll(int num_chars, int delay_time){
for (int i=0; i<num_chars; i++) {
commandWrite(CMD_LEFT);
delay(delay_time);
}
}
void initialize() {
pinMode(dat_pin,OUTPUT);
pinMode(str_pin,OUTPUT);
pinMode(clk_pin,OUTPUT);
pinMode(3,INPUT);
pinMode(4,INPUT);
delay(100);
commandWrite(0x03); // function set: 4 pin initialization
commandWrite(0x03); // function set: 4 pin initialization
commandWrite(0x03); // function set: 4 pin initialization
commandWrite(0x02); // function set: 4 pin initialization
commandWrite(0x28); // function set: 4-bit interface, 2 display lines, 5x7 font
commandWrite(0x06); // entry mode set:
commandWrite(0x0e); // display control:
commandWrite(0x01); // turn display on, cursor on, no blinking
}
void clean() { //initializes the variables for next set of match
wicket=balls=0;
scoreboard[0]=scoreboard[1]=0;
}
int score_engine(int data,int player) { //converts the random value into runs
int run=data%10;
if(run==0)
{
wicket++;
return -999;
}
else if(run==5||run==7||run==8||run==9)
{
return -1;
}
else
{
scoreboard[player]+=run;
return run;
}
}
void display_engine(int data,int player) { //handles all the display function
char* wick="Wicket!!";
char* dot="Dot Ball...";
char* one="1 Run";
char* two="2 Runs";
char* three="3 Runs";
char* four="FOUR!!!";
char* six="SIX!!!";
char *total="Total: ";
int stat=score_engine(data,player);
if(stat==-999)
printIn(wick);
if(stat==-1)
printIn(dot);
else if(stat!=-1)
{
if(stat==1)
printIn(one);
if(stat==2)
printIn(two);
if(stat==3)
printIn(three);
if(stat==4)
printIn(four);
if(stat==6)
printIn(six);
}
cursorTo(2,0);
printIn(total);
disp_int__module(scoreboard[player]);
printIn("/");
disp_int__module(wicket);
printIn(" ");
disp_int__module(balls);
}
int calibrate_wickets() { //takes input from user fo no. of wickets
char* msg1="Set Wickets...";
char* msg2="Press Hit to set";
char *msg3="Wickets: ";
int counter=0;
clear();
printIn(msg1);
delay(2000);
leftScroll(20,50);
clear();
printIn(msg2);
int start_time=millis();
do
{
buttonState=digitalRead(buttonPin);
if(buttonState!=lastButtonState)
{
clear();
if(buttonState==HIGH)
{
counter++;
printIn(msg3);
disp_int__module(counter);
}
else
{
printIn(msg3);
disp_int__module(counter);
}
}
lastButtonState=buttonState;
}
while(millis()-start_time<10000);
return counter;
}
int calibrate_overs() { //takes input from user fo no. of overs
char* msg1="Set Overs...";
char* msg2="Press Hit to set";
char *msg3="Overs: ";
int counter=0;
clear();
printIn(msg1);
delay(2000);
leftScroll(20,50);
clear();
printIn(msg2);
int start_time=millis();
do
{
buttonState=digitalRead(buttonPin);
if(buttonState!=lastButtonState)
{
clear();
if(buttonState==HIGH)
{
counter++;
printIn(msg3);
disp_int__module(counter);
}
else
{
printIn(msg3);
disp_int__module(counter);
}
}
lastButtonState=buttonState;
}
while(millis()-start_time<10000);
return counter;
}
void disp_int__module(int data) { //converts the integer data to char to display using 3 Wire mode
int digitlength=0;
int reversedata=0;
do
{
reversedata=reversedata*10;
reversedata+=(data%10);
data/=10;
digitlength++;
}
while(data!=0);
for(int i=0;i<digitlength;i++)
{
print((48+reversedata%10));
reversedata/=10;
}
}
void player1() { //player 1 related stuff
char* msg1="Player 1 Batting";
char* msg2="Press Hit";
char* eoo="End of Overs!";
char* allout="All Out!!";
char* tot="Player 1 Total:";
clear();
printIn(msg1);
delay(2000);
leftScroll(20,50);
clear();
printIn(msg2);
wicket=0;
balls=(6*overs_set);
do
{
buttonState=digitalRead(buttonPin);
if(buttonState!=lastButtonState)
{
if(buttonState==LOW)
{
--balls;
clear();
data=analogRead(3);
display_engine(data,0);
}
}
lastButtonState=buttonState;
}
while(balls>0&&wicket<wickets_set);
if(balls<=0)
{
clear();
printIn(eoo);
delay(2000);
leftScroll(20,50);
clear();
}
if(wicket>=wickets_set)
{
clear();
printIn(allout);
delay(2000);
leftScroll(20,50);
clear();
}
printIn(tot);
cursorTo(2,0);
disp_int__module(scoreboard[0]);
printIn("/");
disp_int__module(wicket);
delay(4000);
}
void player2() { //player 2 related stuff
char* msg1="Player 2 Batting";
char* msg2="Press Hit";
char* eoo="End of Overs!";
char* allout="All Out!!";
char* tot="Player 2 Total:";
char* mo="Match Over!!";
clear();
printIn(msg1);
delay(2000);
leftScroll(20,50);
clear();
printIn(msg2);
wicket=0;
balls=(6*overs_set);
do
{
buttonState=digitalRead(buttonPin);
if(buttonState!=lastButtonState)
{
if(buttonState==LOW)
{
--balls;
clear();
data=analogRead(3);
display_engine(data,1);
}
}
lastButtonState=buttonState;
}
while(balls>0&&wicket<wickets_set&&scoreboard[1]<=scoreboard[0]);
if(balls<=0)
{
clear();
printIn(eoo);
delay(2000);
leftScroll(20,50);
clear();
}
if(wicket>=wickets_set)
{
clear();
printIn(allout);
delay(2000);
leftScroll(20,50);
clear();
}
if(scoreboard[1]>scoreboard[0])
{
clear();
printIn(mo);
delay(2000);
leftScroll(20,50);
clear();
}
printIn(tot);
cursorTo(2,0);
disp_int__module(scoreboard[1]);
printIn("/");
disp_int__module(wicket);
delay(4000);
}
void determine_winner() { //calculates the winner
char* msg1="Player 1 Wins!!";
char* msg2="Player 2 Wins!!";
char* msg3="Match Draw!!";
char* won="Won by ";
char* runs=" Runs";
if(scoreboard[0]>scoreboard[1])
{
clear();
printIn(msg1);
cursorTo(2,0);
printIn(won);
disp_int__module(scoreboard[0]-scoreboard[1]);
printIn(runs);
delay(2000);
leftScroll(20,50);
clear();
}
else if(scoreboard[1]>scoreboard[0])
{
clear();
printIn(msg2);
cursorTo(2,0);
printIn(won);
disp_int__module(scoreboard[1]-scoreboard[0]);
printIn(runs);
delay(2000);
leftScroll(20,50);
clear();
}
else if(scoreboard[1]==scoreboard[0])
{
clear();
printIn(msg3);
delay(2000);
leftScroll(20,50);
clear();
}
}
void setup() { //performs all the initial setup
initialize();
printIn(startupmsg1);
cursorTo(2,0);
printIn(startupmsg2);
delay(2000);
leftScroll(20,50);
clear();
printIn(startupmsg3);
cursorTo(2,0);
printIn(startupmsg4);
delay(2000);
leftScroll(20,50);
clear();
wickets_set=calibrate_wickets();
overs_set=calibrate_overs();
}
void loop() {
clean();
player1();
player2();
determine_winner();
}