[uCOS/RTOS] 【RTOS】RT-Thread创新大赛——麻雀一号LCD显示各种大小字体

[复制链接]
 楼主| 发表于 2020-6-7 15:35 | 显示全部楼层 |阅读模式
本帖最后由 WoodData 于 2020-6-7 15:40 编辑

    在麻雀一号开发包里面有字符显示字体和中文字体,其中中文是通过SD卡内文件字库显示的。但是字体只有16X16点阵的,不够用。我就在参考这个的基础上添加了多个字库,存储在SD卡中。有16X16,24X24,32X32,40X40,48X48中文的,以及16X8,24X12,32X16,40X20,48X24的ASCII字符。这些基本够用了。其实还可以很简单再加各种字体。
   下面就分享一下如何实现这些字库显示。
  1. /*
  2. * Copyright (c) 2020. By WoodData
  3. *
  4. *
  5. * Change Logs:
  6. * Date           Author       Notes

  7. */

  8. #ifndef                LCD_FONT__H_
  9. #define                LCD_FONT__H_

  10. #include <rtthread.h>
  11. #include <rtdevice.h>
  12. #include <board.h>

  13. #include "drv_lcd.h"



  14. #define     lcd_color_t     uint16_t

  15. /* type define ------------------------------------------------------------*/
  16. typedef        struct _lcd_font
  17. {
  18.         uint8_t                font_height;                //字库通用高度
  19.         uint8_t                * pfont_buff;                 //字库buff
  20.     uint8_t     * pfont_filename;   //字库文件
  21.         uint8_t                (* get_font_w)(uint16_t ch);                //获取指定字符宽度
  22.         void        (* draw_char)(uint16_t x,uint16_t y,uint16_t ch);        //指定字符描点
  23. }lcd_font_t;

  24. typedef        struct _lcd_font_display
  25. {
  26.         lcd_font_t                *pfont;                //字库索引

  27.     lcd_color_t     font_fore;      //字体前景颜色
  28.     lcd_color_t     font_back;      //字体背景颜色

  29.         uint16_t            font_sx;                //字符显示范围起点x
  30.         uint16_t            font_sy;                //字符显示范围起点y
  31.         uint16_t            font_ex;                //字符显示范围终点x
  32.         uint16_t            font_ey;                //字符显示范围终点y

  33. }lcd_font_display_t;

  34. //common
  35. int GetGBKCode_from_sd(uint8_t *filename, uint16_t ch, uint8_t *pBuffer, uint16_t len);
  36. int GetASCCode_from_sd(uint8_t *filename, uint16_t ch, uint8_t *pBuffer, uint16_t len);


  37. //API
  38. lcd_font_t * lcd_set_font( const  lcd_font_t *newfont);
  39. lcd_font_t * lcd_get_font(void);

  40. void lcd_set_font_color(lcd_color_t fore, lcd_color_t back);
  41. lcd_color_t  lcd_get_font_color_fore(void);
  42. lcd_color_t  lcd_get_font_color_back(void);

  43. void  lcd_set_font_window(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey);


  44. void lcd_disp_char_at(uint16_t usX, uint16_t usY,  uint16_t cChar);
  45. void lcd_disp_str_at(uint16_t usX, uint16_t usY, const char *pStr);

  46. void lcd_font_init(void);

  47. //字库
  48. extern const lcd_font_t Font_CH16X16;
  49. extern const lcd_font_t Font_ASCII16X8;
  50. extern const lcd_font_t Font_CH24X24;
  51. extern const lcd_font_t Font_ASCII24X12;
  52. extern const lcd_font_t Font_CH32X32;
  53. extern const lcd_font_t Font_ASCII32X16;
  54. extern const lcd_font_t Font_CH40X40;
  55. extern const lcd_font_t Font_ASCII40X20;
  56. extern const lcd_font_t Font_CH48X48;
  57. extern const lcd_font_t Font_ASCII48X24;


  58. #endif        //LCD_FONT__H_
  1. /*
  2. * Copyright (c) 2020. By WoodData
  3. *
  4. *
  5. * Change Logs:
  6. * Date           Author       Notes

  7. */

  8. #include <rtthread.h>
  9. #include <rtdevice.h>
  10. #include <board.h>

  11. #include "drv_lcd.h"
  12. #include "lcd_font.h"

  13. lcd_font_display_t       cur_lcd_font_display;

  14. /**
  15. * 设置当前字体
  16. * para: *newfont 新字体
  17. * return:  none
  18. */
  19. lcd_font_t * lcd_set_font(const lcd_font_t *  newfont)
  20. {
  21.     lcd_font_t *oldfont;
  22.     oldfont = cur_lcd_font_display.pfont;
  23.     cur_lcd_font_display.pfont = newfont;
  24.     return oldfont;
  25. }

  26. /**
  27. * 获取当前字体
  28. * para: none
  29. * return: 当前字体
  30. */
  31. lcd_font_t * lcd_get_font(void)
  32. {
  33.     return cur_lcd_font_display.pfont;
  34. }

  35. /**
  36. * 设置当前字体颜色
  37. * para1: fore 前景色
  38. * para2: back 背景色
  39. * return:  none
  40. */
  41. void lcd_set_font_color(lcd_color_t fore, lcd_color_t back)
  42. {
  43.     cur_lcd_font_display.font_fore = fore;
  44.     cur_lcd_font_display.font_back = back;
  45. }

  46. /**
  47. * 获取当前字体前景色
  48. * para: none
  49. * return: 当前字体前景色
  50. */
  51. lcd_color_t  lcd_get_font_color_fore(void)
  52. {
  53.     return cur_lcd_font_display.font_fore;
  54. }

  55. /**
  56. * 获取当前字体背景色
  57. * para: none
  58. * return: 当前字体背景色
  59. */
  60. lcd_color_t  lcd_get_font_color_back(void)
  61. {
  62.     return cur_lcd_font_display.font_back;
  63. }

  64. /**
  65. * 设置字符显示范围
  66. * para1: sx
  67. * para2: sy
  68. * para3: ex
  69. * para4: ey
  70. * return: none
  71. */
  72. void  lcd_set_font_window(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey)
  73. {
  74.     cur_lcd_font_display.font_sx = sx;
  75.     cur_lcd_font_display.font_sy = sy;
  76.     cur_lcd_font_display.font_ex = ex;
  77.     cur_lcd_font_display.font_ey = ey;
  78. }


  79. /**
  80. *  LCD 上显示字符
  81. * usX : 在特定扫描的方向下字符的起始 X 坐标
  82. * usY : 在特定扫描的方向下字符的起始 Y 坐标
  83. * cChar : 要显示的字符
  84. * 返回值 : 无
  85. */
  86. void lcd_disp_char_at(uint16_t usX, uint16_t usY, uint16_t cChar)
  87. {   
  88.     if((cur_lcd_font_display.pfont != NULL) && (cur_lcd_font_display.pfont->draw_char != NULL))
  89.     {
  90.         cur_lcd_font_display.pfont->draw_char(usX, usY, cChar);
  91.     }
  92. }

  93. /**
  94. * 在 LCD 上显示英文字符串
  95. * usX : 在特定扫描方向下字符串的起始 X 坐标
  96. * usY : 在特定扫描方向下字符串的起始 Y 坐标
  97. * pStr : 要显示的英文字符串的首地址
  98. * 返回值 : 无
  99. */

  100. void lcd_disp_str_at(uint16_t usX, uint16_t usY, const char *pStr)
  101. {
  102.     uint16_t  w,ch;

  103.     if(cur_lcd_font_display.pfont == NULL)  return;

  104.     while (*pStr != '\0')
  105.     {
  106.         if(*pStr > 126)
  107.         {
  108.             ch = (*pStr << 8);
  109.             pStr++;  
  110.             ch += *pStr;  
  111.         }
  112.         else
  113.         {
  114.             ch = *pStr;
  115.         }
  116.         
  117.         w = cur_lcd_font_display.pfont->get_font_w(ch);  //获取字符宽度
  118.         #if 0
  119.         if ((usX + w) > cur_lcd_font_display.font_ex)
  120.         {
  121.             usX = cur_lcd_font_display.font_sx;
  122.             usY += cur_lcd_font_display.pfont->font_height;
  123.         }

  124.         if ((usY + cur_lcd_font_display.pfont->font_height) > cur_lcd_font_display.font_ey)
  125.         {
  126.             usX = cur_lcd_font_display.font_sx;
  127.             usY = cur_lcd_font_display.font_sy;
  128.         }
  129.         #endif
  130.         
  131.         lcd_disp_char_at(usX, usY, ch);
  132.         pStr++;
  133.         usX += w;
  134.     }
  135. }


  136. void lcd_font_init(void)
  137. {
  138.     lcd_set_font(&Font_ASCII16X8);
  139.     lcd_set_font_color(BLACK,WHITE);
  140.     lcd_set_font_window(0,0,LCD_W-1,LCD_H-1);
  141. }



