基于STM32F103的口袋嵌入式学习/控制平台项目5功能2贪吃蛇小游戏
基于STM32F103的口袋嵌入式学习/控制平台项目5功能2贪吃蛇小游戏
标签
嵌入式系统
赵自旺
更新2021-03-05
1622

                                                       目录

 

1、项目背景

      随着科学技术的不断进步,嵌入式近些年来逐渐兴起,其领域比较新,发展非常迅速,由于它属于新兴领域,接触的人并不是很多,但是嵌入式在各种电子设备上的应用越来越越广泛,并且各种电子设备也在朝着嵌入式微系统,智能化的方向前进。STM32系列是基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M内核。作为21世纪的人才,为了与社会实际需要相衔接,提高我们的学习兴趣,利用STM32系列单片机进行了一次嵌入式系统设计。

2、项目要实现的功能和要达到的性能指标

      实现一个经典的贪吃蛇游戏:可用板上的4个按键操作,同时蜂鸣器能够发出声音,姿态传感器能够感知板子旋转的方向,自动将屏幕调整到合适观看的角度。

3、项目的实施方案

  •    准备过程

      首先下载一个编写代码的软件,在这里我推荐keil5因为我用的就是这个,下载地址:https://www.keil.com/download/product/。并且一定要先下好芯片对应的芯片包。

  •    参考资源

      推荐电子森林“03-1.54IPS程序源码.zip”中的“02-中景园电子1.54IPS显示屏STM32F103C8T6_SPI例程”。虽然板子不同,但只有引脚的差异。(具体差异见附件)

  •    设计思路

FlRgXMSkrp9qcfD-x3oURyi5IlL9

  •    主函数的部分参考
#include "delay.h"
#include "sys.h"
#include "led.h"
#include "lcd_init.h"
#include "lcd.h"
#include "pic.h"
#include "key.h"
#include "stdio.h"
#include "stdlib.h"
#include "buzzer.h"
#include "bsp_i2c.h"
#include "mpu6050.h"
#include "stm32f10x_it.h"
#include "math.h"
extern int k,CountNumber,music;

int front,tail,startX,startY,ori,foodX,foodY,foodFlag,score,dif=1,time=999,SleepNum,N_ori,colour; 
int snake[255],eat,shadow[255];
int stone,stoneX,stoneY;
int bgg[53][53];
int z,flag;
int lcd_change,lcd_origin,xx,yy;
	
	double pitch,roll,yaw,a0,a1,a2;
	int pitchI,rollI,yawI,countP,countR,countY;
	short Accel[3];
	short Gyro[3];
	float Temp;
  u8 i,j;
	float t=0;
	
