基于STM32设计的拼图小游戏详解

2023-06-27  

一、环境介绍

MCU:STM32F103ZET6


编程软件环境:keil5

LCD显示屏:正点原子的TFT 3.5寸显示屏


二、运行效果

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png


三、功能介绍

因为代码原来是在2.8寸屏上设计的,但是2.8寸屏摔碎了,现在手上只有块3.5寸的LCD屏。就把代码移植到3.5寸屏上显示了,目前运行的效果可以看上面的效果图。

拼图游戏在小时候还是经常玩,玩法也比较简单,这里就使用STM32设计一个拼图小游戏分享出来一起学习。

目前游戏是通过开发板上4按键进行控制图片的移动,完成最终的拼图效果,如果想要在上面扩充其他游戏功能都还是比较容易。

当然,设计编写这个款小游戏不仅仅是为了玩游戏这么简单,主要是为了通过设计游戏的过程学习STM32编程、LCD的编程、按键、图片等等很多编程知识。

做拼图这款游戏主要的硬件就是LCD显示屏和几个按键,没有其他外设,如果自己有其他STM32最小系统板有LCD显示屏的话,完全可以把代码移植过去运行。当前的代码兼容正点原子战舰开发板,可以直接在正点原子战舰直接编译下载运行。其他的开发板上运行也是一样的道理,底层替换自己LCD画点函数即可。

目前的拼图的游戏工程里图片是提前通过取模软件取好模之后把数据放在工程里的,如果想要动态更加灵活的切换拼图的图片,可以加上SD卡和FATFS文件系统,把图片放在SD卡,通过按键选择指定图片切割进行拼图。

代码分为3个部分:

1. LCD屏驱动代码部分

2. 按键驱动代码部分

3. 拼图的逻辑代码部分


四、LCD屏驱动代码

4.1 LCD介绍

这款LCD显示屏的驱动芯片型号是NT35310,时序支持8080时序,普通的MCU可以采用IO模拟8080时序驱动,有硬件接口的可以采用硬件接口驱动。STM32F103ZET6的FSMC是可以输出8080时序,为了提高刷屏速度,这里代码就采用FSMC接口来驱动LCD屏。照着LCD的手册指令集,自己编写一遍LCD的初始化代码,可以深入学习一遍LCD编程原理。

4.2 LCD显示屏的初始化代码示例

/*

函数功能:写寄存器函数

参    数:regval:寄存器值

*/  

void LcdWriteReg(u16 regval)

{

LCD_REG=regval;//写入要写的寄存器序号  

}



/*

函数功能:写LCD数据

函数参数:data:要写入的值

*/

void LcdWriteData(u16 data)

{  

LCD_RAM=data;  

}



/*

函数功能:读LCD数据

返 回 值:读到的值

*/

u16 LcdReadData(void)

{

vu16 ram; //防止被优化

ram=LCD_RAM;

return ram;  

}


/*

函数功能:读寄存器

函数参数:LCD_Reg:寄存器地址

返 回 值:读到的数据

*/

u16 LcdReadReg(u16 LCD_Reg)

{    

LcdWriteReg(LCD_Reg); //写入要读的寄存器序号

DelayUs(5);   

return LcdReadData(); //返回读到的值

}



/*

函数功能:开始写GRAM

*/

void LcdWriteRAM_Prepare(void)

{

  LCD_REG=0X2C;   

}



/*

函数功能:LCD写GRAM

函数参数:RGB_Code:颜色值

*/

void LcdWriteRAM(u16 RGB_Code)

{     

LCD_RAM = RGB_Code;//写十六位GRAM

}



/*

函数功能:设置光标位置

函数参数:

         Xpos:横坐标

         Ypos:纵坐标

*/

void LcdSetCursor(u16 Xpos, u16 Ypos)

{  

  LcdWriteReg(0X2A); 

LcdWriteData(Xpos>>8);

  LcdWriteData(Xpos&0XFF);  

LcdWriteReg(0X2B); 

LcdWriteData(Ypos>>8);

  LcdWriteData(Ypos&0XFF); 

}



/*

功能:读取个某点的颜色值

参数:x,y:坐标

返回值:此点的颜色

*/

u16 LcdReadPoint(u16 x,u16 y)

{

  u16 r=0,g=0,b=0;   

LcdSetCursor(x,y);     

LcdWriteReg(0X2E);

  r=LcdReadData(); //dummy Read    

DelayUs(1);   

  r=LcdReadData();    //实际坐标颜色


DelayUs(1);   

b=LcdReadData(); 

g=r&0XFF; //5310第一次读取的是RG的值,R在前,G在后,各占8位

g<<=8;

return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));

}





/*

功  能: 初始化LCD屏幕

说  明: 用于3.5寸屏幕的初始化。 

         LCD ID:5310

*/

void LcdInit(void)

