1. 程式人生 > 實用技巧 >一個OLED的採坑之旅

一個OLED的採坑之旅

最近在做某研究所的專案,拿到的一塊oled螢幕 128*64

mcu 是 f103RC 512kb 的核

本來顯彩色的 LCD 是直接 畫對應的 畫素點就行了

可是這個 OLED 螢幕的 設定卻是下邊的樣子

1             OLED_DrawBMP(0,0,128,8, BMP3y);
2 
3             OLED_ShowChar(10,1,( unsigned char *)"HelTecAutomation",1);
4 
5             OLED_ShowChar(10,2,( unsigned char *)"HOLLEWORLD",1);
6             OLED_ShowChar(10
,4,( unsigned char *)"Voltage:",1); 7 OLED_ShowChar(64,4,( unsigned char *)"20V ",1); 8 OLED_ShowChar(34,6,( unsigned char *)"2020-09-08",1);

這就給我們設定帶來了很多問題

圖片總是偏移了幾個畫素

直到我自己畫圖

轉換 下邊的設定很重要 不然圖形顯示是亂的

最後 發現 還是有一條亮邊,真奇怪

只能修改 總寬度 感覺是沒重新整理這列導致的。於是

大功告成,顯示完美

下邊是程式碼,感覺還是不完美,比如我想自己畫條線,但是畫的是 | | | | 這種。很奇怪

#ifndef __OLED_H__
#define __OLED_H__
#include "stdint.h"


#define OLED_CS PBout(6)
#define OLED_DC PBout(7)

#define    Brightness    0xCF
#define X_WIDTH           129 // 132 //0.96(SSD1306) is 128 ,1.30(SH1106) is 132
#define Y_WIDTH         64
#define        Page            32

#define IIC_SPI_TYPE         1    //
1 is the spi,0 is the i2c #define CHIP_IS_SSD1306 0 //1 - SSD1306; 0 -- SH1106 //#define INCH 0 // 0 is 0.96 inch & 0.91 inch & 1.3 inch & 1.54 inch,1 is 0.49 inch (This Macro definition is for IIC with SSD1306) void OLED_WrDat(uint8_t dat); void OLED_WrCmd(uint8_t cmd); void OLED_SetPos(unsigned char x, unsigned char y); void OLED_Fill(unsigned char bmp_dat); void OLED_CLS(void); void OLED_ON(void); void OLED_OFF(void); void OLED_Init(void); //void OLED_DrawPoint(unsigned char x,unsigned char y,unsigned char t); //void OLED_Char(unsigned char x, unsigned char y, unsigned char ch); void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize); void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N); void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMPx[]); void OLED_Set_Pos(uint8_t x, uint8_t y); //漢字顯示,設定顯示座標 void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode); void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t); void OLED_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); // OLED_Fill(0xFF);//螢幕全亮 void OLED_Refresh(void); /* for(i=0; i<8; i++) { OLED_ShowCN(i*16,0,i); //行,列,第幾個漢字 OLED_ShowCN(i*16,2,i+8); } */ #endif
View Code

#include "spi.h"
#include "OLED.h"
#include "codetab.h"
#include "delay.h"
#include "sys.h"
#include "delay.h"


uint8_t OLED_GRAM[144][8];

void OLED_WrCmd(uint8_t cmd)
{
    OLED_DC = 0;
    SPI3_ReadWriteByte(cmd);
}
void OLED_WrDat(uint8_t dat)
{
    OLED_DC = 1;
    SPI3_ReadWriteByte(dat);
}


void OLED_SetPos(unsigned char x, unsigned char y)
{ 
    OLED_WrCmd(0xb0+y);
    OLED_WrCmd(((x&0xf0)>>4)|0x10);
    OLED_WrCmd((x&0x0f)|0x01); 
}


void OLED_Fill(unsigned char bmp_dat) 
{
    unsigned char y,x;
    for(y=0;y<Page;y++)
    {
        OLED_WrCmd(0xb0+y);
        OLED_WrCmd(0x01);
        OLED_WrCmd(0x10);
        for(x=0;x<X_WIDTH;x++)
        OLED_WrDat(bmp_dat);
    }
}


void OLED_CLS(void)
{
    OLED_Fill(0x00);
}


void OLED_ON(void)
{
    OLED_WrCmd(0X8D);
    OLED_WrCmd(0X14);
    OLED_WrCmd(0XAF);
}


