程序代码优化的可能性

为什么要写这篇

  因为功能的需要,要实现六个呼吸灯可独立控制最大亮度和呼吸时间,可使用的硬件为六路PWM和一个定时器,"独立控制"因此需要使用硬件定时器分出六个软件定时器,每个软件定时器可设置自己的定时时间,在自己的定时回调函数中设置对应灯引脚的PWM占空比。涉及到很多变量,最初的版本(幼嫩)写了六个回调函数,六个软件定时器独立设置定时时间,这种重复性太强的代码不能提升我技术能力,明明有更简洁的版本可以实现,减少重复代码,变量的处理整合在一起,成为一个模块。出了问题,一套逻辑只需要改一次就可以,而不是六次,从大量变量中解放出来。这好像牵扯到什么工厂模式。

有哪些收获

有三点收获

  1. 将一个有static 静态变量的函数变成了一个可重入的函数
  2. 函数指针常量 和 函数指针变量分清楚了
  3. 通过实例了解到了什么时候需要定时回调函数传入参数

新的认识

通过这一次,感觉自己对C语言和数据结构的运用更进了一步,对程序的稳定性更有了一些信心,现在比较欠缺的是关于函数声明的

  1. 函数对接,每位工程师的命名方式并不相同,在对接的时候会产生一些摩擦。
  2. 每个源文件的外部接口函数很多,也比较杂,如何分类。

最初版本的代码实现方式

定时回调函数

/**
 * white_led_1_pwm_callback
 * @brief	White led 1 timer callback: set PWM duty cycle to control white led 1 brightness
 * @note	1. If brightness is re controlled, the duty cycle will be cleared to 0
 * @note	2. If set the brightness to 0, the duty cycle will be 0
 * @note	3. state_change_flag 0: from dark to bright, maximum value : set_brightness.white_led_1_brightness
 * @note	4. state_change_flag 1: from bright to dark, minimum value : 0
 * @note	5. set PWM duty cycle to control white led 1 brightness
 */
void
white_led_1_pwm_callback(void)
{
    
    
    static uint16_t duty_value = 0;
    static uint8_t state_change_flag = 0;

    if(flag_breath_white_1)
    {
    
    
    	flag_breath_white_1 = FALSE;
        duty_value = 0;
        state_change_flag = 0;
    }else
    {
    
    
        /* no code */
    }

    if(set_brightness.white_led_1_brightness == 0)
    {
    
    
    	duty_value = 0;
    }else
    {
    
    
    	if(state_change_flag == 0)
		{
    
    
			duty_value++;
			if(duty_value >= set_brightness.white_led_1_brightness)
			{
    
    
				state_change_flag = 1;
			}
		}else if(state_change_flag == 1)
		{
    
    
			duty_value--;
			if(duty_value < 1)
			{
    
    
				state_change_flag = 0;
			}
		}
    }

    pwm_set_led_n_brightness(PWM_CHANNEL_WHITE_LED_ID(1), WHITE_LED_ID(1), duty_value);
}

void
white_led_2_pwm_callback(void)
{
    
    
    static uint16_t duty_value = 0;
    static uint8_t state_change_flag = 0;

    if(flag_breath_white_2)
    {
    
    
    	flag_breath_white_2 = FALSE;
        duty_value = 0;
        state_change_flag = 0;
    }else
    {
    
    
        /* no code */
    }

    if(set_brightness.white_led_2_brightness == 0)
    {
    
    
    	duty_value = 0;
    }else
    {
    
    
    	if(state_change_flag == 0)
		{
    
    
			duty_value++;
			if(duty_value >= set_brightness.white_led_2_brightness)
			{
    
    
				state_change_flag = 1;
			}
		}else if(state_change_flag == 1)
		{
    
    
			duty_value--;
			if(duty_value < 1)
			{
    
    
				state_change_flag = 0;
			}
		}
    }

    pwm_set_led_n_brightness(PWM_CHANNEL_WHITE_LED_ID(2), WHITE_LED_ID(2), duty_value);
}

