为OLED屏增加GUI支持1:OLED驱动

为OLED屏增加GUI支持1:OLED驱动

本文博客链接:http://blog.csdn.net/jdh99,作者:jdh,转载请注明.

说明:
一个可穿戴项目中使用到0.96寸OLED屏,这是一种小尺寸的单色屏,不需要复杂的界面。移植了emwin发现小屏幕单色屏很不合适,控件显示不尽如人意,占用的flash又太大。所以我自己编写一个轻量级的GUI。

GUI简介:
目前已有控件:
1.文本框
2.单色bmp图片显示控件
3.进度条

并支持:
1.中文字库
2.基本的2D绘图功能

显示效果图:
这里写图片描述

下载链接:
http://download.csdn.net/detail/jdh99/9376437

源代码:
驱动函数为GUI提供绘点函数以供调用
drv_lcd.h

/**
* Copyright (c), 2015-2025
* @file drv_lcd.h
* @brief lcd驱动层头文件
* @author jdh
* @date 2015/7/28
* @verbatim 
* 硬件连接说明
* 电路标号          单片机引脚       LCD引脚
* SDI               PB15            D0    
* SCL               PB13            D1
* CS                PB12            CS
* NRST              NRST            RES
* A0                PB1             DC

* SDI               PB13            D0    
* SCL               PB15            D1
* CS                PB12            CS
* NRST              PB10            RES
* A0                PB11            DC
* @endverbatim 
*/

#ifndef _DRV_LCD_H_
#define _DRV_LCD_H_

/*********************************************************************
*                           头文件
**********************************************************************/

#include "stm32f10x.h"

/*********************************************************************
*                           函数
**********************************************************************/

/**
* @brief 初始lcd
*/

void drv_lcd_init(void);

/**
* @brief 画点
* @param x:x坐标
* @param y:y坐标
* @param show:0:不显示,1:显示
*/

void drv_lcd_draw_pixel(uint8_t x,uint8_t y,uint8_t show);

/**
* @brief 打开显示
* @param 0:关闭,1:打开
*/

void drv_lcd_display_set(uint8_t state);

#en

drv_lcd.c

/**
* Copyright (c), 2015-2025
* @file drv_lcd.c
* @brief lcd驱动层主文件
* @author jdh
* @date 2015/7/28
*/

/*********************************************************************
*                           头文件
**********************************************************************/

#include "drv_lcd.h"

/*********************************************************************
*                           宏定义
**********************************************************************/

/**
* @brief 写入模式
*/

//写命令
#define OLED_CMD            0   
//写数据
#define OLED_DATA           1   

/*********************************************************************
*                           静态变量
**********************************************************************/

/**
* @brief OLED的显存
* @verbatim 
* 存放格式如下:
* [0]0 1 2 3 ... 127    
* [1]0 1 2 3 ... 127    
* [2]0 1 2 3 ... 127    
* [3]0 1 2 3 ... 127    
* [4]0 1 2 3 ... 127    
* [5]0 1 2 3 ... 127    
* [6]0 1 2 3 ... 127    
* [7]0 1 2 3 ... 127
* @endverbatim 
*/

static uint8_t OLED_Gram[128][8];   

/*********************************************************************
*                           静态函数
**********************************************************************/

/**
* @brief 初始io
*/

static void init_io(void);

/**
* @brief 初始化spi
*/

static void init_spi(void);

/**
* @brief 初始化SSD1306 
*/

static void init_oled(void);

/**
* @brief 向SSD1306写入一个字节
* @param dat:要写入的数据/命令
* @param cmd:数据/命令标志 0,表示命令;1,表示数据
*/
static void oled_write_byte(uint8_t dat,uint8_t cmd);

/**
* @brief 切换数据或者命令模式
* @param state:0:命令,1:数据
*/

static void oled_dc_set(uint8_t state);

/**
* @brief 片选
* @param mode:0:片选,1:未选
*/

static void oled_cs_set(uint8_t state);

/**
* @brief 更新显存到LCD   
*/

static void oled_refresh_gram(void);

/**
* @brief 清屏
*/

static void oled_clear(void);

/**
* @brief 设置坐标点
* @param x:x坐标
* @param y:y坐标
*/

static void oled_set_pos(uint8_t x,uint8_t y);

/**
* @brief spi发送一个字节
* @param byte:发送的字节
* @retval 读取的字节
*/

static uint8_t spi_send_byte(uint8_t byte);

/*********************************************************************
*                           函数
**********************************************************************/

/**
* @brief 初始lcd
*/

void drv_lcd_init(void)
{
    init_io();
    init_spi();
    init_oled();
}

/**
* @brief 画点
* @param x:x坐标
* @param y:y坐标
* @param show:0:不显示,1:显示
*/