下面是各个字库实现基础。以16X16点阵为例:
  1. /*
  2. * Copyright (c) 2020. By WoodData
  3. *
  4. *
  5. * Change Logs:
  6. * Date           Author       Notes

  7. */

  8. #include <rtthread.h>
  9. #include <rtdevice.h>
  10. #include <board.h>

  11. #include "drv_lcd.h"
  12. #include "lcd_font.h"


  13. #define     ASCII_W             8
  14. #define     ASCII_H             16
  15. #define     ASCII_NAME          "/sd/font/ASC16.bin"
  16. #define     ASCII_BUFFER_LEN    16


  17. #define     HZK_W               16
  18. #define     HZK_H               16
  19. #define     HZK_FILENAME        "/sd/font/HZK16.bin"
  20. #define     HZK_BUFFER_LEN      32



  21. extern lcd_font_display_t       cur_lcd_font_display;


  22. /**
  23. * �? lcd 上显示ASCII字符
  24. * x : 在特定扫描方向下字符串的起始 X 坐标
  25. * y : 在特定扫描方向下字符串的起始 Y 坐标
  26. * usChar : 要显示的字符
  27. *
  28. */
  29. void lcd_disp_ascii_16x8(uint16_t x, uint16_t y, uint16_t usChar)
  30. {
  31.     uint8_t ucPage, ucColum, ucPoint8, *ucPtr;
  32.     uint8_t ucBuffer[ASCII_BUFFER_LEN] = {0};

  33.     if(usChar < 0x7f)    //ASCII �?
  34.     {  
  35.         if((x>=LCD_W) || (y>=LCD_H)) return;
  36.         lcd_open_window(x, y, (x+ASCII_W >= LCD_W)?(LCD_W-x):ASCII_W, (y+ASCII_H >= LCD_H)?(LCD_H-y): ASCII_H);
  37.         GetASCCode_from_sd(ASCII_NAME, usChar, ucBuffer, ASCII_BUFFER_LEN); //取字模数�?  
  38.         ucPtr = ucBuffer;
  39.         for (ucPage = 0; ucPage < ASCII_H; ucPage++)
  40.         {
  41.             if((y+ucPage) >= LCD_H)    break;

  42.             for (ucColum = 0; ucColum < (ASCII_W); )
  43.             {
  44.                 for(ucPoint8 = 0;ucPoint8 < 8;ucPoint8++)
  45.                 {
  46.                     if((x+ucColum) < LCD_W)
  47.                     {
  48.                         if( *ucPtr & (0x80 >> ucPoint8)) //高位在前
  49.                         {
  50.                             lcd_write_half_word(cur_lcd_font_display.font_fore);
  51.                         }
  52.                         else
  53.                         {
  54.                             lcd_write_half_word(cur_lcd_font_display.font_back);
  55.                         }
  56.                     }
  57.                     ucColum++;
  58.                     if(ucColum == ASCII_W)  break;                    
  59.                 }
  60.                 ucPtr++;
  61.             }
  62.         }
  63.     }else
  64.     {
  65.         
  66.     }
  67. }

  68. uint8_t                ascii16_get_font_w(uint16_t ch)                //获取指定字符宽度
  69. {
  70.     ch = ch;
  71.     return ASCII_W;

  72. }

  73. const lcd_font_t Font_ASCII16X8 =
  74. {
  75.     ASCII_H,
  76.     ASCII_NAME,
  77.     NULL,
  78.     ascii16_get_font_w,
  79.     lcd_disp_ascii_16x8,
  80. };


  81. /**
  82. * �? lcd 上显示中文字�?
  83. * x : 在特定扫描方向下字符串的起始 X 坐标
  84. * y : 在特定扫描方向下字符串的起始 Y 坐标
  85. * usChar : 要显示的字符
  86. *
  87. */
  88. void lcd_disp_ch16x16(uint16_t x, uint16_t y, uint16_t usChar)
  89. {
  90.     uint8_t ucPage, ucColum, ucPoint8, *ucPtr;
  91.     uint8_t ucBuffer[HZK_BUFFER_LEN] = {0};

  92.     ucPage =  usChar >> 8;      /* 取高8位数�? */
  93.     ucColum = usChar & 0x00FF; /* 取低8位数�? */
  94.     if(usChar < 0x7f)    //ASCII �?
  95.     {
  96.         lcd_disp_ascii_16x8(x,y,usChar);
  97.     }else if((ucPage > 0xa0)&&(ucColum >0xa0))  //中文字符
  98.     {
  99.         if((x>=LCD_W) || (y>=LCD_H)) return;  
  100.         lcd_open_window(x, y, (x+HZK_W >= LCD_W)?(LCD_W-x):HZK_W, (y+HZK_H >= LCD_H)?(LCD_H-y): HZK_H);
  101.         GetGBKCode_from_sd(HZK_FILENAME, usChar, ucBuffer, HZK_BUFFER_LEN); //取字模数�?  
  102.         ucPtr = ucBuffer;
  103.         for (ucPage = 0; ucPage < HZK_H; ucPage++)
  104.         {
  105.             if((y+ucPage) >= LCD_H)    break;
  106.             for (ucColum = 0; ucColum < (HZK_W); )
  107.             {
  108.                 for(ucPoint8 = 0;ucPoint8 < 8;ucPoint8++)
  109.                 {
  110.                     if((x+ucColum) < LCD_W)
  111.                     {
  112.                         if( *ucPtr & (0x80 >> ucPoint8)) //高位在前
  113.                         {
  114.                             lcd_write_half_word(cur_lcd_font_display.font_fore);
  115.                         }
  116.                         else
  117.                         {
  118.                             lcd_write_half_word(cur_lcd_font_display.font_back);
  119.                         }
  120.                     }
  121.                     ucColum++;
  122.                     if(ucColum == HZK_W)  break;
  123.                 }
  124.                 ucPtr++;
  125.             }
  126.         }
  127.     }else //不支持字�?
  128.     {
  129.         
  130.     }
  131. }

  132. uint8_t                CH16_get_font_w(uint16_t ch)                //获取指定字符宽度
  133. {
  134.     uint8_t ucPage, ucColum;

  135.     ucPage =  ch >> 8;      /* 取高8位数�? */
  136.     ucColum = ch & 0x00FF; /* 取低8位数�? */
  137.     if(ch < 0x7f)    //ASCII �?
  138.     {
  139.         return ASCII_W;
  140.     }else if((ucPage > 0xa0)&&(ucColum >0xa0))  //中文字符
  141.     {
  142.         return HZK_W;
  143.     }else
  144.     {
  145.         return 0;
  146.     }
  147. }

  148. const lcd_font_t Font_CH16X16 =
  149. {
  150.     HZK_H,
  151.     ASCII_NAME,
  152.     HZK_FILENAME,
  153.     CH16_get_font_w,
  154.     lcd_disp_ch16x16,
  155. };

