实验描述:
ALIENTEK OLED模块的控制器是SSD1306,本章,通过STM32来控制该模块显示字符和数字。代码通过SPI与OLED 屏幕相连
OLED 简介:
OLED,即有机发光二极管(OrganicLight-EmittingDiode),又称为有机电激光显示(OrganicElectroluminesenceDisplay,OELD)。OLED由于同时具备自发光,不需背光源、对比度高、厚度薄、视角广、反应速度快、可用于挠曲性面板、使用温度范围广、构造及制程较简单等优异之特性,被认为是下一代的平面显示器新兴应用技术。
SPI:
串口模式使用的信号线有如下几条:CS:OLED片选信号。RST(RES):硬复位OLED。DC:命令/数据标志(0,读写命令;1,读写数据)。SCLK:串行时钟线。在4线串行模式下,D0信号线作为串行时钟线SCLK。SDIN:串行数据线。在4线串行模式下,D1信号线作为串行数据线SDIN。模块的D2需要悬空,其他引脚可以接到GND。在4线串行模式下,只能往模块写数据而不能读数据。在4线SPI模式下,每个数据长度均为8位,在SCLK的上升沿,数据从SDIN移入到SSD1306,并且是高位在前的。DC线还是用作命令/数据的标志线。
相关设置步骤如下:
1)根据连接电路以及OLED模块所设置的通讯模式来设置设置STM32与OLED模块相连接的模块相连接的IO。这一步,先将我们与OLED模块相连的IO口设置为输出。
2)初始化初始化OLED模块,通过对OLED相关寄存器的初始化,来启动OLED的显示。为后续显示字符和数字做准备。
3)通过函数将字符和数字显示到通过函数将字符和数字显示到OLED模块上。通过我们设计的程序,将要显示的字符送到OLED模块上。
软件设计:
OLED_Init函数的结构比较简单,开始是对IO口的初始化,这里我们用了宏定义OLED_MODE来决定要设置的IO口,其他一些初始化序列,我们按照厂家提供的资料来做就可以。OLED_Init函数代码如下:
//初始化SSD1306
voidOLED_Init(void){GPIO_InitTypeDefGPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD|RCC_APB2Periph_GPIOG,ENABLE);//使能PC,D,G端口时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3|GPIO_Pin_6;//PD3,PD6推挽输出
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//速度
50MHzGPIO_Init(GPIOD,&GPIO_InitStructure);//初始化
GPIOD3,6GPIO_SetBits(GPIOD,GPIO_Pin_3|GPIO_Pin_6);//PD3,PD6输出高
#ifOLED_MODE==1GPIO_InitStructure.GPIO_Pin=0xFF;//PC0~7OUT推挽输出
GPIO_Init(GPIOC,&GPIO_InitStructure);GPIO_SetBits(GPIOC,0xFF);//PC0~7输出高//PG13,14,15OUT推挽输出
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;GPIO_Init(GPIOG,&GPIO_InitStructure);//PG13,14,15OUT输出高
GPIO_SetBits(GPIOG,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15);#elseGPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1;//PC0,1OUT推挽输出
GPIO_Init(GPIOC,&GPIO_InitStructure);
GPIO_SetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1);//PC0,1OUT输出高
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15;//PG15OUT推挽输出
RSTGPIO_Init(GPIOG,&GPIO_InitStructure);GPIO_SetBits(GPIOG,GPIO_Pin_15);//PG15OUT输出高
#endifOLED_RST=0;delay_ms(100);OLED_RST=1;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);//默认为
0OLED_WR_Byte(0x40,OLED_CMD);//设置显示开始行
[5:0],行数.OLED_WR_Byte(0x8D,OLED_CMD);//电荷泵设置
OLED_WR_Byte(0x14,OLED_CMD);//bit2,开启/关闭
OLED_WR_Byte(0x20,OLED_CMD);//设置内存地址模式
OLED_WR_Byte(0x02,OLED_CMD);//[1:0],00,列地址模式;01,//行地址模式;10,页地址模式;默认10;
OLED_WR_Byte(0xA1,OLED_CMD);//段重定义设置,bit0:0,0->0;1,0->127;
OLED_WR_Byte(0xC0,OLED_CMD);//设置COM扫描方向;bit3:0,普通模式;1,//重定义模式COM[N-1]->COM0;N:驱动路数
OLED_WR_Byte(0xDA,OLED_CMD);//设置COM硬件引脚配置
OLED_WR_Byte(0x12,OLED_CMD);//[5:4]配置
OLED_WR_Byte(0x81,OLED_CMD);//对比度设置OLED_WR_Byte(0xEF,OLED_CMD);//1~255;默认0X7F(亮度设置,越大越亮)
OLED_WR_Byte(0xD9,OLED_CMD);//设置预充电周期
OLED_WR_Byte(0xf1,OLED_CMD);//[3:0],PHASE1;[7:4],PHASE2;
OLED_WR_Byte(0xDB,OLED_CMD);//设置VCOMH电压倍率
OLED_WR_Byte(0x30,OLED_CMD);//[6:4]000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
OLED_WR_Byte(0xA4,OLED_CMD);//全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
OLED_WR_Byte(0xA6,OLED_CMD);//设置显示方式;bit0:1,反相显示;0,正常显示
OLED_WR_Byte(0xAF,OLED_CMD);//开启显示
OLED_Clear();//清屏
在STM32内部定义了一个GRAMu8OLED_GRAM[128][8];此部分GRAM对应OLED模块上的GRAM。在操作的时候,我们只要修改STM32内部的GRAM就可以了,然后通过OLED_Refresh_Gram函数把GRAM一次刷新到OLED的GRAM上。该函数代码如下:
//更新显存到LED
voidOLED_Refresh_Gram(void){u8i,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);}}
OLED_Refresh_Gram函数先设置页地址,然后写入列地址(也就是纵坐标)
,然后从0开始写入128个字节,写满该页,最后循环把8页的内容都写入,就实现了整个从STM32显存到OLED显存的拷贝。OLED_Refresh_Gram函数还用到了一个外部函数,也就是我们接着要介绍的函数:OLED_WR_Byte,该函数直接和硬件相关,函数代码如下:
#ifOLED_MODE==1
//向SSD1306写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志0,表示命令;1,表示数据;
voidOLED_WR_Byte(u8dat,u8cmd)
{DATAOUT(dat);
if(cmd)OLED_RS_Set();
elseOLED_RS_Clr();
OLED_CS_Clr();
OLED_WR_Clr();
OLED_WR_Set();
OLED_CS_Set();
OLED_RS_Set();
}
#else
//向SSD1306写入一个字节。
//dat:要写入的数据/命令
//cmd:数据/命令标志0,表示命令;1,表示数据;
voidOLED_WR_Byte(u8dat,u8cmd)
{
u8 i;
if(cmd)OLED_RS_Set();else
OLED_RS_Clr();
OLED_CS_Clr();
for(i=0;i<8;i )
{OLED_SCLK_Clr();
if(dat&0x80)
OLED_SDIN_Set();
else
OLED_SDIN_Clr();
OLED_SCLK_Set();
dat<<=1;
}
OLED_CS_Set();
OLED_RS_Set();
}
#endif
OOLED_GRAM[128][8]中的128代表列数(x坐标)
,而8代表的是页,每页又包含8行,总共64行(y坐标)。从高到低对应行数从小到大。
围为:0127;y的范围为:063。因此,
我们可以得出下一个将要介绍的函数:画点函数,函数代码:
voidOLED_DrawPoint(u8x,u8y,u8t)
{
u8pos,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;
elseOLED_GRAM[x][pos]&=~temp;
}
要显示字符,先要有字符的点阵数据,
ASCII常用的字符集总共有95个,我们先要得到这个字符集的点阵数据,可以使用字符提取软件:PCtoLCD2002完美版。该软件可以提供各种字符,包括汉字(字体和大小都可以自己设置)阵
提取,且取模方式可以设置好几种,常用的取模方式,该软件都支持。
在知道了取模方式之后,我们就可以根据取模的方式来编写显示字符的代码了,这里我们
针对以上取模方式的显示字符代码如下:
voidOLED_ShowChar(u8x,u8y,u8chr,u8size,u8mode)
{
u8temp,t,t1;u8y0=y;chr=chr-'';//得到偏移后的值
for(t=0;t<size;t )
{
if(size==12)temp=oled_asc2_1206[chr][t];//调用1206字体
else
temp=oled_asc2_1608[chr][t];//调用1608字体
for(t1=0;t1<8;t1 )
{
if(temp&0x80)OLED_DrawPoint(x,y,mode);
elseOLED_DrawPoint(x,y,!mode);
temp<<=1;
y ;
if((y-y0)==size)
{y=y0;x ;break;}
}
}
}
我们来看看主函数源码:
intmain(void)
{
u8t;
delay_init();//延时函数初始化
NVIC_Configuration();//设置NVIC中断分组2:2位抢占2位响应优先级
LED_Init();//LED端口初始化
OLED_Init();//初始化
OLEDOLED_ShowString(0,0,"0.96'OLEDTEST");
OLED_ShowString(0,16,"ATOM@ALIENTEK");
OLED_ShowString(0,32,"2010/06/3");
OLED_ShowString(0,48,"ASCII:");
OLED_ShowString(63,48,"CODE:");
OLED_Refresh_Gram();
t='';
while(1)
{
OLED_ShowChar(48,48,t,16,1);//显示ASCII字符
OLED_Refresh_Gram();
t ;
if(t>'~')t='';
OLED_ShowNum(103,48,t,3,16);//显示ASCII字符的码值
delay_ms(300);
LED0=!LED0;
}
}
下载验证:
将代码下载到战舰STM32后,可以看到DS0不停的闪烁,提示程序已经在运行了。最后一行不停的显示ASCII字符以及其码值。
来源:CSDN
作者:武汉市海联天下物联网
链接:https://blog.csdn.net/hltx666/article/details/104189059