STM32智能语音学习笔记day06(主要为代码,无新知识点)

1. OLED显示字符串

        代码中,最外部的while循环用来控制显示字符串中的一个字符,当指针str超出字符串后,while循环跳出,函数返回。

        while循环中,还做了判断,判断当前要显示的字符是否超出了屏幕的x轴,如果超出,则换行显示。接着判断要显示的字符是否超出了屏幕的y轴,如果超出,需要自己想解决方法,例如:滚动显示,延迟再分页显示,清屏再接着显示。我采用的是清屏再继续显示字符串剩下的内容。

        相关代码:

/**
 * @brief OLED显示字符串(如果超出x轴会换行显示)
 *
 * @param x x轴起始位置
 * @param y y轴起始位置
 * @param str 要显示的字符串
 * @param mode 是否要反白显示
 *             1,不反白显示
 *             0,反白显示
 */
void OLED_ShowStr(uint8_t x, uint8_t y, char *str, uint8_t mode)
{
    // 判断字符是否符合ASCII的范围
    while ((*str) >= ' ' && (*str) <= '~')
    {
        if (x > OLED_PIXEL_X - OLED_FONT_WIDTH)
        {
            // 如果要显示的字符超出了屏幕的横向范围,换行显示
            x = 0;
            y += OLED_FONT_HEIGHT;
        }

        if (y > OLED_PIXEL_Y - OLED_FONT_HEIGHT)
        {
            // 如果要显示的字符超出了屏幕的纵向范围
            // 做清屏操作,从(0,0)坐标继续显示
            OLED_Clear();
            x = y = 0;
        }

        OLED_ShowChar(x, y, *str++, mode);
        x += OLED_FONT_WIDTH;
    }
}

2. OLED显示数字

        在函数中,通过for循环将要显示的数字一位一位地显示出来。在for循环内,通过计算将要显示的数字的一位(例如个位、十位、百位等)存放到temp中。

        接着判断当前要显示的这一位数字是否是这个数的有效数字(通过enshow这个变量作为标志位,若enshow为初始值0,说明要显示的数字是000xxxx,前面几位数字还不是这个数的有效数字;直到第四位才是,到第四位时,enshow标志位会变成 1,表示这个数接下来的数位都是有效数字)。

        显示一位数完成后,将显示下一位数字,这是判断显示是否会超出屏幕的x轴范围,若超出则换行显示。再判断显示是否会超出屏幕的y轴范围,若超出则清空屏幕,继续显示接下来的数字。

        相关代码:

/**
 * @brief 求一个数的多次方(n的m次方)
 *
 * @param n 底数
 * @param m 幂
 * @retval  返回这个底数的m次方
 */
static uint64_t __mypow(uint32_t n, uint32_t m)
{
    uint64_t ret = 1;
    while (m--)
    {
        ret *= n;
    }

    return ret;
}

/**
 * @brief OLED显示数字(不考虑负数)
 *
 * @param x x轴起始位置
 * @param y y轴起始位置
 * @param num 要显示的数字
 * @param len 数字的长度
 * @param mode 是否要反白显示
 *             1,不反白显示
 *             0,反白显示
 */
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t mode)
{
    uint8_t i;          // 循环计数值
    uint8_t temp;       // 临时变量
    uint8_t enshow = 0; // 有效数字标志位,1:是有效数字,0,不是有效数字

    // 通过循环将每一个数位显示出来
    for (i = 0; i < len; i++)
    {
        // 通过计算得到当前最高位数的值
        temp = num / __mypow(10, len - 1 - i) % 10;

        if (temp == 0)
        {
            if (enshow == 0)
            {
                // 如果最高位是0,并且不是这个数的有效数字
                OLED_ShowChar(x, y, ' ', mode);
            }
            else
            {
                // 如果当前位是0,并且是这个数的有效数字
                OLED_ShowChar(x, y, '0', mode);
            }
        }
        else
        {
            // 如果遇到非零的数位
            enshow = 1;
            OLED_ShowChar(x, y, '0' + temp, mode);
        }

        x += OLED_FONT_WIDTH;
        if (x > OLED_PIXEL_X - OLED_FONT_WIDTH)
        {
            // 如果要显示的字符超出了屏幕的横向范围,换行显示
            x = 0;
            y += OLED_FONT_HEIGHT;
        }
        if (y > OLED_PIXEL_Y - OLED_FONT_HEIGHT)
        {
            // 如果要显示的字符超出了屏幕的纵向范围
            // 做清屏操作,从(0,0)坐标继续显示
            OLED_Clear();
            x = y = 0;
        }
    }
}

3. OLED显示汉字

        要显示汉字,需要准备汉字对应的字库,我使用 阴码 + 逐列式 + 逆向  + C51格式 生成并编写了如下字库:

struct CH32CharTypeDef
{
    char Index[3];   // 汉字内码索引,一个汉字2字节,加上'\0'共三个字节
    uint8_t Msk[32]; // 点阵码数据
};

