历史上的今天
返回首页

历史上的今天

今天是:2024年10月14日(星期一)

正在发生

2020年10月14日 | 为OLED屏增加GUI支持1:OLED驱动

2020-10-14 来源:eefocus

说明:
一个可穿戴项目中使用到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)

{                                             

推荐阅读

史海拾趣

BLACK&DECKER公司的发展小趣事

2010年3月15日,BLACK&DECKER迎来了公司历史上的一个重要时刻——与史丹利公司合并组建史丹利百得公司。这一合并不仅使BLACK&DECKER获得了更强大的资源和市场支持,还为其未来的发展提供了更广阔的空间。合并后的史丹利百得公司致力于提供整合的五金工具、存储设备和安防系统解决方案,以满足全球消费者的多样化需求。通过整合双方的优势资源和技术力量,史丹利百得公司有望在电子行业中取得更加辉煌的成就。

综上所述,BLACK&DECKER公司在电子行业中的发展故事充满了创新、进取和成功的元素。从创立初期的艰苦创业到如今的全球领先品牌,BLACK&DECKER凭借其卓越的产品质量、技术创新和市场拓展能力,赢得了消费者的信任和市场的认可。未来,随着科技的不断进步和市场需求的不断变化,BLACK&DECKER将继续保持创新精神,推动电子行业的持续发展。

Hilscher Gesellschaft für Systemautomation mbH公司的发展小趣事

面对市场的多元化需求,HVPSI不断扩展其产品线,从最初的高压电源模块拓展到高压直流电源、高压脉冲电源等多个领域。公司还投入大量资源研发新型材料和技术,以提升产品的性能和可靠性。这些努力使得HVPSI能够提供全方位的高压电源解决方案,满足不同行业、不同应用场景的需求。

EEMB Co Ltd公司的发展小趣事

随着全球电子行业的快速发展和市场竞争的加剧,EEMB集团开始意识到单纯依靠锂电池产品已经难以满足市场的多元化需求。因此,公司开始积极探索新的业务领域和市场机会。通过收购和兼并等方式,公司逐渐将业务扩展到智能家居、可穿戴设备等领域,并成功推出了多款具有创新性和竞争力的新产品。这些新产品的推出不仅丰富了公司的产品线,也为公司带来了新的增长点。

友盟(AP)公司的发展小趣事

在追求商业成功的同时,友盟(AP)公司也积极履行社会责任,致力于可持续发展。公司关注环境保护、公益事业等方面的问题,积极参与相关活动和项目。同时,友盟还通过技术创新和产品优化,推动电子行业的绿色发展和数字化转型。这些努力不仅提升了公司的社会形象,也为其未来的发展注入了新的动力。

以上是关于电子行业里友盟(AP)公司发展起来的5个相关故事。这些故事从不同角度展现了友盟在技术创新、合作伙伴关系、市场拓展、人才团队建设以及社会责任等方面的努力和成就。当然,每个公司的发展都是一个复杂而多元的过程,这些故事只是其中的一部分。

Cermetek Microelectronics公司的发展小趣事

Cermetek Microelectronics公司在创立之初,便专注于微电子技术的研发与创新。创始人凭借在半导体领域的深厚背景,带领团队攻克了一系列技术难题,成功开发出具有高性能和稳定性的微电子产品。这些产品不仅满足了市场对微型化、高集成度的需求,更在多个关键领域实现了技术突破,为公司赢得了市场的初步认可。

上海晶岳(AFSEMI)公司的发展小趣事

为了保持技术领先和市场竞争力,晶岳电子一直注重研发团队的建设。目前,公司在上海、深圳及台湾均建有成熟的产品研发团队,核心功率器件及集成电路设计人员均拥有15年以上的设计研发经验。这些优秀的研发人员不仅为公司带来了源源不断的技术创新,也确保了公司在激烈的市场竞争中始终保持领先地位。此外,晶岳电子还积极与高校和研究机构合作,共同开展前沿技术的研发和应用。

问答坊 | AI 解惑

求智能循迹小车驱动电路图

本帖最后由 paulhyde 于 2014-9-15 03:17 编辑 有那位高人能提供智能循迹小车驱动电路的pcb呀 核心板芯片是pc9s12xs128的 电机驱动电路的芯片是33886的 或是其他的芯片耶可以 还有能否提供光电探测板的电路图和pcb 在这 ...…

查看全部问答>

DS18B20的告警搜索命令如何用啊

手册上只说了超过设定值,告警标志位会置位,但是如何查询到呢?单片机在那个Alarm Search(ECh)命令发出后,18B20里面也没有寄存器可以读到报警位啊? 现在只能用软件方式查询,当前温度值与实现设定好的TH,TL的比较关系,从而判断是否超过了温 ...…

查看全部问答>

Microsoft Communication Controls Version 6.0 不支持此接口

RT. 我用vc6.0新建了个对话框的工程,添加MSComm控件时,出现了上面的提示,无法插入该控件。 这个该如何解决?…

查看全部问答>

散分啊,关于24系列的容量与写缓冲大小的判断!

24系列存储器内部没有型号标志信息,在我的板上装有不同型号的24IC,写个程序来判断该24系列IC的地址、存储容量和页写缓冲。各位大虾给个思路啊…

查看全部问答>

Altera PLL 的奇怪问题

我碰到了一个奇怪的问题。我的设计中用到的FPGA是stratix II GX,我的程序在这个FPGA中一直运行正常,两天前,我将它放到高低温箱中作测试,在高低温箱中只是做了常温测试,前两个小时运行正常,突然FPGA就运行不正常了,经过检查发现:FPGA中的PLL ...…

查看全部问答>

STM32 USART 接收问题 已经解决

实现功能:我用串口接收PC端一串数据   然后在把数组中的数据发送给串口 传到PC   遇到问题:串口接收正常 但是发送每次只能发送一两个数据 环境       :串口5 中断接收 请大家帮忙分析下原因 谢谢! ...…

查看全部问答>

mp1540升压电路的问题

图中R5和D1的作用是? R5的作用是不是在EN端为未知状态时,使en可靠接地,芯片不工作? D1不太清楚,是保护?…

查看全部问答>

timer0 关闭溢出中断 问题请假

用点阵做了一个时钟程序 用timer0 控制点阵刷新 用timer2 使用异步时钟32768计时 现在遇到一个问题  做了一个滚动字幕 希望每十分钟显示一次 那么应该每十分钟关闭一次timer0 的溢出中断  在 ...…

查看全部问答>

32.768k晶振不起振问题

我发现很郁闷的问题。我下载了程序到里面,直接上电,发现晶振不启振。上了好几次电。都是不起振。 然后我用仿真的方法,看代码是怎么回事,rtc配置的地方单步走,发现晶振又启振了 而且很正常。我试试了两块板子,都是这种情况。 很郁闷 ...…

查看全部问答>

开关电源电子公式

Pin(av):额定输入功率. fac(min):交流最小频率(40-75Hz) 输入电容:Cin=0.3Pin(av)/fac(min)*Vin(min)*V²ripple(p-p)     功率电阻:Rsc=Vsc(max)/Ipk    输出电容:Cout=Iout(max)*(1-Dmin)/f*Vripple(pk-pk) ...…

查看全部问答>