void GG(void)//死亡后的处理
{
	colour=rand()%17+1;
  if(colour==1)LCD_Fill(0,0,LCD_W,LCD_H,BRED);
	else if(colour==2)LCD_Fill(0,0,LCD_W,LCD_H,GRED);
	else if(colour==3)LCD_Fill(0,0,LCD_W,LCD_H,GBLUE);
	else if(colour==4)LCD_Fill(0,0,LCD_W,LCD_H,RED);
	else if(colour==5)LCD_Fill(0,0,LCD_W,LCD_H,MAGENTA);
	else if(colour==6)LCD_Fill(0,0,LCD_W,LCD_H,GREEN);
	else if(colour==7)LCD_Fill(0,0,LCD_W,LCD_H,CYAN);
	else if(colour==8)LCD_Fill(0,0,LCD_W,LCD_H,YELLOW);
	else if(colour==9)LCD_Fill(0,0,LCD_W,LCD_H,BROWN);
	else if(colour==10)LCD_Fill(0,0,LCD_W,LCD_H,BRRED);
	else if(colour==11)LCD_Fill(0,0,LCD_W,LCD_H,GRAY);
	else if(colour==12)LCD_Fill(0,0,LCD_W,LCD_H,DARKBLUE);
	else if(colour==13)LCD_Fill(0,0,LCD_W,LCD_H,LIGHTBLUE );
	else if(colour==14)LCD_Fill(0,0,LCD_W,LCD_H,GRAYBLUE);
	else if(colour==15)LCD_Fill(0,0,LCD_W,LCD_H,LIGHTGREEN );
	else if(colour==16)LCD_Fill(0,0,LCD_W,LCD_H,LGRAYBLUE );
	else if(colour==17)LCD_Fill(0,0,LCD_W,LCD_H,LBBLUE );
	delay_ms(5000);
	return ;
}
void food(void)//生成食物
{
	while((foodX==0&&foodY==0)||bgg[foodX][foodY]!=0){
	foodX=rand()%47+1;
	foodY=rand()%47+1;
	}
	bgg[foodX][foodY]=3;
	foodFlag=1;
	if(lcd_origin==1)LCD_ShowString((foodX)*5,(foodY)*5,"$",BLACK,WHITE,16,1);
	else if(lcd_origin==2)LCD_ShowString((foodY)*5,(48-foodX)*5,"$",BLACK,WHITE,16,1);
	else if(lcd_origin==3)LCD_ShowString((48-foodX)*5,(48-foodY)*5,"$",BLACK,WHITE,16,1);
	else if(lcd_origin==4)LCD_ShowString((48-foodY)*5,(foodX)*5,"$",BLACK,WHITE,16,1);
}
int hard(void)//设置难度
{
	if(score>=900)score=900;
	if(dif>=1&&dif<=10)return 120-7*dif;
 
	if(dif>10&&dif<=20)return 50-((dif-10));
	if(dif>20)return 39;
	return 100;
}
void Cqueue(void)//循环
{
	 flag=1;
	for( z=tail;z<=front;z++){
		shadow[flag]=snake[z];
		flag++;
	}
	for( z=1;z<=flag;z++){
		snake[z]=shadow[z];
	}
	tail=1;front=flag-1;
}
int Lcd(void)//计算姿态数据
{
				MPU6050ReadAcc(Accel);			
				MPU6050ReadGyro(Gyro);			
				MPU6050_ReturnTemp(&Temp); 
			
			a0=Accel[0];a1=Accel[1];a2=Accel[2];		
			pitch=atan(a0/(sqrt(a1*a1+a2*a2)))*180/3.14;pitchI=pitch;
			roll=atan(a1/(sqrt(a0*a0+a2*a2)))*180/3.14;rollI=roll;
			yaw=atan((sqrt(a0*a0+a1*a1))/a2)*180/3.14;yawI=yaw;
			
			LCD_ShowNumNum(40,210,pitchI,3,RED,WHITE,16);countP=CountNumber;
			LCD_ShowNumNum(40,190,rollI,3,RED,WHITE,16);countR=CountNumber;
			LCD_ShowNumNum(40,170,yawI,3,RED,WHITE,16);countY=CountNumber;
			if((yawI%1000)==(rollI%1000))return 1;
			else if((yawI%1000)==(pitchI%1000))return 2;
			else if(countY==3&&countR==2&&countP==1)return 3;
			else if(countY==3&&countR==1&&countP==2)return 4;
	return lcd_origin;
}
void LcdOutput(void)//输出到屏幕
{
			lcd_change=Lcd();
			if(lcd_origin!=lcd_change){
					LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
					lcd_origin=lcd_change;		 
					if(lcd_change==1){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((xx)*5,(yy)*5,"$",BLUE,WHITE,16,1);}}//straight
					else if(lcd_change==2){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((yy)*5,(48-xx)*5,"$",BLUE,WHITE,16,1);}}//clockwise for once
					else if(lcd_change==3){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((48-xx)*5,(48-yy)*5,"$",BLUE,WHITE,16,1);}}//clockwise for twice
					else if(lcd_change==4){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((48-yy)*5,(xx)*5,"$",BLUE,WHITE,16,1);}}//clockwise for three times	
					
			}
			else{
						if(lcd_origin==1){
							for(i=tail;i<=tail+1;i++)LCD_ShowString((snake[i]/1000)*5,(snake[i]%1000)*5,"$",BLUE,WHITE,16,1);
							LCD_ShowString((snake[front]/1000)*5,(snake[front]%1000)*5,"$",BLUE,WHITE,16,1);
							LCD_ShowString((foodX)*5,(foodY)*5,"$",BLACK,WHITE,16,1);
						}
						if(lcd_origin==2){
							for(i=tail;i<=tail+1;i++)LCD_ShowString((snake[i]%1000)*5,(48-(snake[i]/1000))*5,"$",BLUE,WHITE,16,1);
							LCD_ShowString((snake[front]%1000)*5,(48-(snake[front]/1000))*5,"$",BLUE,WHITE,16,1);
							LCD_ShowString((foodY)*5,(48-foodX)*5,"$",BLACK,WHITE,16,1);
						}
						if(lcd_origin==3){
							for(i=tail;i<=tail+1;i++)LCD_ShowString((48-snake[i]/1000)*5,(48-snake[i]%1000)*5,"$",BLUE,WHITE,16,1);
							LCD_ShowString((48-snake[front]/1000)*5,(48-snake[front]%1000)*5,"$",BLUE,WHITE,16,1);
							LCD_ShowString((48-foodX)*5,(48-foodY)*5,"$",BLACK,WHITE,16,1);
						}
					if(lcd_origin==4){
							for(i=tail;i<=tail+1;i++)LCD_ShowString((48-snake[i]%1000)*5,(snake[i]/1000)*5,"$",BLUE,WHITE,16,1);
						  LCD_ShowString((48-snake[front]%1000)*5,(snake[front]/1000)*5,"$",BLUE,WHITE,16,1);
						  LCD_ShowString((48-foodY)*5,(foodX)*5,"$",BLACK,WHITE,16,1);
						}				
				}
}
void start(void)//开始
{
		k=0;
		LCD_Fill(0,0,LCD_W,LCD_H,LGRAY);
		for(i=1;i<=6;i++)snake[i]=20010+i-1;
		for(i=7;i<=11;i++)snake[i]=20015+(i-6)*1000;
		for(i=12;i<=16;i++)snake[i]=25015+i-11;
		for(i=17;i<=19;i++)snake[i]=25020-(i-16)*1000;
		for(i=20;i<=27;i++)snake[i]=22020+i-19;
		for(i=28;i<=35;i++)snake[i]=22028+(i-27)*1000;
		for(i=36;i<=41;i++)snake[i]=30028-(i-35);
		front=41,tail=1;
		while(!k){			
			lcd_change=Lcd();		
			if(lcd_origin!=lcd_change){
					LCD_Fill(0,0,LCD_W,LCD_H,LGRAY);
					lcd_origin=lcd_change;		 			
			}
			if(lcd_origin==1){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((xx)*5,(yy)*5,"$",BLUE,WHITE,16,1);}}//straight
			else if(lcd_origin==2){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((yy)*5,(48-xx)*5,"$",BLUE,WHITE,16,1);}}//clockwise for once
			else if(lcd_origin==3){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((48-xx)*5,(48-yy)*5,"$",BLUE,WHITE,16,1);}}//clockwise for twice
			else if(lcd_origin==4){for(i=tail;i<=front;i++){xx=snake[i]/1000,yy=snake[i]%1000;LCD_ShowString((48-yy)*5,(xx)*5,"$",BLUE,WHITE,16,1);}}//clockwise for three times						
		}
		k=4;
}
void snake_init(void){
		LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
		for(i=0;i<=49;i++)
				for(j=0;j<=48;j++)bgg[i][j]=0;
		for(i=0;i<=241;i++)snake[0]=0;
		front=0,tail=0,startX=0,startY=0,ori=0,foodX=0,foodY=0,foodFlag=0,score=0,dif=1,time=999,SleepNum=0,N_ori=0,eat=0;
		lcd_origin=1,lcd_change=1,music=1,music=1;
	

		startX=25;startY=5;
		front=4;tail=1;
		ori=4;
		
		food();
		bgg[startX][startY]=2;
		bgg[startX][startY-1]=2;
		bgg[startX][startY-2]=2;
		bgg[startX][startY-3]=2;
		snake[front]=startX*1000+startY;
		snake[front-1]=startX*1000+(startY-1);
		snake[front-2]=startX*1000+(startY-2);
		snake[front-3]=startX*1000+(startY-3);
}
void ori_check(void)//蛇头方向
{
			N_ori=k;	
			if(N_ori!=3&&N_ori!=4&&N_ori!=1&&N_ori!=2)ori=ori;
			else if(ori==4&&N_ori!=3&&N_ori!=4){ori=N_ori;}
			else if(ori==3&&N_ori!=4&&N_ori!=3){ori=N_ori;}
			else if(ori==2&&N_ori!=1&&N_ori!=2){ori=N_ori;}
			else if(ori==1&&N_ori!=2&&N_ori!=1){ori=N_ori;}
}
void snake_delay(void)//延时
{
			dif=(score/3)+1;
			SleepNum=hard();
			delay_ms(SleepNum);
}
  •    蜂鸣器

      这个板子上的蜂鸣器是无源的,所以要设置好电平的频率和持续时间。

                                            原理图

                                          FinVCvfCXZ14MuajrnpB_gIGRIHg

4、项目结果及总结

      达到随机生成果实、蛇上下左右移动、判断蛇生死的功能,达到了设计的目的。

      本寒假对嵌入式的学习在不知不觉中结束了,虽说这次学习时间不是很长,但是感觉自己收获颇丰,不仅学习到了一些新知识,回顾了以前的一些快要遗忘的知识点,而且使自己的学习目标更加明确,学习方法更加完善,也体会到软件开发的趣味,更加清楚地认识到了自己在软件开发及学习上的一些不足之处。在这次的课程中不仅检验了我所学习的知识,也培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。这次项目是我们专业课程知识综合应用的实践训练,是我们迈向社会,从事职业工作前一个必不少的过程。“千里之行始于足下”,通过这次课程设计,我深深体会到这句千古名言的真正含义。

      最后,感谢硬禾学堂给了我学习的机会,让我获得了提高,十分感谢。

 

附件下载
贪吃蛇.zip
团队介绍
南昌大学信息工程学院电子信息类
团队成员
赵自旺
南昌大学一名新手小白
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2024 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号