在CodeBlocks搭建SDL2工程OLED液晶模拟器虚拟OLED单色液晶(128x64)

例程说明

参考例程: 在CodeBlocks下搭建SDL2开发工程
参考例程: STM32F103xx TFT液晶显示ASCII字符串、中文、图片并且显示带有镜像和旋转功能

1. 在CodeBlocks下搭建SDL2工程,并且虚拟OLED单色液晶的显示

源码下载目录

源码下载目录: 在CodeBlocks搭建SDL2工程OLED液晶模拟器虚拟OLED单色液晶(128x64)

工程配置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、SDL2的初始化和退出


/* 初始化SDL2 */
static u8 xInit_SDL2(void)
{
    /* 初始化SDL */
    if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0)
    {
        SDL_Log("SDL Init Fail......%s\r\n", SDL_GetError());
        return 1;
    }

    /* 创建窗口 */
    AppMainWin = SDL_CreateWindow("SDL2 Demo", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WINDOW_PHY_WIDTH, WINDOW_PHY_HEIGHT, SDL_WINDOW_SHOWN);
    if (AppMainWin == NULL)
    {
        SDL_Log("SDL Create Window Fail......%s\r\n", SDL_GetError());
        return 2;
    }

    /* 创建渲染器 */
    AppRender = SDL_CreateRenderer(AppMainWin, -1, SDL_RENDERER_ACCELERATED);
    if (AppRender == NULL)
    {
        SDL_Log("SDL Create Renderer......%s", SDL_GetError());
        return 3;
    }

    // 清空渲染器
    SDL_Rect rect = {0, 0, (OLED_PHY_XWIDTH * A_PIXEL_SIZE), (OLED_PHY_YHEIGHT * A_PIXEL_SIZE)};
    SDL_RenderClear(AppRender);
    SDL_SetRenderDrawColor(AppRender, OLED_DEF_BACK_COLOR); //背景色
    SDL_RenderFillRect(AppRender, &rect);
    SDL_RenderPresent(AppRender);

    return 0;
}




/* 退出SDL2 */
static void vQuit_SDL2(void)
{
    SDL_Log("Complier Date: %s  %s\r\n", __DATE__, __TIME__);

    /* 销毁渲染器 */
    if (AppRender != NULL)  SDL_DestroyRenderer(AppRender);

    /* 销毁窗口 */
    if (AppMainWin != NULL) SDL_DestroyWindow(AppMainWin);

    /* 退出SDL */
    SDL_Quit();
}

二、OLED画点和读点


/* 画点 */
void vOLED_DrawPoint(u16 x, u16 y, u8 mode)
{
    u8  yTemp = 0;
    u16 yPost = 0;

    yPost = y / 8; /* 页位置 */
    yTemp = 0x01 << (y % 8); /* 页偏移位置 */

    if (mode) OLED_DISP_GRAM[x][yPost] |= yTemp;    /* 置位 */
    else      OLED_DISP_GRAM[x][yPost] &= (~yTemp); /* 清零 */
}


/* 读点 */
u8 xOLED_ReadPoint(u16 x, u16 y)
{
    u8  yTemp = 0;
    u16 yPost = 0;

    yPost = y / 8; /* 页位置 */
    yTemp = 0x01 << (y % 8); /* 页偏移位置 */
    return ((OLED_DISP_GRAM[x][yPost] & yTemp) ? 0x01 : 0x00);
}

三、更新OLDE的GRAM


