打印
[STM32]

灵感手环第一步——0.96寸OLED显示实验(二)

[复制链接]
2099|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Andrew55|  楼主 | 2017-12-23 00:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 Andrew55 于 2017-12-23 00:39 编辑

首先是SPI.C,包含了对该模块的各种操作,就是对SPI 写进行符合OLED的包装。写字符,写数字,写字符串,可调显示字体大小,但是需要包含两个ASCII字库。

写完这个文件,就可以在主函数调用  OLED_ShowChinese() ,进行参数配置后,就可以显示了。
具体调用方式为:OLED_ShowChinese(32,0,0);//钱
这个里面前两个参数是进行显示坐标选择,第三个参数是选择你的字库里面第几个汉字的行数。比如我选择了 0,那么在我的字库头文件中前两个ASCII码表就是我要显示汉字的ASCII码表,这个码表是采用字模软件生成的。
#include "spi.h"
#include "word.h"  //字库头文件

#define OLED_Order 0       //定义写命令
#define OLED_Data  1        //定义写数据  

//尽在内部调用函数
static u32 oled_pow(u8 m,u8 n);
static void OLED_GPIO_INIT(void);
static void SPI_Write(u8 data, u8 Mode);
static void OLED_Coord(u8 x, u8 y);  

//使用管脚初始化
static void OLED_GPIO_INIT(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;  
      
    //开启GPIOD的时钟  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    //设置GPIO的基本参数  
    GPIO_InitStruct.GPIO_Pin = OLED_CS_PIN | OLED_RST_PIN | OLED_DC_PIN | OLED_D0_PIN | OLED_D1_PIN;  
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;    //推挽输出  
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;    //输出速度50MHz  
      
    GPIO_Init(OLED_PORT, &GPIO_InitStruct);  
      
    GPIO_SetBits(OLED_PORT, OLED_CS_PIN | OLED_RST_PIN | OLED_DC_PIN | OLED_D0_PIN | OLED_D1_PIN);  
}

/*    SPI写数据/命令
*    Mode :OLED_Order:写命令   OLED_Data:写数据
*    data :数据/命令
*/  
static void SPI_Write(u8 data, u8 Mode)  
{      
    u8 i = 0;

    if(Mode)  
    {  
        OLED_DC(1);        //DC引脚输入高,表示写数据  
    }  
    else  
    {  
        OLED_DC(0);        //DC引脚输入低,表示写命令  
    }  
    OLED_CS(0);            //CS引脚输入低,片选使能  
    for(i = 0; i < 8; i++)  
    {  
        OLED_D0(0);        //D0引脚输入低  
        if(data&0x80)    //判断传输的数据最高位为1还是0  
        {  
            OLED_D1(1);    //D1引脚输入高  
        }  
        else  
        {  
            OLED_D1(0);    //D1引脚输入低  
        }  
        OLED_D0(1);        //D1引脚输入高  
        data<<=1;        //将数据左移一位  
    }  
    OLED_DC(1);            //DC引脚输入低  
    OLED_CS(1);            //CS引脚输入高,片选失能  
}  

/*        设置OLED屏的显示坐标
*      X : 表示OLED的水平坐标(0—127)
*      Y : 表示OLED的页(0—7)     
*/  
static void OLED_Coord(u8 x, u8 y)  
{      
    SPI_Write((0xb0 + y) ,OLED_Order);
    SPI_Write((((x & 0xf0)>>4) | 0x10), OLED_Order);//高4位  
    SPI_Write((x & 0x0f)|0x01, OLED_Order);//低4位  
}  
//清屏,一开始这里写错了,把写命令写成了写数据,导致清屏不正确,发现屏幕上有很多噪点,说明没有清屏成功。
void OLED_Clear(void)  
{  
    u8 i = 0, j = 0;  

    for(i = 0; i < 8; i++)  
    {  
        SPI_Write(0xb0 + i,OLED_Order);
        SPI_Write(0x00,OLED_Order);
        SPI_Write(0x10,OLED_Order);
        for(j = 0; j < 128; j++)  
        {  
            SPI_Write(0x00, OLED_Data);  
        }  
    }  
}  

