0.96寸OLED屏幕

	(题外话)为什么选择寄存器来实现,对于初学者而言我非常建议从寄存器配置开始,主要是因为搞单片机本来就是一项接近于底层硬件的工作,不要嫌麻烦。了解硬件外设工作原理和配置过程会对以后的调试有很大帮助。更容易理解库函数开发。

1.硬件资源描述

主控 STM32F103RC
通讯方式 硬件SPI1 +DMA1(DMA可选)
屏幕 0.96寸蓝色OLED屏幕

下面是屏幕图片
在这里插入图片描述
在这里插入图片描述
2.OLED屏幕驱动方法说明
屏幕的话可以在那啥宝上买到大概10块钱,现在应该还没涨价吧。至于买IIC协议的还是SPI协议的就看单片机使用习惯了,个人还是喜欢SPI的,相比IIC讲SPI传输速度更快点。至于NSS是接地还是硬件控制,看个人习惯,我选择的是硬件控制。

	屏幕与单片机接线如下:

#mermaid-svg-NmO8yY498lOhRTNQ .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-NmO8yY498lOhRTNQ .label text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .node rect,#mermaid-svg-NmO8yY498lOhRTNQ .node circle,#mermaid-svg-NmO8yY498lOhRTNQ .node ellipse,#mermaid-svg-NmO8yY498lOhRTNQ .node polygon,#mermaid-svg-NmO8yY498lOhRTNQ .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-NmO8yY498lOhRTNQ .node .label{text-align:center;fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .node.clickable{cursor:pointer}#mermaid-svg-NmO8yY498lOhRTNQ .arrowheadPath{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-NmO8yY498lOhRTNQ .flowchart-link{stroke:#333;fill:none}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel rect{opacity:0.9}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel span{color:#333}#mermaid-svg-NmO8yY498lOhRTNQ .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-NmO8yY498lOhRTNQ .cluster text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-NmO8yY498lOhRTNQ .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-NmO8yY498lOhRTNQ text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .actor-line{stroke:grey}#mermaid-svg-NmO8yY498lOhRTNQ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sequenceNumber{fill:#fff}#mermaid-svg-NmO8yY498lOhRTNQ #sequencenumber{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ #crosshead path{fill:#333;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .messageText{fill:#333;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-NmO8yY498lOhRTNQ .labelText,#mermaid-svg-NmO8yY498lOhRTNQ .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .loopText,#mermaid-svg-NmO8yY498lOhRTNQ .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-NmO8yY498lOhRTNQ .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-NmO8yY498lOhRTNQ .noteText,#mermaid-svg-NmO8yY498lOhRTNQ .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-NmO8yY498lOhRTNQ .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-NmO8yY498lOhRTNQ .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-NmO8yY498lOhRTNQ .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .section{stroke:none;opacity:0.2}#mermaid-svg-NmO8yY498lOhRTNQ .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-NmO8yY498lOhRTNQ .section2{fill:#fff400}#mermaid-svg-NmO8yY498lOhRTNQ .section1,#mermaid-svg-NmO8yY498lOhRTNQ .section3{fill:#fff;opacity:0.2}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle0{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle1{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle2{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle3{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-NmO8yY498lOhRTNQ .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .grid path{stroke-width:0}#mermaid-svg-NmO8yY498lOhRTNQ .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-NmO8yY498lOhRTNQ .task{stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .taskText:not([font-size]){font-size:11px}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-NmO8yY498lOhRTNQ .task.clickable{cursor:pointer}#mermaid-svg-NmO8yY498lOhRTNQ .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-NmO8yY498lOhRTNQ .taskText0,#mermaid-svg-NmO8yY498lOhRTNQ .taskText1,#mermaid-svg-NmO8yY498lOhRTNQ .taskText2,#mermaid-svg-NmO8yY498lOhRTNQ .taskText3{fill:#fff}#mermaid-svg-NmO8yY498lOhRTNQ .task0,#mermaid-svg-NmO8yY498lOhRTNQ .task1,#mermaid-svg-NmO8yY498lOhRTNQ .task2,#mermaid-svg-NmO8yY498lOhRTNQ .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside0,#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside2{fill:#000}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside1,#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside3{fill:#000}#mermaid-svg-NmO8yY498lOhRTNQ .active0,#mermaid-svg-NmO8yY498lOhRTNQ .active1,#mermaid-svg-NmO8yY498lOhRTNQ .active2,#mermaid-svg-NmO8yY498lOhRTNQ .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-NmO8yY498lOhRTNQ .activeText0,#mermaid-svg-NmO8yY498lOhRTNQ .activeText1,#mermaid-svg-NmO8yY498lOhRTNQ .activeText2,#mermaid-svg-NmO8yY498lOhRTNQ .activeText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .done0,#mermaid-svg-NmO8yY498lOhRTNQ .done1,#mermaid-svg-NmO8yY498lOhRTNQ .done2,#mermaid-svg-NmO8yY498lOhRTNQ .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .doneText0,#mermaid-svg-NmO8yY498lOhRTNQ .doneText1,#mermaid-svg-NmO8yY498lOhRTNQ .doneText2,#mermaid-svg-NmO8yY498lOhRTNQ .doneText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .crit0,#mermaid-svg-NmO8yY498lOhRTNQ .crit1,#mermaid-svg-NmO8yY498lOhRTNQ .crit2,#mermaid-svg-NmO8yY498lOhRTNQ .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit0,#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit1,#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit2,#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit0,#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit1,#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit2,#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-NmO8yY498lOhRTNQ .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-NmO8yY498lOhRTNQ .milestoneText{font-style:italic}#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText0,#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText1,#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText2,#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText0,#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText1,#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText2,#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup text .title{font-weight:bolder}#mermaid-svg-NmO8yY498lOhRTNQ g.clickable{cursor:pointer}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-NmO8yY498lOhRTNQ .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-NmO8yY498lOhRTNQ .dashed-line{stroke-dasharray:3}#mermaid-svg-NmO8yY498lOhRTNQ #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ .commit-id,#mermaid-svg-NmO8yY498lOhRTNQ .commit-msg,#mermaid-svg-NmO8yY498lOhRTNQ .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-NmO8yY498lOhRTNQ .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-NmO8yY498lOhRTNQ .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-NmO8yY498lOhRTNQ .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-NmO8yY498lOhRTNQ .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .node circle.state-start{fill:black;stroke:black}#mermaid-svg-NmO8yY498lOhRTNQ .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-NmO8yY498lOhRTNQ #statediagram-barbEnd{fill:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state .divider{stroke:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-NmO8yY498lOhRTNQ .note-edge{stroke-dasharray:5}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-NmO8yY498lOhRTNQ .error-icon{fill:#522}#mermaid-svg-NmO8yY498lOhRTNQ .error-text{fill:#522;stroke:#522}#mermaid-svg-NmO8yY498lOhRTNQ .edge-thickness-normal{stroke-width:2px}#mermaid-svg-NmO8yY498lOhRTNQ .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-NmO8yY498lOhRTNQ .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-NmO8yY498lOhRTNQ .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-NmO8yY498lOhRTNQ .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-NmO8yY498lOhRTNQ .marker{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .marker.cross{stroke:#333}

:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}
#mermaid-svg-NmO8yY498lOhRTNQ {
color: rgba(0, 0, 0, 0.75);
font: ;
}

或者
D0
SCK : PA5
D1
MOSI : PA7
DC
PA1
RES
PA3
NSS
PA4
GND

注意:VDD和GND千万不要搞反了不然10块钱白给(我就烧坏了一个)😂

2.1:怎么和屏幕通讯并配置单片机的通讯

  • 下面这张图是OLED屏幕驱动芯片手册提供的SPI时序List itemCS# :通讯时一定要保持低电平。
    D/C# :就是命令模式选择信号低电平时SDIN(D1)的数据就是命令控制字节。
    SCLK :空闲电平高低无关,从这条时钟线可以看出屏幕是在上升沿锁存数据,下降沿允许数据变化。(这点很重要!)
    SDIN(D1) :8为数据高位在前。

(第三行的时序就是最后两行的组合)

  • 单片机通讯配置
    在这里插入图片描述
    这张图来自STM32F1参考手册
    stm32f1可以将SPI配置成4种通讯时序。对比我们的屏幕,只能选择上升沿采样的两种方式。

如下表:

序号 控制位 描述
1 CPHA=1 CPOL=1 空闲时高电平,第二个边沿采样(上升沿)
2 CPHA=0 CPOL=0 空闲时低电平,第一个边沿采样(上升沿)

下面的例程使用的是上表中序号2。
stm32SPI1寄存器配置如下:

void SPI1_Init(void)
{
	u16 spitest= 0;
	
	RCC->APB2ENR			|= 1<<2;				//IO端口A时钟开启
	RCC->APB2ENR			|= 1<<0;				//辅助功能IO时钟开启
	RCC->APB2ENR			|= 1<<12;				//SPI1时钟开启
	GPIOA->CRL				&= 0x0F00FFFF;			//PA4配置清除(NSS)		PA5配置清除(SCK)		PA7配置清除(MOSI)
	GPIOA->CRL				|= 0xB0BB0000;			//PA4复用功能推挽输出模式,输出模式,最大速度10MHz		PA5 & PA7复用功能推挽输出模式,输出模式,最大速度50MHz
	
	spitest						|= 1<<2;			//配置为主设备
	spitest						|= 1<<9;			//软件从设备管理
	spitest						|= 1<<8;			//NSS输出
	spitest						|= 1<<15;			//选择“单线双向”模式
	spitest						|= 1<<14;			//输出使能(只发模式)
	spitest						&=~(1<<1);			//空闲状态时,SCK保持低电平
	spitest						&=~(1<<0);			//数据采样从第一个时钟边沿开始
	spitest						&=~(1<<11);			//使用8位数据帧格式进行发送/接收
	spitest						&= 0xFFFFFFC7;		//波特率36Mbs= 4.5M/S
	spitest						&=~(1<<7);			//先发送MSB
	SPI1->CR1				   = spitest;
	SPI1->CR2					|= 1<<1;			//TXDMAEN:发送缓冲区DMA使能
	SPI1->CR1					|=1<<6;				//打开SPI设备
}

2.2:DMA
stm32的DMA可是32的一大特色,优点在于它不需要CPU干预,只要DMA被触发就能直接对数据进行搬运。所以使用它可以节省CPU的工作时间用来处理其他任务,在一些大项目中这点尤为突出。详细的配置介绍请参考STM32F1参考手册,这块我就不多言了。直接上代码。

(不想使用DMA的话可以将主函数注释掉的部分取消注释,并在屏幕初始化函数子函数内倒数第二行取消调用DMA函数)

inline static void DMA_OLED_Init(void)
{
	RCC->AHBENR				 |=	1<<0;		//DMA1时钟开启
	DMA1_Channel3->CPAR = (u32)(&(SPI1->DR));//CPAR:外设数据寄存器的基地址
	DMA1_Channel3->CMAR = (u32)(OLED_SRAM);	//CMAR:存储器的基地址
	DMA1_Channel3->CCR |= 0<<14;			//MEM2MEM:非存储器到存储器模式
	DMA1_Channel3->CCR |= 0<<6;				//MINC:不执行外设地址增量操作
	DMA1_Channel3->CCR |= 1<<7;				//MINC:存储器地址增量模式
	DMA1_Channel3->CCR |= 1<<5;				//CIRC:循环模式
	DMA1_Channel3->CCR |= 1<<4;				//DIR :从存储器读
	DMA1_Channel3->CNDTR= 0x400;			//1024个字节
	DMA1_Channel3->CCR |= 1<<0;				//EN  :通道开启

}

2.3:OLED屏幕的初始化及设置
相关的控制命令在屏幕手册中都有,下面要注意的一点就是DC控制要注意时间问题。DC是由GPIO控制的,所以反转速度很快,数据发送相比DC要慢得多。倒数第四行的 Wait_us(10); 就是在调试过程中遇到的问题,从代码上看数据已经发送完成了然后再改变DC命令选择,貌似没问题。但是屏幕一直没反应,用逻辑分析仪抓取时序图后发现该问题,下面附图。例程代码已纠正放心复制。
在这里插入图片描述
图中时序自上而下分别是SCK,MISO,DC。明显看出数据还未发送结束DC已经改变。

分析原因:子函数OLED_SendCmd(unsigned char)是判断发送区是否为空,然后条件式的装入。而硬件SPI则需等待上一个数据发送完成才会再处理刚送进来的数据,同样也需要时间。

代码部分如下

