[牛人杂谈] 单片机C语言教程之函数封装

[复制链接]
1686|4
 楼主| Beckham_Owen 发表于 2016-4-11 14:55 | 显示全部楼层 |阅读模式
结构体可以把不同类型的变量放在一起,从而能实现对相互联系的变量进行打包。那么结构体能不能把函数打包呢?事实上在单片机编程中,通常我们采用模块化的编程。自然这里面会涉及到很多不同函数的定义和调用,那么如何将这些函数打包呢?函数不能作为结构体的成员,但是函数指针可以作为结构体成员。这里我们通过函数指针在结构体中的应用来介绍如何对不同但是相关的函数打包。
  1. /*目的:练习使用结构体对函数封装同时使用指针来操作
  2. 1. 定义结构体
  3. 2. 定义三个函数
  4. 3. 定义结构体变量
  5. 4. 定义结构体指针
  6. */
  7. #include "stdio.h"
  8. typedef unsigned char uchar;
  9. struct mystruct{
  10.     void(*myfun1)(void);
  11.     void(*myfun2)(void);
  12.     void(*myfun3)(void);
  13. };
  14. struct mystruct test;
  15. struct mystruct *testp;
  16. void myfun1(void);
  17. void myfun2(void);
  18. void myfun3(void);
  19. void main(void)
  20. {
  21.     struct mystruct test = {
  22.         myfun1,
  23.         myfun2,
  24.         myfun3,
  25.     };
  26.     testp = &test;
  27.     testp->myfun1();
  28.     testp->myfun2();
  29.     testp->myfun3();
  30.     system("pause");
  31. }

  32. void myfun1(void)
  33. {
  34.     printf("myfun1\n");
  35. }

  36. void myfun2(void)
  37. {
  38.     printf("myfun2\n");
  39. }

  40. void myfun3(void)
  41. {
  42.     printf("myfun3\n");
  43. }


 楼主| Beckham_Owen 发表于 2016-4-11 14:56 | 显示全部楼层
在以上代码中,我们定义了一个mystruct结构体,其中有三个函数指针作为结构体成员,然后定义了一个结构体指针,通过指针来调用各个函数。
现在我们把这种方法应用到单片机编程中,实现对LCD1602各个功能函数的打包。
  1. /*目的:练习使用结构体封装函数,然后使用结构体指针来控制LCD
  2. 1. 定义一个结构体
  3. 2. 定义一个结构体变量
  4. 3. 定义几个函数
  5. 4. 定义结构体指针
  6. 5. LCD控制引脚,初始化,在哪里显示,显示什么
  7. */
  8. #include "reg52.h"
  9. typedef unsigned char uchar;
  10. sbit RS=P2^7;
  11. sbit EN=P2^6;
  12. struct mystruct {
  13.     void (*LCD_init)(void);
  14.     void (*write_data)(uchar);
  15.     void (*write_string)(uchar *);
  16.     void (*write_com)(uchar);
  17.     void (*delay)(uchar);
  18. };

  19. void LCD_init(void);
  20. void delayUs(uchar t);
  21. void delayMs(uchar t);
  22. void write_com(uchar mycmd);
  23. void write_data(uchar mydata);
  24. void write_string(uchar *p);
  25. struct mystruct LCD_struct;
  26. struct mystruct *LCD;
  27. void main(void)
  28. {
  29.     struct mystruct LCD_struct={
  30.         LCD_init,
  31.         write_data,
  32.         write_string,
  33.         write_com,
  34.         delayMs,
  35.     };
  36.     while(1)
  37.     {
  38.             LCD=&LCD_struct;
  39.             LCD->LCD_init();
  40.             LCD->write_com(0x80);
  41.             LCD->write_string("This is struct");
  42.             while(1);
  43.     }
  44. }
  45. void LCD_init(void)
  46. {
  47.     delayMs(15);
  48.     write_com(0x38);
  49.     delayMs(5);
  50.     write_com(0x38);
  51.     write_com(0x08);
  52.     write_com(0x01);
  53.     write_com(0x06);
  54.     write_com(0x0c);
  55. }

  56. void write_data(uchar mydata)
  57. {
  58.   delayMs(5);//注意这里需要延时5ms比较保险
  59.   P0=mydata;
  60.   RS=1;
  61.   EN=1;
  62.   delayUs(5);
  63.   EN=0;
  64. }

  65. void write_string(uchar *p) //如何写一个字符串
  66. {
  67.     while(*p)
  68.     {
  69.         write_data(*p);
  70.         p++;
  71.     }
  72. }
  73. void write_com(uchar mycmd)
  74. {
  75.   delayMs(5);//注意这里需要延时5ms比较保险 代替判断忙信号
  76.   P0=mycmd;        //准备好指令
  77.   RS=0;         //告诉LCD1602,P0中放的是指令不是数据
  78.   EN=1;
  79.   delayUs(5); //根据时序图,脉冲要有一定宽度
  80.   EN=0;           //使指令有效,开始执行
  81. }  
  82. void delayUs(uchar t)
  83. {
  84.         while(--t);
  85. }

  86. void delayMs(uchar t)
  87. {
  88.         while(--t)
  89.         {
  90.                 delayUs(245);
  91.                 delayUs(245);
  92.         }
  93. }
500days 发表于 2016-4-12 20:57 | 显示全部楼层
函数打包不就是封装成函数吗?不知道我理解的对不对
玛尼玛尼哄 发表于 2016-4-13 13:25 | 显示全部楼层
一般都是参数用于配置寄存器和外设,返回值一般都是外设、寄存器的当前状态值
gejigeji521 发表于 2016-4-13 22:12 | 显示全部楼层
一般用指针传递信息到函数的用法是最科学的。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

32

主题

234

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部