SXSBJSXYT

保持热爱,奔赴山海

 

单片机开发之理解面向对象思想

        假设项目组现在有个需求,需要为一个智能家居系统开发LED灯控制模块,共有三种LED灯,单色LED、RGB灯、智能灯带(SPI控制)。

        小张大学刚毕业,觉得这个需求就是控制个LED灯,没有什么难度,于是自告奋勇,承担了开发工作。由于功能简单,小张很快就开发完了,于是往仓库推送了代码。然后主管审查了小张的代码,意料之中小张用的是面向过程的编程思想,写的代码是又臭又长,不好维护。好在项目不是很着急,于是给小张培训了一下面向对象的编程思想,让他重构了代码。

        本文第一部分面向过程的设计思路是小张初版的代码,第二部分面向过程的设计思路是最终版的代码。两者对比起来看就能发现面向对象编程思想的魅力所在。

目录

1. 面向过程的设计思路

1.1. 按功能模块划分

 1.2. 数据结构定义

1.3. 系统初始化流程 

 1.4. 核心控制逻辑

 1.5. 主程序流程

2. 面向对象的设计思路

2.1. 基类:灯(Light)

2.2. 子类:不同类型的LED灯 

2.3. 面向过程的具体实现

2.4. 多态的威力(统一接口)

3. 总结

3.1. 面向对象设计的好处

3.2. 面向过程实现的必要性

3.3. 两者结合

3.4. 实际开发中的价值


1. 面向过程的设计思路

        面向过程就是按照功能流程来组织代码,重点是"做什么事情,按什么顺序做"。

1.1. 按功能模块划分

// ============ 硬件抽象层 ============
// GPIO操作函数
void gpio_init(uint8_t pin, uint8_t mode);
void gpio_write(uint8_t pin, uint8_t value);
uint8_t gpio_read(uint8_t pin);

// PWM操作函数
void pwm_init(uint8_t pin, uint16_t frequency);
void pwm_set_duty(uint8_t pin, uint16_t duty);
void pwm_stop(uint8_t pin);

// SPI操作函数
void spi_init(uint8_t cs_pin);
void spi_transmit(uint8_t* data, uint16_t len);

// ============ LED硬件控制层 ============
// 单色LED控制
void simple_led_init(uint8_t pin);
void simple_led_on(uint8_t pin, uint8_t brightness);
void simple_led_off(uint8_t pin);

// RGB LED控制
void rgb_led_init(uint8_t r_pin, uint8_t g_pin, uint8_t b_pin);
void rgb_led_on(uint8_t r_pin, uint8_t g_pin, uint8_t b_pin, 
                uint8_t r_val, uint8_t g_val, uint8_t b_val, uint8_t brightness);
void rgb_led_off(uint8_t r_pin, uint8_t g_pin, uint8_t b_pin);

// LED灯带控制
void led_strip_init(uint8_t cs_pin, uint16_t led_count);
void led_strip_on(uint8_t cs_pin, uint16_t led_count, uint8_t brightness);
void led_strip_off(uint8_t cs_pin, uint16_t led_count);

 1.2. 数据结构定义

// ============ 配置数据结构 ============
// 系统中所有LED的配置信息
typedef enum {
    LED_TYPE_SIMPLE,
    LED_TYPE_RGB,
    LED_TYPE_STRIP
} led_type_t;

typedef struct {
    uint8_t led_id;
    led_type_t type;
    uint8_t brightness;
    uint8_t is_on;
    
    // 根据类型使用不同的引脚配置
    union {
        struct {
            uint8_t gpio_pin;
        } simple;
        
        struct {
            uint8_t red_pin;
            uint8_t green_pin;
            uint8_t blue_pin;
            uint8_t red_value;
            uint8_t green_value;
            uint8_t blue_value;
        } rgb;
        
        struct {
            uint8_t spi_cs_pin;
            uint16_t led_count;
        } strip;
    } config;
} led_info_t;

// 全局LED配置数组
#define MAX_LEDS 10
led_info_t g_led_list[MAX_LEDS];
uint8_t g_led_count = 0;