void
white_led_3_pwm_callback(void)
{
    
    
    static uint16_t duty_value = 0;
    static uint8_t state_change_flag = 0;

    if(flag_breath_white_3)
    {
    
    
    	flag_breath_white_3 = FALSE;
        duty_value = 0;
        state_change_flag = 0;
    }else
    {
    
    
        /* no code */
    }

    if(set_brightness.white_led_3_brightness == 0)
    {
    
    
    	duty_value = 0;
    }else
    {
    
    
    	if(state_change_flag == 0)
		{
    
    
			duty_value++;
			if(duty_value >= set_brightness.white_led_3_brightness)
			{
    
    
				state_change_flag = 1;
			}
		}else if(state_change_flag == 1)
		{
    
    
			duty_value--;
			if(duty_value < 1)
			{
    
    
				state_change_flag = 0;
			}
		}
    }

    pwm_set_led_n_brightness(PWM_CHANNEL_WHITE_LED_ID(3), WHITE_LED_ID(3), duty_value);
}

设置定时函数

/**
 * rgb_pwm_breath_set
 * @brief	set up 6 white led breathe info
 * @param	led_breath_time : timer interval, Unit : 0.51 second
 * @note	1. If set timer interval to 0, return
 * @note	2. Clear the original status information of the 6 white led
 * @note	3. PWM init
 * @note	4. According to led_breath_time and set_brightness.white_led_1_brightness set timer interval
 */
void
rgb_pwm_breath_set(uint8_t led_breath_time)
{
    
    
	if(!led_breath_time)
	{
    
    
		return;
	}
	reset_to_gpio();

	pwm_set_clk(CLOCK_SYS_CLOCK_HZ, CLOCK_SYS_CLOCK_HZ);

	if(set_brightness.white_led_1_brightness)
	{
    
    
		uint16_t used_white_1_set_time = (led_breath_time * 510)/(set_brightness.white_led_1_brightness * 2);
		flag_breath_white_1 = TRUE;
		software_timer_set(&timer_white_led_1, white_led_1_pwm_callback, used_white_1_set_time, TRUE);
	}

	if(set_brightness.white_led_2_brightness)
	{
    
    
		uint16_t used_white_2_set_time = (led_breath_time * 510)/(set_brightness.white_led_2_brightness * 2);
		flag_breath_white_2 = TRUE;
		software_timer_set(&timer_white_led_2, white_led_2_pwm_callback, used_white_2_set_time, TRUE);
	}

	if(set_brightness.white_led_3_brightness)
	{
    
    
		uint16_t used_white_3_set_time = (led_breath_time * 510)/(set_brightness.white_led_3_brightness * 2);
		flag_breath_white_3 = TRUE;
		software_timer_set(&timer_white_led_3, white_led_3_pwm_callback, used_white_3_set_time, TRUE);
	}

}

  它们之间有太强的相似性,但是要将它们整合在一起并不是一个简单的事情。 涉及到局部变量,静态变量,结构体变量,位域,宏定义 ,结构体指针和函数指针。但这是一件很有必要的事情,相当于将所有的数据进行了一次整合,对程序代码进行了一次优化,程序逻辑更清晰了,对变量的操作少了,更容易维护了。

怎么优化

  我想到了软件定时器的那种链表查询方式,想到了表驱动,因为这个灯的数目是一定的,相对于链表实现,数组实现更好一些,实现起来简单。

  通过这一次,新增了两个结构体和一个结构体数组,以及去掉了一个结构体,一个位域。

去掉的结构体和位域

/* Maximum set brightness of white led */
typedef struct
{
    
    
	uint8_t white_led_1_brightness;
	uint8_t white_led_2_brightness;
	uint8_t white_led_3_brightness;
	uint8_t white_led_4_brightness;
	uint8_t white_led_5_brightness;
	uint8_t white_led_6_brightness;
}White_Led_Brightness;

