1、驱动芯片及MCU介绍
SSD1106是一款常用于嵌入式设备中的小型屏幕OLED(有机发光二极管)显示器驱动芯片 ,被广泛应用于各种嵌入式设备中,本示例程序基于SSD1106驱动芯片的OLED显示屏。
本次示例采用STM32F103系列MCU,使用标准库硬件SPI驱动OLED屏幕,相较于IIC,刷新速度更快更加稳定,本示例程序以刷新显存方式驱动OLED,通过对不同显示页显存处理来实现图标裁剪显示等操作。
显示效果:(小刺猬以100ms移动一个像素点的方式移动)
2、工程说明
本次示例程序需要使用资源如下:
1、一组硬件SPI
2、一个通用定时器用于移动图标刷新时间
3、程序部分
1、主函数
#include "stm32f10x.h"
#include "printfsupport.h"
#include "Timer.h"
#include "OLED_12864.h"
//图片显示函数声明
void Photo_Show(void);
uint8_t abscissa = 0; //图标横坐标
uint8_t ordinate = 16; //图标纵坐标
uint8_t Refresh_Flag = 0; //图标刷新标志
int main(void)
{
//打印信息接口
Printf_Init(115200);
//OLED初始化
OLED_Init();
//定时器2配置
Timer2_Config();
//主循环
while(1)
{
//图片显示
Photo_Show();
}
}
//图片显示测试
void Photo_Show(void)
{
OLED_VRAM_Clear(); //清屏
OLED_VRAM_SymbolWrite(0,0,0,Symbol_Test_Photo); //显示图标
OLED_VRAM_SymbolWrite(abscissa,ordinate,0,Symbol_Hedgehog); //显示图标
OLED_VRAM_RemapReflesh(); //刷新显存
while(1)
{
if(Refresh_Flag)
{
Refresh_Flag = 0;
//擦除图标移动区域显存
OLED_VRAM_AreaClear(0,16,128,48);
//显示图标
OLED_VRAM_SymbolWrite(abscissa,ordinate,0,Symbol_Hedgehog);
//刷新显存
OLED_VRAM_RemapReflesh();
}
}
}
2、用于控制刷新时间和坐标的定时器配置
#include "Timer.h"
extern uint8_t abscissa,ordinate,Refresh_Flag; //图标横坐标 图标纵坐标 刷新标志
//定时器2配置
void Timer2_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 开启定时器时钟,即内部时钟CK_INT=72M
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
TIM_TimeBaseStructure.TIM_Period = 1000 - 1;
// 时钟预分频数
TIM_TimeBaseStructure.TIM_Prescaler = 7200-1;
// 时钟分频因子
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
// 计数器计数模式,设置为向上计数
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
// 重复计数器的值,没用到不用管
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
// 初始化定时器
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
// 清除计数器中断标志位
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
// 开启计数器中断
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
// 设置中断组为
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
// 设置中断来源
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn ;
// 设置主优先级为 3
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;
// 设置抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// 使能计数器
TIM_Cmd(TIM2, ENABLE);
}
//定时器中断
void TIM2_IRQHandler (void)
{
if(TIM_GetITStatus( TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);
//横坐标移动
abscissa ++;
abscissa %= (128-80);
//刷新显存标志
if(Refresh_Flag == 0)
{
Refresh_Flag = 1;
}
}
}
3、硬件OLED配置接口(c源文件) , 图片显示驱动接口篇幅太长,不一一贴出。
#include "stm32f10x.h"
#include "OLED_Symbol.h"
#include "OLED_12864.h"
#include "stdio.h"
#include "string.h"
//OLED虚拟映射内存
uint8_t OLED_VRAM[VRAM_LOGIC_PAGE_MAX][VRAM_LOGIC_COLUMN_MAX];
uint8_t OLED_VRAM1[VRAM_LOGIC_PAGE_MAX][VRAM_LOGIC_COLUMN_MAX];
//延时
void delay_ms(uint32_t time)
{
uint16_t temp=7200;
while(time--)
{
while(temp--){};
}
}
/*-------------------------------SSD1106驱动函数-------------------------------*/
/*************************************************
Function: OLED_Init
Description: 初始化SSD1106
Parameter: None
Return: None
Others: None
*************************************************/
void OLED_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
//时钟配置
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
//SPI1 CS引脚软件控制
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
//SPI1 SCK MOSI引脚硬件控制
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_13|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
// D/C RES引脚软件控制
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
//SPI Configration
SPI_InitStructure.SPI_Direction =SPI_Direction_2Lines_FullDuplex; //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //设置SPI的数据大小:SPI发送接收8位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; //串行同步时钟的空闲状态为高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的第二个跳变沿(上升或下降)数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //NSS信号软件管理
SPI_InitStructure.SPI_BaudRatePrescaler =SPI_BaudRatePrescaler_8; //定义波特率预分频的值:波特率预分频值为8
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
OLED_RST_Set();
delay_ms(100);
OLED_RST_Clr();
delay_ms(100);
OLED_RST_Set();
delay_ms(100);
OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panel
OLED_WR_Byte(0x02,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 register
OLED_WR_Byte(0xCF,OLED_CMD); // Set SEG Output Current Brightness
OLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WR_Byte(0xA6,OLED_CMD);//--set normal display
OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty
OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WR_Byte(0x00,OLED_CMD);//-not offset
OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency
OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
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(0xDA,OLED_CMD);//--set com pins hardware configuration
OLED_WR_Byte(0x12,OLED_CMD);
OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh
OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level
OLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WR_Byte(0x02,OLED_CMD);//
OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disable
OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable
OLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)
OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7)
OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
OLED_WR_Byte(0xAF,OLED_CMD);/*display ON*/
OLED_Clear(); //清屏
OLED_Set_Pos(0,0); //设置原点
}
4、图片资源
#include "stdint.h"
#include "OLED_Symbol.h"
const unsigned char Test_Photo[]=
{
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x88,0x10,0xF8,0x08,0xE8,0x08,0xF8,0x00,0xF0,0x00,0xFC,
0x00,0x44,0xC8,0x00,0x00,0x90,0x90,0x90,0x10,0xFC,0x10,0x14,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x10,0x09,0x27,0x10,0x0F,0x10,0x27,0x00,0x07,0x20,0x3F,
0x00,0x00,0x3F,0x10,0x00,0x10,0x1F,0x08,0x00,0x0F,0x10,0x38,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
const unsigned char Hedgehog[] = {
0x00,0x80,0x80,0xC0,0x30,0x38,0x84,0x06,0x2E,0x0A,0x02,0xC0,0x01,0x01,0x87,0x31,
0x01,0x01,0x03,0x31,0x01,0x00,0x88,0x82,0xE6,0x38,0xC0,0xC0,0xC0,0xC0,0xC0,0xE0,
0xE0,0xC0,0x40,0xC0,0xC0,0xC0,0xC0,0x40,0xC0,0xC0,0xC0,0x80,0x80,0xC0,0x80,0x80,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0xC0,0x41,0x7F,0xA1,0x8C,0x85,0x82,0xFA,0xF6,0x72,0x72,0x5C,0x18,0x1D,0x1D,
0x06,0x06,0x06,0x07,0x02,0x02,0x07,0x07,0x87,0xC1,0x41,0x23,0x13,0x10,0x08,0x48,
0x18,0x1D,0x3C,0x68,0x48,0x91,0x31,0x60,0xC0,0xC0,0x41,0x40,0xE1,0x41,0x01,0x01,
0x03,0x03,0x03,0x02,0x04,0x0C,0x0E,0x18,0x1C,0x78,0x60,0x60,0xF0,0xF0,0xC0,0xC0,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x91,0xD9,0x7E,0x3F,0x37,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0xC0,0x30,0x0C,0x22,0x21,0x04,0x04,0x20,0x00,0x01,0x00,0x88,
0x80,0x01,0x00,0x18,0x80,0x1F,0x08,0x24,0x26,0x18,0x33,0xED,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x09,0x1D,0xFF,0xF9,
0xB8,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x02,0x13,0xDB,0xFF,0x77,0x33,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x0E,0x7F,0x80,0x82,0x02,0x00,0x10,0x10,0x02,0x00,0x20,0x20,0x80,
0x84,0x80,0x80,0x40,0x40,0x2C,0x20,0x10,0x19,0x0C,0x02,0x01,0x00,0x00,0x00,0x00,
0x80,0x60,0x10,0x08,0x80,0x40,0xA0,0xA0,0xC0,0x00,0x20,0xE0,0xF8,0x3A,0x3E,0x0F,
0x0B,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,
0x00,0x00,0x00,0x01,0x0D,0x2F,0x7F,0xF2,0xF0,0xB0,0x80,0x80,0x80,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x03,0x04,0x00,0x00,0xC1,0x06,0x07,0x07,0x81,0x80,0x80,0x00,0x01,0x01,0x81,0x81,
0x83,0x82,0x82,0x82,0x42,0x42,0x62,0x26,0x26,0x32,0x1B,0x18,0x18,0x18,0x0C,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x03,0x07,0x0C,0x3C,0x7C,
0x5C,0x58,0x78,0x78,0x78,0x70,0x30,0x30,0x30,0x30,0x30,0x20,0x30,0x30,0x30,0x38,
0x30,0x10,0x10,0x38,0x38,0x10,0x10,0x18,0x18,0x18,0x38,0x38,0x3C,0x48,0x4C,0x4C,
0x28,0x2C,0x2C,0x1A,0x09,0x08,0x04,0x04,0x04,0x05,0x07,0x07,0x01,0x01,0x01,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};
struct OLED_SymbolStruct Symbol_Test_Photo={128,16,256,1,Test_Photo}; //单个符号宽度128个像素 高度16个像素 占用256个字节 共1个符号 正常显示
struct OLED_SymbolStruct Symbol_Hedgehog={80,47,480,1,Hedgehog}; //单个符号宽度80个像素 高度47个像素 占用480个字节 共1个符号 正常显示
图标定义头文件
#ifndef __OLED_SYMBOL_H
#define __OLED_SYMBOL_H
#include "stdint.h"
#include "stm32f10x.h"
struct OLED_SymbolStruct
{
uint16_t Width; //单个符号宽度 单位像素
uint16_t Height; //单个符号高度 单位像素
uint16_t Bytes; //单个符号占用字节数
uint16_t Number; //全体符号数量
const unsigned char* Symbol_Array; //符号数据数组
};
extern struct OLED_SymbolStruct Symbol_Test_Photo;
extern struct OLED_SymbolStruct Symbol_Hedgehog;
#endif
驱动演示完毕,取模软件为PCtoLCD2002完美版,软件资源及代码均已免费上传,如有需要自取。