测试:
  1. #include <rtthread.h>
  2. #include <rtdevice.h>

  3. #if defined RT_USING_LCD_TEST

  4. //添加 lcd 显示使用的头文件
  5. #include "drv_lcd.h"
  6. #include "lcd_font.h"


  7. int test_lcd_ch(int argc, char *argv[])
  8. {
  9.     rt_err_t ret = RT_EOK;

  10.     lcd_clear(BLUE);

  11.     lcd_set_font(&Font_CH16X16);
  12.     lcd_set_font_color(BLACK, RED);
  13.     lcd_disp_str_at(0, 0, "RT-Thread物联网操作系统");
  14.     rt_thread_mdelay(1000);

  15.     lcd_set_font(&Font_CH24X24);
  16.     lcd_set_font_color(GREEN, BLACK);
  17.     lcd_disp_str_at(20,20, "小而美的物联网操作系统");
  18.     rt_thread_mdelay(1000);

  19.     lcd_set_font(&Font_CH32X32);
  20.     lcd_set_font_color(GREEN, BLACK);
  21.     lcd_disp_str_at(10, 50, "RT-Thread物联网操作系统");
  22.     rt_thread_mdelay(1000);

  23.     lcd_set_font(&Font_CH40X40);
  24.     lcd_set_font_color(WHITE, BLACK);
  25.     lcd_disp_str_at(3, 90, "RT-Thread物联网操作系统");
  26.     rt_thread_mdelay(1000);

  27.     lcd_set_font(&Font_CH48X48);
  28.     lcd_set_font_color(RED, BLUE);
  29.     lcd_disp_str_at(0, 140, "Hi,你好,小而美的物联网操作系统.");
  30.    
  31.     return ret;
  32. }

  33. MSH_CMD_EXPORT(test_lcd_ch, test_lcd_ch);

  34. #endif