void drv_lcd_draw_pixel(uint8_t x,uint8_t y,uint8_t show)
{
    uint8_t pos = 0;
    uint8_t bx = 0;
    uint8_t temp = 0;

    //设置坐标点
    oled_set_pos(x,y);
    //p岸段是否超出范围
    if (x > 127 || y > 64)
    {
        return;
    }

    pos = 7 - y / 8;
    bx = y % 8;
    temp = 1 << (7 - bx);
    if (show)
    {
        OLED_Gram[x][pos] |= temp;
    }
    else
    {
        OLED_Gram[x][pos] &= ~temp;
    }       

    //设置显示位置—列高地址   
    oled_write_byte(OLED_Gram[x][pos],OLED_DATA); 
}

/**
* @brief 打开显示
* @param 0:关闭,1:打开
*/

void drv_lcd_display_set(uint8_t state)
{
    if (state)
    {
        oled_write_byte(0xAF,OLED_CMD);
    }
    else
    {
        oled_write_byte(0xAE,OLED_CMD);
    }
}

/**
* @brief 初始io
*/

static void init_io(void)
{
    //定义IO初始化结构体
    GPIO_InitTypeDef GPIO_InitStructure;

    //初始化时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    //管脚初始化  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    //选择GPIO响应速度
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
    //设置为输出           
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
    //初始化               
    GPIO_Init(GPIOB, &GPIO_InitStructure); 

    //复位脚
    //初始化时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    //管脚初始化  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    //选择GPIO响应速度
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    
    //设置为输出           
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 
    //初始化               
    GPIO_Init(GPIOB, &GPIO_InitStructure);  
    GPIO_SetBits(GPIOB,GPIO_Pin_10);
}

/*********************************************************************
*                           初始化spi
**********************************************************************/

static void init_spi(void)
{
    //定义IO初始化结构体
    GPIO_InitTypeDef GPIO_InitStructure ;
    //定义SPI初始化结构体
    SPI_InitTypeDef  SPI_InitStructure ;

    //配置其他引脚
    //配置CSN
    //开启时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE ) ;
    //配置SPI引脚CSN
    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 );

    //初始化SPI
    //关闭SPI
    SPI_Cmd(SPI2,DISABLE);
    //初始化SPI时钟  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE);
    //设置IO口时钟      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); 
    //配置SPI1引脚:SCK, MISO and MOSI
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP ;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ;
    GPIO_Init( GPIOB, &GPIO_InitStructure );
    // SPI配置
    //SPI_I2S_DeInit(SPI2);
    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex ;
    SPI_InitStructure.SPI_Mode = SPI_Mode_Master ;
    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b ;
    SPI_InitStructure.SPI_CPOL = SPI_CPOL_High ;
    SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge ;
    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft ;
    //SPI波特率分频设置
    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2 ;
    //SPI设置成LSB模式
    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB ;
    SPI_InitStructure.SPI_CRCPolynomial = 7 ;
    SPI_Init( SPI2, &SPI_InitStructure ) ;

    //启动SPI
    SPI_Cmd(SPI2,ENABLE);
}

/**
* @brief 初始化SSD1306 
*/

static void init_oled(void)
{                                             
    oled_write_byte(0xAE,OLED_CMD); //关闭显示
    oled_write_byte(0xD5,OLED_CMD); //设置时钟分频因子,震荡频率
    oled_write_byte(80,OLED_CMD);   //[3:0],分频因子;[7:4],震荡频率
    oled_write_byte(0xA8,OLED_CMD); //设置驱动路数
    oled_write_byte(0X3F,OLED_CMD); //默认0X3F(1/64) 
    oled_write_byte(0xD3,OLED_CMD); //设置显示偏移
    oled_write_byte(0X00,OLED_CMD); //默认为0

    oled_write_byte(0x40,OLED_CMD); //设置显示开始行 [5:0],行数.

    oled_write_byte(0x8D,OLED_CMD); //电荷泵设置
    oled_write_byte(0x14,OLED_CMD); //bit2,开启/关闭
    oled_write_byte(0x20,OLED_CMD); //设置内存地址模式
    oled_write_byte(0x02,OLED_CMD); //[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10;
    oled_write_byte(0xA1,OLED_CMD); //段重定义设置,bit0:0,0->0;1,0->127;
    oled_write_byte(0xC0,OLED_CMD); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
    oled_write_byte(0xDA,OLED_CMD); //设置COM硬件引脚配置
    oled_write_byte(0x12,OLED_CMD); //[5:4]配置

    oled_write_byte(0x81,OLED_CMD); //对比度设置
    oled_write_byte(0xEF,OLED_CMD); //1~255;默认0X7F (亮度设置,越大越亮)
    oled_write_byte(0xD9,OLED_CMD); //设置预充电周期
    oled_write_byte(0xf1,OLED_CMD); //[3:0],PHASE 1;[7:4],PHASE 2;
    oled_write_byte(0xDB,OLED_CMD); //设置VCOMH 电压倍率
    oled_write_byte(0x30,OLED_CMD); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;

    oled_write_byte(0xA4,OLED_CMD); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
    oled_write_byte(0xA6,OLED_CMD); //设置显示方式;bit0:1,反相显示;0,正常显示                                
    oled_write_byte(0xAF,OLED_CMD); //开启显示   
    oled_clear();
}  

