为什么要写这篇
近期一直在看C Primer Plus,对于C语言的掌握能力有了显著提升,运用也更灵活。因此对C语言刷新的认知是:C语言是把刻刀。同时在习以为常之前记录一下成长:成长中实践。
编译出错,语义错误什么的不再是简单的认为改改就好,问题解决能用就行,到如何用好C语言,少犯一些低级错误。为什么觉得低级,又为什么觉得是刻刀?因为工具参考书就在那里,写得明明白白,不去使用手册。遇到问题不从自身找原因,那种吃一堑长一智的做法,前期可行,但想一直用下去,永远对C语言掌握的不够透彻,永远不会觉得这只是一个工具(刻刀)。而且不看C语言的书籍,不会清楚明白的了解C语言和其它编程语言的界限在哪里。更别提以他山之石,攻己之玉。
为什么会用到结构体数组
对于结构体数组,前些天有个同事说链表真好用,但是它的关注点是插入排序(用于对蓝牙设备顺序存入,然后将新的蓝牙设备按照接收灵敏度插入到链表中,既完成了存入,又完成了排序)。但因为他是第一次用链表,表述成了链表排序真好用,根据这个情况,当时我想到的是用结构体数组应该更好一些吧,数组的排序要比链表快吧(回头查一下链表的插入排序与数组的冒泡排序或快速排序 的对比),但这时在我心里留下了一个结,因为我还没用过结构体数组,却劝别人用。
什么时候用得到结构体数组
因为一个灯板的电路进行了更改,因为选择的芯片引脚不够控制那么多RGB灯,因此用上了74HC595芯片(串转并),想了解的可以看一下这篇文章:74HC595引脚图详解
一开始没有想到更改硬件之后会对原来的功能产生影响,认为只需要把RGB灯控制部分的程序更改为用74HC595控制就好了,但是后来发现个问题。
之前RGB灯的七种颜色控制是直接用红、绿、蓝颜色的灯亮灭来拼出来的,控制红、绿、蓝颜色灯的引脚高低就可以控制灯颜色,程序函数实现并非用常量来标识要显示的颜色,而是通过表示常量的标识符(宏定义或枚举类型)来表示的颜色。当常量要控制的颜色修改时,只需修改宏定义处数值或枚举类型的标识符顺序,而无需修改程序内部逻辑。
但换成74HC595后,红绿蓝颜色灯的引脚不能单独控制了,通过按位输入到74HC595,导致常量控制的颜色是固定死的,修改常量对应的颜色已经不是宏定义就能决定的了。
{BLUE,GREEN, RED} 红灯{0,0,1} 黄灯{0,1,1} 绿灯{0,1,0} 青灯{1,1,0} 蓝灯{1,0,0} 紫灯{1,0,1} 白灯{1,1,1}
常量和颜色控制这种关联对于改需求来说太困难了,说不定一句话更改需求就得让人费一番功夫;而且可读性也是个问题,给其控制常量从1~7,按照人的常规印象是颜色渐变 ,红->黄->绿->青->蓝->紫->白。如果不是这个顺序,对于项目经理来说,这设计可能有点儿反人类了。
怎么改?颜色标识符与对应的常量分开,怎么分?标识符也是必须表示什么东西才可以,变量常量或数组结构体函数等,最简单的还是是标记常量,然后该常量有与控制颜色的常量无关,那么就可以用枚举类型了,标识符的顺序决定了对应的标识符常量。不过这没关系,因为颜色标识符对应的常量已经与控制颜色的常量无关了,顺序随意。这时候就想到结构体数组了。
之后要修改常量对应的颜色只需修改枚举类型 rgb_color的标识符顺序就可以了, 如果硬件电路有修改只需要更改total_color数组每一项的set_color值就可以啦。
为什么要顺序查找,因为结构体数组的每一项下标是固定的,只是每一项结构体的成员变量可能发生改变(修改常量对应的颜色)。若按照标识符表示的常量值(要设置的颜色对应的常量)进行排序,只需初始化时进行一次,使其与结构体的下标相对应,之后直接访问结构体另一项成员变量就可以了。
下面是改进后的测试程序,可以直接在菜鸟C在线工具运行。此处对排序的使用还是基于之前的架构,交换的函数有所不同,冒泡排序的实现和以前也有所不同,感兴趣的小伙伴可以拿这篇文章对照下:把数据滤波写成不明觉厉的样子
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <time.h>
#define DEBUG_OUTPUT 1
typedef struct color_set
{
uint8_t color;
uint8_t set_color;
}COLOR_SET;
enum rgb_color ///< 为测试而修改
{
NO_COLOR = 0,
PURPLE,
RED,
GREEN,
BLUE,
WHITE,
YELLOW,
CHING,
};
COLOR_SET total_color[8] =
{
{NO_COLOR, 0},
{RED, 1},
{YELLOW, 3},
{GREEN, 2},
{CHING, 6},
{BLUE, 4},
{PURPLE, 5},
{WHITE, 7}
};
typedef void (*Exchange_Func)(void *, void *);
uint8_t _74HC595_set_color(uint8_t color);
void struct_binary_exchange(void* num1, void* num2);
void bubble_sort(void * buf, uint16_t num, uint8_t size, Exchange_Func operator_func);
uint8_t _74HC595_set_color_Init(void);
/**
* _74HC595_set_color
* @brief 得到74HC595实际输出的值
* @param 要设置的颜色对应的常量color_set.color
* @return 转换成要设置的颜色对应值 color_set.set_color
*/
uint8_t
_74HC595_set_color(uint8_t color)
{
#if DEBUG_OUTPUT
printf("output color is: %d", total_color[color].set_color);
#endif
return total_color[color].set_color;
}
/**
* uint8_t_binary_exchange
* @brief 设计判断条件交换两数在数组中的位置
* @param num1 按照uint8_t类型进行处理
* @param num2 按照uint8_t类型进行处理
* @retval None
* @note 将 > 改为 < 即由递增序列变为递减序列
*/
void
struct_binary_exchange(void* num1, void* num2)
{
if((*(COLOR_SET *)num1).color > (*(COLOR_SET *)num2).color)
{
COLOR_SET temp = *(COLOR_SET *)num1;
*(COLOR_SET *)num1 = *(COLOR_SET *)num2;
*(COLOR_SET *)num2 = temp;
}else
{
/* no code */
}
}
/**
* bubble_sort
* @brief 冒泡排序法,为处理不同数据准备的框架
* @details 使用回调函数来实现只改底层,不动上层的分层思想
* @param buf 数组首地址,void* 修饰,表示任意类型传入
* @param num 数组大小,通常用sizeof(buf)/sizeof(buf[0]) 来得到
* @param size 要处理的数据类型占用字节数,通常用sizeof(buf[0]) 来得到
* @param operator_fuc 函数指针,用于调用相应函数实现功能
* @retval None
* @note 为功能测试而通过宏切换验证
*/
void
bubble_sort(void * buf, uint16_t num, uint8_t size, Exchange_Func operator_func)
{
uint16_t ex_cycle_i, in_cycle_j;
if(size == 0 || size > 16)
{
printf("please check input data type size !\n");
return;
}else
{
for(ex_cycle_i = 0; ex_cycle_i < num - 1; ex_cycle_i++)
{
for(in_cycle_j = ex_cycle_i + 1; in_cycle_j < num; in_cycle_j++)
{
operator_func(buf + size*ex_cycle_i, buf + size*in_cycle_j);
}
}
}
}
/**
* _74HC595_set_color_Init
* @brief 将用于74HC595的数组排序
* @note 对于频繁调用的函数_74HC595_set_color 减轻工作量
*/
uint8_t
_74HC595_set_color_Init(void)
{
#if DEBUG_OUTPUT
printf("origin data is :\n");
for(uint8_t i=0; i<8; i++)
{
printf("total_color[%d].color = %d, total_color[%d].set_color = %d \n", i, total_color[i].color, i, total_color[i].set_color);
}
#endif
bubble_sort((void *)total_color, sizeof(total_color)/sizeof(total_color[0]), sizeof(total_color[0]), struct_binary_exchange);
#if DEBUG_OUTPUT
printf("sort data is :\n");
for(uint8_t i=0; i<8; i++)
{
printf("total_color[%d].color = %d, total_color[%d].set_color = %d \n", i, total_color[i].color, i, total_color[i].set_color);
}
printf("\n");
#endif
}
int main(void)
{
_74HC595_set_color_Init();
#if DEBUG_OUTPUT
srand((unsigned)time(NULL));
uint8_t random_val = rand() % 7 + 1;
printf("random_val is %d \n", random_val);
_74HC595_set_color(random_val);
#endif
return 0;
}