1.3. 系统初始化流程 

// ============ 系统初始化 ============
void led_system_init(void) {
    // 第1步:硬件初始化
    gpio_init_all();
    pwm_init_all();
    spi_init_all();
    
    // 第2步:加载LED配置
    load_led_config();
    
    // 第3步:初始化各个LED
    for (int i = 0; i < g_led_count; i++) {
        switch (g_led_list[i].type) {
            case LED_TYPE_SIMPLE:
                simple_led_init(g_led_list[i].config.simple.gpio_pin);
                break;
            case LED_TYPE_RGB:
                rgb_led_init(g_led_list[i].config.rgb.red_pin,
                           g_led_list[i].config.rgb.green_pin,
                           g_led_list[i].config.rgb.blue_pin);
                break;
            case LED_TYPE_STRIP:
                led_strip_init(g_led_list[i].config.strip.spi_cs_pin,
                             g_led_list[i].config.strip.led_count);
                break;
        }
    }
    
    printf("LED系统初始化完成,共%d个LED\n", g_led_count);
}

void load_led_config(void) {
    // 硬编码配置(实际项目中可能从EEPROM或配置文件读取)
    g_led_list[0] = (led_info_t){1, LED_TYPE_SIMPLE, 0, 0, {.simple = {12}}};
    g_led_list[1] = (led_info_t){2, LED_TYPE_RGB, 0, 0, {.rgb = {5, 6, 7, 255, 255, 255}}};
    g_led_list[2] = (led_info_t){3, LED_TYPE_STRIP, 0, 0, {.strip = {8, 30}}};
    g_led_count = 3;
}

 1.4. 核心控制逻辑

// ============ LED控制接口 ============
void led_turn_on(uint8_t led_id, uint8_t brightness) {
    // 第1步:查找LED
    int index = find_led_by_id(led_id);
    if (index < 0) {
        printf("LED %d 未找到\n", led_id);
        return;
    }
    
    // 第2步:更新状态
    g_led_list[index].brightness = brightness;
    g_led_list[index].is_on = 1;
    
    // 第3步:根据类型执行相应操作
    switch (g_led_list[index].type) {
        case LED_TYPE_SIMPLE:
            simple_led_on(g_led_list[index].config.simple.gpio_pin, brightness);
            break;
            
        case LED_TYPE_RGB:
            rgb_led_on(g_led_list[index].config.rgb.red_pin,
                      g_led_list[index].config.rgb.green_pin,
                      g_led_list[index].config.rgb.blue_pin,
                      g_led_list[index].config.rgb.red_value,
                      g_led_list[index].config.rgb.green_value,
                      g_led_list[index].config.rgb.blue_value,
                      brightness);
            break;
            
        case LED_TYPE_STRIP:
            led_strip_on(g_led_list[index].config.strip.spi_cs_pin,
                        g_led_list[index].config.strip.led_count,
                        brightness);
            break;
    }
    
    printf("LED %d 已开启,亮度 %d%%\n", led_id, brightness);
}

void led_turn_off(uint8_t led_id) {
    // 第1步:查找LED
    int index = find_led_by_id(led_id);
    if (index < 0) return;
    
    // 第2步:更新状态
    g_led_list[index].is_on = 0;
    
    // 第3步:根据类型执行相应操作
    switch (g_led_list[index].type) {
        case LED_TYPE_SIMPLE:
            simple_led_off(g_led_list[index].config.simple.gpio_pin);
            break;
        case LED_TYPE_RGB:
            rgb_led_off(g_led_list[index].config.rgb.red_pin,
                       g_led_list[index].config.rgb.green_pin,
                       g_led_list[index].config.rgb.blue_pin);
            break;
        case LED_TYPE_STRIP:
            led_strip_off(g_led_list[index].config.strip.spi_cs_pin,
                         g_led_list[index].config.strip.led_count);
            break;
    }
    
    printf("LED %d 已关闭\n", led_id);
}