/**
* @brief 向SSD1306写入一个字节
* @param dat:要写入的数据/命令
* @param cmd:数据/命令标志 0,表示命令;1,表示数据
*/

static void oled_write_byte(uint8_t dat,uint8_t cmd)
{       
    //设置传输模式
    oled_dc_set(cmd);
    //片选
    oled_cs_set(0);
    //发送数据
    spi_send_byte(dat);
    //关闭片选
    oled_cs_set(1); 
    //设置传输模式
    oled_dc_set(cmd);   
    //设置传输模式:数据
    oled_dc_set(OLED_DATA); 
} 

/**
* @brief 切换数据或者命令模式
* @param state:0:命令,1:数据
*/

static void oled_dc_set(uint8_t state)
{
    if (state)
    {
        GPIO_SetBits(GPIOB,GPIO_Pin_11);
    }
    else
    {
        GPIO_ResetBits(GPIOB,GPIO_Pin_11);
    }
}

/**
* @brief 片选
* @param mode:0:片选,1:未选
*/

static void oled_cs_set(uint8_t state)
{
    if (state)
    {
        GPIO_SetBits(GPIOB,GPIO_Pin_12);
    }
    else
    {
        GPIO_ResetBits(GPIOB,GPIO_Pin_12);
    }
}

/**
* @brief 更新显存到LCD   
*/

static void oled_refresh_gram(void)
{
    uint8_t i = 0;
    uint8_t n = 0;

    for (i = 0;i < 8;i++)  
    {  
        //设置页地址(0~7)
        oled_write_byte(0xb0 + i,OLED_CMD);
        //设置显示位置—列低地址
        oled_write_byte(0x02,OLED_CMD);
        //设置显示位置—列高地址   
        oled_write_byte(0x10,OLED_CMD);

        //更新数据
        for (n = 0;n < 128;n++)
        {
            oled_write_byte(OLED_Gram[n][i],OLED_DATA); 
        }
    }   
}

/**
* @brief 清屏
*/

static void oled_clear(void)
{  
    uint8_t i = 0;
    uint8_t n = 0;

    for (i = 0;i < 8;i++)
    {
        for(n=0;n<128;n++)
        {
            OLED_Gram[n][i] = 0; 
        }           
    }
    //更新显示
    oled_refresh_gram();
}

/**
* @brief 设置坐标点
* @param x:x坐标
* @param y:y坐标
*/

static void oled_set_pos(uint8_t x,uint8_t y) 
{ 
    oled_write_byte(0xb0 + (7 - y / 8),OLED_CMD);
    oled_write_byte(((x & 0xf0) >> 4) | 0x10,OLED_CMD);
    oled_write_byte((x & 0x0f),OLED_CMD); 
} 

/**
* @brief spi发送一个字节
* @param byte:发送的字节
* @retval 读取的字节
*/

static uint8_t spi_send_byte(uint8_t byte)
{       
    while (SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI2,byte);
    while (SPI_I2S_GetFlagStatus(SPI2,SPI_I2S_FLAG_RXNE) == RESET);
    return SPI_I2S_ReceiveData(SPI2);
}

inf_lcd.h

/**
* Copyright (c), 2015-2025
* @file inf_lcd.c
* @brief lcd接口层头文件
* @author jdh
* @date 2015/7/28
*/

#ifndef _INF_LCD_H_
#define _INF_LCD_H_

/*********************************************************************
*                           头文件
**********************************************************************/

#include "drv_lcd.h"

/*********************************************************************
*                           函数
**********************************************************************/

/**
* @brief 初始lcd
*/

void inf_lcd_init(void);

/**
* @brief 画点
* @param x:x坐标
* @param y:y坐标
* @param show:0:不显示,1:显示
*/

void inf_lcd_draw_pixel(uint8_t x,uint8_t y,uint8_t show);

/**
* @brief 打开显示
* @param 0:关闭,1:打开
*/

void inf_lcd_display_set(uint8_t state);

#endif


inf_lcd.c

/**
* Copyright (c), 2015-2025
* @file inf_lcd.c
* @brief lcd接口层主文件
* @author jdh
* @date 2015/7/28
* @update 2015/9/2
* @update 2015/9/3
*/

/*********************************************************************
*                           头文件
**********************************************************************/

#include "inf_lcd.h"
#include "string.h"

/*********************************************************************
*                           函数
**********************************************************************/

/**
* @brief 初始lcd
*/

void inf_lcd_init(void)
{
    drv_lcd_init();  
}

/**
* @brief 画点
* @param x:x坐标
* @param y:y坐标
* @param show:0:不显示,1:显示
*/

void inf_lcd_draw_pixel(uint8_t x,uint8_t y,uint8_t show)
{
    drv_lcd_draw_pixel(x,y,show);
}

/**
* @brief 打开显示
* @param 0:关闭,1:打开
*/

void inf_lcd_display_set(uint8_t state)
{
    drv_lcd_display_set(state);
}

你可能感兴趣的:(STM32,gui,oled)