使用分层模型复用代码(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举例。
这里我们用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操作时会略微增加一些运行时间(忽略不计)。
总体来说还是优点大于缺点的。
上一篇: STM32F1笔记(二)GPIO输入
下一篇: AutoSar网络管理