面向对象的编程思想写单片机程序——(1)学习笔记 之 程序设计

面向对象的编程思想写单片机程序——(1)学习笔记 之 程序设计,第1张

系列文章目录

面向对象的编程思想写单片机程序——(1)学习笔记 之 程序设计
面向对象的编程思想写单片机程序——(2)学习笔记 之 怎么抽象出结构体

文章目录
  • 系列文章目录
  • 前言
  • 程序怎么写?
    • 1、常规写法
    • 2、面向对象的写法
  • 小结


前言

高内聚、低耦合的软件编程中判断程序好坏的标准,目的就是能够使程序可重用性,可移植性增强,那么在单片机嵌入式的编程中能否做到高内聚、低耦合性呢 ?? 能否通过程序设计来实现呢 ?? 肯定是可以的,可以通过使用面向对象的编程思想来设计程序,通过对程序分层来隔离硬件对软件程序的依赖性。
那么如何使用面向对象的编程思想来编写单片机程序呢 ??? 请持续关注本栏内容,本栏内容将记录如何进行面向对象编程,如何进行程序分层。。


程序怎么写?

本章内容以点亮单片机 LED 灯为示例来记录常规写法,以及面向对象的编程思想写法。

1、常规写法

针对点亮 LED 这样的程序的常规写法相信大家就很熟悉了,直接看代码:


int main()
{

	while(1)
	{
		if(key){             // 如果按键按下,执行 LED 函数。
			write_gpio_led();    //函数可以是 LED 亮、灭、翻转、流水灯等 *** 作。
		}
	}
}

针对于这种写法当然没有问题,可是

  1. 如果写其他的模块呢,比如 LCD 屏幕、输入(按键、鼠标、触摸屏)等;
  2. 如果单个按键、屏幕很多呢,难道要写很多判断语句吗 ?
  3. 如果该产品的模块很多,你每个模块都写很多函数,是不同的人开发,这些函数都需要别人知道才能使用,是不是很不人性化。

如果使用面向对象的写法这些问题就可以避免。

2、面向对象的写法

面向对象的写法可以把很多变量、函数等,抽象出结构体,别人只需知道我有这个结构体就行了,需要使用什么函数直接在结构体里找就行了,废话不多说看代码:

/*  定义设备对应的结构体   */
typedef struct LEDDevice {
  int type;                   // LED 类型
  GPIO_TypeDef* GPIOx;     //哪一组
  uint16_t  LED_PIN;     //哪个引脚
  uint32_t  LED_CLK;     //哪个时钟
  void (* LED_Init)(struct LEDDevice * p_Dev);              //初始化函数指针
  void (* LED_Control)(struct LEDDevice * p_Dev, int istatus);    //控制led函数指针
}LEDDevice, *p_LEDDevice;

然后,写对应的函数:

/**
  * @说明   定义 LED 灯的结构体数组全局变量,存放各种类型的 LED 灯
  */
struct LEDDevice LED[] = {
		{0, GPIOB, GPIO_Pin_5, RCC_APB2Periph_GPIOB, My_LED_Init, My_LED_Control},
		{1, GPIOB, GPIO_Pin_0, RCC_APB2Periph_GPIOB, My_LED_Init, My_LED_Control},
		{2, GPIOB, GPIO_Pin_1, RCC_APB2Periph_GPIOB, My_LED_Init, My_LED_Control}
};


/**
  * @说明   调用函数 get_LCD_type() 可以获得需要亮的灯类型
  * @参数   无
  * @返回值  返回 int 型
  */
int get_LCD_type(void)
{
	int type;
	/******************************************/
	// 需要在哪种情况下 控制哪种灯,写在这里,返回控制的类型
	/******************************************/
	return type;
}

/**
  * @说明   调用函数 get_lcd_for_type() 可以获得需要亮的灯类型对应的存储该类型的 灯的地址,从而找到该灯
  * @参数   无
  * @返回值  返回 灯设备的结构体指针 类型    struct LEDDevice * 
  */
struct LEDDevice * get_lcd_for_type(void)
{
	int i;
	int type = get_LCD_type();  //获得类型
	for(i = 0; i < sizeof(LED)/sizeof(LED[0]); i++)   // 遍历数组, sizeof(LED)/sizeof(LED[0]) 数组中有几项数据
	{                       
		if(LED[i].type == type) //类型相同,就返回该项地址
		{
			return &LED[i];
		}
	}
	return NULL;
}

/**
  * @说明   调用函数 My_LED_Init(struct LEDDevice * p_Dev) 可以初始化 LED
  * @参数   p_Dev  , 设备结构体指针类型    struct LEDDevice * 
  * @返回值  无
  */
void My_LED_Init(struct LEDDevice * p_Dev)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(p_Dev->LED_CLK , ENABLE); //使能时钟
  /*LED 结构体初始化*/
  GPIO_InitStructure.GPIO_Pin = p_Dev->LED_PIN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(p_Dev->GPIOx, &GPIO_InitStructure);
  
  GPIO_SetBits(p_Dev->GPIOx, p_Dev->LED_PIN);
}

/**
  * @说明   调用函数 My_LED_Control(struct LEDDevice * p_Dev, int istatus) 可以控制 LED
  * @参数   p_Dev  , 设备结构体指针类型    struct LEDDevice * 
  * @参数   istatus, 是 0 或者 1 ,来控制 LED 对应的 IO 端口
  * @返回值  无
  */
void My_LED_Control(struct LEDDevice * p_Dev, int istatus)
{
  GPIO_WriteBit(p_Dev->GPIOx, p_Dev->LED_PIN, istatus);
}

下面是主函数直接通过结构体来调用函数:
注意:在写代码时注意,全局变量、函数要在头文件声明。

int main()
{
	struct LEDDevice * p_LED = get_lcd_for_type();
	p_LED->LED_Init(p_LED);  // LED 初始化

	p_LED->LED_Control(p_LED, 0);  // LED 亮
}

使用面向对象的方法写程序更有利于多人协作写程序,将自己负责的模块抽象出结构体,其他人在使用该模块时,只需调用结构体就行了。
可以通过面向对象的思想写程序,通过程序分层写函数,将硬件和软件程序尽可能的分割开来,以提高程序的兼容性。


小结

本文主要讲述单片机程序的面向对象的编程思想,针对如何抽象出对象设备的结构体、程序的分层问题,请持续关注本专栏。

学习百问网资源总结笔记。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/713792.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-24
下一篇 2022-04-24

发表评论

登录后才能评论

评论列表(0条)

保存