void OLED_Init(void) //初始化函数
{
	#define OLED_DC  	PA1
	#define OLED_RES 	PA3
	#define OLED_NSS 	PA4
	#define OLED_D0  	PA5
	#define OLED_D1  	PA7
	
	GPIOA->CRL				&= 0xFFFF0F0F;	//rs,dc
	GPIOA->CRL				|= 0x00003030;	//
	
	OLED_RES = 0;			 //低电平复位
	Wait_us(100);
	OLED_RES = 1;			 //复位结束
	OLED_DC	 = 0;			 //命令模式
	Wait_us(100);

	OLED_SendCmd(0xAE);//关闭显示
	OLED_SendCmd(0xD5);//设置时钟分频因子,震荡频率
	OLED_SendCmd(0xF0);//[3:0],分频因子;[7:4],震荡频率
	OLED_SendCmd(0x81);//设置对比度
	OLED_SendCmd(0x7F);//128
	OLED_SendCmd(0x8D);//设置电荷泵开关
	OLED_SendCmd(0x14);//开
	OLED_SendCmd(0x20);//设置模式
	OLED_SendCmd(0x00);//设置为水平地址模式
	OLED_SendCmd(0xD3);//行偏移命令
	OLED_SendCmd(0x2A);//校正参数
  	OLED_SendCmd(0x21);//设置列地址的起始和结束的位置
  	OLED_SendCmd(0x00);//0
  	OLED_SendCmd(0x7F);//127   
  	OLED_SendCmd(0x22);//设置页地址的起始和结束的位置
  	OLED_SendCmd(0x00);//0
 	OLED_SendCmd(0x07);//7
	OLED_SendCmd(0xC8);//0xc9上下反置 0xc8正常
 	OLED_SendCmd(0xA1);//0xa0左右反置 0xa1正常
	OLED_SendCmd(0xA4);//全局显示开启;0xa4正常,0xa5无视命令点亮全屏
	OLED_SendCmd(0xA6);//设置显示方式;A7,反相显示;A6,正常显示	
	OLED_SendCmd(0xAF);//开启显示
 	OLED_SendCmd(0x56);
	Wait_us(10);//
	OLED_DC	 = 1;			 //显示数据模式
	DMA_OLED_Init();
	Wait_us(10);//

}

OLED_SendCmd(0xA4);//全局显示开启;0xa4正常,0xa5无视命令点亮全屏
这行代码在程序调试的时候可以将参数改为0xa5判断通讯是否正常。

这个是命令发送函数
OLED屏幕刷新一帧需要128*8个字节,每个字节的每一位控制屏幕的一个像素点(位的0或1表示亮灭),刚好是128 *64个位。

static void OLED_SendCmd(unsigned char ctrl_data)
{
	unsigned char t=200;
	while(! (SPI1->SR & 1<<1) )			//SPI1->SR & 1<<1=1:发送缓冲为空。
	{
		t--;
		if(t<=0)
			break;
	}

	SPI1->DR	= ctrl_data;
}




void OLED_Write(unsigned char ASII,unsigned char ye,unsigned char lie)
{
	char i;
	for(i=0;i<6;i++)
	{
		OLED_SRAM[ye][lie+i]=F6X8[(ASII-32)*6+i];
	}
}

这个是ASII字库,网上能找到太多了。

const unsigned char F6X8[] =
{
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,   // sp
    0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 ,   // !
    0x00, 0x00, 0x07, 0x00, 0x07, 0x00 ,   // "
    0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 ,   // #
    0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 ,   // $
    0x00, 0x62, 0x64, 0x08, 0x13, 0x23 ,   // %
    0x00, 0x36, 0x49, 0x55, 0x22, 0x50 ,   // &
    0x00, 0x00, 0x05, 0x03, 0x00, 0x00 ,   // '
    0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 ,   // (
    0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 ,   // )
    0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 ,   // *
    0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 ,   // +
    0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 ,   // ,
    0x00, 0x08, 0x08, 0x08, 0x08, 0x08 ,   // -
    0x00, 0x00, 0x60, 0x60, 0x00, 0x00 ,   // .
    0x00, 0x20, 0x10, 0x08, 0x04, 0x02 ,   // /
    0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E ,   // 0				//30[16]48
    0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 ,   // 1
    0x00, 0x42, 0x61, 0x51, 0x49, 0x46 ,   // 2
    0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 ,   // 3
    0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 ,   // 4
    0x00, 0x27, 0x45, 0x45, 0x45, 0x39 ,   // 5
    0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 ,   // 6
    0x00, 0x01, 0x71, 0x09, 0x05, 0x03 ,   // 7
    0x00, 0x36, 0x49, 0x49, 0x49, 0x36 ,   // 8
    0x00, 0x06, 0x49, 0x49, 0x29, 0x1E ,   // 9
    0x00, 0x00, 0x36, 0x36, 0x00, 0x00 ,   // :
    0x00, 0x00, 0x56, 0x36, 0x00, 0x00 ,   // ;
    0x00, 0x08, 0x14, 0x22, 0x41, 0x00 ,   // <
    0x00, 0x14, 0x14, 0x14, 0x14, 0x14 ,   // =
    0x00, 0x00, 0x41, 0x22, 0x14, 0x08 ,   // >
    0x00, 0x02, 0x01, 0x51, 0x09, 0x06 ,   // ?
    0x00, 0x32, 0x49, 0x59, 0x51, 0x3E ,   // @
    0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C ,   // A
    0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 ,   // B
    0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 ,   // C
    0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C ,   // D
    0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 ,   // E
    0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 ,   // F
    0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A ,   // G
    0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F ,   // H
    0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 ,   // I
    0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 ,   // J
    0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 ,   // K
    0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 ,   // L
    0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F ,   // M
    0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F ,   // N
    0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E ,   // O
    0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 ,   // P
    0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E ,   // Q
    0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 ,   // R
    0x00, 0x46, 0x49, 0x49, 0x49, 0x31 ,   // S
    0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 ,   // T
    0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F ,   // U
    0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F ,   // V
    0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F ,   // W
    0x00, 0x63, 0x14, 0x08, 0x14, 0x63 ,   // X
    0x00, 0x07, 0x08, 0x70, 0x08, 0x07 ,   // Y
    0x00, 0x61, 0x51, 0x49, 0x45, 0x43 ,   // Z
    0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 ,   // [
    0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 ,   // 55
    0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 ,   // ]
    0x00, 0x04, 0x02, 0x01, 0x02, 0x04 ,   // ^
    0x00, 0x40, 0x40, 0x40, 0x40, 0x40 ,   // _
    0x00, 0x00, 0x01, 0x02, 0x04, 0x00 ,   // '
    0x00, 0x20, 0x54, 0x54, 0x54, 0x78 ,   // a
    0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 ,   // b
    0x00, 0x38, 0x44, 0x44, 0x44, 0x20 ,   // c
    0x00, 0x38, 0x44, 0x44, 0x48, 0x7F ,   // d
    0x00, 0x38, 0x54, 0x54, 0x54, 0x18 ,   // e
    0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 ,   // f
    0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C ,   // g
    0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 ,   // h
    0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 ,   // i
    0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 ,   // j
    0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 ,   // k
    0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 ,   // l
    0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 ,   // m
    0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 ,   // n
    0x00, 0x38, 0x44, 0x44, 0x44, 0x38 ,   // o
    0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 ,   // p
    0x00, 0x18, 0x24, 0x24, 0x18, 0xFC ,   // q
    0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 ,   // r
    0x00, 0x48, 0x54, 0x54, 0x54, 0x20 ,   // s
    0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 ,   // t
    0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C ,   // u
    0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C ,   // v
    0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C ,   // w
    0x00, 0x44, 0x28, 0x10, 0x28, 0x44 ,   // x
    0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C ,   // y
    0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 ,   // z
    0x14, 0x14, 0x14, 0x14, 0x14, 0x14     // horiz lines
};

