以 ID 为数组下标,能够根据 ID 得到 驱动或设备 句柄。(LiteOS 里任务ID和任务句柄也相似噢)linux
数组为 驱动数组或设备数组或其它须要统一管理的数组等等。主要为实体开辟空间,直接定位使用。git
图解算法
驱动数组
api
驱动 ID 表
数组
设备数组
框架
设备 ID 表
函数
实现 驱动部分学习
驱动 ID
实现 设备部分ui
设备 ID
: 用于标识本结构体为哪个设备驱动 ID
: 就是绑定的 驱动 IDstatic uint32_t selectClkByGpio(const uint32_t addr)
选择时钟信号函数void i2cGpioInit(eI2C_ID id)
I2C 引脚初始化函数void i2cStart(eI2C_ID id)
I2C Start 函数void i2cStop(eI2C_ID id)
I2C Stop 函数uint8_t i2cSendByte(eI2C_ID id, uint16_t TxData)
I2C SendByte 函数uint8_t i2cReceiveByte(eI2C_ID id)
I2C ReceiveByte 函数void i2cAck(eI2C_ID id, uint8_t Ack)
I2C Ack 函数uint8_t i2cWaitAck(eI2C_ID id)
I2C WaitAck 函数ei2cDEVICE_COUNT
是和 i2cI2C_DEVICE_COUNT
同样的大小,在实际工程中,二选一便可。/* ********************************************************************************************************* * CONFIG ********************************************************************************************************* */ // [注][I2C] 根据实际设备修改 // i2c 驱动数量 #define i2cI2C_DRIVER_COUNT 3 /** * @brief i2c id * @author lzm */ typedef enum { ei2cEEPROM_1 = 0, // 第一个 EEPROM 设备驱动 ei2cEEPROM_2, // 第二个 EEPROM 设备驱动 ei2cMPU6050, // MPU6050设备驱动 ei2cDEVICE_COUNT; // 驱动数量 }eI2C_ID;
I2C ID
: 就是一个实体 I2C 的 ID 及 驱动数组下标。/* ********************************************************************************************************* * BASIC ********************************************************************************************************* */ /** * @brief i2c struct * @author lzm */ struct I2C_T{ /* id */ eI2C_ID ID; /* delay */ // cnt unsigned char delayUsCnt; // delay function void ( *delayUsFun )(int cnt); /* pin */ GPIO_TypeDef * sclGpiox; uint16_t sclPin; GPIO_TypeDef * sdaGpiox; uint16_t sdaPin; }; typedef struct I2C_T i2c_t;
/* ********************************************************************************************************* * DEFINE [API] FUNCTION ********************************************************************************************************* */ /** * @brief 注册IIC设备 * i2cDeviceElem[i2cID].id = i2cID; // 保持下标与ID相等,查找时能够直接定位,实现时间复杂度为O(1); * @param * @retval none * @author lzm */ #define REGISTER_I2C_DRI(i2cID, delayuscnt, fun, sclgpio, sclpin, sdagpio, sdapin) \ { \ i2cDeviceElem[i2cID].id = i2cID; \ i2cDeviceElem[i2cID].delayUsCnt = delayuscnt; \ i2cDeviceElem[i2cID].delayUsFun = fun; \ i2cDeviceElem[i2cID].sclGpiox = sclgpio; \ i2cDeviceElem[i2cID].sclPin = sclpin; \ i2cDeviceElem[i2cID].sdaGpiox = sdagpio; \ i2cDeviceElem[i2cID].sdaPin = sdapin; \ }
i2cI2C_DRIVER_COUNT
表示有 i2cI2C_DRIVER_COUNT 个 I2C 驱动/* ********************************************************************************************************* * DEFINE ********************************************************************************************************* */ // i2c 驱动元素(设备表) i2c_t i2cDriverElem[i2cI2C_DRIVER_COUNT];
static uint32_t selectClkByGpio(const uint32_t addr)
选择时钟信号函数const uint32_t addr
须要初始化引脚对应的 port/** * @brief 选出时钟信号线 * @param addr : 引脚对应 port * @retval 返回时钟值 或 NULL * @author lzm */ static uint32_t selectClkByGpio(const uint32_t addr) { switch(addr) { case GPIOA_BASE: return RCC_APB2Periph_GPIOA; case GPIOB_BASE: return RCC_APB2Periph_GPIOB; case GPIOC_BASE: return RCC_APB2Periph_GPIOC; case GPIOD_BASE: return RCC_APB2Periph_GPIOD; case GPIOE_BASE: return RCC_APB2Periph_GPIOE; case GPIOF_BASE: return RCC_APB2Periph_GPIOF; case GPIOG_BASE: return RCC_APB2Periph_GPIOG; } return NULL; }
void i2cGpioInit(eI2C_ID id)
初始化I2C引脚eI2C_ID id
为 I2C 驱动 ID,能够理解为须要初始化哪个 I2C 驱动,从 I2C 驱动命名表中选出。sclGpioClk
和 sdaGpioClk
/** * @brief 初始化I2C引脚 * @param id : I2C 驱动 ID * @retval none * @author lzm */ void i2cGpioInit(eI2C_ID id) { GPIO_InitTypeDef G_GPIO_IniStruct; //定义结构体 uint32_t sclGpioClk; uint32_t sdaGpioClk; const i2c_t * i2c = &i2cDeviceElem[id]; sclGpioClk = selectClkByGpio((uint32_t)(i2c->sclGpiox)); sdaGpioClk = selectClkByGpio((uint32_t)(i2c->sdaGpiox)); RCC_APB2PeriphClockCmd(sclGpioClk | sdaGpioClk, ENABLE); //打开时钟 G_GPIO_IniStruct.GPIO_Pin = i2c->sclPin; //配置端口及引脚(指定方向) G_GPIO_IniStruct.GPIO_Mode = GPIO_Mode_Out_OD; G_GPIO_IniStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(i2c->sclGpiox, &G_GPIO_IniStruct); //初始化端口(开往指定方向) G_GPIO_IniStruct.GPIO_Pin = i2c->sdaPin; //配置端口及引脚(指定方向) G_GPIO_IniStruct.GPIO_Mode = GPIO_Mode_Out_OD; G_GPIO_IniStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(i2c->sdaGpiox, &G_GPIO_IniStruct); //初始化端口(开往指定方向) // 初始化完之后先拉高 iicOutHi(i2c->sclGpiox, i2c->sclPin); iicOutHi(i2c->sdaGpiox, i2c->sdaPin); }
void i2cStart(eI2C_ID id)
I2C Start函数eI2C_ID id
为 I2C 驱动 ID,能够理解为须要初始化哪个 I2C 驱动,从 I2C 驱动命名表中选出。i2c_t * i2c = &i2cDeviceElem[id];
/** * @brief IIC START * @param id : I2C 驱动 ID * @retval none * @author lzm */ void i2cStart(eI2C_ID id) { i2c_t * i2c = &i2cDeviceElem[id]; iicSdaOutHi(i2c); iicSclOutHi(i2c); i2c->delayUsFun(i2c->delayUsCnt); iicSdaOutLo(i2c); i2c->delayUsFun(i2c->delayUsCnt); }
void i2cStart(eI2C_ID id)
函数原理同样,只是实现的逻辑不同而已,完整源码能够参考个人gitee上的 LiteOS 源码工程。eeeprom_COUNT
是和 eeEEPROM_DEVICE_COUNT
同样的大小,在实际工程中,二选一便可。/* ********************************************************************************************************* * CONFIG API ********************************************************************************************************* */ /* [注][eeprom]实时修改 */ // eeprom 设备数量 #define eeEEPROM_DEVICE_COUNT 2 /* delay API */ #define eeDelayMs(cnt) vTaskDelay(cnt) /* 调度式延时 */ #define eeEEPROM_WRITE_COUNT 5 /* 写页时等待时间 */ /* fpga id. */ typedef enum { eAT24C08_1 = 0, eAT24C08_2, eeeprom_COUNT, }eEEPROM_ID;
eEEPROM_ID ID
: 就是一个实体 EEPROM 的 ID 及 设备数组下标。eI2C ID
: 就是一个实体 I2C 的 ID 及 驱动数组下标。eEEPROM_ID ID
绑定 eI2C ID
,设备结构体只须要知道它对应哪个 I2C 实体便可,便是只须要知道一个 I2C ID便可。/* ********************************************************************************************************* * BASIC ********************************************************************************************************* */ /* eeprom struct */ struct EEPROM_T{ /* id */ eEEPROM_ID ID; /* i2c id */ eI2C_ID i2cID; };
/* ********************************************************************************************************* * DEFINE [API] FUNCTION ********************************************************************************************************* */ /** * @brief 注册IIC设备 * @param eeid : EEPROM ID,用于直接定位,也能够同时用于定位校验。 * @param i2cid : 设备绑定的 I2C 驱动 ID。 * @retval none * @author lzm */ #define REGISTER_EEPROM_DEV(eeid, i2cid) \ { \ eepromDeviceElem[eeid].ID = eeid; \ eepromDeviceElem[eeid].i2cID = i2cid; \ }
eeEEPROM_DEVICE_COUNT
表示有 eeEEPROM_DEVICE_COUNT 个 EEPROM 设备/* ********************************************************************************************************* * DEFINE ********************************************************************************************************* */ // eeprom 设备元素(设备表) eeprom_t eepromDeviceElem[eeEEPROM_DEVICE_COUNT];
eI2C_ID i2cid = eepromDeviceElem[id].i2cID;
获取对应的 I2C 驱动实体eEEPROM_ID
管理便可,APP 用户不需接触到 I2C 驱动名字的操做,只须要本身操做的设备的设备名字便可。/** * @brief read [size] bytes from pReadBuf * @param pReadBuf : store data form addr * addr : start addr * size : the size of need read * @retval 1 : normal * 0 : abnormal * @author lzm */ uint8_t __eeReadBytes(eEEPROM_ID id, uint16_t addr, uint8_t *pReadBuf, uint16_t lenght) { uint16_t i; uint8_t active = 0x0A; eI2C_ID i2cid = eepromDeviceElem[id].i2cID; while( active-- ) { i2cStart(i2cid); if (i2cSendByte(i2cid, eeEEPROM_DEVICE_ADDR + ((addr>>8)<<1))) { i2cStop(i2cid); continue; /* EEPROM器件无应答 */ } #if 0 // [注][eeprom] AT24C32 及以上的 eeprom才启用 /* High 8 bits address. */ if(LSS_I2C_SendByte(addr>>8)) { LSS_I2C_Stop();continue; } #endif if (i2cSendByte(i2cid, (uint8_t)(addr))) { i2cStop(i2cid); continue; /* EEPROM器件无应答 */ } i2cStart(i2cid); if (i2cSendByte(i2cid, eeEEPROM_DEVICE_ADDR | eeEEPROM_I2C_RD)) { i2cStop(i2cid); continue; /* EEPROM器件无应答 */ } for (i = 0; i < lenght; i++) { pReadBuf[i] = i2cReceiveByte(i2cid); if(i == lenght-1) i2cAck(i2cid,1); //No ACK else i2cAck(i2cid,0); //ACK } i2cStop(i2cid); return 0; /* 执行成功 */ } return 1; }
/** * @brief 全部EEPROM设备初始化 * @param * @retval * @author lzm */ void eepromInit(void) { uint8_t eepromID; // 先注册 I2C 驱动 REGISTER_I2C_DRI(ei2cEEPROM_1, 5, dwtDelayUs, EEP_SCL_PORT, EEP_SCL_PIN, EEP_SDA_PORT, EEP_SDA_PIN); REGISTER_I2C_DRI(ei2cEEPROM_2, 5, dwtDelayUs, EEP_SCL_PORT, EEP_SCL_PIN, EEP_SDA_PORT, EEP_SDA_PIN); // 注册 EEPROM 设备并绑定 i2c 驱动 REGISTER_EEPROM_DEV(eAT24C08_1, ei2cEEPROM_1); REGISTER_EEPROM_DEV(eAT24C08_2, ei2cEEPROM_2); for (eepromID = 0; eepromID < eeEEPROM_DEVICE_COUNT; eepromID++) { // 初始化 I2C i2cGpioInit( (eI2C_ID)(ei2cEEPROM + eepromID) ); // 业务 [待写] } // 业务 [待写] }