/* LED mode start flag bit */
union rgb_flag
{
    
    
    struct mode
    {
    
    
        unsigned bit0   : 1;
        unsigned bit1   : 1;
        unsigned bit2   : 1;
        unsigned bit3   : 1;
        unsigned bit4   : 1;
        unsigned bit5   : 1;
        unsigned bit6   : 1;
        unsigned bit7   : 1;
    }bit_type;
    unsigned char byte;
}FLAG_RGB;

#define flag_mode				FLAG_RGB.byte
#define flag_blink_white		FLAG_RGB.bit_type.bit0
#define flag_breath_white_1    	FLAG_RGB.bit_type.bit1
#define flag_breath_white_2		FLAG_RGB.bit_type.bit2
#define flag_breath_white_3		FLAG_RGB.bit_type.bit3
#define flag_breath_white_4		FLAG_RGB.bit_type.bit4
#define flag_breath_white_5		FLAG_RGB.bit_type.bit5
#define flag_breath_white_6		FLAG_RGB.bit_type.bit6

优化后的代码实现方式

一些相关设置

/* Configure white led pin */
#define WHITE_LED_ID_1		GPIO_PB5
#define WHITE_LED_ID_2		GPIO_PB4
#define WHITE_LED_ID_3		GPIO_PC2
#define WHITE_LED_ID(n)		WHITE_LED_ID_##n

/* Configure PWM channel for controlling white led */
#define PWM_CHANNEL_WHITE_LED_ID_1 		PWM5_ID
#define PWM_CHANNEL_WHITE_LED_ID_2 		PWM4_ID
#define PWM_CHANNEL_WHITE_LED_ID_3 		PWM0_ID
#define PWM_CHANNEL_WHITE_LED_ID(n)		PWM_CHANNEL_WHITE_LED_ID_##n

typedef (*Breath_Callback)(FOR_CALLBACK* para_val);
void white_led_breath_callback(FOR_CALLBACK* para_val);

相关数据结构定义

typedef struct 
{
    
    
    uint8_t flag_led_breath_start;          ///< Flag of breath start, used to clear variables : flag_state_change and u8_duty_value
    uint8_t u8_led_brightness;              ///< Store the maximum brightness setting
    Pwm_Id pwm_id;                          ///< pwm channel ID
    GPIO_PinTypeDef pwm_pin;                ///< Pin configured in PWM mode

    uint8_t flag_state_change;              ///< Private, protected, flag of state change, state : darkest -> brightest  or  brightest -> darkest
    uint16_t u8_duty_value;                 ///< Private, protected, PWM duty cycle
}FOR_CALLBACK;

typedef struct 
{
    
    
    Soft_Timer * timer;                     ///< point of soft timer
    Breath_Callback timer_callback;         ///< callback of soft timer
    FOR_CALLBACK series_variables;          ///< A series of variables used for callback
}Breath_Info;

Breath_Info array_breath_info[3];

相关初始化

void breath_info_array_regist(void)
{
    
    
    array_breath_info[0].timer = &timer_white_led_1;
    array_breath_info[0].timer_callback = white_led_breath_callback;
    array_breath_info[0].series_variables.flag_led_breath_start = 0;
    array_breath_info[0].series_variables.u8_led_brightness = 0;
    array_breath_info[0].series_variables.pwm_id = PWM_CHANNEL_WHITE_LED_ID(1);
    array_breath_info[0].series_variables.pwm_pin = WHITE_LED_ID(1);

    array_breath_info[1].timer = &timer_white_led_2;
    array_breath_info[1].timer_callback = white_led_breath_callback;
    array_breath_info[1].series_variables.flag_led_breath_start = 0;
    array_breath_info[1].series_variables.u8_led_brightness = 0;
    array_breath_info[1].series_variables.pwm_id = PWM_CHANNEL_WHITE_LED_ID(2);
    array_breath_info[1].series_variables.pwm_pin = WHITE_LED_ID(2);

    array_breath_info[2].timer = &timer_white_led_3;
    array_breath_info[2].timer_callback = white_led_breath_callback;
    array_breath_info[2].series_variables.flag_led_breath_start = 0;
    array_breath_info[2].series_variables.u8_led_brightness = 0;
    array_breath_info[2].series_variables.pwm_id = PWM_CHANNEL_WHITE_LED_ID(3);
    array_breath_info[2].series_variables.pwm_pin = WHITE_LED_ID(3);
}