最终效果:







字库bin文件:
游客,如果您要查看本帖隐藏内容请回复

实现代码:
游客,如果您要查看本帖隐藏内容请回复



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
发表于 2020-6-7 17:59 | 显示全部楼层
优秀!想请教下,字库bin文件如何生成?比如就是想定制多少区到多少区的字符。
 楼主| 发表于 2020-6-7 18:17 | 显示全部楼层
downloadtext 发表于 2020-6-7 17:59
优秀!想请教下,字库bin文件如何生成?比如就是想定制多少区到多少区的字符。 ...

有个软件生成的。很方便
发表于 2020-6-13 15:51 | 显示全部楼层
这个一定要用SD卡吗?
 楼主| 发表于 2020-6-13 16:43 | 显示全部楼层
gyh974 发表于 2020-6-13 15:51
这个一定要用SD卡吗?

SD卡方便些,你要是有其他存储器把字库文件存进去也行啊
发表于 2020-6-18 00:30 | 显示全部楼层
同问 字体是怎么生成的呢
发表于 2021-2-19 20:20 | 显示全部楼层
感谢分享,学习进步
发表于 2021-2-25 09:53 | 显示全部楼层
谢谢分享
发表于 2022-5-11 16:30 | 显示全部楼层
不错,不错,看看的
发表于 2022-10-4 17:42 | 显示全部楼层
感谢分享,学习进步
发表于 2022-12-14 09:10 | 显示全部楼层
赞一个
发表于 2022-12-15 15:10 | 显示全部楼层
本帖最后由 lzx2475 于 2022-12-15 15:14 编辑

