цифровая электроника
вычислительная техника
встраиваемые системы

 
» » » Игра с динозавром из браузера Chrome на ЖК-дисплее 16x2 и микроконтроллере AVR


Игра с динозавром из браузера Chrome на ЖК-дисплее 16x2 и микроконтроллере AVR

Автор: Mike(admin) от 5-03-2021, 23:55

Если у вас нет хороших идей в плане того, чтобы сделать с микроконтроллером и ЖК-дисплеем, то проект, имитирующий игру в прыгающего динозавра из браузера Chrome, будет отличной практикой и весьма веселым занятием.


Игра с динозавром из браузера Chrome на ЖК-дисплее 16x2 и микроконтроллере AVR

Отметим, что этот проект НЕ был написан на Arduino, а был написан на чистом коде AVR C с использованием Atmel Studio. Здесь используется Arduino Uno и Uno-совместимый экран, но в основном потому, что это самая дешевая и самая доступная вещь. Таким образом, для любого, кто знаком с C, но работал только в Arduino, примерно половина кода здесь могла бы сбивать с толку, но если взять кого-то, кто изучал AVR C (сам), это будет совсем не сложно.


Основные моменты программирования касаются взаимодействия с дисплеем. Многое зависит от установки битов в верхних 4 слотах регистра PORTD и правильного использования контактов EN и RS. В данной реализации весь PORTD тратится впустую для связи с дисплеем (что сводит на нет преимущества 4-битного режима) и эффективно тратит UART, но в данном случае мы не собираемся использовать их для чего-либо еще, так что это нормально для этого варианта использования.


Убедитесь, что при взаимодействии с ИС ЖК-дисплея используются правильные задержки, в противном случае она не сможет правильно обработать данные (это довольно медленный чип). Другой момент заключается в том, что скорость игры ограничена тем, насколько быстро может обновляться дисплей. При максимальной скорости дисплей обновляется с частотой 11,8 Гц (задержка в цикле 85 мс), и он достаточно удобочитаемый, чтобы играть в такую игру, все в дальнейшем вызывает серьезные проблемы с яркостью.


Поскольку одной из целей было – сделать эту игру как можно более случайной, каждый раз, когда программа зацикливается, она читает аналоговое значение ADC5, которое остается плавающим, и использует это число в качестве начального числа для функции генератора случайных чисел. Это далеко не идеально, поскольку могут появиться повторяющиеся последовательности, которые исчезнут через несколько секунд, но без добавления какого-либо дополнительного оборудования это (вероятно) лучшее, что что-либо еще.


Каждые 500 мкс Timer1 настроен на запуск TIMER1_COMPA_vect IS, где он проверяет, нажата ли кнопка вверх, и глобальные переменные установлены соответственно.


Чтобы упростить программирование и эффективно уменьшить логику приложения, здесь используюется буфер для первой строки и буфер для второй строки дисплея. Все записывается в эти 2 буфера, и они выводятся на дисплей целиком.


Для создания изображений динозавра и кактуса 5x8 был использован paint.net. Каждый цветной квадрат представляет собой 1, а пустой (белый) – ноль. После этого все было переведено в шестнадцатеричный формат и добавлено все в два массива uint8. Эти 2 символа хранятся в CGRAM IC, где динозавр – 0x00, а кактус – 0x01.


Игра с динозавром из браузера Chrome на ЖК-дисплее 16x2 и микроконтроллере AVR

Игра с динозавром из браузера Chrome на ЖК-дисплее 16x2 и микроконтроллере AVR

Игра с динозавром из браузера Chrome на ЖК-дисплее 16x2 и микроконтроллере AVR

Игра с динозавром из браузера Chrome на ЖК-дисплее 16x2 и микроконтроллере AVR

Код программы следующий:



#include <avr/io.h>
#define  F_CPU 16000000UL 
#include <util/delay.h>
#include <avr/interrupt.h>
#define command 0 
#define write 1

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};
uint8_t canup = 1, longhold = 0, distance = 6, speed = 200, isup = 0, dontprint = 0; 
uint16_t aVal = 0, score = 1, bestscore = 0;
int i;

void dispInit();
void dispWrite(uint8_t bits);
void dispSend(uint8_t bits, uint8_t act);
void dispSetLine(uint8_t line);
void dispClear();
void dispHome();
void dispPrintChar(uint8_t chr[], uint8_t size);
uint16_t aRead();