{   

RCC->AHBENR|=1<<8;      //使能FSMC时钟   

  RCC->APB2ENR|=1<<3;      //使能PORTB时钟

RCC->APB2ENR|=1<<5;      //使能PORTD时钟

RCC->APB2ENR|=1<<6;      //使能PORTE时钟

  RCC->APB2ENR|=1<<8;      //使能PORTG时钟  

GPIOB->CRL&=0XFFFFFFF0; //PB0 推挽输出 背光

GPIOB->CRL|=0X00000003;    

//PORTD复用推挽输出

GPIOD->CRH&=0X00FFF000;

GPIOD->CRH|=0XBB000BBB; 

GPIOD->CRL&=0XFF00FF00;

GPIOD->CRL|=0X00BB00BB;     

//PORTE复用推挽输出

GPIOE->CRH&=0X00000000;

GPIOE->CRH|=0XBBBBBBBB; 

GPIOE->CRL&=0X0FFFFFFF;

GPIOE->CRL|=0XB0000000;         

//PORTG12复用推挽输出      

GPIOG->CRH&=0XFFF0FFFF;

GPIOG->CRH|=0X000B0000; 

GPIOG->CRL&=0XFFFFFFF0;//PG0->RS

GPIOG->CRL|=0X0000000B;  


//寄存器清零

//bank1有NE1~4,每一个有一个BCR+TCR,所以总共八个寄存器。

//这里我们使用NE4 ,也就对应BTCR[6],[7]。     

FSMC_Bank1->BTCR[6]=0X00000000;

FSMC_Bank1->BTCR[7]=0X00000000;

FSMC_Bank1E->BWTR[6]=0X00000000;

//操作BCR寄存器 使用异步模式

FSMC_Bank1->BTCR[6]|=1<<12; //存储器写使能

FSMC_Bank1->BTCR[6]|=1<<14; //读写使用不同的时序

FSMC_Bank1->BTCR[6]|=1<<4; //存储器数据宽度为16bit    

//操作BTR寄存器

//读时序控制寄存器     

FSMC_Bank1->BTCR[7]|=0<<28; //模式A    

FSMC_Bank1->BTCR[7]|=1<<0; //地址建立时间(ADDSET)为2个HCLK 1/36M=27ns(实际>200ns)  

//因为液晶驱动IC的读数据的时候,速度不能太快,尤其对1289这个IC。

FSMC_Bank1->BTCR[7]|=0XF<<8;  //数据保存时间为16个HCLK  

//写时序控制寄存器  

FSMC_Bank1E->BWTR[6]|=0<<28; //模式A     

FSMC_Bank1E->BWTR[6]|=0<<0; //地址建立时间(ADDSET)为1个HCLK 

 

//4个HCLK(HCLK=72M)因为液晶驱动IC的写信号脉宽,最少也得50ns。72M/4=24M=55ns   

FSMC_Bank1E->BWTR[6]|=3<<8; //数据保存时间为4个HCLK

//使能BANK1,区域4

FSMC_Bank1->BTCR[6]|=1<<0; //使能BANK1,区域4

DelayMs(50); // delay 50 ms 

  

lcddev.id=LcdReadReg(0x0000); //读ID(9320/9325/9328/4531/4535等IC)   


LcdWriteReg(0XD4);    

lcddev.id=LcdReadData();//dummy read  

lcddev.id=LcdReadData();//读回0X01  

lcddev.id=LcdReadData();//读回0X53

lcddev.id<<=8;  

lcddev.id|=LcdReadData(); //这里读回0X10  


printf(" LCD ID:%xrn",lcddev.id); //打印LCD ID

//if(lcddev.id==0x5310)

LcdWriteReg(0xED);

LcdWriteData(0x01);

LcdWriteData(0xFE);


LcdWriteReg(0xEE);

LcdWriteData(0xDE);

LcdWriteData(0x21);


LcdWriteReg(0xF1);

LcdWriteData(0x01);

LcdWriteReg(0xDF);

LcdWriteData(0x10);


//VCOMvoltage//

LcdWriteReg(0xC4);

LcdWriteData(0x8F);   //5f


LcdWriteReg(0xC6);

LcdWriteData(0x00);

LcdWriteData(0xE2);

LcdWriteData(0xE2);

LcdWriteData(0xE2);

LcdWriteReg(0xBF);

LcdWriteData(0xAA);


LcdWriteReg(0xB0);

LcdWriteData(0x0D);

LcdWriteData(0x00);

LcdWriteData(0x0D);

LcdWriteData(0x00);

LcdWriteData(0x11);

LcdWriteData(0x00);

LcdWriteData(0x19);

LcdWriteData(0x00);

LcdWriteData(0x21);

LcdWriteData(0x00);

LcdWriteData(0x2D);

LcdWriteData(0x00);

LcdWriteData(0x3D);

LcdWriteData(0x00);

LcdWriteData(0x5D);

LcdWriteData(0x00);

LcdWriteData(0x5D);

LcdWriteData(0x00);


LcdWriteReg(0xB1);

LcdWriteData(0x80);

LcdWriteData(0x00);

LcdWriteData(0x8B);

LcdWriteData(0x00);

LcdWriteData(0x96);

LcdWriteData(0x00);


LcdWriteReg(0xB2);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x02);

LcdWriteData(0x00);

LcdWriteData(0x03);

LcdWriteData(0x00);