void OLED_Init(void)
{
      GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(    RCC_APB2Periph_GPIOB, ENABLE );//PORTB時鐘使能 
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;                 //
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //推輓輸出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;         //IO口速度為50MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);                       //配置
    GPIO_SetBits(GPIOB,GPIO_Pin_6 | GPIO_Pin_7);
    SPI3_Init();
    OLED_CS = 0;
    delay_ms(100);
    
#if CHIP_IS_SSD1306
    
    OLED_WrCmd(0xae);//--turn off oled panel
    OLED_WrCmd(0x00);//---set low column address
    OLED_WrCmd(0x10);//---set high column address
    OLED_WrCmd(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_WrCmd(0x81);//--set contrast control register
    OLED_WrCmd(Brightness); // Set SEG Output Current Brightness
    OLED_WrCmd(0xa1);//--Set SEG/Column Mapping
    OLED_WrCmd(0xc8);//Set COM/Row Scan Direction
    OLED_WrCmd(0xa6);//--set normal display
    OLED_WrCmd(0xa8);//--set multiplex ratio(1 to 64)
    OLED_WrCmd(0x3f);//--1/64 duty
    OLED_WrCmd(0xd3);//-set display offset    Shift Mapping RAM Counter (0x00~0x3F)
    OLED_WrCmd(0x00);//-not offset
    OLED_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency
    OLED_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
    OLED_WrCmd(0xd9);//--set pre-charge period
    OLED_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_WrCmd(0xda);//--set com pins hardware configuration
    OLED_WrCmd(0x12);
    OLED_WrCmd(0xdb);//--set vcomh
    OLED_WrCmd(0x40);//Set VCOM Deselect Level
    OLED_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
    OLED_WrCmd(0x02);//
    OLED_WrCmd(0x8d);//--set Charge Pump enable/disable
    OLED_WrCmd(0x14);//--set(0x10) disable
    OLED_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
    OLED_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7) 
    OLED_WrCmd(0xaf);//--turn on oled panel
    
#else //1106
    
    OLED_WrCmd(0xAE);    /*display off*/
    OLED_WrCmd(0x02);    /*set lower column address*/
    OLED_WrCmd(0x10);    /*set higher column address*/
    OLED_WrCmd(0x40);    /*set display start line*/
    OLED_WrCmd(0xB0);    /*set page address*/
    OLED_WrCmd(0x81);    /*contract control*/
    OLED_WrCmd(Brightness);    /*128*/
    OLED_WrCmd(0xA1);    /*set segment remap*/
    OLED_WrCmd(0xA6);    /*normal / reverse*/
    OLED_WrCmd(0xA8);    /*multiplex ratio*/
    OLED_WrCmd(0x3F);    /*duty = 1/32*/
    OLED_WrCmd(0xad);    /*set charge pump enable*/
    OLED_WrCmd(0x8b);    /*    0x8a    ??VCC   */
    OLED_WrCmd(0x30);    /*0X30---0X33  set VPP   9V liangdu!!!!*/
    OLED_WrCmd(0xC8);    /*Com scan direction*/
    OLED_WrCmd(0xD3);    /*set display offset*/
    OLED_WrCmd(0x00);    /*   0x20  */
    OLED_WrCmd(0xD5);    /*set osc division*/
    OLED_WrCmd(0x80);    
    OLED_WrCmd(0xD9);    /*set pre-charge period*/
    OLED_WrCmd(0x1f);    /*0x22*/
    OLED_WrCmd(0xDA);    /*set COM pins*/
    OLED_WrCmd(0x12);         //0x02 -- duanhang xianshi,0x12 -- lianxuhang xianshi!!!!!!!!!
    OLED_WrCmd(0xdb);    /*set vcomh*/
    OLED_WrCmd(0x40);     
    OLED_WrCmd(0xAF);    /*display ON*/
    
#endif
    
    OLED_Fill(0x00);
    OLED_SetPos(0,0);     
} 

//顯示英文字元,
void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize)
{
    unsigned char c = 0,i = 0,j = 0;
    switch(TextSize)
    {
        case 1:
        {
            while(ch[j] != '\0')
            {
                c = ch[j] - 32;
                if(x > 126)
                {
                    x = 0;
                    y++;
                }
                OLED_SetPos(x,y);
                for(i=0;i<6;i++)
                    OLED_WrDat(F6x8[c][i]);
                x += 6;
                j++;
            }
        }break;
        case 2:
        {
            while(ch[j] != '\0')
            {
                c = ch[j] - 32;
                if(x > 120)
                {
                    x = 0;
                    y++;
                }
                OLED_SetPos(x,y);
                for(i=0;i<8;i++)
                    OLED_WrDat(F8X16[c*16+i]);
                OLED_SetPos(x,y+1);
                for(i=0;i<8;i++)
                    OLED_WrDat(F8X16[c*16+i+8]);
                x += 8;
                j++;
            }
        }break;
    }
}


void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N)
{
    unsigned char wm=0;
    unsigned int  adder=32*N;
    OLED_SetPos(x , y);
    for(wm = 0;wm < 16;wm++)
    {
        OLED_WrDat(F16x16[adder]);
        adder += 1;
    }
    OLED_SetPos(x,y + 1);
    for(wm = 0;wm < 16;wm++)
    {
        OLED_WrDat(F16x16[adder]);
        adder += 1;
    }
}







//void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[])
//{
//    unsigned int j=0;
//    unsigned char x,y;

//  if(y1%8==0)
//        y = y1/8;
//  else
//        y = y1/8 + 1;
//    for(y=y0;y<y1;y++)
//    {
//        OLED_SetPos(x0,y);
//    for(x=x0;x<x1;x++)
//        {
//            OLED_WrDat(BMP[j++]);
//        }
//    }
//}


