|
之前做过一个项目,用户测试阶段
要求提供HEX文件,说要自行修改相关输出动作表
觉得他们提出一份动作,我们烧写一个样片太麻烦
在我看来是很NC的,而且他们不一定能改...
后来,我提出一个方案
用atmega32来代替原本的pic16f57:作了块atmega32的芯片转接板,焊上插针后,直接兼容PIC16F57的I/O,VDD,VSS等
再在上面叠加一块串口通信板,连接PC,PC端用c#写了相关动作编辑调试软件,
可以自动转换成表格数据下载到M32的RAM中在线调试动作,或保存到EEPROM中装机后运行,
同类型产品硬件有较多种型号,关于动作表及其它输出,在不同硬件上用到的端口是不一样的
为了提高输出能力,某些地方用了双口线并连的方式(我觉得很NC的方法)
但此时正好给atmega32识别不同硬件带来了方便,一个口输入带上拉,一个口输出0,自动识别硬件的能力就有了
但相关输出时,如何能简化操作呢
于是用到了函数指针
======================================
首先,定义void_Func类型做为无类型函数指针
typedef void (*void_Func)(void);
然后,定义任务类型
typedef struct
{
void_Func InitPort;
void_Func UpdateData;
void_Func SetLevel;
...//其它成员这里就不写了
} TASK;
extern TASK Task;
================================
再定义函数指针数组,以下数组成员都是函数名,有相关定义和实现
和硬件有关,需要不同操作的函数都定义了相关函数指针
const void_Func Func_InitPort[] =
{
Init_Port,
InitPort_1,//具体产品型号就不写了,用数字代替
InitPort_2,
InitPort_3,
};
const void_Func Func_UpdateData[] =
{
UpdateData_Default,
UpdateData_1,
UpdateData_2,
UpdateData_3
};
const void_Func Func_SetLevel[] =
{
SetLevel_Default,
SetLevel_1,
SetLevel_2,
SetLevel_3
};
================================
使用时
执行完自动检测型号后,将型号放到Task.Task.MainBoard中
然后调用Task_SetFunction()
void Task_SetFunction()
{
Task.InitPort = Func_InitPort[Task.MainBoard];
Task.UpdateData = Func_UpdateData[Task.MainBoard];
Task.SetLevel = Func_SetLevel[Task.MainBoard];
Task.InitPort();
}
================================
最后,凡是需要用到相关端口操作的地方,就可以用函数指针实现了
也就是可以
Task.InitPort(); //初始化端口
Task.UpdateData();//表格数据转换化端口输出
Task.SetLevel(); //输出等级控制
这样用了,看起来简洁明了,效率也高
如果是常规的方法,每个用到这些函数的地方都判断一次
Task.MainBoard的值来选择函数,看上去会让我很不爽,也没现在这种有效率
特别是当Task.MainBoard类型较多时,更为明显
=================================
下面是函数指针编译出的相关汇编代码
=================================
(0058) Task.InitPort();
3C0 91E0 0490 LDS R30,0x0490
3C2 91F0 0491 LDS R31,0x0491
3C4 940E 06AA CALL xicall
=================================
(0241) Task.UpdateData();
501 91E0 0492 LDS R30,0x0492
503 91F0 0493 LDS R31,0x0493
505 940E 06AA CALL xicall
=================================
(0252) Task.SetLevel();
515 91E0 0494 LDS R30,0x0494
517 91F0 0495 LDS R31,0x0495
519 940E 06AA CALL xicall
=================================
xicall:
6AA 920A ST -Y,R0
6AB 95C8 LPM
6AC 920A ST -Y,R0
6AD 9631 ADIW R30,1
6AE 95C8 LPM
6AF 2DF0 MOV R31,R0
6B0 91E9 LD R30,Y+
6B1 9009 LD R0,Y+
6B2 9409 IJMP
=================================
当有3个不同时,其对应汇编的代码效率和运行效率应该已经不比if else差了
当不只一处调用时,差别就更大了,函数指针的优势尽显 |
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|