/* 写GRAM */
void vOLED_UpdateGRAM(void)
{
    // SDL_Log("OLED Update Start......%llu\r\n", SDL_GetTicks64());

    SDL_Rect rect = {0, 0, A_PIXEL_SIZE, A_PIXEL_SIZE};
    u16 x = 0, y = 0, i = 0;
    u8  dat = 0;

    for (x = 0; x < OLED_DISP_GRAM_XWIDTH_MAX; ++x)
    {
        rect.x = x * A_PIXEL_SIZE;/* 实际绘制X */
        for (y = 0; y < OLED_DISP_GRAM_YHEIGHT_MAX; ++y)
        {
            dat = OLED_DISP_GRAM[x][y];
            for (i = 0; i < 8; ++i)
            {
                rect.y = ((y << 3) + i) * A_PIXEL_SIZE;/* 实际绘制Y */
                if ((dat >> i) & 0x01) SDL_SetRenderDrawColor(AppRender, OLED_DEF_FORE_COLOR); //前景色
                else                   SDL_SetRenderDrawColor(AppRender, OLED_DEF_BACK_COLOR); //背景色

                SDL_RenderFillRect(AppRender, &rect); // 填充矩形
            }
        }
    }

    SDL_RenderPresent(AppRender); /* 更新屏幕 */
    // SDL_Log("OLED Update End......%llu\r\n", SDL_GetTicks64());
}

四、清屏和清某区域

/* 清屏 */
void vOLED_ClearScreen(void)
{
    u16 x = 0, y = 0;

    for (x = 0; x < OLED_DISP_GRAM_XWIDTH_MAX; ++x)
    {
        for (y = 0; y < OLED_DISP_GRAM_YHEIGHT_MAX; ++y)
        {
            OLED_DISP_GRAM[x][y] = 0;
        }
    }

    SDL_Rect rect = {0, 0, (OLED_PHY_XWIDTH * A_PIXEL_SIZE), (OLED_PHY_YHEIGHT * A_PIXEL_SIZE)};
    SDL_SetRenderDrawColor(AppRender, OLED_DEF_BACK_COLOR);
    SDL_RenderFillRect(AppRender, &rect);
    SDL_RenderPresent(AppRender);
}


void vOLED_ClearArea(u16 x0, u16 y0, u16 x1, u16 y1, u8 mode)
{
    u16 x = 0, y = 0;

    for (x = x0; x <= x1; x++)
    {
        for (y = y0; y <= y1; y++)
        {
            if ((x < AppDevOLED.xWidth) && (y < AppDevOLED.yHeight))
            {
                vOLED_DrawPoint(x, y, mode); 
            }       
        }
    }
}

五、点阵字库