//顯示BMP圖片128×64起始點座標(x,y),x的範圍0~127,y為頁的範圍0~7
void OLED_DrawBMP(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1, uint8_t BMPx[])
{
    u16 j = 0;
    uint8_t x, y;

//    if(y1 % 8 == 0) y = y1 / 8;
//    else y = y1 / 8 + 1;
//    for(y = y0; y < y1; y++)
//    {
//        OLED_SetPos(x0, y);
//        for(x = x0; x < x1; x++)
//        {
//            OLED_WrDat(BMPx[j++]);
//        }
//    }
//        
     if(y1 % Page == 0) y = y1 / Page;
    else y = y1 / Page + 1;
    for(y = y0; y < y1; y++)
    {
        OLED_SetPos(x0, y);
        for(x = x0; x < x1; x++)
        {
            OLED_WrDat(BMPx[j++]);
        }
    }
    
        
}

//更新視訊記憶體到OLED    
void OLED_Refresh(void)
{
//       for(y = 0; y < sizeof( OLED_GRAM[0]); y++)
//    {
//        OLED_SetPos(x0, y);
//        for(x = x0; x < x1; x++)
//        {
//            OLED_WrDat(OLED_GRAM[x,y]);
//        }
//    }
    //OLED_DrawBMP(0,0,127,7,OLED_GRAM);
//    u8 i,n;
//    for(i=0;i<8;i++)
//    {
//       OLED_WrDat(0xb0+i,OLED_CMD); //設定行起始地址
//       OLED_WR_Byte(0x00,OLED_CMD);   //設定低列起始地址
//       OLED_WR_Byte(0x10,OLED_CMD);   //設定高列起始地址
//       for(n=0;n<128;n++)
//         OLED_WR_Byte(OLED_GRAM[n][i],OLED_DATA);
//  }
}

//畫點 
//x:0~127
//y:0~63
//t:1 填充 0,清空    
void OLED_DrawPoint(uint8_t x,uint8_t y,uint8_t t)
{
    uint8_t i,m,n;
    i=y/8;
    m=y%8;
    n=1<<m;
    if(t){

    OLED_GRAM[x][i]|=n;
         OLED_SetPos(x, y);
       OLED_WrDat(0xff);
    
    }
    else
    {
        OLED_GRAM[x][i]=~OLED_GRAM[x][i];
        OLED_GRAM[x][i]|=n;
        OLED_GRAM[x][i]=~OLED_GRAM[x][i];
    }
}

//畫線
//x1,y1:起點座標
//x2,y2:結束座標
void OLED_DrawLine(uint8_t x1,uint8_t y1,uint8_t x2,uint8_t y2,uint8_t mode)
{
    u16 t; 
    int xerr=0,yerr=0,delta_x,delta_y,distance;
    int incx,incy,uRow,uCol;
    delta_x=x2-x1; //計算座標增量 
    delta_y=y2-y1;
    uRow=x1;//畫線起點座標
    uCol=y1;
    if(delta_x>0)incx=1; //設定單步方向 
    else if (delta_x==0)incx=0;//垂直線 
    else {incx=-1;delta_x=-delta_x;}
    if(delta_y>0)incy=1;
    else if (delta_y==0)incy=0;//水平線 
    else {incy=-1;delta_y=-delta_x;}
    if(delta_x>delta_y)distance=delta_x; //選取基本增量座標軸 
    else distance=delta_y;
    for(t=0;t<distance+1;t++)
    {
        OLED_DrawPoint(uRow,uCol,mode);//畫點

        xerr+=delta_x;
        yerr+=delta_y;
        if(xerr>distance)
        {
            xerr-=distance;
            uRow+=incx;
        }
        if(yerr>distance)
        {
            yerr-=distance;
            uCol+=incy;
        }
    }
}
void OLED_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
{
    OLED_DrawLine(x1,y1,x2,y1,0);
    OLED_DrawLine(x1,y1,x1,y2,0);
    OLED_DrawLine(x1,y2,x2,y2,1);
    OLED_DrawLine(x2,y1,x2,y2,1);
}

void OLED_Set_Pos(uint8_t x, uint8_t y)     //漢字顯示,設定顯示座標
{
//    OLED_WriteCmd(0xb0 + y);
//    OLED_WriteCmd(((x & 0xf0) >> 4) | 0x10);
//    OLED_WriteCmd((x & 0x0f) | 0x01);
}


void OLED_WriteData(uint8_t dat)        //寫一位元組資料
{
//    uint8_t i = 8;
//    OLED_DC = 1;
//    OLED_SCL = 0;
//    for(i = 0; i < 8; i++)
//    {
//        if(dat & 0x80)
//            OLED_SDA = 1;
//        else
//            OLED_SDA = 0;
//        OLED_SCL = 1;
//        OLED_SCL = 0;
//        dat <<= 1;
//    }
}
View Code