//关oled显示
void OLED_Display_Off(void)  
{
    SPI_Write(0x8D,OLED_Order);
    SPI_Write(0x10,OLED_Order);
    SPI_Write(0xAE,OLED_Order);
}  
//开oled显示
void OLED_Display_On(void)
{  
    //电荷泵设置(初始化时必须打开,否则看不到显示)
    SPI_Write(0x8D, OLED_Order);  
    SPI_Write(0x14, OLED_Order);//bit2   0:关闭        1:打开  
    SPI_Write(0xAF, OLED_Order);//0xAF:开显示      
}  

//oled参数初始化
void OLED_Init(void)  
{  
    OLED_GPIO_INIT();  //端口初始化
      
    OLED_RST(1);     
    delay_ms(100);  
    OLED_RST(0);  
    delay_ms(100);  
    OLED_RST(1);
   
    SPI_Write(0xAE, OLED_Order);//0xAE:关显示     
      
    SPI_Write(0x00, OLED_Order);//设置低列地址  
    SPI_Write(0x10, OLED_Order);//设置高列地址  
      
    //设置行显示的开始地址(0-63)  
    //40-47: (01xxxxx)  
    SPI_Write(0x40, OLED_Order);
      
    //设置对比度  
    SPI_Write(0x81, OLED_Order);
    SPI_Write(0xff, OLED_Order);//这个值越大,屏幕越亮(和上条指令一起使用)(0x00-0xff)  
      
    SPI_Write(0xA1, OLED_Order);//0xA1: 左右反置,  0xA0: 正常显示(默认0xA0)  
    SPI_Write(0xC8, OLED_Order);//0xC8: 上下反置,  0xC0: 正常显示(默认0xC0)  
      
    //0xA6: 表示正常显示(在面板上1表示点亮,0表示不亮)  
    //0xA7: 表示逆显示(在面板上0表示点亮,1表示不亮)  
    SPI_Write(0xA6, OLED_Order);  
      
    SPI_Write(0xA8, OLED_Order);//设置多路复用率(1-64)  
    SPI_Write(0x3F, OLED_Order);//(0x01-0x3f)(默认为3f)  
      
      
    //设置显示抵消移位映射内存计数器  
    SPI_Write(0xD3, OLED_Order);  
    SPI_Write(0x00, OLED_Order);//(0x00-0x3f)(默认为0x00)  
      
    //设置显示时钟分频因子/振荡器频率  
    SPI_Write(0xD5, OLED_Order);  
    //低4位定义显示时钟(屏幕的刷新时间)(默认:0000)分频因子= [3:0]+1  
    //高4位定义振荡器频率(默认:1000)  
    SPI_Write(0x80, OLED_Order);//  
      
    //时钟预充电周期  
    SPI_Write(0xD9, OLED_Order);  
    SPI_Write(0xF1, OLED_Order);//[3:0],PHASE 1;   [7:4] PHASE 2  
      
    //设置COM硬件应脚配置  
    SPI_Write(0xDA, OLED_Order);  
    SPI_Write(0x12, OLED_Order);//[5:4]  默认:01  
      
    SPI_Write(0xDB, OLED_Order);//  
    SPI_Write(0x40, OLED_Order);//  
      
    //设置内存寻址方式  
    SPI_Write(0x20, OLED_Order);  
    //00: 表示水平寻址方式  
    //01: 表示垂直寻址方式  
    //10: 表示页寻址方式(默认方式)  
    SPI_Write(0x02, OLED_Order);//      
      
    //电荷泵设置(初始化时必须打开,否则看不到显示)  
    SPI_Write(0x8D, OLED_Order);  
    SPI_Write(0x14, OLED_Order);//bit2   0:关闭        1:打开  
      
    //设置是否全部显示 0xA4: 禁止全部显示  
    SPI_Write(0xA4, OLED_Order);  
  
    //0xA6: 表示正常显示(在面板上1表示点亮,0表示不亮)  
    //0xA7: 表示逆显示(在面板上0表示点亮,1表示不亮)  
    SPI_Write(0xA6, OLED_Order);//  
      
    SPI_Write(0xAF, OLED_Order);//0xAF:开显示     
    SPI_Write(0xAF, OLED_Order); //不知道为什么要写两次
   
    OLED_Clear();
    OLED_Coord(0,0);
}  