LcdWriteReg(0xB3);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);


LcdWriteReg(0xB4);

LcdWriteData(0x8B);

LcdWriteData(0x00);

LcdWriteData(0x96);

LcdWriteData(0x00);

LcdWriteData(0xA1);

LcdWriteData(0x00);


LcdWriteReg(0xB5);

LcdWriteData(0x02);

LcdWriteData(0x00);

LcdWriteData(0x03);

LcdWriteData(0x00);

LcdWriteData(0x04);

LcdWriteData(0x00);


LcdWriteReg(0xB6);

LcdWriteData(0x00);

LcdWriteData(0x00);


LcdWriteReg(0xB7);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x3F);

LcdWriteData(0x00);

LcdWriteData(0x5E);

LcdWriteData(0x00);

LcdWriteData(0x64);

LcdWriteData(0x00);

LcdWriteData(0x8C);

LcdWriteData(0x00);

LcdWriteData(0xAC);

LcdWriteData(0x00);

LcdWriteData(0xDC);

LcdWriteData(0x00);

LcdWriteData(0x70);

LcdWriteData(0x00);

LcdWriteData(0x90);

LcdWriteData(0x00);

LcdWriteData(0xEB);

LcdWriteData(0x00);

LcdWriteData(0xDC);

LcdWriteData(0x00);


LcdWriteReg(0xB8);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);


LcdWriteReg(0xBA);

LcdWriteData(0x24);

LcdWriteData(0x00);

LcdWriteData(0x00);

LcdWriteData(0x00);


LcdWriteReg(0xC1);

LcdWriteData(0x20);

LcdWriteData(0x00);

LcdWriteData(0x54);

LcdWriteData(0x00);

LcdWriteData(0xFF);

LcdWriteData(0x00);


LcdWriteReg(0xC2);

LcdWriteData(0x0A);

LcdWriteData(0x00);

LcdWriteData(0x04);

LcdWriteData(0x00);


LcdWriteReg(0xC3);

LcdWriteData(0x3C);

LcdWriteData(0x00);

LcdWriteData(0x3A);

LcdWriteData(0x00);

LcdWriteData(0x39);

LcdWriteData(0x00);

LcdWriteData(0x37);

LcdWriteData(0x00);

LcdWriteData(0x3C);

LcdWriteData(0x00);

LcdWriteData(0x36);

LcdWriteData(0x00);

LcdWriteData(0x32);

LcdWriteData(0x00);

LcdWriteData(0x2F);

LcdWriteData(0x00);

LcdWriteData(0x2C);

LcdWriteData(0x00);

LcdWriteData(0x29);

LcdWriteData(0x00);

LcdWriteData(0x26);

LcdWriteData(0x00);

LcdWriteData(0x24);

LcdWriteData(0x00);

LcdWriteData(0x24);

LcdWriteData(0x00);

LcdWriteData(0x23);

LcdWriteData(0x00);

LcdWriteData(0x3C);

LcdWriteData(0x00);

LcdWriteData(0x36);

LcdWriteData(0x00);

LcdWriteData(0x32);

LcdWriteData(0x00);

LcdWriteData(0x2F);

LcdWriteData(0x00);

LcdWriteData(0x2C);

LcdWriteData(0x00);

LcdWriteData(0x29);

LcdWriteData(0x00);

LcdWriteData(0x26);

LcdWriteData(0x00);

LcdWriteData(0x24);

LcdWriteData(0x00);

LcdWriteData(0x24);

LcdWriteData(0x00);

LcdWriteData(0x23);

LcdWriteData(0x00);


LcdWriteReg(0xC4);

LcdWriteData(0x62);

LcdWriteData(0x00);

LcdWriteData(0x05);

LcdWriteData(0x00);

LcdWriteData(0x84);

LcdWriteData(0x00);

LcdWriteData(0xF0);

LcdWriteData(0x00);

LcdWriteData(0x18);

LcdWriteData(0x00);

LcdWriteData(0xA4);

LcdWriteData(0x00);

LcdWriteData(0x18);

LcdWriteData(0x00);

LcdWriteData(0x50);

LcdWriteData(0x00);

LcdWriteData(0x0C);

LcdWriteData(0x00);

LcdWriteData(0x17);

LcdWriteData(0x00);

LcdWriteData(0x95);

LcdWriteData(0x00);

LcdWriteData(0xF3);

LcdWriteData(0x00);

LcdWriteData(0xE6);

LcdWriteData(0x00);


LcdWriteReg(0xC5);

LcdWriteData(0x32);

LcdWriteData(0x00);

LcdWriteData(0x44);

LcdWriteData(0x00);

LcdWriteData(0x65);

LcdWriteData(0x00);

LcdWriteData(0x76);

LcdWriteData(0x00);

LcdWriteData(0x88);

LcdWriteData(0x00);


LcdWriteReg(0xC6);

LcdWriteData(0x20);

LcdWriteData(0x00);

LcdWriteData(0x17);

LcdWriteData(0x00);

LcdWriteData(0x01);

LcdWriteData(0x00);


LcdWriteReg(0xC7);

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。