历史上的今天
返回首页

历史上的今天

今天是:2024年09月10日(星期二)

正在发生

2018年09月10日 | STM32硬件SPI驱动0.96寸的OLED

2018-09-10 来源:eefocus

1.OLED相关


参见—->51 软件模拟SPI驱动OLED


2.硬件SPI


参见—->SPI专题(二)——STM32驱动FLASH(W25Q64)


3.驱动程序


驱动程序参照51单片机进行移植,只不过模拟的SPI换成STM32硬件SPI,不用再写时序部分的代码。对于STM32的硬件SPI,我们在驱动FLASH中已有介绍,这里就不再做介绍。


OLED引脚部分定义:


#ifndef __OLED_H

#define __OLED_H


#include "spi.h"

#include "stm32f10x.h"

#include "stm32f10x_conf.h"


#define Max_Column  128

#define Max_Row     64

#define SIZE 16 //显示字体选择



#define RCC_APB2Periph_OLED_PORT    RCC_APB2Periph_GPIOA

#define OLED_PORT                   GPIOA


#define OLED_CS_PIN     GPIO_Pin_2

#define OLED_CS_LOW     GPIO_ResetBits(GPIOA,GPIO_Pin_2)                        

#define OLED_CS_HIGH    GPIO_SetBits(GPIOA,GPIO_Pin_2)


#define OLED_DC_PIN     GPIO_Pin_3

#define OLED_DC_LOW     GPIO_ResetBits(GPIOA,GPIO_Pin_3)

#define OLED_DC_HIGH    GPIO_SetBits(GPIOA,GPIO_Pin_3)


#define OLED_RST_PIN    GPIO_Pin_4

#define OLED_RST_LOW    GPIO_ResetBits(GPIOA,GPIO_Pin_4)

#define OLED_RST_HIGH   GPIO_SetBits(GPIOA,GPIO_Pin_4)


#define OLED_CLK_PIN    GPIO_Pin_5

#define OLED_DATA_PIN   GPIO_Pin_7


void SPI_OLED_Init(void);

void OLED_Write_Byte(uint8_t dat);

void OLED_Write_Data(uint8_t dat);

void OLED_Write_Cmd(uint8_t cmd);



void OLED_Set_Pos(u8 x,u8 y);

void OLED_Display_On(void);

void OLED_Display_Off(void);

void OLED_Display_Clear(void);

void OLED_Display_Onechar(u8 x,u8 y,u8 str);

void OLED_Display_String(u8 x,u8 y,u8 *str);

void OLED_Display_Chinese(u8 x,u8 y,u8 no);

void OLED_Display_Picture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[]);

u32 OLED_Pow(u8 m,u8 n);

void OLED_Display_Num(u8 x,u8 y,u32 num,u8 len,u8 size_num);

void OLED_Init(void);


#endif


连接的时候需要看清楚,一开始我就不小心把SPI的CLK与DO接反了,半天找不到原因,这种问题就太低级了,一定得多细心。


OLED初始化:


void SPI_OLED_Init(void)

{

    GPIO_InitTypeDef GPIO_InitStructure;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_OLED_PORT, ENABLE );


    //片选信号初始化

    GPIO_InitStructure.GPIO_Pin = OLED_CS_PIN|OLED_DC_PIN|OLED_RST_PIN;  

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //复用推挽输出

    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_Init(OLED_PORT, &GPIO_InitStructure);

    GPIO_SetBits(OLED_PORT,OLED_CS_PIN|OLED_DC_PIN|OLED_RST_PIN);


    SPI1_Init();           //初始化SPI

    SPI1_SetSpeed(SPI_BaudRatePrescaler_16);    //设置为18M时钟,高速模式

}  


OLED写数据实现:


//硬件SPI发送数据

void OLED_Write_Byte(uint8_t dat)

{

    SPI1_ReadWriteByte(dat);

}


//写入数据

void OLED_Write_Data(uint8_t dat)

{

    OLED_CS_LOW;

    OLED_DC_HIGH;

    OLED_Write_Byte(dat);

}


//写入命令

void OLED_Write_Cmd(uint8_t cmd)

{

    OLED_CS_LOW;

    OLED_DC_LOW;

    OLED_Write_Byte(cmd);

}


下面就是OLED的具体实现,开启,初始化,写一个字节,写字符串等,也是在51MCU的基础上修改而成。


//Function:设置显示坐标

//Input:x:横坐标;y:纵坐标

//Output:无

//Return:无

//Others:无

void OLED_Set_Pos(uint8_t x,uint8_t y)