//显示汉字,设置坐标,
void OLED_ShowChinese(u8 x, u8 y, u8 chinese)  
{  
    u8 t,adder=0;
   
    OLED_Coord(x,y);

    for(t=0;t<16;t++)  //每行16个元素,一个字需要两行字符串
    {
        SPI_Write(Hzk[2*chinese][t],OLED_Data);
        adder+=1;
     }   
   
    OLED_Coord(x,y+1);
     
    for(t=0;t<16;t++)
    {   
        SPI_Write(Hzk[2*chinese+1][t],OLED_Data);
        adder+=1;
      }   
}


//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x, u8 y, u8 chr)  
{  
    unsigned char c=0,   i=0;   
   
    c = chr - ' ';    //得到偏移后的值
   
        if(x > Max_Column - 1)
            {x=0;y=y+2;}
            
        if(SIZE ==16)  //8*16字符
        {
            OLED_Coord(x,y);
            
            for(i=0;i<8;i++)
                SPI_Write(F8X16[c*16+i],OLED_Data);
            
            OLED_Coord(x,y+1);
            
            for(i=0;i<8;i++)
                SPI_Write(F8X16[c*16+i+8],OLED_Data);
        }
        else    //6*8字符
        {   
            OLED_Coord(x,y+1);
            
            for(i=0;i<6;i++)
                SPI_Write(F6x8[c][i],OLED_Data);
            
        }
}  

//显示字符串
void OLED_Show_String(u8 x, u8 y, u8 *chr)
{
    u8 j=0;
    while (chr[j]!='\0')
    {
        OLED_ShowChar(x,y,chr[j]);

        x+= 8 ;

        if(x>120){x=0;y+=2;}  //自动换行写

        j++;
    }
}


//m^n函数
static u32 oled_pow(u8 m,u8 n)
{
    u32 result = 1;
    while(n--)result*=m;   
    return result;
}

//显示数字
//x,y :起点坐标     
//len :数字的位数
//size:字体大小
//mode:模式    0,填充模式;1,叠加模式
//num:数值(0~4294967295);               
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size)
{            
    u8 t = 0, temp = 0;
    u8 enshow=0;
   
    for(t=0;t<len;t++)
    {
        temp=(num/oled_pow(10,len-t-1))%10;
        
        if(enshow==0&&t<(len-1))
        {
            if(temp==0)
            {
                OLED_ShowChar(x+(size/2)*t,y,' ');
                continue;
            }else enshow=1;
              
        }
         OLED_ShowChar(x+(size/2)*t,y,temp+'0');
    }
}

char Hzk[][32]={{0x20,0x10,0x2C,0xE7,0x24,0x24,0x00,0x90,0x90,0xFF,0x90,0x49,0x4A,0x48,0x40,0x00},{0x01,0x01,0x01,0x7F,0x21,0x11,0x40,0x40,0x20,0x13,0x0C,0x14,0x22,0x41,0xF8,0x00},/*"钱",7*//* (16 X 16 , 宋体 )*/
使用PCtoLCD2002完美版进行取模。具体字模生成方式可参见中景园官方教程。



汉字生成为两行16进制码表。
显示效果:

好了,第一部分算是写完了。


相关帖子

沙发
ywb888| | 2018-3-2 22:54 | 只看该作者
是不是后面的图片挂了?

使用特权

评论回复
板凳
大鱼lik| | 2018-6-10 20:07 | 只看该作者
是的

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

9

主题

20

帖子

4

粉丝