这个是用到的延时初始化函数和ms级延时函数

inline void Wait_Init(void)
{
	SysTick->CTRL			&= (unsigned int)(~(1<<0));			//关闭SysTick定时器
	SysTick->CTRL			&= (unsigned int)(~(1<<2));			//9MHz
	SysTick->CTRL			&= (unsigned int)(~(1<<1));			//不产生下溢中断
}
void Wait_ms(unsigned int t)
{
#define ms_t 9000
	SysTick->LOAD			 = ms_t;				//1ms定时
	SysTick->VAL			 = 0;						//当前值清零
	SysTick->CTRL			|= 1<<0;				//打开SysTick定时器
	while(t)
	{
		if(SysTick->CTRL & 1<<16)				//判断下溢
		{t--;}
	}
}

下面是主函数
注意:前面用到的子函数请做好声明

unsigned char OLED_SRAM[8][128]; //图像储存
extern const unsigned char F6X8[];

int main()
{
	Wait_Init();//这里的延时函数我用的是SYSTICK
	SPI1_Init();
	OLED_Init();
	OLED_Write('L',0,0);
	OLED_Write('i',0,6);
	OLED_Write('a',0,12);
	OLED_Write('n',0,18);
	OLED_Write('g',0,24);
	while(1)
	{
//		for(j=0;j<8;j++)
//		{
//				for(i=0;i<128;i++)
//					OLED_Write(OLED_SRAM[j][i]);
//		}
		
	}
}

结果





在这里插入图片描述

如果有问题欢迎指正和讨论

版权声明:本文为CSDN博主「呆萌球球」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45615478/article/details/118404609

	(题外话)为什么选择寄存器来实现,对于初学者而言我非常建议从寄存器配置开始,主要是因为搞单片机本来就是一项接近于底层硬件的工作,不要嫌麻烦。了解硬件外设工作原理和配置过程会对以后的调试有很大帮助。更容易理解库函数开发。

1.硬件资源描述

主控 STM32F103RC
通讯方式 硬件SPI1 +DMA1(DMA可选)
屏幕 0.96寸蓝色OLED屏幕

下面是屏幕图片
在这里插入图片描述
在这里插入图片描述
2.OLED屏幕驱动方法说明
屏幕的话可以在那啥宝上买到大概10块钱,现在应该还没涨价吧。至于买IIC协议的还是SPI协议的就看单片机使用习惯了,个人还是喜欢SPI的,相比IIC讲SPI传输速度更快点。至于NSS是接地还是硬件控制,看个人习惯,我选择的是硬件控制。

	屏幕与单片机接线如下:

#mermaid-svg-NmO8yY498lOhRTNQ .label{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);fill:#333;color:#333}#mermaid-svg-NmO8yY498lOhRTNQ .label text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .node rect,#mermaid-svg-NmO8yY498lOhRTNQ .node circle,#mermaid-svg-NmO8yY498lOhRTNQ .node ellipse,#mermaid-svg-NmO8yY498lOhRTNQ .node polygon,#mermaid-svg-NmO8yY498lOhRTNQ .node path{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-NmO8yY498lOhRTNQ .node .label{text-align:center;fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .node.clickable{cursor:pointer}#mermaid-svg-NmO8yY498lOhRTNQ .arrowheadPath{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .edgePath .path{stroke:#333;stroke-width:1.5px}#mermaid-svg-NmO8yY498lOhRTNQ .flowchart-link{stroke:#333;fill:none}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel{background-color:#e8e8e8;text-align:center}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel rect{opacity:0.9}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel span{color:#333}#mermaid-svg-NmO8yY498lOhRTNQ .cluster rect{fill:#ffffde;stroke:#aa3;stroke-width:1px}#mermaid-svg-NmO8yY498lOhRTNQ .cluster text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:12px;background:#ffffde;border:1px solid #aa3;border-radius:2px;pointer-events:none;z-index:100}#mermaid-svg-NmO8yY498lOhRTNQ .actor{stroke:#ccf;fill:#ECECFF}#mermaid-svg-NmO8yY498lOhRTNQ text.actor>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .actor-line{stroke:grey}#mermaid-svg-NmO8yY498lOhRTNQ .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .messageLine1{stroke-width:1.5;stroke-dasharray:2, 2;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ #arrowhead path{fill:#333;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sequenceNumber{fill:#fff}#mermaid-svg-NmO8yY498lOhRTNQ #sequencenumber{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ #crosshead path{fill:#333;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .messageText{fill:#333;stroke:#333}#mermaid-svg-NmO8yY498lOhRTNQ .labelBox{stroke:#ccf;fill:#ECECFF}#mermaid-svg-NmO8yY498lOhRTNQ .labelText,#mermaid-svg-NmO8yY498lOhRTNQ .labelText>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .loopText,#mermaid-svg-NmO8yY498lOhRTNQ .loopText>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .loopLine{stroke-width:2px;stroke-dasharray:2, 2;stroke:#ccf;fill:#ccf}#mermaid-svg-NmO8yY498lOhRTNQ .note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-NmO8yY498lOhRTNQ .noteText,#mermaid-svg-NmO8yY498lOhRTNQ .noteText>tspan{fill:#000;stroke:none}#mermaid-svg-NmO8yY498lOhRTNQ .activation0{fill:#f4f4f4;stroke:#666}#mermaid-svg-NmO8yY498lOhRTNQ .activation1{fill:#f4f4f4;stroke:#666}#mermaid-svg-NmO8yY498lOhRTNQ .activation2{fill:#f4f4f4;stroke:#666}#mermaid-svg-NmO8yY498lOhRTNQ .mermaid-main-font{font-family:"trebuchet ms", verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .section{stroke:none;opacity:0.2}#mermaid-svg-NmO8yY498lOhRTNQ .section0{fill:rgba(102,102,255,0.49)}#mermaid-svg-NmO8yY498lOhRTNQ .section2{fill:#fff400}#mermaid-svg-NmO8yY498lOhRTNQ .section1,#mermaid-svg-NmO8yY498lOhRTNQ .section3{fill:#fff;opacity:0.2}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle0{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle1{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle2{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle3{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .sectionTitle{text-anchor:start;font-size:11px;text-height:14px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .grid .tick{stroke:#d3d3d3;opacity:0.8;shape-rendering:crispEdges}#mermaid-svg-NmO8yY498lOhRTNQ .grid .tick text{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .grid path{stroke-width:0}#mermaid-svg-NmO8yY498lOhRTNQ .today{fill:none;stroke:red;stroke-width:2px}#mermaid-svg-NmO8yY498lOhRTNQ .task{stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .taskText{text-anchor:middle;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .taskText:not([font-size]){font-size:11px}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideRight{fill:#000;text-anchor:start;font-size:11px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideLeft{fill:#000;text-anchor:end;font-size:11px}#mermaid-svg-NmO8yY498lOhRTNQ .task.clickable{cursor:pointer}#mermaid-svg-NmO8yY498lOhRTNQ .taskText.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideLeft.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutsideRight.clickable{cursor:pointer;fill:#003163 !important;font-weight:bold}#mermaid-svg-NmO8yY498lOhRTNQ .taskText0,#mermaid-svg-NmO8yY498lOhRTNQ .taskText1,#mermaid-svg-NmO8yY498lOhRTNQ .taskText2,#mermaid-svg-NmO8yY498lOhRTNQ .taskText3{fill:#fff}#mermaid-svg-NmO8yY498lOhRTNQ .task0,#mermaid-svg-NmO8yY498lOhRTNQ .task1,#mermaid-svg-NmO8yY498lOhRTNQ .task2,#mermaid-svg-NmO8yY498lOhRTNQ .task3{fill:#8a90dd;stroke:#534fbc}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside0,#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside2{fill:#000}#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside1,#mermaid-svg-NmO8yY498lOhRTNQ .taskTextOutside3{fill:#000}#mermaid-svg-NmO8yY498lOhRTNQ .active0,#mermaid-svg-NmO8yY498lOhRTNQ .active1,#mermaid-svg-NmO8yY498lOhRTNQ .active2,#mermaid-svg-NmO8yY498lOhRTNQ .active3{fill:#bfc7ff;stroke:#534fbc}#mermaid-svg-NmO8yY498lOhRTNQ .activeText0,#mermaid-svg-NmO8yY498lOhRTNQ .activeText1,#mermaid-svg-NmO8yY498lOhRTNQ .activeText2,#mermaid-svg-NmO8yY498lOhRTNQ .activeText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .done0,#mermaid-svg-NmO8yY498lOhRTNQ .done1,#mermaid-svg-NmO8yY498lOhRTNQ .done2,#mermaid-svg-NmO8yY498lOhRTNQ .done3{stroke:grey;fill:#d3d3d3;stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .doneText0,#mermaid-svg-NmO8yY498lOhRTNQ .doneText1,#mermaid-svg-NmO8yY498lOhRTNQ .doneText2,#mermaid-svg-NmO8yY498lOhRTNQ .doneText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .crit0,#mermaid-svg-NmO8yY498lOhRTNQ .crit1,#mermaid-svg-NmO8yY498lOhRTNQ .crit2,#mermaid-svg-NmO8yY498lOhRTNQ .crit3{stroke:#f88;fill:red;stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit0,#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit1,#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit2,#mermaid-svg-NmO8yY498lOhRTNQ .activeCrit3{stroke:#f88;fill:#bfc7ff;stroke-width:2}#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit0,#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit1,#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit2,#mermaid-svg-NmO8yY498lOhRTNQ .doneCrit3{stroke:#f88;fill:#d3d3d3;stroke-width:2;cursor:pointer;shape-rendering:crispEdges}#mermaid-svg-NmO8yY498lOhRTNQ .milestone{transform:rotate(45deg) scale(0.8, 0.8)}#mermaid-svg-NmO8yY498lOhRTNQ .milestoneText{font-style:italic}#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText0,#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText1,#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText2,#mermaid-svg-NmO8yY498lOhRTNQ .doneCritText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText0,#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText1,#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText2,#mermaid-svg-NmO8yY498lOhRTNQ .activeCritText3{fill:#000 !important}#mermaid-svg-NmO8yY498lOhRTNQ .titleText{text-anchor:middle;font-size:18px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup text{fill:#9370db;stroke:none;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family);font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup text .title{font-weight:bolder}#mermaid-svg-NmO8yY498lOhRTNQ g.clickable{cursor:pointer}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ g.classGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5}#mermaid-svg-NmO8yY498lOhRTNQ .classLabel .label{fill:#9370db;font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ .relation{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-NmO8yY498lOhRTNQ .dashed-line{stroke-dasharray:3}#mermaid-svg-NmO8yY498lOhRTNQ #compositionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #compositionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #aggregationStart{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #aggregationEnd{fill:#ECECFF;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #dependencyStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #dependencyEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #extensionStart{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ #extensionEnd{fill:#9370db;stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ .commit-id,#mermaid-svg-NmO8yY498lOhRTNQ .commit-msg,#mermaid-svg-NmO8yY498lOhRTNQ .branch-label{fill:lightgrey;color:lightgrey;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .pieTitleText{text-anchor:middle;font-size:25px;fill:#000;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .slice{font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup text{fill:#9370db;stroke:none;font-size:10px;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup text{fill:#9370db;fill:#333;stroke:none;font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ g.statediagram-cluster .cluster-label text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup .state-title{font-weight:bolder;fill:#000}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup rect{fill:#ECECFF;stroke:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ g.stateGroup line{stroke:#9370db;stroke-width:1}#mermaid-svg-NmO8yY498lOhRTNQ .transition{stroke:#9370db;stroke-width:1;fill:none}#mermaid-svg-NmO8yY498lOhRTNQ .stateGroup .composit{fill:white;border-bottom:1px}#mermaid-svg-NmO8yY498lOhRTNQ .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px}#mermaid-svg-NmO8yY498lOhRTNQ .state-note{stroke:#aa3;fill:#fff5ad}#mermaid-svg-NmO8yY498lOhRTNQ .state-note text{fill:black;stroke:none;font-size:10px}#mermaid-svg-NmO8yY498lOhRTNQ .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.7}#mermaid-svg-NmO8yY498lOhRTNQ .edgeLabel text{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .stateLabel text{fill:#000;font-size:10px;font-weight:bold;font-family:'trebuchet ms', verdana, arial;font-family:var(--mermaid-font-family)}#mermaid-svg-NmO8yY498lOhRTNQ .node circle.state-start{fill:black;stroke:black}#mermaid-svg-NmO8yY498lOhRTNQ .node circle.state-end{fill:black;stroke:white;stroke-width:1.5}#mermaid-svg-NmO8yY498lOhRTNQ #statediagram-barbEnd{fill:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster rect{fill:#ECECFF;stroke:#9370db;stroke-width:1px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster rect.outer{rx:5px;ry:5px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state .divider{stroke:#9370db}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state .title-state{rx:5px;ry:5px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster.statediagram-cluster .inner{fill:white}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster.statediagram-cluster-alt .inner{fill:#e0e0e0}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-cluster .inner{rx:0;ry:0}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state rect.basic{rx:5px;ry:5px}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#efefef}#mermaid-svg-NmO8yY498lOhRTNQ .note-edge{stroke-dasharray:5}#mermaid-svg-NmO8yY498lOhRTNQ .statediagram-note rect{fill:#fff5ad;stroke:#aa3;stroke-width:1px;rx:0;ry:0}:root{--mermaid-font-family: '"trebuchet ms", verdana, arial';--mermaid-font-family: "Comic Sans MS", "Comic Sans", cursive}#mermaid-svg-NmO8yY498lOhRTNQ .error-icon{fill:#522}#mermaid-svg-NmO8yY498lOhRTNQ .error-text{fill:#522;stroke:#522}#mermaid-svg-NmO8yY498lOhRTNQ .edge-thickness-normal{stroke-width:2px}#mermaid-svg-NmO8yY498lOhRTNQ .edge-thickness-thick{stroke-width:3.5px}#mermaid-svg-NmO8yY498lOhRTNQ .edge-pattern-solid{stroke-dasharray:0}#mermaid-svg-NmO8yY498lOhRTNQ .edge-pattern-dashed{stroke-dasharray:3}#mermaid-svg-NmO8yY498lOhRTNQ .edge-pattern-dotted{stroke-dasharray:2}#mermaid-svg-NmO8yY498lOhRTNQ .marker{fill:#333}#mermaid-svg-NmO8yY498lOhRTNQ .marker.cross{stroke:#333}

