Advertisement
Guest User

Untitled

a guest
Oct 11th, 2018
2,368
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.60 KB | None | 0 0
  1. #include <avr/io.h>
  2. #define  F_CPU 16000000UL //Our CPU speed (16MHz)
  3. #include <util/delay.h> //Libraries for delay and interrupt utilities
  4. #include <avr/interrupt.h>
  5. #define command 0 //explained in dispSend() function
  6. #define write 1
  7.  
  8. uint8_t upperBuff[16] , downerBuff[16], overMsgUpper[] = "Score: ", overMsgDowner[] = "Best: ", scoremsg[] = "Score:" , din[] = {0x0E, 0x17, 0x1E, 0x1F, 0x18, 0x1F, 0x1A, 0x12}, cact[] = {0x04, 0x05, 0x15, 0x15, 0x16, 0x0C, 0x04, 0x04};
  9.         //Buffers for line one and two. Message to display after lost game.                     //Score text during game. //Dinosaur and cactus bitmaps
  10. uint8_t canup = 1, longhold = 0, distance = 6, speed = 200, isup = 0, dontprint = 0; //All of these are explained further
  11. uint16_t aVal = 0, score = 1, bestscore = 0;
  12. int i;
  13.  
  14. void dispInit();
  15. void dispWrite(uint8_t bits);
  16. void dispSend(uint8_t bits, uint8_t act);
  17. void dispSetLine(uint8_t line);
  18. void dispClear();
  19. void dispHome();
  20. void dispPrintChar(uint8_t chr[], uint8_t size);
  21. uint16_t aRead();
  22.  
  23. void setup() {
  24.   for(i = 0; i < 17; i++) downerBuff[i] = ' '; //Initialize upper and downward buffer
  25.   for(i = 0; i < 17; i++) upperBuff[i] = ' ';
  26.  
  27.   dispInit(); //Initialize the display
  28.  
  29.   TCCR1B |= (1 << WGM12) | (1 << CS11); //Set Timer1 to compare to OCR1A and prescaler of 8
  30.   OCR1AH = (500 >> 8); //This equals to 2000Hz or 500us timing, look for TIMER1_COMPA_vect down below
  31.   OCR1AL = 500;
  32.   TIMSK1 |= (1 << OCIE1A); //Enable Timer1 CompA ISR
  33.   sei(); //Enable global interrupt
  34.  
  35.  
  36.   ADMUX = (1 << REFS0); //Set AREF to VCC
  37.   ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN); //set ADC prescaler to 128 and enable ADC (defaulted to free running mode)
  38.  
  39. }
  40.  
  41. void loop() {
  42.   ADMUX |= (1 << MUX2) | (1 << MUX0); //Set pin from ADMUX to ADC5 (floating)
  43.     srand(aRead()); //Use it as a random seed
  44.     ADMUX &= ~(1 << MUX2) & ~(1 << MUX0); //Revert back to ADC0 to read the button value
  45.  
  46.     if(aRead() > 900) longhold = 0; //Reads if Up button has been released to prevent cheating. The value is so low because if you hold your fingers beneath one of the buttons the voltage would drop, this prevents the dinosaur from locking up
  47.  
  48.     for(i = 0; i < 16; i++) downerBuff[i] = downerBuff[i + 1]; //Shifts everything in downward buffer by one place to the left
  49.      if((rand() % 100) > (rand() % 100) && !dontprint){ //This portion decides if it should put a cactus or a blank spot, dontprint is used to prevent cactus grouping
  50.       downerBuff[15] = 0x01; //0x01 represents the cactus (we added cactus and dinosaur to CGRAM when we initialized the display)
  51.       dontprint = 1; //This part acts both as a boolean and a counter to ensure cactus separation
  52.      }
  53.      else downerBuff[15] = ' ';
  54.      char lastchar = downerBuff[3]; //We remember the whats initially added to the downward buffer before replacing it with the dinosaur
  55.      if(!isup){ //If din should be placed down
  56.       downerBuff[3] = 0x00; //Place it down
  57.       dispSetLine(2);
  58.       dispPrintChar(downerBuff, sizeof(downerBuff)); //Draw it
  59.       downerBuff[3] = lastchar; //Place back previous thing to the buffer
  60.       canup = 1;  //This flag is used to disable dinosaur from getting up before it was drawn down, in this case he can go up
  61.     } else { //If din should be placed up
  62.       upperBuff[3] = 0x00; //Place it up in upper buff
  63.       dispSetLine(1);
  64.       dispPrintChar(upperBuff, sizeof(upperBuff));
  65.       dispSetLine(2);
  66.       dispPrintChar(downerBuff, sizeof(downerBuff)); //Draw it
  67.       canup = 0; //In this case he wont go up until rendered on line 2
  68.     }
  69.  
  70.     if(dontprint) dontprint++;
  71.     if(dontprint > distance) dontprint = 0; //This is the part that ensures cactus separation, it will keep the cactus 3-5 spaces apart minimally (depends on the game progress)
  72.    
  73.     if(isup) isup++; //This part makes sure din is on upper side for 3 loops after he was initially drawn there
  74.     if(isup > 4){
  75.      upperBuff[3] = ' ';
  76.      dispSetLine(1);
  77.      dispPrintChar(upperBuff, sizeof(upperBuff));
  78.      isup = 0;
  79.     }
  80.     for(i = 0; i < sizeof(scoremsg); i++) upperBuff[i + 5] = scoremsg[i]; //This part prints the current score during the game
  81.     uint8_t cnt = 11;
  82.     for(i = 10000; i > 0; i /= 10){
  83.       upperBuff[cnt] = ((score / i) % 10) + '0';
  84.       cnt++;
  85.       dispSetLine(1);
  86.       dispPrintChar(upperBuff, sizeof(upperBuff));
  87.     }
  88.  
  89.     score++; //Increment the score once on loop
  90.     if(score > bestscore) bestscore = score; //Remember best score
  91.    
  92.     if(lastchar == 0x01 && !isup){ //Check if the dinosaur is downward and hit a cactus
  93.       dispClear(); //Clear the display and buffers
  94.       for(i = 0; i < 17; i++) downerBuff[i] = ' ';
  95.       for(i = 0; i < 17; i++) upperBuff[i] = ' ';
  96.       uint8_t cnt;
  97.      
  98.       dispSetLine(1);
  99.       for(i = 0; i < sizeof(overMsgUpper); i++) upperBuff[i] = overMsgUpper[i]; //Display worst and best score
  100.       cnt = sizeof(overMsgUpper) - 1;
  101.       for(i = 10000; i > 0; i /= 10){
  102.         upperBuff[cnt] = ((score / i) % 10) + '0';
  103.         cnt++;
  104.       }
  105.       dispPrintChar(upperBuff, sizeof(upperBuff));
  106.      
  107.       dispSetLine(2);
  108.       for(i = 0; i < sizeof(overMsgDowner); i++) downerBuff[i] = overMsgDowner[i];
  109.       cnt = sizeof(overMsgDowner) - 1;
  110.       for(i = 10000; i > 0; i /= 10){
  111.         downerBuff[cnt] = ((bestscore / i) % 10) + '0';
  112.         cnt++;
  113.       }
  114.       dispPrintChar(downerBuff, sizeof(downerBuff));
  115.      
  116.       while(1){ //Wait for select button to be pressed
  117.         aVal = aRead();
  118.         if(aVal > 635 && aVal < 645){ //After that clear all the variables
  119.           for(i = 0; i < 17; i++) downerBuff[i] = ' ';
  120.           dispSetLine(1);
  121.           dispPrintChar(downerBuff, sizeof(downerBuff));
  122.           for(i = 0; i < 17; i++) upperBuff[i] = ' ';
  123.           dispSetLine(2);
  124.           dispPrintChar(upperBuff, sizeof(upperBuff));
  125.           dontprint = 0;
  126.           isup = 0;
  127.           score = 1;
  128.           speed = 200;
  129.           longhold = 0;
  130.           distance = 6;
  131.           canup = 1;
  132.           break;
  133.              }
  134.       }
  135.      
  136.     }
  137.         if(score % 5 == 0) speed -=2; //If score is divisible by 5 make game faster by -2ms
  138.     if(speed < 85) speed = 85; //Minimal time in ms (+ ~2ms) that the loop will be halted for (limited by display refreshing, in my testing 11.8Hz was readable enough to be playable)
  139.     if(score % 175 == 0) distance--; //Every time you score a number divisible by 175 minimal cactus distance gets smaller
  140.     if(distance < 4) distance = 4;
  141.     for(i = 0; i < speed; i++) _delay_ms(1); //This is the only way as the compiler expects a const number here
  142. }
  143.  
  144. void dispInit(){
  145.   _delay_ms(50); //Just in case
  146.   DDRD = 0b11110000; //Set these pins to output. PD4 - PD7 correspond to D4 - D7 on display, we need to configure it to run in 4 bit mode
  147.   DDRB = 0b00000011; //PB0 is tied to RS and PB1 to EN
  148.   dispWrite(0x30);//*This part here is explained in Hitachi HD44780 datasheet on how to initialize the display in 4bit mode
  149.   _delay_us(4500);//*Essentially you send the reset signal 3 times, and then set it to 4 bit mode
  150.   dispWrite(0x30);//*
  151.   _delay_us(4500);//*
  152.   dispWrite(0x30);//*
  153.   _delay_us(4500);//*
  154.   dispWrite(0x28);//*
  155.   dispSend(0x28, command); //Send 4bit mode function set
  156.   dispSend(0x08, command); //Turn the display off
  157.   dispSend(0x01, command); //Clear its RAM (if MCU resets that doesn't mean the display was reset, so we clear everything)
  158.     _delay_ms(50);
  159.   dispSend(0x0C, command); //Turn the display on
  160.   _delay_ms(5);
  161.   dispSend(0x40, command); //Tell the display we want to enter a custom character to its CGRAM (on address 0x00)
  162.   for(i=0; i<8; i++) dispSend(din[i], write);
  163.   dispSend(0x80, command); //Transaction end
  164.   dispSend(0x48, command); //Same thing, but for 0x01
  165.   for(i=0; i<8; i++) dispSend(cact[i], write);
  166.   dispSend(0x80, command);
  167. }
  168.  
  169. void dispPrintChar(uint8_t chr[], uint8_t size){
  170.   for(uint8_t i = 0; i < size; i++) dispSend(chr[i], write); //Self explanatory
  171. }
  172.  
  173. void dispSetLine(uint8_t line){
  174.   if(line == 2) dispSend(0xC0, command); //Sets the line where 0xC0 is line 2 and 0x80 is line 1
  175.   else dispSend(0x80, command);
  176. }
  177.  
  178. void dispClear(){
  179.   dispSend(0x01, command); //Self explanatory
  180.   _delay_ms(2); //This command takes longer for the IC to process, this delay is necessary
  181. }
  182.  
  183. void dispHome(){ //This function isn't used in this application but its there for expandability, it places the cursor on the line 1 column 1
  184.   dispSend(0x02, command); //Self explanatory
  185.   _delay_ms(2);
  186. }
  187.  
  188. void dispSend(uint8_t bits, uint8_t act){
  189.   if(act) PORTB |= (1 << DDB0); //Set PB0 if we are writing a character, else pull it low
  190.   else PORTB &= ~(1<<DDB0);
  191.   dispWrite(bits); //Send the bit then shift them 4 bit to the left to work in displays 4bit mode
  192.   dispWrite(bits << 4);
  193.   _delay_us(80);
  194. }
  195.  
  196. void dispWrite(uint8_t bits){
  197.   PORTD = bits; //This is a dirty way to write it but it's perfect for this application as it's not bulky and PORTD isn't used for anything else anyway
  198.   PORTB |= (1<<DDB1); //Pulse the PB1 to signal the IC to read the data
  199.   _delay_us(1);
  200.   PORTB &= ~(1<<DDB1);
  201.   _delay_us(1);
  202. }
  203.  
  204. uint16_t aRead(){
  205.   ADCSRA |= (1 << ADSC); //This signal the avr to read the ADC value
  206.   while  (ADCSRA & (1 << ADSC)); //Wait until it's finished
  207.   return ADCL | (ADCH << 8); //Send it back stitched together
  208. }
  209.  
  210. ISR (TIMER1_COMPA_vect){ //Timer ISR we set up earlier
  211.   if(!longhold){ //Return if the Up button was still held
  212.     aVal = aRead(); //Read from ADC0
  213.     if(aVal > 95 && aVal < 104 && canup){ //Check if Up is pressed and that din was rendered down
  214.      isup = 1;
  215.      longhold++;
  216.      }
  217.     }
  218. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement