|
当我第一次用PE生成了一个MDK工程的时候,发现这个东西的架构有点绕,好在也总算整明白了!这里以IO模块为例,发点心得:
1、模块注册
每个模块都有一个初始化函数 ,以IO口为例,它的初始化函数定义如下:
LDD_TDeviceData* Bit1_Init(LDD_TUserData *UserDataPtr)
{
/* Allocate device structure */
Bit1_TDeviceDataPtr DeviceDataPrv;
/* {MQXLite RTOS Adapter} Driver memory allocation: Dynamic allocation is simulated by a pointer to the static object */
DeviceDataPrv = &DeviceDataPrv__DEFAULT_RTOS_ALLOC;
DeviceDataPrv->UserDataPtr = UserDataPtr; /* Store the RTOS device structure */
/* Configure pin as output */
/* GPIOE_PDDR: PDD|=1 */
GPIOE_PDDR |= GPIO_PDDR_PDD(0x01);
/* Set initialization value */
/* GPIOE_PDOR: PDO&=~1 */
GPIOE_PDOR &= (uint32_t)~(uint32_t)(GPIO_PDOR_PDO(0x01));
/* Initialization of Port Control register */
/* PORTE_PCR0: ISF=0,MUX=1 */
PORTE_PCR0 = (uint32_t)((PORTE_PCR0 & (uint32_t)~(uint32_t)(
PORT_PCR_ISF_MASK |
PORT_PCR_MUX(0x06)
)) | (uint32_t)(
PORT_PCR_MUX(0x01)
));
/* Registration of the device structure */
PE_LDD_RegisterDeviceStructure(PE_LDD_COMPONENT_Bit1_ID,DeviceDataPrv);
return ((LDD_TDeviceData *)DeviceDataPrv);
}
这个函数的参数LDD_TUserData *UserDataPtr是定义了一个指针,这个指针的作用是引入一个用户数据的指针,一般用于MQXLite系统中,用来传递的是用户的一些参数,这是一种面向对像的使用方法,等到后面我们再分析他的用法。我们在初始化函数中可以找到下面的一行代码:
PE_LDD_RegisterDeviceStructure(PE_LDD_COMPONENT_Bit1_ID,DeviceDataPrv);
在此行代码中PE_LDD_COMPONENT_Bit1_ID是一个常量,而DeviceDataPrv是函数开头定义的一个 Bit1_TDeviceDataPtr 型的指针,并把一个static的变量DeviceDataPrv__DEFAULT_RTOS_ALLOC的地址赋给了DeviceDataPrv。
我们找到PE_LDD_RegisterDeviceStructure的定义,会发现它其实是一个宏(PE_Type.h):
#define PE_LDD_RegisterDeviceStructure(ComponentIndex, DeviceStructure) (PE_LDD_DeviceDataList[ComponentIndex] = DeviceStructure)
这个宏的意思是将参数中的DeviceDataPrv指针(即static变量DeviceDataPrv__DEFAULT_RTOS_ALLOC的地址)赋给一个指针数组PE_LDD_DeviceDataList的PE_LDD_COMPONENT_Bit1_ID序号的空间内。
也就是说在此函数中,注册的时候将一个指针与PE_LDD_COMPONENT_Bit1_ID常量联系起来,并将指针保存下来,保存下来有什么用呢?我们再看看此模块中其它的应用函数:
void Bit1_SetDir(LDD_TDeviceData *DeviceDataPtr, bool Dir);
void Bit1_SetInput(LDD_TDeviceData *DeviceDataPtr);
bool Bit1_GetVal(LDD_TDeviceData *DeviceDataPtr);
void Bit1_PutVal(LDD_TDeviceData *DeviceDataPtr, bool Val);
void Bit1_ClrVal(LDD_TDeviceData *DeviceDataPtr);
void Bit1_SetVal(LDD_TDeviceData *DeviceDataPtr);
在此可以看出来这些应用函数有一个共同的特点,他们的第一个参数都是一个LDD_TDeviceData 型的指针,那么,根据我们刚才分析的初始化函数中的指针保存,我们知道了,在使用这些函数的时候,要把刚才保存的那个指针取出来当作参数传给他们。
既然有保存指针的宏,那么肯定有取出指针的宏,我们依然在PE_Type.h文件中找到这个宏:
#define PE_LDD_GetDeviceStructure(ComponentIndex) (PE_LDD_DeviceDataList[ComponentIndex])
这个宏就是取出指针的宏,到此,我们就知道这些函数都怎么应用了,用PE_LDD_COMPONENT_Bit1_ID常量将指针取出来就是了:
Bit1_SetInput( PE_LDD_GetDeviceStructure(PE_LDD_COMPONENT_Bit1_ID) );
到此,我们就能将这些函数应用起来。当然在我们目前的分析看来,其实没发现这个指针有什么用途,下面我们就来分析此指针的用途。
再回到初始化函数的前几行:
/* Allocate device structure */
Bit1_TDeviceDataPtr DeviceDataPrv;
/* {MQXLite RTOS Adapter} Driver memory allocation: Dynamic allocation is simulated by a pointer to the static object */
DeviceDataPrv = &DeviceDataPrv__DEFAULT_RTOS_ALLOC;
DeviceDataPrv->UserDataPtr = UserDataPtr; /* Store the RTOS device structure */
我们又看到了UserDataPtr,假如我们在此模块中有一些私有的模块数据定义,那么就可以把它强制转换成LDD_TUserData 型的指针,传给初始化函数,然后通过上面几行代码,我们知道,它会把我们定义的私有模块数据的指针给了
DeviceDataPrv__DEFAULT_RTOS_ALLOC结构体中的UserDataPtr指针,而我们在刚才说明的注册中,已经把DeviceDataPrv__DEFAULT_RTOS_ALLOC保存到一个数组指针中了,在使用的时候可以用PE_LDD_GetDeviceStructure宏再将指针取出来,此时我们应该已经明白了,其实这就是把一个静态的变量用指针分离了出来,在我们后面的编程中,可以在任意的模块中使用DeviceDataPrv__DEFAULT_RTOS_ALLOC结构体中的数组,但又跟它没有关系,因为我们可以随时将DeviceDataPrv__DEFAULT_RTOS_ALLOC结构体中的数据进行改动。
到此我们应该明白了,Bit1_TDeviceDataPtr类型的指针,可以将全局的变量进行分离,定义成每个模块的私有变量,而在使用的时候,可以通过Bit1_TDeviceDataPtr指针找到我们需要的数据,真正实现各个模块的分离,移植性能增强。
|
阿莫论坛20周年了!感谢大家的支持与爱护!!
你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
|