// 批量控制
void led_control_all(uint8_t brightness) {
    printf("开始控制所有LED,亮度:%d%%\n", brightness);
    
    for (int i = 0; i < g_led_count; i++) {
        led_turn_on(g_led_list[i].led_id, brightness);
    }
    
    printf("所有LED控制完成\n");
}

// 辅助函数
int find_led_by_id(uint8_t led_id) {
    for (int i = 0; i < g_led_count; i++) {
        if (g_led_list[i].led_id == led_id) {
            return i;
        }
    }
    return -1;
}

 1.5. 主程序流程

// ============ 主程序 ============
int main(void) {
    // 第1步:系统初始化
    led_system_init();
    
    // 第2步:执行控制逻辑
    while (1) {
        // 场景1:单独控制
        led_turn_on(1, 80);  // 厨房灯
        delay_ms(1000);
        
        led_turn_on(2, 60);  // 客厅RGB灯
        delay_ms(1000);
        
        led_turn_on(3, 40);  // 卧室灯带
        delay_ms(2000);
        
        // 场景2:全部关闭
        led_turn_off(1);
        led_turn_off(2);
        led_turn_off(3);
        delay_ms(2000);
        
        // 场景3:批量控制
        led_control_all(50);
        delay_ms(3000);
    }
}

2. 面向对象的设计思路

2.1. 基类:灯(Light)

// 所有灯的通用"图纸"
typedef struct {
    uint8_t id;           // 灯的编号
    uint8_t brightness;   // 亮度 0-100
    uint8_t is_on;        // 开关状态
    
    // 所有灯都应该有的基本功能(接口)
    void (*turn_on)(void* self);
    void (*turn_off)(void* self);
    void (*set_brightness)(void* self, uint8_t level);
    void (*get_status)(void* self);
} Light;

2.2. 子类:不同类型的LED灯 

// 单色LED灯
typedef struct {
    Light base;        // 继承基本灯的功能
    uint8_t gpio_pin;  // GPIO引脚号
} SimpleLED;

// RGB LED灯
typedef struct {
    Light base;        // 继承基本灯的功能
    uint8_t red_pin;
    uint8_t green_pin;
    uint8_t blue_pin;
    uint8_t red_value;   // 红色分量
    uint8_t green_value; // 绿色分量
    uint8_t blue_value;  // 蓝色分量
} RgbLED;

// 智能LED灯带
typedef struct {
    Light base;        // 继承基本灯的功能
    uint8_t spi_cs_pin;
    uint16_t led_count; // LED数量
    uint8_t* led_data;  // LED数据缓冲区
} LedStrip;

2.3. 面向过程的具体实现

虽然接口统一,但每种LED的具体实现是面向过程的:

// 单色LED的具体实现(面向过程的步骤)
void simple_led_turn_on(void* self) {
    SimpleLED* led = (SimpleLED*)self;
    
    // 第1步:设置GPIO为输出模式
    gpio_set_mode(led->gpio_pin, GPIO_OUTPUT);
    
    // 第2步:根据亮度计算PWM占空比
    uint16_t pwm_value = (led->base.brightness * 255) / 100;
    
    // 第3步:启动PWM输出
    pwm_set_duty(led->gpio_pin, pwm_value);
    
    // 第4步:更新状态
    led->base.is_on = 1;
    
    printf("单色LED %d 已开启,亮度: %d%%\n", led->base.id, led->base.brightness);
}

// RGB LED的具体实现(面向过程的步骤)
void rgb_led_turn_on(void* self) {
    RgbLED* led = (RgbLED*)self;
    
    // 第1步:计算各颜色通道的PWM值
    uint16_t red_pwm = (led->red_value * led->base.brightness) / 100;
    uint16_t green_pwm = (led->green_value * led->base.brightness) / 100;
    uint16_t blue_pwm = (led->blue_value * led->base.brightness) / 100;
    
    // 第2步:设置各个颜色通道
    pwm_set_duty(led->red_pin, red_pwm);
    pwm_set_duty(led->green_pin, green_pwm);
    pwm_set_duty(led->blue_pin, blue_pwm);
    
    // 第3步:更新状态
    led->base.is_on = 1;
    
    printf("RGB LED %d 已开启,颜色: R%d G%d B%d,亮度: %d%%\n", 
           led->base.id, led->red_value, led->green_value, led->blue_value, led->base.brightness);
}