请问对ASC24.bin 怎么根据ascii读取字节

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 发表于 2022-12-15 21:08 | 显示全部楼层
lzx2475 发表于 2022-12-15 15:10
请问对ASC24.bin 怎么根据ascii读取字节


#define     ASCII_W             12
#define     ASCII_H             24
#define     ASCII_NAME          "0:/font/ASC24.bin"
#define     ASCII_BUFFER_LEN    48


#define     HZK_W               24
#define     HZK_H               24
#define     HZK_FILENAME        "0:/font/HZK24.bin"
#define     HZK_BUFFER_LEN      72

/**
* 在 lcd 上显示ASCII字符
* x : 在特定扫描方向下字符串的起始 X 坐标
* y : 在特定扫描方向下字符串的起始 Y 坐标
* usChar : 要显示的字符
*
*/
void lcd_disp_ascii_24x12(uint16_t x, uint16_t y, uint16_t usChar)
{
    uint8_t ucPage, ucColum, ucPoint8, *ucPtr;

    if((usChar >= 0x20)&&(usChar<=0x20+94))    //ASCII 码
    {
        lcd_open_window(x, y, ASCII_W, ASCII_H);
        ucPtr = &ASCII_NAME[(usChar-0x20)*ASCII_BUFFER_LEN];
        for (ucPage = 0; ucPage < ASCII_H; ucPage++)
        {
            for (ucColum = 0;ucColum < ASCII_W;)
            {            
                for(ucPoint8 = 0;ucPoint8 < 8;ucPoint8++)
                {
                    if( *ucPtr & (0x80 >> ucPoint8)) //高位在前
                    {
                        lcd_write_half_word(cur_lcd_font_display.font_fore);
                    }
                    else
                    {
                        lcd_write_half_word(cur_lcd_font_display.font_back);
                    }
                    ucColum++;
                    if(ucColum == ASCII_W)  break;
                }
                ucPtr++;
            }
        }
    }else //不支持字符
    {
        
    }
}
#endif