/****************************************************************************************************
  (0) !(1)  "(2)  #(3)  $(4)  %(5)  &(6)  '(7)  ((8)  )(9)  *(10) +(11) ,(12) -(13) .(14) /(15)
0(16) 1(17) 2(18) 3(19) 4(20) 5(21) 6(22) 7(23) 8(24) 9(25) :(26) ;(27) <(28) =(29) >(30) ?(31)
@(32) A(33) B(34) C(35) D(36) E(37) F(38) G(39) H(40) I(41) J(42) K(43) L(44) M(45) N(46) O(47)
P(48) Q(49) R(50) S(51) T(52) U(53) V(54) W(55) X(56) Y(57) Z(58) [(59) \(60) ](61) ^(62) _(63)
`(64) a(65) b(66) c(67) d(68) e(69) f(70) g(71) h(72) i(73) j(74) k(75) l(76) m(77) n(78) o(79)
p(80) q(81) r(82) s(83) t(84) u(85) v(86) w(87) x(88) y(89) z(90) {(91) |(92) }(93) ~(94)

* ASCII常规字符集:
* !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
*
* 1. PCtoLCD2018.exe : 宋体 + 阴码 + 逐列式 + 逆向(低位在前) + C51格式 + 等比缩放
* 2. 英文长宽点阵集(6x12),字宽(12),字高(12)
****************************************************************************************************/
const unsigned char ASCII_FONT_1206[95][12] = 
{
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
    {0x00,0x00,0x00,0x00,0x7C,0x02,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
    {0x00,0x00,0x04,0x00,0x03,0x00,0x04,0x00,0x03,0x00,0x00,0x00},/*""",2*/
    {0x90,0x00,0xFC,0x03,0x90,0x00,0xFC,0x03,0x90,0x00,0x00,0x00},/*"#",3*/
    {0x18,0x01,0x24,0x02,0xFE,0x07,0x44,0x02,0x88,0x01,0x00,0x00},/*"$",4*/
    {0x38,0x00,0x44,0x03,0xF8,0x00,0xD0,0x01,0x2C,0x02,0xC0,0x01},/*"%",5*/
    {0xC0,0x01,0x38,0x02,0xE4,0x02,0x18,0x01,0xE0,0x02,0x20,0x01},/*"&",6*/
    {0x04,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
    {0x00,0x00,0x00,0x00,0xF8,0x00,0x06,0x03,0x01,0x04,0x00,0x00},/*"(",8*/


const unsigned char ASCII_FONT_1608[95][16] = 
{
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
    {0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x33,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
    {0x00,0x00,0x10,0x00,0x0C,0x00,0x02,0x00,0x10,0x00,0x0C,0x00,0x02,0x00,0x00,0x00},/*""",2*/
    {0x00,0x00,0x40,0x04,0xC0,0x3F,0x78,0x04,0x40,0x04,0xC0,0x3F,0x78,0x04,0x00,0x00},/*"#",3*/
    {0x00,0x00,0x70,0x18,0x88,0x20,0x88,0x20,0xFC,0xFF,0x08,0x21,0x30,0x1E,0x00,0x00},/*"$",4*/
    {0xF0,0x00,0x08,0x31,0xF0,0x0C,0x80,0x03,0x60,0x1E,0x18,0x21,0x00,0x1E,0x00,0x00},/*"%",5*/
    {0x00,0x1E,0xF0,0x21,0x08,0x23,0x88,0x2C,0x70,0x19,0x00,0x27,0x00,0x21,0x00,0x10},/*"&",6*/
    {0x00,0x00,0x12,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
    {0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x07,0x18,0x18,0x04,0x20,0x02,0x40,0x00,0x00},/*"(",8*/




const unsigned char ASCII_FONT_2412[95][36] = 
{
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0x77,0x1C,0xF0,0x0F,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
    {0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x00,0x00,0x60,0x00,0x00,0x30,0x00,0x00,0x1C,0x00,0x00,0x8C,0x00,0x00,0x60,0x00,0x00,0x30,0x00,0x00,0x1C,0x00,0x00,0x0C,0x00,0x00,0x00,0x00,0x00},/*""",2*/
    {0x00,0x00,0x00,0x00,0x83,0x01,0x00,0x83,0x1F,0x00,0xFF,0x01,0xF0,0x83,0x01,0x00,0x83,0x01,0x00,0x83,0x01,0x00,0x83,0x01,0x00,0xFB,0x1F,0xF0,0x87,0x01,0x00,0x83,0x01,0x00,0x00,0x00},/*"#",3*/
    {0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x03,0x07,0xC0,0x07,0x0F,0x60,0x0C,0x12,0x20,0x18,0x10,0xF8,0xFF,0x7F,0x20,0x71,0x10,0xE0,0xE1,0x0F,0xC0,0x81,0x07,0x00,0x00,0x00,0x00,0x00,0x00},/*"$",4*/
    {0xC0,0x07,0x00,0x30,0x18,0x00,0x10,0x10,0x18,0x30,0x18,0x07,0xC0,0xCF,0x00,0x00,0x38,0x00,0x00,0xC6,0x07,0xC0,0x31,0x18,0x30,0x10,0x10,0x00,0x30,0x18,0x00,0xC0,0x07,0x00,0x00,0x00},/*"%",5*/
    {0x00,0xC0,0x07,0x00,0xE0,0x0F,0xE0,0x17,0x18,0xF0,0x3F,0x10,0x10,0xF8,0x10,0xF0,0xC7,0x13,0xE0,0x03,0x0F,0x00,0x08,0x0E,0x00,0xF8,0x19,0x00,0x08,0x10,0x00,0x08,0x10,0x00,0x00,0x0C},/*"&",6*/
    {0x00,0x00,0x00,0x00,0x00,0x00,0x8C,0x00,0x00,0x4C,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
    {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x80,0x01,0x03,0x60,0x00,0x0C,0x10,0x00,0x10,0x08,0x00,0x20,0x04,0x00,0x40,0x00,0x00,0x00},/*"(",8*/

六、显示字符串

/* 获取字符数据源地址 */
static void vGet_CharSrc(u8 chr, u8 charSize, u8 ** pSrc)
{
    switch (charSize)
    {
        case ASCII_FONT_TYPE_1206 : *pSrc = (u8 *)(&ASCII_FONT_1206[chr - ' ']); break;
        case ASCII_FONT_TYPE_1608 : *pSrc = (u8 *)(&ASCII_FONT_1608[chr - ' ']); break;
        case ASCII_FONT_TYPE_2412 : *pSrc = (u8 *)(&ASCII_FONT_2412[chr - ' ']); break;
        default: *pSrc = NULL; break;
    }
}


/* 显示字符 */
static void vOLED_DisplayChar(u16 x, u16 y, u8 chr, u8 charSize)
{
    u8 charByte = 0, k = 0, i = 0;
    u8 dat = 0, * pSrcDat = NULL;
    u16 y0 = y;


    //获取字符数据源地址
    vGet_CharSrc(chr, charSize, &pSrcDat);
    if (pSrcDat == NULL) return;

    // 字符点阵占用字节数
    charByte = ((charSize >> 3) + ((charSize & 0x07) ? 1 : 0)) * (charSize >> 1);

    // 遍历字符点阵数据
    for(k = 0; k < charByte; ++k)
    {
        dat = pSrcDat[k];
        for(i = 0; i < 8; ++i)
        {
            // 显示有效范围
            if ((x < AppDevOLED.xWidth) && (y < AppDevOLED.yHeight))
            {
                //低位在前
                if ((dat >> i) & 0x01) vOLED_DrawPoint(x, y, 1);//正常模式
                else                   vOLED_DrawPoint(x, y, 0);//清空模式
            }

            y++;// 纵坐标自加
            if (XABS2(y , y0) >= charSize)//纵坐标偏移量等于字符点阵高度
            {
                y = y0;
                x++;
                break;
            }
        }
    }
}

/* 显示字符串 */
void vOLED_DisplayString(u16 x, u16 y, u8 * pStr, u8 strSize)
{
    //显示ASCII常规字符
    while ((*pStr >= ' ') && (*pStr <= '~'))
    {
        /* 剩余的横纵小于字体宽度 换行显示 */
        if ((x + (strSize >> 1)) >= AppDevOLED.xWidth)
        {
            y += strSize;
            x  = 0;
        }

        /* 剩余纵轴小于字体高度 */
        if ((y + strSize) >= AppDevOLED.yHeight)
        {
            return;
        }

        vOLED_DisplayChar(x, y, *pStr, strSize);
        x += (strSize >> 1);
        pStr++;
    }
}

七、显示中文字符

/* 显示中文字符串 */
void vOLED_Display_ChineseString(u16 x, u16 y, u16 xWidth, u16 yHeight, u8 * pData, u16 num)
{
    u16 i = 0;
    u8 charByte = 0;
    u8 * pMem = pData;


    /* 异常 */
    if ((!num) || (pData == NULL))
    {
        return;
    }

	// 字符点阵占用字节数
    charByte = ((yHeight >> 3) + ((yHeight & 0x07) ? 1 : 0)) * xWidth;

	for (i = 0; i < num; ++i)
	{
		/* 剩余纵轴小于字体高度 */
        if ((y + yHeight) >= AppDevOLED.yHeight)
        {
            return;
        }

        /* 剩余的横纵小于字体宽度 换行显示 */
        if ((x + xWidth) > AppDevOLED.xWidth)
        {
            y += yHeight;
            x  = 0;
        }

        pMem = pData + (charByte * i);
        vOLED_Display_ChineseChar(x, y, xWidth, yHeight, pMem);
        x += xWidth;
	}
}

八、显示图片


/* 图片显示 */
void vOLED_Display_Picture(u16 x, u16 y, u16 xWidth, u16 yHeight, const u8 * pImage)
{
    u16 k = 0, j = 0, i = 0, n = 0;
    u16 yMax = 0, y0 = y;
    u8  dat   = 0;


    yMax = (yHeight >> 3) + ((yHeight & 0x07) ? 1 : 0); //图片高度
    y0 = y; //原始纵坐标

    //图片宽度
    for(k = 0; k < xWidth; k++)
    {
        for(j = 0; j < yMax; j++)
        {
            dat = pImage[n++];
            for(i = 0; i < 8; i++)
            {
                if ((y < AppDevOLED.yHeight) && (x < AppDevOLED.xWidth))
                {
                    //低位在前
                    if ((dat >> i) & 0x01) vOLED_DrawPoint(x, y, 1);//正常模式
                    else                   vOLED_DrawPoint(x, y, 0);//清空模式
                }

                y++;//纵坐标处理
                if (XABS2(y , y0) >= yHeight)
                {
                    y = y0;
                    x++;//横坐标处理
                    break;
                }
            }
        }
    }
}

九、测试代码

/* 正常显示 */
static void vOLED_Test_Show_Normal(void)
{
    static uint8 count = 0;

    vOLED_DisplayString(2, 0, (u8 *)"Normal Show Demo", ASCII_FONT_TYPE_1206);
    vOLED_ClearArea(0, 13, AppDevOLED.xWidth, AppDevOLED.yHeight, 0);

    if ((++count) > 4) count = 0;
    switch (count)
    {
        case 0:
        {
            vOLED_DisplayString(2, 13, (u8 *)"Str:12x06", ASCII_FONT_TYPE_1206);
            vOLED_DisplayString(40, 36, (u8 *)"ABCDE12345678aabcdefghi?#$^&*()-=+[]<>", ASCII_FONT_TYPE_1206);
        }
        break;

        case 1:
        {
            vOLED_DisplayString(2, 13, (u8 *)"Str:16x08:", ASCII_FONT_TYPE_1206);
            vOLED_DisplayString(32, 36, (u8 *)"ABC123", ASCII_FONT_TYPE_1608);
        }
        break;

        case 2:
        {
            vOLED_DisplayString(2, 13, (u8 *)"Str:24x12:", ASCII_FONT_TYPE_1206);
            vOLED_DisplayString(18, 34, (u8 *)"ABC123", ASCII_FONT_TYPE_2412);
        }
        break;

        case 3:
        {
            vOLED_DisplayString(2, 13, (u8 *)"Chin:18x18", ASCII_FONT_TYPE_1206);
            vOLED_Display_ChineseString(1, 37, 18, 18, (u8 *)&ChineseDemo[1], 7);
        }
        break;

        case 4:
        {
            vOLED_DisplayString(2, 13, (u8 *)"Pic:73x36", ASCII_FONT_TYPE_1206);
            vOLED_Display_Picture(53, 25, 73, 36, gImage_VER1_73x36);
        }
        break;

        default: break;
    }
}



void vOLED_Test(void)
{
    vOLED_Test_Show_Normal();
    vOLED_UpdateGRAM();
    ubSuperTimer_Start(vOLED_Test, 2000);
 }


十、主函数

在这里插入图片描述


int main( int argc, char * argv[])
{
    Uint64 curTick = 0;
    SDL_Event event = {0};
    uint8 quitFlg = 1;


    if (xInit_SDL2()) return -1;
    xSuperTimer_Init();
    vOLED_Init();

    ubSuperTimer_Start(vOLED_Test , 500);
    curTick = SDL_GetTicks64();
    while (quitFlg)
    {
        if (SDL_PollEvent(&event))
        {
            switch (event.type)
            {
                case SDL_QUIT: quitFlg = 0; break;

                case SDL_KEYDOWN:
                {
                    switch (event.key.keysym.sym)
                    {
                        case SDLK_UP:    SDL_Log("SDLK_UP......\r\n");    break;
                        case SDLK_DOWN:  SDL_Log("SDLK_DOWN......\r\n");  break;
                        case SDLK_LEFT:  SDL_Log("SDLK_LEFT......\r\n");  break;
                        case SDLK_RIGHT: SDL_Log("SDLK_RIGHT......\r\n"); break;
                        default: break;
                    }
                }
                break;
            
                default: break;
            }
        }

        if (((uint64)(SDL_GetTicks64() - curTick)) > 0)
        {
            vSuperTimer_IncTick();
            curTick = SDL_GetTicks64();
        }

        vSuperTimer_RunHandler();
    }

    vQuit_SDL2();
    return 1;
}

十一、运行结果

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值