前言
随着科学技术的不断进步,嵌入式近些年来逐渐兴起,其领域比较新,发展非常迅速,由于它属于新兴领域,接触的人并不是很多,但是嵌入式在各种电子设备上的应用越来越越广泛,并且各种电子设备也在朝着嵌入式微系统,智能化的方向前进。STM32系列是基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex-M内核。作为21世纪的人才,为了与社会实际需要相衔接,提高我们的学习兴趣,利用STM32系列单片机进行了一次嵌入式系统设计。
摘要
在本次作业中采用STM32系列中的STM32F103RCT6微控制器芯片,采用ALIENTEK战舰STM32开发板,使用MiniSTM32开发板上的 LCD 接口,来点亮 TFTLCD,实现触摸屏功能。
本次的课程设计目的是实现一个经典的贪吃蛇游戏,整个游戏实现功能分别为: 1、初始化程序。 2、随机红点、左转、右转、判断边框。 硬件设计原理图 根据此硬件设计图再结合软件设计就能做出此游戏。 此次的课程设计在于开发个贪吃蛇游戏,其流程图如下图所示。 程序流程图为方便介绍,此软件实现只给出主要程序部分: 1、本例程提供了硬件平台的初始化 GPIO是常规输入/输出端口,STM32F103RCT6有PA、PB、PC、PD、PE共5个16位的GPIO。STM32的GPIO都可编程,具有很多复用功能。GPIO可以配置为很多总模式,这些模式有:输入浮空、输入上拉、输入下拉、模拟输入、开漏输入、推挽输出、推挽复用、开漏复用。通过对GPIO寄存器编程,可以设置每个端口的工作模式。 24C02 EEPROM是开发板板载的 2Kbit(256 个字节)EEPROM ,型号为:24C02,用于掉电数据保存。因为 STM32 内部没有 EEPROM,所开发板外扩了24C02,用于存储重要数据,用来做IIC 实验,该芯片直接挂在 STM32 的 IO 口上。 IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于连接微控制器及其外围设备。 它是由数据线 SDA 和时钟 SCL 构成的串行总线, 可发送和接收数据。在 CPU 与被控 IC 之间、IC 与 IC 之间进行双向传送,高速 IIC 总线一般可达 400kbps 以上。IIC 总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。 开始信号:SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。 结束信号:SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。 应答信号: 接收数据的 IC 在接收到 8bit 数据后, 向发送数据的 IC 发出特定的低电平脉冲,表示已收到数据。CPU 向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU 接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。
- /********************************************************************
- * 名 称:AT24CXX_Init(void)
- * 功 能:初始化IIC接口
- ********************************************************************/
- //初始化IIC接口
- void AT24CXX_Init(void)
- {
- IIC_Init();
- }
- void IIC_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- //RCC->APB2ENR|=1<<4;//先使能外设IO PORTC时钟
- RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE );
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_11;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
-
- IIC_SCL=1;
- IIC_SDA=1;
-
- }
- /*******************************************************************
- * 名 称:void CMLCD_Init(void)
- * 功 能:初始化触摸屏的硬件接口
- ********************************************************************/
- void CMLCD_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能PORTC时钟
-
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_3|GPIO_Pin_13;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置成推免输出
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC 0 3 13
-
- GPIO_InitStructure.GPIO_Pin =GPIO_Pin_2|GPIO_Pin_1; //初始化GPIOC 2 1
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;//浮空输入
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOC, &GPIO_InitStructure);
- TPEN=1;
- }
复制代码
2、贪吃蛇功能控制
SPI是串行外设端口,是一种同步串行外设端口,它可以使MCU与各种外围设备以串行方式进行通信、交换信息。STM32的SPI支持全双工同步传输,可选择以8或16位传输帧格式进行传输,支持多种模式。
USART为STM32的同步异步接收器。它提供了一种灵活的方法与使用异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。另外,它还允许多处理器通信。USART也可以使用DMA方式直接将接受的数据存储到内存或从内存中批量发送数据,也支持多种中断方式。
TFT-LCD 即薄膜晶体管液晶显示器。其英文全称为:Thin Film Transistor-Liquid CrystalDisplay。TFT-LCD 与无源 TN-LCD、STN-LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT) ,可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关,因此大大提高了图像质量。TFT-LCD 也被叫做真彩液晶显示器。ALIENTEK 提供的 2.8寸TFTLCD 模块,其驱动芯片有很多种类型,比如有:ILI9341/ILI9325/RM68042/RM68021/ILI9320/ILI9328/LGDP4531/LGDP4535/SPFD5408/SSD1289/1505/B505/C505/NT35310/NT35510 等。
LED(DS0 和 DS1)。其电路在ALIENTEK MiniSTM32开发板上默认是已经连接好了的。DS0接PA8,DS1接PD2。
调试过程: 在测试过程中出现了一些问题,点触的时候点不准确,我觉得可以加上触屏校准,使其精准。 实验结果: 达到随机生成果实、蛇上下左右移动、判断蛇生死的功能,达到了设计的目的。实验设计效果如下图所示:
本学期嵌入式课程在不知不觉中结束了,虽说这次课程时间不是很长,但是感觉自己收获颇丰,不仅学习到了一些新知识,回顾了以前的一些快要遗忘的知识点,而且使自己的学习目标更加明确,学习方法更加完善,也体会到软件开发的趣味,更加清楚地认识到了自己在软件开发及学习上的一些不足之处。在这次的课程中不仅检验了我所学习的知识,也培养了我如何去把握一件事情,如何去做一件事情,又如何完成一件事情。在设计过程中,与同学分工设计,和同学们相互探讨,相互学习,相互监督。学会了合作,学会了运筹帷幄,学会了宽容,学会了理解,也学会了做人与处世。 课程是我们专业课程知识综合应用的实践训练,着是我们迈向社会,从事职业工作前一个必不少的过程。“千里之行始于足下”,通过这次课程设计,我深深体会到这句千古名言的真正含义。也感谢老师和同学们的帮助。我今天认真的进行作业设计,学会脚踏实地迈开这一步,就是为以后打下坚实的基础。
- /********************************************************************
- * 名 称:int main(void)
- * 功 能:主函数
- ********************************************************************/
- #include "led.h"
- #include "delay.h"
- #include "sys.h"
- #include "usart.h"
- #include "lcd.h"
- #include "tanchishe.h"
- #include "cmlcd.h"
- #include "timeit.h"
- #include "stdlib.h"
- //画一个大点(2*2的点)
- //x,y:坐标
- //color:颜色
- void TP_Draw_Big_Point(u16 x,u16 y,u16 color)
- {
- POINT_COLOR=color;
- LCD_DrawPoint(x,y);//中心点
- LCD_DrawPoint(x+1,y);
- LCD_DrawPoint(x,y+1);
- LCD_DrawPoint(x+1,y+1);
- }
- int main(void)
- {
- u8 sta,sta1;
- u16 rand_color;
- delay_init(); //延时函数初始化
- uart_init(9600); //串口初始化为9600
- LED_Init(); //初始化与LED连接的硬件接口
- LCD_Init();
- time_init();
- CMLCD_Init(); // 触摸屏初始化
- AT24CXX_Init(); //eeprom 初始化
- sta1=TP_Get_Adjdata();
- if(!sta1)
- {
- sta=CMLCD_Adjust();
- if(sta)
- {
- TP_Save_Adjdata(); //校准成功就保存参数
- LCD_ShowString(40,40,100,16,16,"SUCCESSFUL!");
- }
- else
- {
- LCD_ShowString(40,40,100,16,16,"NO SUCCESSFUL!");
- }
- }
- TABCHISHE_Init();
- while(1)
- {
- delay_ms(500);
- //产生随机坐标
- if(snake.eat_sta)
- {
- snake.eat_sta=0;
- snake.rand_x=8*(1+(int)(29.0*rand()/(RAND_MAX+1.0)));
- snake.rand_y=8*(1+(int)(34.0*rand()/(RAND_MAX+1.0)));
- rand_color=LCD_ReadPoint(snake.rand_x,snake.rand_y);
- while(rand_color==BLUE) //随机点不能是蛇身上的点
- {
- snake.rand_x=8*(1+(int)(29.0*rand()/(RAND_MAX+1.0)));
- snake.rand_y=8*(1+(int)(34.0*rand()/(RAND_MAX+1.0)));
- rand_color=LCD_ReadPoint(snake.rand_x,snake.rand_y);
- }
- LCD_Fill(snake.rand_x,snake.rand_y,snake.rand_x+snake.size,snake.rand_y+snake.size,RED);
- }
- LED0=!LED0;
- TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE ); //关中断 防止中断服务函数对 显示坐标的影响
- snake.eat_sta=show(snake.d1);
- disappear(snake.d2,turn);
- TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //开中断
- }
- }
- /*******************************************************************
- * 名 称:void TABCHISHE_Init(void)
- * 功 能:贪吃蛇初始化
- ********************************************************************/
- void TABCHISHE_Init(void)
- {
- Shuzu_Init(turn); // 转向数组初始化
- LCD_Clear(WHITE);
- POINT_COLOR=RED;
- LCD_DrawLine(0,282, 240, 282);
- LCD_DrawLine(120,280, 120, 320);
- LCD_ShowString(20,290,72,12,12,"left/down");
- LCD_ShowString(20,303,36,12,12,"score:");
- LCD_ShowString(140,290,64,12,12,"right/up");
-
- // 以下为贪吃蛇程序初始化
- LCD_Fill(120,160,136,168,BLUE); //一开始蛇长度为2个SIZE
- snake.eat_sta=0;
- snake.length=2;
- LCD_ShowxNum(56,303,snake.length,3,12,0x80);
- snake.max=MAX;
- snake.size=8;
- snake.d1=0;
- snake.d2=0;
- snake.x1=128;snake.x2=snake.x1+snake.size;snake.y1=160;snake.y2=snake.y1+snake.size;
- snake.X1=112;snake.X2=snake.X1+snake.size;snake.Y1=160;snake.Y2=snake.Y1+snake.size;
- snake.rand_x=8*(1+(int)(29.0*rand()/(RAND_MAX+1.0)));
- snake.rand_y=8*(1+(int)(34.0*rand()/(RAND_MAX+1.0)));
- LCD_Fill(snake.rand_x,snake.rand_y,snake.rand_x+snake.size,snake.rand_y+snake.size,RED);
- }
- /*******************************************************************
- * 名 称:void disappear(u8 d,u16 turn[MAX][3])
- * 功 能:贪吃蛇移动尾部消失格子
- ********************************************************************/
- //新消失的一格
- //参数: 往左消失,往右消失
- void disappear(u8 d,u16 turn[MAX][3])
- {
- int i=0;
- if(d==0) //默认 方向为从左到右
- {
- snake.X1=snake.X1+snake.size;snake.X2=snake.X2+snake.size;
- LCD_Fill(snake.X1,snake.Y1,snake.X2,snake.Y2,WHITE); //新显示的一格
- }
- else if(d==1) //方向为下到上
- {
- snake.Y1=snake.Y1-snake.size;snake.Y2=snake.Y2-snake.size;
- LCD_Fill(snake.X1,snake.Y1,snake.X2,snake.Y2,WHITE); //新显示的一格
- }
- else if(d==2) //方向为右到左
- {
- snake.X1=snake.X1-snake.size;snake.X2=snake.X2-snake.size;
- LCD_Fill(snake.X1,snake.Y1,snake.X2,snake.Y2,WHITE); //新显示的一格
- }
- else if(d==3) //方向为上到下
- {
- snake.Y1=snake.Y1+snake.size;snake.Y2=snake.Y2+snake.size;
- LCD_Fill(snake.X1,snake.Y1,snake.X2,snake.Y2,WHITE); //新显示的一格
- }
- for(i=0;i<MAX;i++) //先判断是否是转方向点
- {
- if(snake.X1==turn[i][0]&&snake.Y1==turn[i][1])
- {
- snake.d2=turn[i][2];
- turn[i][0]=400; //转向完毕 清除记录的坐标(将坐标变为LCD以外区域)
- turn[i][1]=400;
- break;
- }
- }
-
- }
- /*******************************************************************
- * 名 称:u8 show(u8 d)
- * 功 能:贪吃蛇移动前部新增格子
- ********************************************************************/
-
- //新显示的一格
- //参数: 往左显示,往右显示
- u8 show(u8 d)
- {
- static u8 i=0;
- u16 color,color1;
- //判断是否撞到自己的身体
- if(d==0)
- {
- color=LCD_ReadPoint(snake.x2+4,snake.y2-4);
- color1=LCD_ReadPoint(snake.x2+3,snake.y2-3);
- if(color==BLUE&&color1==BLUE)
- {
- LCD_ShowString(40,40,100,16,16,"NO SUCCESSFUL!");
- printf("color%x color1%x\r\n",color,color1);
- printf("shezhuangziji0\r\n");
- delay_ms(5000);
- TABCHISHE_Init();
- d=snake.d1;
- }
- }
- else if(d==1)
- {
- color=LCD_ReadPoint(snake.x1+4,snake.y1-4);
- color1=LCD_ReadPoint(snake.x1+3,snake.y1-3);
- if(color==BLUE&&color1==BLUE)
- {
- LCD_ShowString(40,40,100,16,16,"NO SUCCESSFUL!");
- printf("color%x color1%x\r\n",color,color1);
- printf("shezhuangziji1%d %d %d\r\n",snake.d1,snake.d2,d);
- delay_ms(5000);
- TABCHISHE_Init();
- d=snake.d1;
- printf("%d %d %d\r\n",snake.d1,snake.d2,d);
- }
- }
- else if(d==2)
- {
- color=LCD_ReadPoint(snake.x1-4,snake.y1+4);
- color1=LCD_ReadPoint(snake.x1-3,snake.y1+3);
- if(color==BLUE&&color1==BLUE)
- {
- LCD_ShowString(40,40,100,16,16,"NO SUCCESSFUL!");
- printf("color%x color1%x\r\n",color,color1);
- printf("shezhuangziji2\r\n");
- delay_ms(5000);
- TABCHISHE_Init();
- d=snake.d1;
- }
- }
- else if(d==3)
- {
- color=LCD_ReadPoint(snake.x2-4,snake.y2+4);
- color1=LCD_ReadPoint(snake.x2-3,snake.y2+3);
- if(color==BLUE&&color1==BLUE)
- {
- LCD_ShowString(40,40,100,16,16,"NO SUCCESSFUL!");
- printf("color%x color1%x\r\n",color,color1);
- printf("shezhuangziji3\r\n");
- delay_ms(5000);
- TABCHISHE_Init();
- d=snake.d1;
- }
- }
- if((snake.y1==0&&d==1)||(snake.x1==0&&d==2)||(snake.y2==280&&d==3)||(snake.x2==240&&d==0)) //蛇撞到墙了
- {
- LCD_ShowString(40,40,100,16,16,"NO SUCCESSFUL!");
- printf("shezhuangqiang\r\n");
- delay_ms(5000);
- TABCHISHE_Init();
- d=snake.d1;
- }
- if(snake.rand_x==snake.x1&&snake.rand_y==snake.y1) //判断是否增加长度即碰到随机点
- {
- i=1;
- if(snake.d2==0)
- {snake.X1-=16;snake.X2-=16;} //在尾端增加一格
- else if(snake.d2==1)
- {snake.Y1+=16;snake.Y2+=16;}
- else if(snake.d2==2)
- {snake.X1+=16;snake.X2+=16;}
- else if(snake.d2==3)
- {snake.Y1-=16;snake.Y2-=16;}
- snake.length++;
- LCD_ShowxNum(56,303,snake.length,3,12,0x80);
- }
- if(d==0) //默认 方向为从左到右
- {
- snake.x1=snake.x1+snake.size;snake.x2=snake.x2+snake.size;
- LCD_Fill(snake.x1,snake.y1,snake.x2,snake.y2,BLUE); //新显示的一格
- }
- else if(d==1) //方向为下到上
- {
- snake.y1=snake.y1-snake.size;snake.y2=snake.y2-snake.size;
- LCD_Fill(snake.x1,snake.y1,snake.x2,snake.y2,BLUE); //新显示的一格
- }
- else if(d==2) //方向为右到左
- {
- snake.x1=snake.x1-snake.size;snake.x2=snake.x2-snake.size;
- LCD_Fill(snake.x1,snake.y1,snake.x2,snake.y2,BLUE); //新显示的一格
- }
- else if(d==3) //方向为上到下
- {
- snake.y1=snake.y1+snake.size;snake.y2=snake.y2+snake.size;
- LCD_Fill(snake.x1,snake.y1,snake.x2,snake.y2,BLUE); //新显示的一格
- }
- if(i==1)
- { i=0;return 1;}
- return 0;
- }
- /*******************************************************************
- * 名 称:void CM_Scan()
- * 功 能:触摸屏扫描函数
- ********************************************************************/
- void CM_Scan()
- {
- static u8 times=0;
- static u8 i=0;
- if(TPEN==0&&!times)
- {
- times=1;
- if(CMLCD_GetLCD()) //取坐标成功后再选择是否转向
- {
- if(cmlcdxy.X>=0&&cmlcdxy.X<=120&&cmlcdxy.Y>=280&&cmlcdxy.Y<=320)
- {
- if(snake.d1==0||snake.d1==2)
- snake.d1=3;
- else if(snake.d1==1||snake.d1==3)
- snake.d1=2;
- turn[i][0]=snake.x1; //第i次转弯坐标
- turn[i][1]=snake.y1;
- turn[i][2]=snake.d1; //第i次转弯方向
- i++;
- if(i>MAX-1)
- i=0;
- }
- else if(cmlcdxy.X>=121&&cmlcdxy.X<=240&&cmlcdxy.Y>=280&&cmlcdxy.Y<=320)
- {
- if(snake.d1==0||snake.d1==2)
- snake.d1=1;
- else if(snake.d1==1||snake.d1==3)
- snake.d1=0;
- turn[i][0]=snake.x1; //第i次转弯坐标
- turn[i][1]=snake.y1; //第i次转弯方向
- turn[i][2]=snake.d1;
- i++;
- if(i>MAX-1)
- i=0;
- }
- }
- }else if(TPEN==1) times=0;
- }
复制代码
完整的Word格式文档51黑下载地址:
|