电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
厂商活动
正点原子
板卡试用
资源库
下载
文章
社区首页
文章
STM32F103 之 8080/SPI并口 OLED实战总结 贪吃蛇游戏
分 享
扫描二维码分享
STM32F103 之 8080/SPI并口 OLED实战总结 贪吃蛇游戏
STM32
oled
Hello Pointer!!!
关注
发布时间: 2019-11-08
丨
阅读: 8352
今天,我们主要来介绍一下STM32F103ZET6,驱动OLED步骤和实际效果。 OLED 主要特点: 色彩丰富 驱动简单 高分辨率 接口丰富: 6800 8080 并口 SPI IIC 3.3v 供电 (不兼容5v) 前1/4 是黄色 后3/4 是蓝色 ![OLED](https://cf04.ickimg.com/bbsimages/201911/b0305c6250e44cb9e037d4ea7a96c1d9.png "OLED") | 接口方式 | 4线SPI | IIC | 8位6800 | 8位8080 | | :- | :- | :- | :- | :- | | BS1 | 0 | 1 | 0 | 1 | | BS2 | 0 | 0 | 1 | 1 | 8080并口 接口说明 CS: OLED 片选信号 WR: 向OLED写入数据 RD: 从OLED读数据 D[7:0]: 8位双向数据线 RST: 硬件复位OLED DC: 命令数据标志(0:读写命令 1:读写数据) OLED控制器为 SSD1306 程序源码链接: https://pan.baidu.com/s/1pzTTHjVWin1cmetuFK1HkA 提取码: pocd ![接线](https://cf04.ickimg.com/bbsimages/201911/5ac22a57e95bbc8459e6ad735e1941c6.png "接线") OLED 8080并口 OLED模块显存 SSD1306的显存总共为128*64bit大小,分为8页,每页128字节,每行128bit,共8页, ![](https://cf04.ickimg.com/bbsimages/201911/8239705f2212b543827983971361b54a.png) OLED的显示原理: 建立一个 128*8的数组,每次只修改数组内容每次修改之后再写入到OLED的GRAM中,(但是不利于SRAM较小的单片机) ![](https://cf04.ickimg.com/bbsimages/201911/35e1d9afbb4d8e89739ea95ee79573a6.png) 命令0x81 设置对比度 包含两个字节,第一个0x81为命令,随后发送的一个字节为要设置的对比度值,对比度越大屏幕越亮。 命令 0xAE/0xAF: 0xAE关闭显示命令 0xAF开启显示命令 命令 0X8D 包含两个字节,第一个为命令字节第二个为设置值,第二个字节为电荷泵的开关状态 1开 0关 ,初始化应该开启 命令 0xB0 -0xB7 用于设置页地址,其低三位的值对应GRAM的页地址 命令 0x00 -0x0f 用于设置显示时的起始列地址低四位 命令 0x10 -0x1f 用于设置显示时的起始列地址高四位 ![贪吃蛇程序效果1](https://cf04.ickimg.com/bbsimages/201911/ae86cd78c66196d13faf4eab608decf0.jpg "贪吃蛇程序效果1") ![贪吃蛇程序效果2](https://cf04.ickimg.com/bbsimages/201911/355bef98c57635f5b7d57cd38cffa968.jpg "贪吃蛇程序效果2") ![贪吃蛇程序效果3](https://cf04.ickimg.com/bbsimages/201911/8a91dba3ef80b433d650e639e518180d.jpg "贪吃蛇程序效果3") led.h 文件 ```c #ifndef __OLED_H #define __OLED_H #include "stm32f10x.h" /@@****************************port definition*********************************/ #define OLED_CS_Set() GPIO_SetBits(GPIOD,GPIO_Pin_3); #define OLED_CS_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_3); #define OLED_RST_Set() GPIO_SetBits(GPIOD,GPIO_Pin_4); #define OLED_RST_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_4); #define OLED_DC_Set() GPIO_SetBits(GPIOD,GPIO_Pin_5); #define OLED_DC_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_5); #define OLED_SCLK_Set() GPIO_SetBits(GPIOD,GPIO_Pin_6); #define OLED_SCLK_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_6); #define OLED_SDIN_Set() GPIO_SetBits(GPIOD,GPIO_Pin_7); #define OLED_SDIN_Clr() GPIO_ResetBits(GPIOD,GPIO_Pin_7); #define OLED_DATA 1 //Write data #define OLED_CMD 0 //Write command #define OLED_PAGE_Address 0xB0 #define OLED_LINE_Address_H 0x10 #define OLED_LINE_Address_L 0x00 #define OLED_MODE 0 #define SIZE 16 #define XLevelL 0x00 #define XLevelH 0x10 #define Max_Column 128 #define Max_Row 64 #define Brightness 0xFF #define X_WIDTH 128 #define Y_WIDTH 64 void OLED_Configuration(void); void OLED_Init(void); void OLED_WR_Byte(uint8_t DATA,uint8_t CMD); void OLED_Set_Address(uint8_t page,uint8_t column); void OLED_Clear(uint8_t data); void OLED_ShowChar(u8 x,u8 y,u8 chr); u32 oled_pow(u8 m,u8 n); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size); void OLED_ShowString(u8 x,u8 y,u8 *chr); #endif ``` led.c 文件 ```c #include "include.h" #include "oledfont.h" /@@************************************************* 函数名 oled初始化 配置OLED 引脚 输入参数 无 输出参数 无 **************************************************/ void OLED_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//ÍÆÍìÊä³ö GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOD,&GPIO_InitStructure); GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7); } void OLED_Init(void) { OLED_RST_Set(); delay_ms(100); OLED_RST_Clr(); delay_ms(100); OLED_RST_Set(); OLED_WR_Byte(0xAE,OLED_CMD);//Set display off OLED_WR_Byte(0x00,OLED_CMD);//set low column address OLED_WR_Byte(0x10,OLED_CMD);//set high column address OLED_WR_Byte(0x40,OLED_CMD);//set start line address Set Mapping RAM Display Start Line (0x00~0x3F) OLED_WR_Byte(0x81,OLED_CMD);//Set contrast control OLED_WR_Byte(0xCF,OLED_CMD);//Select1-256 OLED_WR_Byte(0xA4,OLED_CMD);//Disable entire display OLED_WR_Byte(0xA6,OLED_CMD);//Set normal display OLED_WR_Byte(0xAF,OLED_CMD);//Set display on OLED_WR_Byte(0x20,OLED_CMD);//Set memory addressing mode OLED_WR_Byte(0x02,OLED_CMD);//Set page addressing mode OLED_WR_Byte(0xA1,OLED_CMD);//Disable segment re-map OLED_WR_Byte(0xA8,OLED_CMD);//Set multiplex ratio OLED_WR_Byte(0x3F,OLED_CMD);//1/64 duty OLED_WR_Byte(0xC8,OLED_CMD);//Set normal mode scan OLED_WR_Byte(0xD3,OLED_CMD);//Set display offset OLED_WR_Byte(0x00,OLED_CMD);//No offset OLED_WR_Byte(0xDA,OLED_CMD);//Set COM pins hardware configuration OLED_WR_Byte(0x12,OLED_CMD);//Alternative COM pin configuration OLED_WR_Byte(0xD5,OLED_CMD);//Set display clock clock divide OLED_WR_Byte(0x80,OLED_CMD);//100 frames/s OLED_WR_Byte(0xD9,OLED_CMD);//Set pre-charge period OLED_WR_Byte(0xF1,OLED_CMD);//Set pre-charge as 15 clocks,discharge as 1 clock OLED_WR_Byte(0xDB,OLED_CMD);//Set Vcomh deselect level OLED_WR_Byte(0x40,OLED_CMD);//~0.77xVcc OLED_WR_Byte(0x8D,OLED_CMD);//Set DCDC OLED_WR_Byte(0x14,OLED_CMD);//Enable DCDC (0x10 disable) OLED_Clear(0); OLED_Set_Address(0,0); } void OLED_WR_Byte(uint8_t DATA,uint8_t CMD) { uint8_t i; OLED_CS_Clr(); if(CMD) {OLED_DC_Set();} else OLED_DC_Clr(); for(i=0;i<8;i++) { OLED_SCLK_Clr(); if(DATA&0x80) {OLED_SDIN_Set();} else OLED_SDIN_Clr(); OLED_SCLK_Set(); DATA<<=1; } OLED_CS_Set(); OLED_DC_Set(); } void OLED_Set_Address(uint8_t column,uint8_t page) { OLED_WR_Byte(OLED_PAGE_Address+page,OLED_CMD); OLED_WR_Byte(OLED_LINE_Address_L+column%16,OLED_CMD); OLED_WR_Byte(OLED_LINE_Address_H+column/16,OLED_CMD); } void OLED_Clear(uint8_t data) { uint32_t counter_x,counter_y; for(counter_y=0;counter_y<8;counter_y++) { OLED_WR_Byte(OLED_PAGE_Address+counter_y,OLED_CMD); OLED_WR_Byte(OLED_LINE_Address_L,OLED_CMD); OLED_WR_Byte(OLED_LINE_Address_H,OLED_CMD); for(counter_x=0;counter_x<128;counter_x++) OLED_WR_Byte(data,OLED_DATA); } } void OLED_ShowChar(u8 x,u8 y,u8 chr) { unsigned char c=0,i=0; c=chr-' '; if(x>Max_Column-1){x=0;y=y+2;} if(SIZE ==16) { OLED_Set_Address(x,y); for(i=0;i<8;i++) OLED_WR_Byte(F8X16[c*16+i],OLED_DATA); OLED_Set_Address(x,y+1); for(i=0;i<8;i++) OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA); } else { OLED_Set_Address(x,y+1); for(i=0;i<6;i++) OLED_WR_Byte(F6x8[c][i],OLED_DATA); } } u32 oled_pow(u8 m,u8 n) { u32 result=1; while(n--)result*=m; return result; } void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size) { u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { OLED_ShowChar(x+(size/2)*t,y,' '); continue; }else enshow=1; } OLED_ShowChar(x+(size/2)*t,y,temp+'0'); } } void OLED_ShowString(u8 x,u8 y,u8 *chr) { unsigned char j=0; while (chr[j]!='\0') { OLED_ShowChar(x,y,chr[j]); x+=8; if(x>120){x=0;y+=2;} j++; } } ``` OLED初始化流程 复位SSD1306(RST=0 延时10ms RST=1) -> 驱动IC初始化代码(复位所有寄存器,数据手册有代码)->开启显示-> 清0显存->开始显示 ```c void OLED_INIT(void) { //设置io模式,为推挽模式 GPIO_INIT(); //初始化代码,写相关寄存器 OLED_WR_Byte(0xAE,OLED_CMD);//关闭显示 OLED_WR_Byte(0xD5,OLED_CMD);//设置时钟分频因子,震荡频率 OLED_WR_Byte(80,OLED_CMD);//[3:0] 分频因子[7:4] 震荡频率 OLED_WR_Byte(0xA8,OLED_CMD);//设置驱动路数 OLED_WR_Byte(0x3F,OLED_CMD);//默认0x3f(1/64) OLED_WR_Byte(0xD3,OLED_CMD);//设置显示偏移 OLED_WR_Byte(0x00,OLED_CMD);//默认为0 OLED_CLear(); } OLED 写时序 (写一个字节) 向SSD1306写入一个字节 dat 要写入的数据/命令 cmd 数据/命令 标志位 0代表命令 1代表数据```c void OLED_WR_Byte(u8 dat,u8 cmd) { DATAOUT(dat); if(cmd) OLED_RS_Set(); //set 置高 对应时序中的DC else OLED_RS_Clr(); //clr 是置低 OLED_CS_Clr(); OLED_WR_Clr(); OLED_WR_Set();//wr 拉低再拉高 数据就可以写完 OLED_CS_Set(); //片选拉高 OLED_RS_Set();//恢复DC状态 } ![](https://cf04.ickimg.com/bbsimages/201911/e6806c0b34bf7686a625de9973cf8575.png) OLED更新缓存,显示内容 u8 OLED_GRAM[128][8]; void OLED_Refresh_Gram(void) { u8 i, n; for(i=0;i<8;i++) { OLED_WR_Byte(0xb0+i,OLED_CMD);//设置页地址(0-7) OLED_WR_Byte(0x00,OLED_CMD);//设置显示位置——列低地址 OLED_WR_Byte(0x10,OLED_CMD);//设置显示位置——列高地址 for(n=0;n<128;n++)//写入一列数据 OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);//写入数据 } } ![](https://cf04.ickimg.com/bbsimages/201911/62a68f1e270561a3d143499b83002dca.png) OLED画点函数 ```c void OLED_DrawPoint(u8 x,u8 y,u8 t) { u8 pos,bx,temp=0; if(x>127||y>63)return; //超出范围 pos=7-y/8; bx=y%8; temp=1<<(7-bx); if(t)OLED_GRAM[x][pos]|=temp; else OLED_GRAM[x][pos]&=~temp; } ``` OLED 字符显示函数 // 在指定位置显示一个字符, // x 0-127 y 0-63 //mode 0反白显示 1 size 选择字体 12/16/24 ```c void OLED_ShowChar(u8 x, u8 y, u8 chr,u8 size,u8 mode) { u8 temp,t,t1; u8 y0=y; u8 csize=(size/8+((size%8)?1:0))*(size/2);//得到字体一个字符对应点阵集所占的字节数 chr=chr-' ';//得到偏移后的值 for(t=0;t<csize;t++) {="" if(size="=12)temp=asc2_1206[chr][t];//调用1206字体" else="" return;="" 没有的字库="" for(t1="0;t1<8;t1++)" if(temp&0x80)oled_drawpoint(x,y,mode);="" oled_drawpoint(x,y,!mode);="" temp<<="1;" y++;="" if((y-y0)="=size)" y="0;" x++;="" break;="" }="" ```="" 上面的1206="" 1608="" 2412="" 都是对应的字库="" 例如1608就是="" 高度为两个字节="" 宽度为8个字节,一页一共就有16字节="" 码表可以通过字库工具(pctolcd2002)获得<="" div=""> <div class="agreement mt10 c-666"> <input class="vm" type="checkbox" checked="" name="no-use"><span> 我已阅读并同意<a href="/info/agree.html" class="c-0a0" target="_blank">《电子芯吧客文章发布协议》</a></span> </div> <!--提交成功弹框--> <div class="gray-pop"> <div class="success-pop"> <div class="close-pop">x</div> <div class="suc-tip"><img src="//bbsstatic.ickimg.com/bbs/release/img/common/success.png"> 作品提交成功</div> <div class="suc-gray">运营小妹将在24小时内审核稿件,请耐心等待。</div> <div class="suc-gray">审核状态请留意站内信、短信或邮件通知</div> <div class="suc-gray">如有问题请咨询 <span>QQ : 2850579158</span> </div> <div class="pro-btn"> <a href="/ucenter/my-article?type=1">我的文章</a> <a href="/article.html" class="on">返回首页</a> </div> </div> </div> <input type="hidden" value="1024" id="aid"> <!--阅读协议弹框--> <div class="bbs-gray-pop"></div> <div class="warn-agreement fs-12 c-333">请阅读《电子芯吧客文章发布协议》并进行勾</div> </csize;t++)>
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
0
)
Hello Pointer!!!
关注
评论
(3)
登录后可评论,请
登录
或
注册
KVIN
163
天前...
最后一个代码段是网页出错了?
1
回复
发布
Hello Pointer!!!
163
天前...
完整代码可以看链接
0
回复
发布
哈里波菜
60
天前...
有疑问的可以加Q860099671
0
回复
发布
相关文章推荐
MK-米客方德推出工业级存储卡
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交