设置呼吸时间

  根据某种功能要求,先设置亮度,再设置呼吸时间。

  设置亮度 : 将亮度数值传入 array_breath_info[i].series_variables.u8_led_brightness 变量

  设置呼吸时间 :

/**
 * test_rgb_pwm_breath_set
 * @brief	set up 6 white led breathe info
 * @param	led_breath_time : timer interval, Unit : 0.51 second
 * @note	1. If set timer interval to 0, return
 * @note	2. Clear the original status information of the 6 white led
 * @note	3. PWM init
 * @note	4. According to led_breath_time and set_brightness.white_led_1_brightness set timer interval
 */
void test_rgb_pwm_breath_set(uint8_t led_breath_time)
{
    
    
    if(!led_breath_time)
    {
    
    
        return;
    }

    for(uint8_t i = 0; i < sizeof(array_breath_info) / sizeof(array_breath_info[0]); i++)
    {
    
    
        if(array_breath_info[i].series_variables.u8_led_brightness)
        {
    
    
            uint16_t used_white_set_time = (led_breath_time * 510)/(array_breath_info[i].series_variables.u8_led_brightness * 2);
            array_breath_info[i].series_variables.flag_led_breath_start = 1;
            software_timer_set(array_breath_info[i].timer, array_breath_info[i].timer_callback, used_white_set_time, TRUE, &array_breath_info[i].series_variables);
        }
    }
}

呼吸的定时回调

/**
 * white_led_breath_callback
 * @brief   Timer callback function for white LED breathing
 * @param   para_val, para description: Variable pointer
 */
void
white_led_breath_callback(FOR_CALLBACK* para_val)
{
    
    
    if(para_val->flag_led_breath_start)
    {
    
    
    	para_val->flag_led_breath_start = 0;
        para_val->u8_duty_value = 0;
        para_val->flag_state_change = 0;
    }else
    {
    
    
        /* no code */
    }

    if(para_val->u8_led_brightness == 0)
    {
    
    
    	para_val->u8_duty_value = 0;
    }else
    {
    
    
    	if(para_val->flag_state_change == 0)
		{
    
    
			para_val->u8_duty_value++;
			if(para_val->u8_duty_value >= para_val->u8_led_brightness)
			{
    
    
				para_val->flag_state_change = 1;
			}
		}else if(para_val->flag_state_change == 1)
		{
    
    
			para_val->u8_duty_value--;
			if(para_val->u8_duty_value < 1)
			{
    
    
				para_val->flag_state_change = 0;
			}
		}
    }

    pwm_set_led_n_brightness(para_val->pwm_id, para_val->pwm_pin, para_val->u8_duty_value);
}

代码用于实际的可能性

  因为该代码是基于软件定时器Multi_timer的,要想将代码用于实际,需要软件定时器支持回调函数传入参数,而要想支持的话,需要修改模块底层实现,同时将设置定时器的接口多一个传入参数指针的形参。

  从技术上完全可以实现,然后将代码用于实际,如果是自己写的代码可以,但如果是公司成熟(大量使用)的代码更多时候是不让改。

lue–;
if(para_val->u8_duty_value < 1)
{
para_val->flag_state_change = 0;
}
}
}

pwm_set_led_n_brightness(para_val->pwm_id, para_val->pwm_pin, para_val->u8_duty_value);

}


## 代码用于实际的可能性

&emsp;&emsp;因为该代码是基于软件定时器Multi_timer的,要想将代码用于实际,需要软件定时器支持回调函数传入参数,而要想支持的话,需要修改模块底层实现,同时将设置定时器的接口多一个传入参数指针的形参。

&emsp;&emsp;从技术上完全可以实现,然后将代码用于实际,如果是自己写的代码可以,但如果是公司成熟(大量使用)的代码更多时候是不让改。



猜你喜欢

转载自blog.csdn.net/quanquanxiaobu/article/details/114830076