以 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) ); // 業務 [待寫] } // 業務 [待寫] }