目录
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例程”。虽然板子不同,但只有引脚的差异。(具体差异见附件)
- 设计思路
- 主函数的部分参考
#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);
}
- 蜂鸣器
这个板子上的蜂鸣器是无源的,所以要设置好电平的频率和持续时间。
原理图
4、项目结果及总结
达到随机生成果实、蛇上下左右移动、判断蛇生死的功能,达到了设计的目的。
本寒假对嵌入式的学习在不知不觉中结束了,虽说这次学习时间不是很长,但是感觉自己收获颇丰,不仅学习到了一些新知识,回顾了以前的一些快要遗忘的知识点,而且使自己的学习目标更加明确,学习方法更加完善,也体会到软件开发的趣味,更加清楚地认识到了自己在软件开发及学习上的一些不足之处。在这次的课程中不仅检验了我所学习的知识,也培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。这次项目是我们专业课程知识综合应用的实践训练,是我们迈向社会,从事职业工作前一个必不少的过程。“千里之行始于足下”,通过这次课程设计,我深深体会到这句千古名言的真正含义。
最后,感谢硬禾学堂给了我学习的机会,让我获得了提高,十分感谢。