:root { --mermaid-font-family: "trebuchet ms", verdana, arial;}
#mermaid-svg-NmO8yY498lOhRTNQ {
color: rgba(0, 0, 0, 0.75);
font: ;
}

或者
D0
SCK : PA5
D1
MOSI : PA7
DC
PA1
RES
PA3
NSS
PA4
GND

注意:VDD和GND千万不要搞反了不然10块钱白给(我就烧坏了一个)😂

2.1:怎么和屏幕通讯并配置单片机的通讯

  • 下面这张图是OLED屏幕驱动芯片手册提供的SPI时序List itemCS# :通讯时一定要保持低电平。
    D/C# :就是命令模式选择信号低电平时SDIN(D1)的数据就是命令控制字节。
    SCLK :空闲电平高低无关,从这条时钟线可以看出屏幕是在上升沿锁存数据,下降沿允许数据变化。(这点很重要!)
    SDIN(D1) :8为数据高位在前。

(第三行的时序就是最后两行的组合)

  • 单片机通讯配置
    在这里插入图片描述
    这张图来自STM32F1参考手册
    stm32f1可以将SPI配置成4种通讯时序。对比我们的屏幕,只能选择上升沿采样的两种方式。

如下表:

序号 控制位 描述
1 CPHA=1 CPOL=1 空闲时高电平,第二个边沿采样(上升沿)
2 CPHA=0 CPOL=0 空闲时低电平,第一个边沿采样(上升沿)

下面的例程使用的是上表中序号2。
stm32SPI1寄存器配置如下:

void SPI1_Init(void)
{
	u16 spitest= 0;
	
	RCC->APB2ENR			|= 1<<2;				//IO端口A时钟开启
	RCC->APB2ENR			|= 1<<0;				//辅助功能IO时钟开启
	RCC->APB2ENR			|= 1<<12;				//SPI1时钟开启
	GPIOA->CRL				&= 0x0F00FFFF;			//PA4配置清除(NSS)		PA5配置清除(SCK)		PA7配置清除(MOSI)
	GPIOA->CRL				|= 0xB0BB0000;			//PA4复用功能推挽输出模式,输出模式,最大速度10MHz		PA5 & PA7复用功能推挽输出模式,输出模式,最大速度50MHz
	
	spitest						|= 1<<2;			//配置为主设备
	spitest						|= 1<<9;			//软件从设备管理
	spitest						|= 1<<8;			//NSS输出
	spitest						|= 1<<15;			//选择“单线双向”模式
	spitest						|= 1<<14;			//输出使能(只发模式)
	spitest						&=~(1<<1);			//空闲状态时,SCK保持低电平
	spitest						&=~(1<<0);			//数据采样从第一个时钟边沿开始
	spitest						&=~(1<<11);			//使用8位数据帧格式进行发送/接收
	spitest						&= 0xFFFFFFC7;		//波特率36Mbs= 4.5M/S
	spitest						&=~(1<<7);			//先发送MSB
	SPI1->CR1				   = spitest;
	SPI1->CR2					|= 1<<1;			//TXDMAEN:发送缓冲区DMA使能
	SPI1->CR1					|=1<<6;				//打开SPI设备
}