/**
* 在 lcd 上显示ASCII字符
* x : 在特定扫描方向下字符串的起始 X 坐标
* y : 在特定扫描方向下字符串的起始 Y 坐标
* usChar : 要显示的字符
*
*/
void lcd_disp_ascii_24x12(uint16_t x, uint16_t y, uint16_t usChar)
{
    uint8_t ucBuffer[ASCII_BUFFER_LEN] = {0};

    if(usChar < 0x7f)    //ASCII 鐮?
    {  
        if((x>=LCD_W) || (y>=LCD_H)) return;
        GetGBKCode_from_sd(ASCII_NAME, usChar, ucBuffer, ASCII_BUFFER_LEN); //鍙栧瓧妯℃暟鎹?  
                lcd_char_dot(x,y,ASCII_W,ASCII_H,ucBuffer,cur_lcd_font_display.font_fore,cur_lcd_font_display.font_back);
    }else
    {
        
    }
}

uint8_t                ascii24_get_font_w(uint16_t ch)                //获取指定字符宽度
{
    ch = ch;
    return ASCII_W;

}

const lcd_font_t Font_ASCII24X12 =
{
    ASCII_H,
    ASCII_NAME,
    NULL,
    ascii24_get_font_w,
    lcd_disp_ascii_24x12,
};


/**
* 在 lcd 上显示中文字符
* x : 在特定扫描方向下字符串的起始 X 坐标
* y : 在特定扫描方向下字符串的起始 Y 坐标
* usChar : 要显示的字符
*
*/
void lcd_disp_ch24x24(uint16_t x, uint16_t y, uint16_t usChar)
{
    uint8_t ucPage, ucColum;
    uint8_t ucBuffer[HZK_BUFFER_LEN] = {0};

    ucPage =  usChar >> 8;      /* 取高8位数据 */
    ucColum = usChar & 0x00FF; /* 取低8位数据 */
    if((usChar >= 0x20)&&(usChar <= (0x20+94)))    //ASCII 码
    {
        lcd_disp_ascii_24x12(x,y,usChar);
    }else if((ucPage > 0xa0)&&(ucColum >0xa0))  //中文字符
    {   
        if((x>=LCD_W) || (y>=LCD_H)) return;  
        GetGBKCode_from_sd(HZK_FILENAME, usChar, ucBuffer, HZK_BUFFER_LEN); //取字模数据  
        lcd_char_dot(x,y,HZK_W,HZK_H,ucBuffer,cur_lcd_font_display.font_fore,cur_lcd_font_display.font_back);       
    }else //不支持字符
    {
        
    }
}

uint8_t                CH24_get_font_w(uint16_t ch)                //获取指定字符宽度
{
    uint8_t ucPage, ucColum;

    ucPage =  ch >> 8;      /* 取高8位数据 */
    ucColum = ch & 0x00FF; /* 取低8位数据 */
    if(ch < 0x7f)    //ASCII 码
    {
        return ASCII_W;
    }else if((ucPage > 0xa0)&&(ucColum >0xa0))  //中文字符
    {
        return HZK_W;
    }else
    {
        return 0;
    }
}

const lcd_font_t Font_CH24X24 =
{
    HZK_H,
    ASCII_NAME,
    HZK_FILENAME,
    CH24_get_font_w,
    lcd_disp_ch24x24,
};

发表于 2023-4-24 09:55 | 显示全部楼层

厉害,
发表于 2023-6-1 18:34 | 显示全部楼层
进来好好学习一下
发表于 2025-4-15 16:47 | 显示全部楼层
学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

4784

帖子

28

粉丝
快速回复 返回顶部 返回列表