面向对象的编程思想写单片机程序——(1)学习笔记 之 程序设计
面向对象的编程思想写单片机程序——(2)学习笔记 之 怎么抽象出结构体
- 系列文章目录
- 前言
- 程序怎么写?
- 1、常规写法
- 2、面向对象的写法
- 小结
前言
高内聚、低耦合的软件编程中判断程序好坏的标准,目的就是能够使程序可重用性,可移植性增强,那么在单片机嵌入式的编程中能否做到高内聚、低耦合性呢 ?? 能否通过程序设计来实现呢 ?? 肯定是可以的,可以通过使用面向对象的编程思想来设计程序,通过对程序分层来隔离硬件对软件程序的依赖性。
那么如何使用面向对象的编程思想来编写单片机程序呢 ??? 请持续关注本栏内容,本栏内容将记录如何进行面向对象编程,如何进行程序分层。。
程序怎么写?
本章内容以点亮单片机 LED 灯为示例来记录常规写法,以及面向对象的编程思想写法。
1、常规写法针对点亮 LED 这样的程序的常规写法相信大家就很熟悉了,直接看代码:
int main()
{
while(1)
{
if(key){ // 如果按键按下,执行 LED 函数。
write_gpio_led(); //函数可以是 LED 亮、灭、翻转、流水灯等 *** 作。
}
}
}
针对于这种写法当然没有问题,可是
- 如果写其他的模块呢,比如 LCD 屏幕、输入(按键、鼠标、触摸屏)等;
- 如果单个按键、屏幕很多呢,难道要写很多判断语句吗 ?
- 如果该产品的模块很多,你每个模块都写很多函数,是不同的人开发,这些函数都需要别人知道才能使用,是不是很不人性化。
如果使用面向对象的写法这些问题就可以避免。
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 亮
}
使用面向对象的方法写程序更有利于多人协作写程序,将自己负责的模块抽象出结构体,其他人在使用该模块时,只需调用结构体就行了。
可以通过面向对象的思想写程序,通过程序分层写函数,将硬件和软件程序尽可能的分割开来,以提高程序的兼容性。
小结
本文主要讲述单片机程序的面向对象的编程思想,针对如何抽象出对象设备的结构体、程序的分层问题,请持续关注本专栏。
学习百问网资源总结笔记。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)