int main(void)
{
	for(i = 0; i < 17; i++) downerBuff[i] = ' '; 
	for(i = 0; i < 17; i++) upperBuff[i] = ' ';
	
	dispInit();
	
	TCCR1B |= (1 << WGM12) | (1 << CS11); 
	OCR1AH = (500 >> 8); 
	OCR1AL = 500;
	TIMSK1 |= (1 << OCIE1A); 
	sei(); 

	
	ADMUX = (1 << REFS0);
	ADCSRA = (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0) | (1 << ADEN);
	
	while (1) {		
		
		ADMUX |= (1 << MUX2) | (1 << MUX0); 
		srand(aRead()); 
		ADMUX &= ~(1 << MUX2) & ~(1 << MUX0); 

		if(aRead() > 900) longhold = 0;

		for(i = 0; i < 16; i++) downerBuff[i] = downerBuff[i + 1]; 
		 if((rand() % 100) > (rand() % 100) && !dontprint){ 
		  downerBuff[15] = 0x01; 
		  dontprint = 1; 
		 }
		 else downerBuff[15] = ' ';
		 char lastchar = downerBuff[3];
		 if(!isup){ 
			downerBuff[3] = 0x00; 
			dispSetLine(2);
			dispPrintChar(downerBuff, sizeof(downerBuff)); 
			downerBuff[3] = lastchar
			canup = 1;  
		} else {
			upperBuff[3] = 0x00; 
			dispSetLine(1);
			dispPrintChar(upperBuff, sizeof(upperBuff));
			dispSetLine(2);
			dispPrintChar(downerBuff, sizeof(downerBuff));
			canup = 0;
		}

		if(dontprint) dontprint++;
		if(dontprint > distance) dontprint = 0; 
		
		if(isup) isup++; 
		if(isup > 4){
		 upperBuff[3] = ' ';
		 dispSetLine(1);
		 dispPrintChar(upperBuff, sizeof(upperBuff));
		 isup = 0;
		}
		for(i = 0; i < sizeof(scoremsg); i++) upperBuff[i + 5] = scoremsg[i];
		uint8_t cnt = 11;
		for(i = 10000; i > 0; i /= 10){
			upperBuff[cnt] = ((score / i) % 10) + '0';
			cnt++;
			dispSetLine(1);
			dispPrintChar(upperBuff, sizeof(upperBuff));
		}

		score++;
		if(score > bestscore) bestscore = score; 
		
		if(lastchar == 0x01 && !isup){ 
			dispClear(); 
			for(i = 0; i < 17; i++) downerBuff[i] = ' ';
			for(i = 0; i < 17; i++) upperBuff[i] = ' ';
			uint8_t cnt;
			
			dispSetLine(1);
			for(i = 0; i < sizeof(overMsgUpper); i++) upperBuff[i] = overMsgUpper[i]; 
			cnt = sizeof(overMsgUpper) - 1;
			for(i = 10000; i > 0; i /= 10){
				upperBuff[cnt] = ((score / i) % 10) + '0';
				cnt++;
			}
			dispPrintChar(upperBuff, sizeof(upperBuff));
			
			dispSetLine(2);
			for(i = 0; i < sizeof(overMsgDowner); i++) downerBuff[i] = overMsgDowner[i];
			cnt = sizeof(overMsgDowner) - 1;
			for(i = 10000; i > 0; i /= 10){
				downerBuff[cnt] = ((bestscore / i) % 10) + '0';
				cnt++;
			}
			dispPrintChar(downerBuff, sizeof(downerBuff));
			
			while(1){ 
				aVal = aRead();
				if(aVal > 635 && aVal < 645){ 
					for(i = 0; i < 17; i++) downerBuff[i] = ' ';
					dispSetLine(1);
					dispPrintChar(downerBuff, sizeof(downerBuff));
					for(i = 0; i < 17; i++) upperBuff[i] = ' ';
					dispSetLine(2);
					dispPrintChar(upperBuff, sizeof(upperBuff));
					dontprint = 0;
					isup = 0;
					score = 1;
					speed = 200;
					longhold = 0;
					distance = 6;
					canup = 1;
					break;
			       }
			}
			
		}
        if(score % 5 == 0) speed -=2; 
		if(speed < 85) speed = 85; 
		if(score % 175 == 0) distance--; 
		if(distance < 4) distance = 4;
		for(i = 0; i < speed; i++) _delay_ms(1); 
	}
}

void dispInit(){
	_delay_ms(50);
	DDRD = 0b11110000; 
	DDRB = 0b00000011; 
	dispWrite(0x30);
	_delay_us(4500);
	dispWrite(0x30);
	_delay_us(4500);
	dispWrite(0x30);
	_delay_us(4500);
	dispWrite(0x28);
	dispSend(0x28, command);
	dispSend(0x08, command); 
	dispSend(0x01, command); 
    _delay_ms(50);
	dispSend(0x0C, command); 
	_delay_ms(5);
	dispSend(0x40, command); 
	for(i=0; i<8; i++) dispSend(din[i], write);
	dispSend(0x80, command); 
	dispSend(0x48, command); 
	for(i=0; i<8; i++) dispSend(cact[i], write);
	dispSend(0x80, command);
}

void dispPrintChar(uint8_t chr[], uint8_t size){
	for(uint8_t i = 0; i < size; i++) dispSend(chr[i], write); 
}

void dispSetLine(uint8_t line){
	if(line == 2) dispSend(0xC0, command); 
	else dispSend(0x80, command);
}

void dispClear(){
	dispSend(0x01, command);
	_delay_ms(2);
}

void dispHome(){
	dispSend(0x02, command);
	_delay_ms(2);
}

void dispSend(uint8_t bits, uint8_t act){
	if(act) PORTB |= (1 << DDB0); 
	else PORTB &= ~(1<<DDB0);
	dispWrite(bits); 
	dispWrite(bits << 4);
	_delay_us(80);
}

void dispWrite(uint8_t bits){
	PORTD = bits;
	PORTB |= (1<<DDB1);
	_delay_us(1);
	PORTB &= ~(1<<DDB1);
	_delay_us(1);
}

uint16_t aRead(){
	ADCSRA |= (1 << ADSC);
	while  (ADCSRA & (1 << ADSC));
	return ADCL | (ADCH << 8);
}

ISR (TIMER1_COMPA_vect){
	if(!longhold){
		aVal = aRead();
		if(aVal > 95 && aVal < 104 && canup){
		 isup = 1;
		 longhold++;
		 }
		}
}



© digitrode.ru


Теги: AVR




Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Комментарии:

Оставить комментарий