2.2:DMA
stm32的DMA可是32的一大特色,优点在于它不需要CPU干预,只要DMA被触发就能直接对数据进行搬运。所以使用它可以节省CPU的工作时间用来处理其他任务,在一些大项目中这点尤为突出。详细的配置介绍请参考STM32F1参考手册,这块我就不多言了。直接上代码。

(不想使用DMA的话可以将主函数注释掉的部分取消注释,并在屏幕初始化函数子函数内倒数第二行取消调用DMA函数)

inline static void DMA_OLED_Init(void)
{
	RCC->AHBENR				 |=	1<<0;		//DMA1时钟开启
	DMA1_Channel3->CPAR = (u32)(&(SPI1->DR));//CPAR:外设数据寄存器的基地址
	DMA1_Channel3->CMAR = (u32)(OLED_SRAM);	//CMAR:存储器的基地址
	DMA1_Channel3->CCR |= 0<<14;			//MEM2MEM:非存储器到存储器模式
	DMA1_Channel3->CCR |= 0<<6;				//MINC:不执行外设地址增量操作
	DMA1_Channel3->CCR |= 1<<7;				//MINC:存储器地址增量模式
	DMA1_Channel3->CCR |= 1<<5;				//CIRC:循环模式
	DMA1_Channel3->CCR |= 1<<4;				//DIR :从存储器读
	DMA1_Channel3->CNDTR= 0x400;			//1024个字节
	DMA1_Channel3->CCR |= 1<<0;				//EN  :通道开启

}

2.3:OLED屏幕的初始化及设置
相关的控制命令在屏幕手册中都有,下面要注意的一点就是DC控制要注意时间问题。DC是由GPIO控制的,所以反转速度很快,数据发送相比DC要慢得多。倒数第四行的 Wait_us(10); 就是在调试过程中遇到的问题,从代码上看数据已经发送完成了然后再改变DC命令选择,貌似没问题。但是屏幕一直没反应,用逻辑分析仪抓取时序图后发现该问题,下面附图。例程代码已纠正放心复制。
在这里插入图片描述
图中时序自上而下分别是SCK,MISO,DC。明显看出数据还未发送结束DC已经改变。

分析原因:子函数OLED_SendCmd(unsigned char)是判断发送区是否为空,然后条件式的装入。而硬件SPI则需等待上一个数据发送完成才会再处理刚送进来的数据,同样也需要时间。

代码部分如下

void OLED_Init(void) //初始化函数
{
	#define OLED_DC  	PA1
	#define OLED_RES 	PA3
	#define OLED_NSS 	PA4
	#define OLED_D0  	PA5
	#define OLED_D1  	PA7
	
	GPIOA->CRL				&= 0xFFFF0F0F;	//rs,dc
	GPIOA->CRL				|= 0x00003030;	//
	
	OLED_RES = 0;			 //低电平复位
	Wait_us(100);
	OLED_RES = 1;			 //复位结束
	OLED_DC	 = 0;			 //命令模式
	Wait_us(100);

	OLED_SendCmd(0xAE);//关闭显示
	OLED_SendCmd(0xD5);//设置时钟分频因子,震荡频率
	OLED_SendCmd(0xF0);//[3:0],分频因子;[7:4],震荡频率
	OLED_SendCmd(0x81);//设置对比度
	OLED_SendCmd(0x7F);//128
	OLED_SendCmd(0x8D);//设置电荷泵开关
	OLED_SendCmd(0x14);//开
	OLED_SendCmd(0x20);//设置模式
	OLED_SendCmd(0x00);//设置为水平地址模式
	OLED_SendCmd(0xD3);//行偏移命令
	OLED_SendCmd(0x2A);//校正参数
  	OLED_SendCmd(0x21);//设置列地址的起始和结束的位置
  	OLED_SendCmd(0x00);//0
  	OLED_SendCmd(0x7F);//127   
  	OLED_SendCmd(0x22);//设置页地址的起始和结束的位置
  	OLED_SendCmd(0x00);//0
 	OLED_SendCmd(0x07);//7
	OLED_SendCmd(0xC8);//0xc9上下反置 0xc8正常
 	OLED_SendCmd(0xA1);//0xa0左右反置 0xa1正常
	OLED_SendCmd(0xA4);//全局显示开启;0xa4正常,0xa5无视命令点亮全屏
	OLED_SendCmd(0xA6);//设置显示方式;A7,反相显示;A6,正常显示	
	OLED_SendCmd(0xAF);//开启显示
 	OLED_SendCmd(0x56);
	Wait_us(10);//
	OLED_DC	 = 1;			 //显示数据模式
	DMA_OLED_Init();
	Wait_us(10);//

}

OLED_SendCmd(0xA4);//全局显示开启;0xa4正常,0xa5无视命令点亮全屏
这行代码在程序调试的时候可以将参数改为0xa5判断通讯是否正常。

这个是命令发送函数
OLED屏幕刷新一帧需要128*8个字节,每个字节的每一位控制屏幕的一个像素点(位的0或1表示亮灭),刚好是128 *64个位。

static void OLED_SendCmd(unsigned char ctrl_data)
{
	unsigned char t=200;
	while(! (SPI1->SR & 1<<1) )			//SPI1->SR & 1<<1=1:发送缓冲为空。
	{
		t--;
		if(t<=0)
			break;
	}

	SPI1->DR	= ctrl_data;
}




void OLED_Write(unsigned char ASII,unsigned char ye,unsigned char lie)
{
	char i;
	for(i=0;i<6;i++)
	{
		OLED_SRAM[ye][lie+i]=F6X8[(ASII-32)*6+i];
	}
}

这个是ASII字库,网上能找到太多了。