{

    OLED_Write_Cmd(0xb0+y);//列偏移

    OLED_Write_Cmd(((x&0xf0)>>4)|0x10);//行高四位地址

    OLED_Write_Cmd((x&0x0f)|0X01);//行低四位地址

}


//Function:开启OLED显示

//Input:无

//Output:无

//Return:无

//Others:无

void OLED_Display_On(void)

{

    OLED_Write_Cmd(0X8D);//设置DCDC

    OLED_Write_Cmd(0X14);//打开DCDC

    OLED_Write_Cmd(0XAF);//打开OLED

}


//Function:关闭OLED显示

//Input:无

//Output:无

//Return:无

//Others:无

void OLED_Display_Off(void)

{

    OLED_Write_Cmd(0X8D);//设置DCDC

    OLED_Write_Cmd(0X10);//关闭DCDC

    OLED_Write_Cmd(0XAE);//关闭OLED

}


//Function:清屏

//Input:无

//Output:无

//Return:无

//Others:无

void OLED_Display_Clear(void)

{

    u8 page,len;


    for(page=0;page<8;page++)

    {

        OLED_Write_Cmd(0xB0+page);//设置页地址(0--7)

        OLED_Write_Cmd(0X00);//设置显示位置—列低地址

        OLED_Write_Cmd(0X10); //设置显示位置—列高地址


        for(len=0;len<128;len++)

            OLED_Write_Data(0);//写入0;屏熄灭

    }

}

//Function:在指定位置显示一个字符,包括部分字符

    //x:0~127;y:0~63;size:选择字体 16/12 

//Input:x:横坐标;y:纵坐标;str:显示的字符

//Output:无

//Return:无

//Others:无               

void OLED_Display_Onechar(u8 x,u8 y,u8 str)

{

    u8 i=0,ret=0;

    //ret = str -32;

    ret = str - ' ';//得到偏移后的值,对ASCLL码进行一个减法.即在二维数组里找它的位置  

    if(x>Max_Column-1)

    {

        x = 0;

        y = y + 2;//针对16号的字符

    }

    if(SIZE == 16 )

    {

        OLED_Set_Pos(x,y);

        //16的字体分成两部分写入

        for(i=0;i<8;i++)

        OLED_Write_Data(F8X16[ret*16+i]);

        OLED_Set_Pos(x,y+1);

        for(i=0;i<8;i++)

            OLED_Write_Data(F8X16[ret*16+i+8]);

    }

    else{

        OLED_Set_Pos(x,y+1);

        for(i=0;i<6;i++)

            OLED_Write_Data(F6x8[ret][i]);

    }

}


//Function:显示字符串

//Input:x:横坐标;y:纵坐标;str:显示的字符串

//Output:无

//Return:无

//Others:无

void OLED_Display_String(u8 x,u8 y,u8 *str)

{

    u8 i=0;


    while(str[i]!='\0')

    {

        OLED_Display_Onechar(x,y,str[i]);

        x += 8;

        if(x>120)

        {

            x = 0;

            y += 2;

        }

        i++;

    }

}


//Function:显示中文

//Input:x:横坐标;y:纵坐标;no:显示的字的序号

//Output:无

//Return:无

//Others:无

void OLED_Display_Chinese(u8 x,u8 y,u8 no)

{

    u8 ch,addr=0;


    OLED_Set_Pos(x,y);

    for(ch=0;ch<16;ch++)//数组行列寻址

    {

        OLED_Write_Data(TEST[2*no][ch]);//汉字是2个字节

        addr += 1;

    }

    OLED_Set_Pos(x,y+1);

    for(ch=0;ch<16;ch++)

    {

        OLED_Write_Data(TEST[2*no+1][ch]);

        addr += 1;

    }


}


//Function:显示图片

//Input:x0,x1:横坐标;y0,y1:纵坐标;BMP:显示的图片

//注意:y1<8,页寻址模式

//Output:无

//Return:无

//Others:无

void OLED_Display_Picture(u8 x0,u8 y0,u8 x1,u8 y1,u8 BMP[])