// LED灯带的具体实现(面向过程的步骤)
void led_strip_turn_on(void* self) {
    LedStrip* strip = (LedStrip*)self;
    
    // 第1步:准备SPI数据
    for (int i = 0; i < strip->led_count * 3; i++) {
        strip->led_data[i] = (strip->base.brightness * 255) / 100;
    }
    
    // 第2步:选中SPI设备
    gpio_write(strip->spi_cs_pin, 0);
    
    // 第3步:发送数据到LED灯带
    spi_transmit(strip->led_data, strip->led_count * 3);
    
    // 第4步:取消选中
    gpio_write(strip->spi_cs_pin, 1);
    
    // 第5步:更新状态
    strip->base.is_on = 1;
    
    printf("LED灯带 %d 已开启,%d个LED,亮度: %d%%\n", 
           strip->base.id, strip->led_count, strip->base.brightness);
}

2.4. 多态的威力(统一接口)

// 统一的控制函数(多态)
void control_all_lights(Light** lights, int count, uint8_t brightness) {
    for (int i = 0; i < count; i++) {
        // 不管是什么类型的LED,调用方式都一样
        lights[i]->set_brightness(lights[i], brightness);
        lights[i]->turn_on(lights[i]);
    }
}

// 使用示例
int main() {
    // 创建不同类型的LED对象
    SimpleLED kitchen_light = {{1, 80, 0, simple_led_turn_on, simple_led_turn_off, simple_led_set_brightness, simple_led_get_status}, 12};
    RgbLED living_room_light = {{2, 60, 0, rgb_led_turn_on, rgb_led_turn_off, rgb_led_set_brightness, rgb_led_get_status}, 5, 6, 7, 255, 200, 100};
    LedStrip bedroom_strip = {{3, 40, 0, led_strip_turn_on, led_strip_turn_off, led_strip_set_brightness, led_strip_get_status}, 8, 30, NULL};
    
    // 统一管理(多态的好处)
    Light* all_lights[] = {(Light*)&kitchen_light, (Light*)&living_room_light, (Light*)&bedroom_strip};
    
    // 一键控制所有LED - 每种LED用自己的方式实现
    control_all_lights(all_lights, 3, 75);
    
    return 0;
}

3. 总结

3.1. 面向对象设计的好处

  1. 统一接口:不管什么LED,都用 turn_on() 开灯
  2. 便于扩展:新增LED类型不影响现有代码
  3. 便于管理:可以用同一套代码控制所有LED

3.2. 面向过程实现的必要性

  • 单色LED需要控制一个GPIO
  • RGB LED需要控制三个PWM通道
  • LED灯带需要SPI通信
  • 每种都有自己具体的硬件操作步骤

3.3. 两者结合

  • 面向对象让你的代码结构清晰,易于维护
  • 面向过程让你的代码能真正控制硬件

3.4. 实际开发中的价值

// 如果只用面向过程,代码可能是这样:
void turn_on_kitchen_light() { /* 控制GPIO12 */ }
void turn_on_living_room_light() { /* 控制RGB PWM */ }
void turn_on_bedroom_strip() { /* 控制SPI */ }
void set_kitchen_brightness(uint8_t level) { /* ... */ }
void set_living_room_brightness(uint8_t level) { /* ... */ }
// ... 每种LED都要写一套函数

// 用面向对象后:
Light* light = get_light_by_id(room_id);
light->turn_on(light);  // 简洁统一

        这就是面向对象的价值:用统一的方式处理不同的事物,让复杂系统变得简单易懂。但底层实现依然是面向过程的硬件操作步骤。 

posted on 2025-06-15 16:53  SXSBJSXYT  阅读(15)  评论(0)    收藏  举报  来源

导航