static const struct CH32CharTypeDef CHCHar_16_16[] = {
"温", {0x10,0x04,0x60,0x04,0x02,0x7E,0x8C,0x01,0x00,0x40,0x00,0x7E,0xFE,0x42,0x92,0x42,0x92,0x7E,0x92,0x42,0x92,0x7E,0x92,0x42,0xFE,0x42,0x00,0x7E,0x00,0x40,0x00,0x00},/*"温",0*/
"湿", {0x10,0x04,0x60,0x04,0x02,0x7E,0x8C,0x01,0x00,0x44,0xFE,0x48,0x92,0x50,0x92,0x7F,0x92,0x40,0x92,0x40,0x92,0x7F,0x92,0x50,0xFE,0x48,0x00,0x44,0x00,0x40,0x00,0x00},/*"湿",1*/
"度", {0x00,0x40,0x00,0x30,0xFC,0x8F,0x24,0x80,0x24,0x84,0x24,0x4C,0xFC,0x55,0x25,0x25,0x26,0x25,0x24,0x25,0xFC,0x55,0x24,0x4C,0x24,0x80,0x24,0x80,0x04,0x80,0x00,0x00},/*"度",2*/
",", {0x00,0x00,0x00,0x00,0x00,0x58,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,0x00},/*",",3*/
":", {0x00,0x00,0x00,0x00,0x00,0x36,0x00,0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*":",4*/
};

        在字库中,首先定义了一个结构体类型,成员1是汉字内码索引,用于比对要打印的汉字是否与当前汉字内码索引的汉字一致。

        成员2是在OLED上显示使用到的数据,对应每个像素的亮/灭情况。

        在字库中,接着结构体类型,定义了该结构体类型的变量,存放可能会用上的 汉字内码索引 和 OLED显示相关的点阵数据。

        OLED显示汉字相关代码:

/**
 * @brief OLED显示汉字
 * 
 * @param x x轴起始位置
 * @param y y轴起始位置
 * @param pHZ 要显示的汉字
 * @param mode 是否要反白显示
 *             1,不反白显示
 *             0,反白显示
 */
void OLED_ShowHZ(uint8_t x, uint8_t y, char *pHZ, uint8_t mode)
{
    uint8_t i; // 循环计数值
    uint8_t j; // 循环计数值
    uint8_t k;
    uint8_t temp; // 临时变量
    uint8_t y0 = y;

    // 计算出汉字字库中数组元素的个数
    uint8_t len = sizeof(CHCHar_16_16) / sizeof(CHCHar_16_16[0]);

    // 字体的大小(所占多少个字节)
    // 通过三目运算符判断字体是跨 奇数个页 还是 偶数个页
    uint8_t size = OLED_CH_FONE_WIDTH * ((OLED_CH_FONT_HEIGHT % 8) ? (OLED_CH_FONT_HEIGHT / 8 + 1) : (OLED_CH_FONT_HEIGHT / 8));

    while (*pHZ != '\0')
    {
        // 当前要显示的汉字不为'\0'时,继续循环

        for (i = 0; i < len; i++)
        {
            if (pHZ[0] == CHCHar_16_16[i].Index[0] && pHZ[1] == CHCHar_16_16[i].Index[1])
            {
                // 如果在字库中找到了该汉字

                // 判断当前汉字有没有超出屏幕显示
                if (x > OLED_PIXEL_X - OLED_CH_FONE_WIDTH)
                {
                    // 如果要显示的字符超出了屏幕的横向范围,换行显示
                    x = 0;
                    y += OLED_CH_FONT_HEIGHT;
                    y0 = y;
                }
                if (y > OLED_PIXEL_Y - OLED_CH_FONT_HEIGHT)
                {
                    // 如果要显示的字符超出了屏幕的纵向范围
                    // 做清屏操作,从(0,0)坐标继续显示
                    OLED_Clear();
                    x = y = 0;
                }

                for (j = 0; j < size; j++)
                {
                    temp = CHCHar_16_16[i].Msk[j];

                    for (k = 0; k < 8; k++)
                    {
                        if (temp & 0x01)
                        {
                            // 如果temp当前最低位是1,画点
                            OLED_DrawPoint(x, y, mode);
                        }
                        else
                        {
                            // 如果temp当前最低位是0,不画点,向显存写入0
                            OLED_DrawPoint(x, y, !mode);
                        }

                        temp >>= 1; // temp的次低位成为最低位,准备画点
                        y++;        // 列,也就是纵坐标,加一

                        if (y - y0 >= OLED_CH_FONT_HEIGHT)
                        {
                            // 如果画完了一列,就要换下一列了
                            y = y0;
                            x++; // x轴加一
                            break;
                        }
                    }
                }

                break; // 如果在字库中找不到汉字
            }
        }

        pHZ += 2;
    }
}

  • 10
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值