设为首页 加入收藏

TOP

表驱动法在STM32中的应用(一)
2023-07-23 13:31:24 】 浏览:123
Tags:STM32 应用

1、概念

所谓表驱动法(Table-Driven Approach)简而言之就是用查表的方法获取数据。此处的“表”通常为数组,但可视为数据库的一种体现。根据字典中的部首检字表查找读音未知的汉字就是典型的表驱动法,即以每个字的字形为依据,计算出一个索引值,并映射到对应的页数。相比一页一页地顺序翻字典查字,部首检字法效率极高。

具体到编程方面,在数据不多时可用逻辑判断语句(if…else或switch…case)来获取值;但随着数据的增多,逻辑语句会越来越长,此时表驱动法的优势就开始显现。

2、简单示例

上面讲概念总是枯燥的,我们简单写一个C语言的例子。下面例子功能:传入不同的数字打印不同字符串。

使用if…else逐级判断的写法如下

void fun(int day)
{
    if (day == 1)
    {
        printf("Monday\n");
    }
    else if (day == 2)
    {
        printf("Tuesday\n");
    }
    else if (day == 3)
    {
        printf("Wednesday\n");
    }
    else if (day == 4)
    {
        printf("Thursday\n");
    }
    else if (day == 5)
    {
        printf("Friday\n");
    }
    else if (day == 6)
    {
        printf("Saturday\n");
    }
    else if (day == 7)
    {
        printf("Sunday\n");
    }
}

使用switch…case的方法写

void fun(int day)
{
    switch (day)
    {
    case 1:
        printf("Monday\n");
        break;
    case 2:
        printf("Tuesday\n");
        break;
    case 3:
        printf("Wednesday\n");
        break;
    case 4;
        printf("Thursday\n");
        break;
        case 5:
        printf("Friday\n");
        break;
    case 6:
        printf("Saturday\n");
        break;
    case 7:printf("Sunday\n");
        break;
    default:
        break;
    }
}

使用表驱动法实现

char weekDay[] = {Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
void fun(int day)
{
  printf("%s\n",weekDay[day]);
}

看完示例,可能“恍然大悟”,一拍大腿,原来表驱动法就是这么简单啊。是的,它的核心原理就是这个简单,如上面例子一样。

如果上面的例子还没get这种用法的好处,那么再举一个栗子。

统计用户输入的一串数字中每个数字出现的次数。

常规写法

int32_t aDigitCharNum[10] = {0}; /* 输入字符串中各数字字符出现的次数 */
int32_t dwStrLen = strlen(szDigits);

int32_t dwStrIdx = 0;
for (; dwStrIdx < dwStrLen; dwStrIdx++)
{
    switch (szDigits[dwStrIdx])
    {
    case '1':
        aDigitCharNum[0]++;
        break;
    case '2':
        aDigitCharNum[1]++;
        break;
    //... ...
    case '9':
        aDigitCharNum[8]++;
        break;
    }
}

表驱动法

for(; dwStrIdx < dwStrLen; dwStrIdx++)
{
    aDigitCharNum[szDigits[dwStrIdx] - '0']++;
}

偶尔在一些开源项目中看到类似的操作,惊呼“骚操作”,其实他们有规范的叫法:表驱动法。

3、在MCU中应用

在MCU中的应用示例,怎么少的了点灯大师操作呢?首先来点一下流水LED灯吧。

常规写法

void LED_Ctrl(void)
{
    static uint32_t sta = 0;

    if (0 == sta)
    {
        LED1_On();
    }
    else
    {
        LED1_Off();
    }

    if (1 == sta)
    {
        LED2_On();
    }
    else
    {
        LED2_Off();
    }

    /* 两个灯,最大不超过2 */
    sta = (sta + 1) % 2;
}

/* 主函数运行 */
int main(void)
{
    while (1)
    {
        LED_Ctrl();
        os_delay(200);
    }
}

表驱动法

extern void LED1_On(void);
extern void LED1_Off(void);
extern void LED2_On(void);
extern void LED2_Off(void);

/* 把同一个灯的操作封装起来 */
struct tagLEDFuncCB
{
    void (*LedOn)(void);
    void (*LedOff)(void);
};

/* 定义需要操作到的灯的表 */
const static struct tagLEDFuncCB LedOpTable[] =
{
        {LED1_On, LED1_Off},
        {LED2_On, LED2_Off},
};

void LED_Ctrl(void)
{
    static uint32_t sta = 0;
    uint8_t i;

    for (i = 0; i < sizeof(LedOpTable) / sizeof(LedOpTable[0]); i++)
    {
        (sta == i) ? (LedOpTable[i].LED_On()) : (LedOpTable[i].LED_Off());
    }

    /* 跑下个灯 */
    sta = (sta + 1) % (sizeof(LedOpTable) / sizeof(LedOpTable[0]));
}

int main(void)
{
    while (1)
    {
        LED_Ctrl();
        os_delay(200);
    }
}

这样的代码结构紧凑,因为和结构体结合起来了,方便添加下一个LED灯到流水灯序列中,这其中涉及到函数指针,详细请看《回调函数》,只需要修改LedOpTable如下

const static struct tagLEDFuncCB LedOpTable[] =
{
    {LED1_On, LED1_Off},
    {LED2_On, LED2_Off},
    {LED3_On, LED3_Off},
};

这年头谁还把流水灯搞的这么花里胡哨的啊,那么就举例在串口解析中的应用,之前的文章推送过《回调函数在命令解析中的应用》,下面只贴一下代码

typedef struct
{
    rt_uint8_t CMD;
    rt_uint8_t (*callback_func)(rt_uint8_t cmd, rt_uin
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇STM32F7xx外设驱动1-led(寄存器) 下一篇《痞子衡嵌入式半月刊》 第 66 期

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目