欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用分层模型复用代码(GPIO)

程序员文章站 2022-04-01 18:43:16
...

使用分层模型复用代码(GPIO)

代码获取

本文代码托管于github上,欢迎各位star,https://github.com/zrw269113179/drv_pin

分层模型

分层模型可以使代码的应用层逻辑与硬件解耦合,可以使你的代码高度复用,完全解耦合,并且可以使你快速上手任意一款mcu。说了这么多好处,如何具体实现?简单来说就是定义一套统一的入口函数,无论什么mcu都可以通过这套函数访问硬件。

具体实现

本文讲述的为GPIO模型的具体实现。首先需要对GPIO模型进行抽象,显而易见,GPIO只有2个功能,输入和输出。因此我们只需要完成以下这些函数:
1、pin_mode_set:端口模式设置
2、pin_write:端口输出
3、pin_read:读取端口电平
4、pin_irq_set:外部中断设置
编写完成这些函数后,在应用层只需要调用pin_write、pin_read就可以完成对端口的操作。
确定了函数名后,我们要对函数参数进行确定,因为不同芯片对于GPIO的命名是不同的,有些芯片命名为GPIOA、GPIOB…而有些命名为GPIO1、GPIO2等,这里我们抛弃芯片原有的port+pin来表示一个端口的模式,而直接用1234端口号来表示一个端口。
这里我们以stm8l052举例。

使用分层模型复用代码(GPIO)这里我们用1来表示PA0,64表示PE7。
首先我们建立一张索引图,将引脚号和端口名称建立联系。

static unsigned char pin_map[] ={    
(1 << 4) + 0, (1 << 4) + 1, (1 << 4) + 2, (1 << 4) + 3, (1 << 4) + 4, (1 << 4) + 5, (1 << 4) + 6, 
(1 << 4) + 7, (0 << 4) + 0, (0 << 4) + 0, (0 << 4) + 0, (0 << 4) + 0, (0 << 4) + 0, (7 << 4) + 0, 
(7 << 4) + 1, (7 << 4) + 2, (7 << 4) + 3, (0 << 4) + 0, (5 << 4) + 0, (5 << 4) + 1, (5 << 4) + 2,
(5 << 4) + 3, (5 << 4) + 4, (5 << 4) + 5, (4 << 4) + 0, (4 << 4) + 1, (4 << 4) + 2, (4 << 4) + 3, 
(0 << 4) + 0, (0 << 4) + 0, (2 << 4) + 0, (2 << 4) + 1, (2 << 4) + 2, (2 << 4) + 3, (2 << 4) + 4, 
(2 << 4) + 5, (2 << 4) + 6, (2 << 4) + 7, (6 << 4) + 0, (6 << 4) + 1, (6 << 4) + 4, (6 << 4) + 5, 
(6 << 4) + 6, (6 << 4) + 7, (4 << 4) + 4, (4 << 4) + 5, (4 << 4) + 6, (4 << 4) + 7, (7 << 4) + 4, 
(7 << 4) + 5, (7 << 4) + 6, (7 << 4) + 7, (3 << 4) + 0, (3 << 4) + 1, (0 << 4) + 0, (0 << 4) + 0,
(3 << 4) + 2, (3 << 4) + 3, (3 << 4) + 4, (3 << 4) + 5, (3 << 4) + 6, (3 << 4) + 7, (5 << 4) + 6, 
(5 << 4) + 7
};

用一个unsigned char 表示存储port和pin,其中前4位为port号,1:GPIOA,2:GPIOB以此类推,后4位为pin号,0:GPIO_Pin_0,1:GPIO_Pin_1以此类推,当数为0((0 << 4) + 0)时表示该引脚没有gpio功能(芯片上的vss,vdd等脚)。具体如何定义可以根据芯片灵活更改。
然后就可以编写具体函数了,以pin_write()为例:

void pin_write(unsigned char id, unsigned char level)
{    
	GPIO_TypeDef *port;    
	uint8_t pin;    
	switch (pin_map[id - 1] >> 4)    
	{    
		case 1:        
			port = GPIOA;        
		break;
    		case 2:        
    			port = GPIOB;        
    		break;
    		case 3:        
    			port = GPIOC;        
    		break;
    		case 4:        
    			port = GPIOD;        
    		break;
    		case 5:        
    			port = GPIOE;        
    		break;
    		case 6:        
    			port = GPIOF;        
    		break;
    		case 7:        
    			port = GPIOG;        
    		break;
    		default:        
    			port = GPIOA;        
    		break;    
    	}    
    	pin = 1 << (pin_map[id - 1] & 0xf);    
    	if (level == 0)    
    	{        
    		GPIO_ResetBits( port, pin );    
    	}    
    	else   
    	{        
    		GPIO_SetBits( port, pin );    
    	}
}

代码很简单,只需要调用pin_write(1,1);就可以使PA0输出高电平了(不要忘了初始化)。

更换芯片

完成上述工作后,我们的应用层所有关于GPIO的代码将通过这个drv_pin.c\drv_pin.h接管,又由于该文仅控制输入输出,所以当芯片更换后,只需更换drv_pin.c\drv_pin.h文件即可,新芯片的drv_pin.c\drv_pin.h只需完成drv_pin.h中的功能即可。

优缺点

优点

1、drv_pin.c和drv_pin.h只需编写1遍即可重复使用,将这两个文件交给新手,新手完全不需要重新读datasheet就可以马上上手,极大的减少项目时间,并且提高稳定性。
2、应用层完全与硬件隔离,应用层不再出现硬件提供的库的代码,这样我们写的一些其他组件就无需更改,如模拟iic、spi,当更换项目后就需要更改这些函数内部的代码,如果使用drv_pin就不需要更改,有利于模块的封装。

缺点

因为操作需要多一层代理,因此会占用一些程序空间,在进行gpio操作时会略微增加一些运行时间(忽略不计)。
总体来说还是优点大于缺点的。