const unsigned char F6X8[] =
{
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ,   // sp
    0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 ,   // !
    0x00, 0x00, 0x07, 0x00, 0x07, 0x00 ,   // "
    0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 ,   // #
    0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 ,   // $
    0x00, 0x62, 0x64, 0x08, 0x13, 0x23 ,   // %
    0x00, 0x36, 0x49, 0x55, 0x22, 0x50 ,   // &
    0x00, 0x00, 0x05, 0x03, 0x00, 0x00 ,   // '
    0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 ,   // (
    0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 ,   // )
    0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 ,   // *
    0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 ,   // +
    0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 ,   // ,
    0x00, 0x08, 0x08, 0x08, 0x08, 0x08 ,   // -
    0x00, 0x00, 0x60, 0x60, 0x00, 0x00 ,   // .
    0x00, 0x20, 0x10, 0x08, 0x04, 0x02 ,   // /
    0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E ,   // 0				//30[16]48
    0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 ,   // 1
    0x00, 0x42, 0x61, 0x51, 0x49, 0x46 ,   // 2
    0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 ,   // 3
    0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 ,   // 4
    0x00, 0x27, 0x45, 0x45, 0x45, 0x39 ,   // 5
    0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 ,   // 6
    0x00, 0x01, 0x71, 0x09, 0x05, 0x03 ,   // 7
    0x00, 0x36, 0x49, 0x49, 0x49, 0x36 ,   // 8
    0x00, 0x06, 0x49, 0x49, 0x29, 0x1E ,   // 9
    0x00, 0x00, 0x36, 0x36, 0x00, 0x00 ,   // :
    0x00, 0x00, 0x56, 0x36, 0x00, 0x00 ,   // ;
    0x00, 0x08, 0x14, 0x22, 0x41, 0x00 ,   // <
    0x00, 0x14, 0x14, 0x14, 0x14, 0x14 ,   // =
    0x00, 0x00, 0x41, 0x22, 0x14, 0x08 ,   // >
    0x00, 0x02, 0x01, 0x51, 0x09, 0x06 ,   // ?
    0x00, 0x32, 0x49, 0x59, 0x51, 0x3E ,   // @
    0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C ,   // A
    0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 ,   // B
    0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 ,   // C
    0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C ,   // D
    0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 ,   // E
    0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 ,   // F
    0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A ,   // G
    0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F ,   // H
    0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 ,   // I
    0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 ,   // J
    0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 ,   // K
    0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 ,   // L
    0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F ,   // M
    0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F ,   // N
    0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E ,   // O
    0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 ,   // P
    0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E ,   // Q
    0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 ,   // R
    0x00, 0x46, 0x49, 0x49, 0x49, 0x31 ,   // S
    0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 ,   // T
    0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F ,   // U
    0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F ,   // V
    0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F ,   // W
    0x00, 0x63, 0x14, 0x08, 0x14, 0x63 ,   // X
    0x00, 0x07, 0x08, 0x70, 0x08, 0x07 ,   // Y
    0x00, 0x61, 0x51, 0x49, 0x45, 0x43 ,   // Z
    0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 ,   // [
    0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55 ,   // 55
    0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 ,   // ]
    0x00, 0x04, 0x02, 0x01, 0x02, 0x04 ,   // ^
    0x00, 0x40, 0x40, 0x40, 0x40, 0x40 ,   // _
    0x00, 0x00, 0x01, 0x02, 0x04, 0x00 ,   // '
    0x00, 0x20, 0x54, 0x54, 0x54, 0x78 ,   // a
    0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 ,   // b
    0x00, 0x38, 0x44, 0x44, 0x44, 0x20 ,   // c
    0x00, 0x38, 0x44, 0x44, 0x48, 0x7F ,   // d
    0x00, 0x38, 0x54, 0x54, 0x54, 0x18 ,   // e
    0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 ,   // f
    0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C ,   // g
    0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 ,   // h
    0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 ,   // i
    0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 ,   // j
    0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 ,   // k
    0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 ,   // l
    0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 ,   // m
    0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 ,   // n
    0x00, 0x38, 0x44, 0x44, 0x44, 0x38 ,   // o
    0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 ,   // p
    0x00, 0x18, 0x24, 0x24, 0x18, 0xFC ,   // q
    0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 ,   // r
    0x00, 0x48, 0x54, 0x54, 0x54, 0x20 ,   // s
    0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 ,   // t
    0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C ,   // u
    0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C ,   // v
    0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C ,   // w
    0x00, 0x44, 0x28, 0x10, 0x28, 0x44 ,   // x
    0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C ,   // y
    0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 ,   // z
    0x14, 0x14, 0x14, 0x14, 0x14, 0x14     // horiz lines
};

这个是用到的延时初始化函数和ms级延时函数

inline void Wait_Init(void)
{
	SysTick->CTRL			&= (unsigned int)(~(1<<0));			//关闭SysTick定时器
	SysTick->CTRL			&= (unsigned int)(~(1<<2));			//9MHz
	SysTick->CTRL			&= (unsigned int)(~(1<<1));			//不产生下溢中断
}
void Wait_ms(unsigned int t)
{
#define ms_t 9000
	SysTick->LOAD			 = ms_t;				//1ms定时
	SysTick->VAL			 = 0;						//当前值清零
	SysTick->CTRL			|= 1<<0;				//打开SysTick定时器
	while(t)
	{
		if(SysTick->CTRL & 1<<16)				//判断下溢
		{t--;}
	}
}

下面是主函数
注意:前面用到的子函数请做好声明

unsigned char OLED_SRAM[8][128]; //图像储存
extern const unsigned char F6X8[];

int main()
{
	Wait_Init();//这里的延时函数我用的是SYSTICK
	SPI1_Init();
	OLED_Init();
	OLED_Write('L',0,0);
	OLED_Write('i',0,6);
	OLED_Write('a',0,12);
	OLED_Write('n',0,18);
	OLED_Write('g',0,24);
	while(1)
	{
//		for(j=0;j<8;j++)
//		{
//				for(i=0;i<128;i++)
//					OLED_Write(OLED_SRAM[j][i]);
//		}
		
	}
}

结果





在这里插入图片描述

如果有问题欢迎指正和讨论

版权声明:本文为CSDN博主「呆萌球球」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45615478/article/details/118404609

生成海报
点赞 0

呆萌球球

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

ATmega16智能遥控小车

AVR-ATmega16智能遥控小车 AVR单片机相信不少的伙伴在大学的电设课中接触过,不像51单片机和32单片机的资料这么多,但是学校又要求去学,还要设计结题项目,这是最头疼的。该项目

常兴串口调试助手

1,支持常用的300-9600波特率,能设置端口参数; 2,能以ASCII码或十六进制收发数据,真正支持中文字符的收发; 3,接收到的16进制数据选中后能以10进制和2进制显示。方便查看数

USB转TTL给ESP8266-12F芯片下载程序

物料准备: 最近在写ESP8266的程序,想着自己动手做一块电路板,于是学习了一下怎么给一块ESP8266-12F芯片烧录程序,作为新手小白,过程中遇到了一些问题&#xff0