一、成果展示
功能:
1.贪吃蛇的基本游戏规则
2.有开始和结束界面
3.实现计分功能
4.游戏有无墙和有墙两种模式
5.游戏有简单和困难两种难度
6.在开始和结束时有声音提示
源码链接,提取码:o93u
二、软件部分
1.OLED模块与SSD1306使用
- OLED引脚图
OLED的引脚与SSD1306和单片机的通信方式有关。常见的有SPI,I2C串行通信和并行通信等。博主购买的是7针的OLED模块,引脚详情如下。
引脚 | 名称 | 解释 |
---|---|---|
1 | GND | 接地端 |
2 | VCC | 电源端 |
3 | D0 | 在 SPI 和 I2C 通信中为时钟管脚(SCLK) |
4 | D1 | 在 SPI 和 I2C 通信中为数据管脚(MOSI) |
5 | RES | 复位管脚,低电平有效 |
6 | DC | 数据和命令控制管脚,0写命令,1写数据 |
7 | CS | 片选信号输入端,当输入低电平,表明OLED被选中,若只有OLED通信可直接接地 |
- OLED指令
与LCD1602类似,DC管脚置0之后,向OLED中写入命令,下表为部分指令。
指令 | 解释 |
---|---|
00H-0FH | 页地址模式下设置列起始地址低位 |
10H-1FH | 页地址模式下设置列起始地址高位 |
20H | 设置寻址模式,00H/01H/02H为水平/垂直/页地址模式 |
26H/27H | 设置水平滚动的起始页,终止页和滚动速度 |
29H/2AH | 设置垂直和水平滚动的起始页,终止页,滚动速度,垂直滚动偏移 |
2EH | 禁用滚动,调用后RAM数据需要重写 |
2FH | 启用滚动,在26H/27H/29H/2AH设置好后调用 |
40H-7FH | 设置屏幕(地址)起始行,取值范围为[0,63],一般从头显示 |
81H | 设置对比度,共有256级对比度 |
A0H/A1H | 设置段重映射,A0H左右反置,A1H正常 |
A3H | 设置滚动垂直区 |
A4H/A5H | 设置全屏点亮,A5H无视GDDRAM点亮全屏,A4H正常 |
A6H/A7H | 设置反转显示,A7H反转(0表示点亮),A6H正常(1表示点亮) |
A8H | 设置复用率,默认63 |
AEH/AFH | 设置屏幕开启/关闭,AEH关闭屏幕,AFH开启屏幕 |
B0H-B7H | 页地址模式下设置目标显示位置页起始地址 |
C0H/C8H | 设置列输出扫描方向,C0H左右反置,C8H正常 |
D3H | 设置显示偏移 |
D5H | 设置显示时钟震荡频率 |
D9H | 设置预充电周期 |
DAH | 设置列引脚硬件配置 |
DBH | 设置VCOMH反压值 |
E3H | 空指令,不产生作用 |
- OLED与贪吃蛇
第一,由于OLED模块不能发送数据,所以不能读取OLED显存(GDDRAM)中的值。第二,OLED是对页地址进行整体赋值,贪吃蛇在显示蛇,食物等方面都要求对像素点进行操作。所以在OLED上显示像素点就会有困难。比如说某一页上的数据是 (0100 0000) 。如果想让其他像素点显示,会对这一页重新赋值,比如(0010 0000)。赋值过后,先前的数据就会被覆盖。也就是说一页只能打一个点,因此为了避免这种情况,要记录之前显示过的值,必须要在单片机内部申请一块内存区域充当OLED的显示缓存区,每次打点的时候读取先前的数据进行运算后再给OLED传送数据。
- 在OLED上打印像素点
博主购买的OLED附带中景园电子的部分源码,商家可能考虑到内存问题,就给打点函数删除掉了,博主花了好几天时间,查阅了相关资料,以及学长的帮助下,才完成了下面打印像素点的两个函数。
/*****************************************************************/
unsigned char OLED_GRAM[64][8] = {
0}; //申请一个二维数组作为显存
/*****************************************************************/
//显示地图上的点
//我设置的是y轴向下的坐标系
void OLED_Write_GRAM(u8 x,u8 y,bit value)
{
u8 OLED_page = y/8;
u8 OLED_page_value = 1 << y%8;
if(x>=64)
return;
if(value)OLED_GRAM[x][OLED_page]|=OLED_page_value;
else OLED_GRAM[x][OLED_page]&=~OLED_page_value;
}
/*****************************************************************/
//向OLED传输显存数据
//更新显存到OLED
void OLED_Refresh(void)
{
unsigned char i,n;
for(i=0;i<8;i++)
{
OLED_WR_Byte(0xb0+i,OLED_CMD); //设置行起始地址
OLED_WR_Byte(0x00,OLED_CMD); //设置低列起始地址