{

    u8 x,y;

    u32 i=0;


    if(y1%8==0)

        y = y1 / 8;

    else

        y = y1 /8 + 1;

    for(y=y0;y

    {

        OLED_Set_Pos(x0,y);

        for(x=x0;x

        {

            OLED_Write_Data(BMP[i++]);

        }

    }

}


//计算m的n次方

u32 OLED_Pow(u8 m,u8 n)

{

    u32 ret = 1;

    while(n--)

        ret *= m;

    return ret;

}


//Function:显示数字

//Input:x:横坐标;1:纵坐标;num:显示的数字:len:数字长度;size_num:数字字体

//Output:无

//Return:无

//Others:无

void OLED_Display_Num(u8 x,u8 y,u32 num,u8 len,u8 size_num)

{

    u8 t,temp;

    u8 enshow = 0;


    for(t=0;t

    {

        temp = (num/OLED_Pow(10,len-t-1))%10;//把显示的数字一位一位取出来

        if(enshow==0&&t<(len-1))

        {

            if(temp==0)

            {

                OLED_Display_Onechar(x+(size_num/2)*t,y,' ');

                continue;

            }

            else

                enshow = 1;

        }

        OLED_Display_Onechar(x+(size_num/2)*t,y,temp+'0');

    }

}


//初始化SSD1306

//命令设置与开启函数作用重叠......

void OLED_Init(void)

{

    SPI_OLED_Init();


    OLED_RST_HIGH;

    delay_ms(200);

    OLED_RST_LOW;

    delay_ms(200);

    OLED_RST_HIGH; 


    OLED_Write_Cmd(0xAE);//关闭OLED

    OLED_Write_Cmd(0x00);//设置列低位地址

    OLED_Write_Cmd(0x10);//设置列高位地址

    OLED_Write_Cmd(0x40);//设置起始行地址及映射RAM显示起始行 (0x00~0x3F)

    OLED_Write_Cmd(0x81);//对比度设置

    OLED_Write_Cmd(0xCF); // Set SEG Output Current Brightness

    OLED_Write_Cmd(0xA1);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常

    OLED_Write_Cmd(0xC8);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常

    OLED_Write_Cmd(0xA6);//设置显示方式;bit0:1,反相显示;0,正常显示

    OLED_Write_Cmd(0xA8);//设置驱动路数(1 to 64)

    OLED_Write_Cmd(0x3f);//--1/64 duty

    OLED_Write_Cmd(0xD3);//-设置显示偏移(0x00~0x3F)

    OLED_Write_Cmd(0x00);//-not offset

    OLED_Write_Cmd(0xd5);//--set display clock divide ratio/oscillator frequency

    OLED_Write_Cmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec

    OLED_Write_Cmd(0xD9);//--set pre-charge period

    OLED_Write_Cmd(0xF1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock

    OLED_Write_Cmd(0xDA);//--set com pins hardware configuration

    OLED_Write_Cmd(0x12);

    OLED_Write_Cmd(0xDB);//--set vcomh

    OLED_Write_Cmd(0x40);//Set VCOM Deselect Level

    OLED_Write_Cmd(0x20);//设置页地址模式(0x00/0x01/0x02)

    OLED_Write_Cmd(0x02);//

    OLED_Write_Cmd(0x8D);//--set Charge Pump enable/disable

    OLED_Write_Cmd(0x14);//--set(0x10) disable

    OLED_Write_Cmd(0xA4);//禁用显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)(0xa4/0xa5)

    OLED_Write_Cmd(0xA6);// 不使用反向显示 (0xa6/a7) 

    OLED_Write_Cmd(0xAF);//打开显示


    OLED_Write_Cmd(0xAF); /*display ON*/

    OLED_Display_Clear();

    OLED_Set_Pos(0,0);  

}  


实现效果:

这里写图片描述

推荐阅读

史海拾趣

Densitron公司的发展小趣事

为了扩大市场份额,Densitron公司制定了一系列市场拓展策略。公司首先分析了市场需求和竞争态势,确定了目标市场。然后,通过加强品牌宣传、优化销售渠道、提高客户服务质量等手段,不断提升品牌知名度和客户满意度。此外,公司还积极开展国际合作,与全球知名电子企业建立了紧密的合作关系,共同开拓市场。这些策略的实施,使得Densitron公司的市场份额逐年上升,成为行业内的领军企业。

ENTRELECUK公司的发展小趣事

在电子行业中,绿色环保和可持续发展已成为重要的议题。ENTRELEC UK积极响应这一趋势,致力于研发和生产环保型产品。公司采用环保材料和节能技术,降低产品对环境的影响。同时,公司还积极参与环保公益活动,推动行业的可持续发展。

Eurosil Electronics Ltd公司的发展小趣事

作为一家有社会责任感的企业,Eurosil始终关注社会公益事业。公司积极参与各种公益活动,如捐赠教育设施、支持贫困地区发展等。通过这些活动,Eurosil不仅回馈了社会,也提升了企业的社会形象和品牌价值。同时,公司还鼓励员工参与志愿服务活动,培养员工的公益意识和社会责任感。

ALSC [Alliance Semiconductor Corporation]公司的发展小趣事

随着产品质量的不断提升和市场口碑的积累,ALSC开始积极拓展国内外市场。公司不仅在国内建立了完善的销售网络,还与多家国际知名企业建立了战略合作关系。通过与国际伙伴的紧密合作,ALSC成功将产品推向全球市场,进一步提升了公司的知名度和影响力。

冠西电子(COSMO)公司的发展小趣事

近年来,冠西电子积极布局全球市场,设立了多个分公司和办事处,以便更好地服务全球客户。同时,冠西电子还不断关注新兴技术和市场需求的变化,积极寻求新的发展机遇。展望未来,冠西电子将继续秉承“专业、创新、品质、服务”的理念,不断推动公司业务的发展和进步。

以上五个故事概要涵盖了冠西电子(COSMO)公司从创立到发展的主要阶段和事实。每个阶段都体现了冠西电子在技术、市场、品质、品牌等方面的努力和成就。

Hongfa公司的发展小趣事

宏发公司在发展过程中,积极实施国际化战略。2003年,宏发成立了欧洲公司,加快了国际化进程。随后,公司又在美国等地设立了分支机构,建立了本土化营销及服务网络。通过国际市场的拓展,宏发不仅提升了品牌知名度和影响力,还获得了更多的市场机会和客户资源。如今,宏发的产品已畅销全球多个国家和地区,成为了继电器行业的领军企业。

问答坊 | AI 解惑

晒板子28335

28335电力电子与电力传动专用控制板 …

查看全部问答>

1-wire系统中TM卡的单片机等效替换

1 TM卡简介   TM(Touch Memory)卡是美国Dallas公司的专利产品。它采用单线协议通信,通过瞬间碰触完成数据读写,既具有非接触式IC卡的易操作性,又具有接触式IC 卡的廉价性,是当前性价比最优秀的IC卡之一。它的外形类似于一个钮扣(button) ...…

查看全部问答>

浙江大学RF设计(前端系统)(pdf)

第10个附件是一个超外差高频头的实例,很宝贵的资料…

查看全部问答>

说说模拟设计那点事儿和那几本书

我学习模电有一段时间了,向大家推荐几本自认为的\"宝典\",谈下自己使用它们的感受以及在学习模电过程中的体会,供后来者参考: 1. 拉扎维的《模拟CMOS集成电路设计》,我们研二模电课的教材,汪宁老师把这门课讲得可圈可点。当时没意识到有其他 ...…

查看全部问答>

基于Win32 API函数和多线程技术的串行通信编程.pdf

基于Win32 API函数和多线程技术的串行通信编程.pdf…

查看全部问答>

无法收到PBT_TRANSITION消息

在WinCE6下一个应用程序里,使用RequestPowerNotifications(hPowerNotificationMsgs, POWER_NOTIFY_ALL); 去请求power状态改变的通知。可是从开始菜单进入suspend的时候并没有收到任何power消息,但是按Power Button从suspend状态resume回来的时 ...…

查看全部问答>

RAS拨号监视消息

如何在RAS异步拨号时,得到当前拨号的状态,我写的消息和回调函数都可以在PC机上用,但在CE上都不能用(CE只支持消息),代码如下:消息的、 先注册了消息: const   UINT   WM_RASEVENT   =   ::Regist ...…

查看全部问答>

u-boot 的 配置问题.(从NAND启动)

提示的是 bad crc or nand 在网上查了下,应该是env的问题!麻烦各位有经验的朋友,说一下具体怎么改! 我用的是mini2440,page size应该是2048的,但是u-boot启动输出的还是512~已经进行过CONFIG_了…

查看全部问答>

请教高手:如何在扫描输入完成后,光标自动跳到下一个TEXTBOX

我想让程序在扫描输入完成后,光标自动跳到下一个TEXTBOX 可是我在WINCE上捕捉不到扫描键,也不知道如何区分 输入 是由键盘上输入的还是扫描读入的 哪位高手知道的帮帮我,谢谢 啦 …

查看全部问答>

VxWorks嵌入式国际认证培训班

        为满足各大企业及研发机构对嵌入式操作系统VxWorks人才需求,顺应广大学员学习嵌入式操作系统、获得国际认证证书、增强就业竞争力、取得高薪职位的要求,上海双实科技与上海张江信息技术专修学院继续合作举办VxWorks嵌 ...…

查看全部问答>