日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ZStack中的编程技巧

發布時間:2025/4/16 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ZStack中的编程技巧 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 像函數一樣使用的宏

//這個宏,用來被其他宏使用,構造一個正確有效的表達式。這個適合于一些離散語句的組合,不適合函數的重新命名

#define st(x)????? do { x } while (__LINE__ == -1)

?

例如:#define aps_GroupsRemaingCapacity() ( APS_MAX_GROUPS - aps_CountAllGroups() )

上述的這個宏,調用的其他函數來實現其功能,因此,不適合使用st()宏。

使用場景:? aps_GroupsRemaingCapacity(); 或者?? aps_GroupsRemaingCapacity() 當做函數的參數。

?

例如:#define AES_SET_MODE(mode)????? st( ENCCS &= ~0x70; ENCCS |= mode; )

上述這個宏,使用st宏來嵌套,功能為設置AES加密模式。

使用場景: 向個函數一樣調用 AES_SET_MODE(AES_MODE_CTR); 即可。

?

2. 消息隊列中的存儲分配機制

在ZStack中,每個任務都在OSAL的大循環中輪訓處理,任務與任務之間,任務與OSAL之間,是通過消息來傳遞信息的。每一個任務都對于一系列事件,系統發給每個任務的事件為UINT16 events,它采用獨熱碼的機制,2個字節,一共可以處理16個事件。

#define SYS_EVENT_MSG 0x8000 //系統任務事件#define ZDO_CB_MSG 0xD3 //系統任務事件里面的ZDO消息#define AF_DATA_CONFIRM_CMD 0xFD //系統任務事件里面的接收數據指示消息#define AF_INCOMING_MSG_CMD 0x1A //系統任務事件里面的接收數據消息#define ZDO_STATE_CHANGE 0xD1 //系統任務事件里面的ZDO狀態改變消息#define KEY_CHANGE 0xC0 //系統任務事件里面的按鍵消息其他事件為用戶自定義事件,可以使用的值為0x4000,0x2000,0x1000,0x8000...依次類推,供有15個自定義事件,可以通過osal_start_timerEx( ZDAppTaskID, ZDO_NETWORK_INIT, delay ); //延遲發起事件osal_set_event( ZDAppTaskID, ZDO_NETWORK_INIT ); //立刻發起事件 來進行通知。

2.1 消息分配

函數原型: uint8 * osal_msg_allocate( uint16 len )

使用場景:任務調用此函數用于分配指定長度的消息緩沖。實際上,分配的長度為len加上消息頭的長度

?

消息頭結構體如下:

typedef struct {void *next; //指向下一個消息uint16 len;uint8 dest_id; //指向當前的任務ID,分配消息時,初始化為TASK_NO_TASK } osal_msg_hdr_t; //消息頭結構體 typedef struct {uint8 event;uint8 status; } osal_event_hdr_t; //事件結構體

osal_msg_allocate實際返回的指針為指向len長度的地址空間。 實際使用時,返回值經常被強制類型轉換,以下面的函數為例子說明:

/********************************************************************** @fn ZDO_SendMsgCBs** @brief This function sends messages to registered tasks.* Local to ZDO and shouldn't be called outside of ZDO.** @param inMsg - incoming message** @return TRUE if sent to at least 1 task, FALSE if not*/ uint8 ZDO_SendMsgCBs( zdoIncomingMsg_t *inMsg ) {uint8 ret = FALSE;ZDO_MsgCB_t *pList = zdoMsgCBs;while ( pList ){if ( pList->clusterID == inMsg->clusterID ) //對比接收到數據中的簇ID和ZDO中注冊的簇ID {zdoIncomingMsg_t *msgPtr; // Send the address to the taskmsgPtr = (zdoIncomingMsg_t *)osal_msg_allocate( sizeof( zdoIncomingMsg_t ) + inMsg->asduLen ); //分配消息緩存,包含消息頭和數據長度if ( msgPtr ){// copy structosal_memcpy( msgPtr, inMsg, sizeof( zdoIncomingMsg_t )); //分配成功,拷貝相關內容到消息中if ( inMsg->asduLen ){msgPtr->asdu = (byte*)(((byte*)msgPtr) + sizeof( zdoIncomingMsg_t ));osal_memcpy( msgPtr->asdu, inMsg->asdu, inMsg->asduLen );}msgPtr->hdr.event = ZDO_CB_MSG; //聲明此消息的事件類型osal_msg_send( pList->taskID, (uint8 *)msgPtr ); //將此消息發送給指定的任務IDret = TRUE;}}pList = (ZDO_MsgCB_t *)pList->next; // 與當前ZDO中的簇ID不符,指向下一個ZDO的注冊消息 }return ( ret ); }

在osal_msg_send中,用到了幾個宏,

//獲得msg_ptr所指向的下一個消息

#define OSAL_MSG_NEXT(msg_ptr)????? ((osal_msg_hdr_t *) (msg_ptr) - 1)->next

?

//獲得msg_ptr所指向的任務(消息分配時,初始化為TASK_NO_TASK)

#define OSAL_MSG_ID(msg_ptr)????? ((osal_msg_hdr_t *) (msg_ptr) - 1)->dest_id

uint8 osal_msg_send( uint8 destination_task, uint8 *msg_ptr ) {if ( msg_ptr == NULL ) return ( INVALID_MSG_POINTER );if ( destination_task >= tasksCnt ){osal_msg_deallocate( msg_ptr );return ( INVALID_TASK );} //參數有效性檢查// Check the message headerif ( OSAL_MSG_NEXT( msg_ptr ) != NULL ||OSAL_MSG_ID( msg_ptr ) != TASK_NO_TASK ){osal_msg_deallocate( msg_ptr );return ( INVALID_MSG_POINTER );} //確保當前消息為新分配的消息 OSAL_MSG_ID( msg_ptr ) = destination_task; //將當前消息的任務指定為入口參數// queue messageosal_msg_enqueue( &osal_qHead, msg_ptr ); //將此消息插入到全局消息隊列的尾部// Signal the task that a message is waitingosal_set_event( destination_task, SYS_EVENT_MSG ); //給此任務發起一個系統消息事件return ( SUCCESS ); } /********************************************************************** @fn osal_set_event** @brief** This function is called to set the event flags for a task. The* event passed in is OR'd into the task's event variable.** @param uint8 task_id - receiving tasks ID* @param uint8 event_flag - what event to set** @return SUCCESS, INVALID_TASK*/ uint8 osal_set_event( uint8 task_id, uint16 event_flag ) {if ( task_id < tasksCnt ){halIntState_t intState;HAL_ENTER_CRITICAL_SECTION(intState); // Hold off interruptstasksEvents[task_id] |= event_flag; // Stuff the event bit(s) 給當前的task賦予事件值,以便于在OSAL大循環中可以處理HAL_EXIT_CRITICAL_SECTION(intState); // Release interruptsreturn ( SUCCESS );}else{return ( INVALID_TASK );} }

在對于任務的事件處理中,需要用到osal_msg_receive(task_id)函數,從指定事件下獲取對于的消息。然后循環取消息,循環處理,直到SYS_EVENT_MSG中的消息都處理完了才會退出。

系統事件下的消息類型結構體定義,在開始的部分都采用添加了事件頭,便于后級循環處理。

OSAL事件頭? 事件內部的消息頭結構,不同的消息有不同的數據內容,但有一點是相同的,就是消息頭結構體的第一個元素一定是OSAL事件頭。

以上大概就是OSAL的消息機制。網上有很多其他資料整理的很好,但是,總覺的不是自己的,自己寫出來,才能真實的消化掉。

以按鍵消息為例子:OSAL的消息頭(上)+OSAL的事件頭(中)+事件內部的數據頭(下)

,結合上圖和以上的理解,是不是一下子很清楚啦。

消息入隊:

?

?

3.定義變量的技巧

enum
???? {
????? ZDO_SRC_RTG_IND_CBID,???????????????????????? // 0
????? ZDO_CONCENTRATOR_IND_CBID,??????????????? // 1
????? ZDO_NWK_DISCOVERY_CNF_CBID,????????????? // 2
????? ZDO_BEACON_NOTIFY_IND_CBID,?????????????? // 3
????? ZDO_JOIN_CNF_CBID,?????????????????????????????? // 4
????? ZDO_LEAVE_CNF_CBID,???????????????????????????? // 5
????? ZDO_LEAVE_IND_CBID,???????????????????????????? // 6
????? MAX_ZDO_CB_FUNC???????????????????????????????? // 7(枚舉變量個數,數組索引0~6)

??????????????????????????????????????????????????????????? // Must be at the bottom of the list
??? };

上述枚舉變量,前面都是名稱的定義,取值從0開始,依次遞增,后續,需要增加一個入口的話,直接在倒數第一個之前添加就可以了,其他的都不用改。

定義通用函數指針時,入口參數和出口參數最好都設置成void*類型,方便后續類型轉換。

函數指針聲明: /* ZDO Indication Callback Registration */typedef void* (*pfnZdoCb)( void *param );函數指針數組定義:pfnZdoCb zdoCBFunc[MAX_ZDO_CB_FUNC];函數指針數組初始化void ZDApp_InitZdoCBFunc( void ) {uint8 i;for ( i=0; i< MAX_ZDO_CB_FUNC; i++ ){zdoCBFunc[i] = NULL;} }

自定義結構體:

一律采用如下的定義方式:

typedef struct //不需要結構體名 {osal_event_hdr_t hdr;uint8 endpoint;uint8 transID; } afDataConfirm_t; //指定重新定義的結構體名,后面加上_t,表示是一個自定義類型

? 在具體使用時, 使用 afDataConfirm_t *afDataConfirm;

?

4.宏定義

對于一些較長的宏定義,建議加上分行符來寫,格式規范,便于檢查。注意,最后一行,不能有分行符

#define SystemReset()???????????? \
?????? {??????????????????????????????????????? \
?????? HAL_DISABLE_INTERRUPTS();?? \
?????? HAL_SYSTEM_RESET();?????????? \?
?????? }

?

在宏定義中,對于一些預編譯的條件判斷,可以添加#error指令,來確保在編譯過程中,保持條件配置的一致性。

對于一些需要使用默認配置的選項,采用如下的定義方法:

如果不做任何其他的設定,默認是開啟ADC功能的。如果用戶要自定義開啟或者關閉,則定義

#define HAL_ADC TRUE? 或者 #define HAL_ADC FALSE 就可以了。

?

在條件宏定義中,采用適當的縮進比例,便于檢查。

看到左邊的減號了嗎?那是編譯器提供的折疊功能,使用起來也很方便,但是,適當的縮進,還是很有必要的,便于配對檢查,不多不漏。

?

可以在編譯時,添加對過期模塊的編譯檢查,在軟件升級時,可能需要用到。

?

?

5. 在編譯中查看宏值

?? 采用如下的宏,可以在編譯時,打印出想要查看的宏的內容。這個技巧,在之前的博文里面提到過,覺的很好用,再次再提一次。

查看已定義宏內容:

輸出內容:

?

查看未定義宏內容:

輸出內容:

?

一般編譯器都支持message偽指令,因此,這個小技巧很好用。

如果需要對一些延遲做較為精確的計算或者對時序要求比較嚴格的操作,在函數上面加上禁止優化的偽指令

#pragma optimize=none //指示不對A函數進行優化 void A() { }

?

6. 調試

設計一個程序,重要的是它的設計流程。

所有程序都是調試出來的,不是寫出來的。如何去調試,實際上是如何卻解決問題。

把問題拆開來思考,

?

7. 用于設置寄存器的宏

以ZStack中的hal_lcd.c中的寄存器設置為例子。

使用時,直接使用LCD_DO_WRITE就可以了,像個函數一樣用它。從名字上可以看出,它是往第port的第pin個管腳寫val數值。LCD_DO_WRITE宏執行的功能 就是往P0.0寫1.在這里,P0_0需要有相應的定義才可以正確進行,如果移植到其他處理機,做相應的更改就可以了。

一般來說,IO線都有復用的功能,建議使用不同的宏分開設置。如下圖所示:

前兩個是針對普通GPIO來設置的宏,功能也是類似的,向port的pin管腳輸出val值。

后兩個是針對peripheral function的GPIO來設置的宏。

轉載于:https://www.cnblogs.com/cherishui/p/3868214.html

總結

以上是生活随笔為你收集整理的ZStack中的编程技巧的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 亚洲最大成人在线视频 | 黄色一级一片免费播放 | 久久性感视频 | 91丨国产丨捆绑调教 | 好看的中文字幕av | 日韩大片免费观看视频播放 | 黄网站色 | 国产精品嫩草影院精东 | av大全免费 | 天堂av成人 | www.欧美.com | 性感美女高潮 | 日本成人黄色片 | 双性高h1v1| 成人一级视频在线观看 | 亚洲精品国产精品国自产 | 久久这里只有精品久久 | 欧美videos另类精品 | 国产午夜精品一区二区三区视频 | 91香蕉一区二区三区在线观看 | 久久久夜色 | 亚洲av无码乱码国产精品 | 97自拍视频在线 | 国产一区二区三区四区五区 | 天堂网在线观看 | 99re在线视频免费观看 | 人妻久久一区二区 | 亚洲中文字幕无码av | www日本视频| 视频一区在线免费观看 | 97在线免费视频 | 国产女人18水真多18精品一级做 | 欧美日韩精品久久久 | 色天天干 | 亚洲一二三四视频 | 99久久人妻无码精品系列 | 手机在线观看日韩av | 亚洲清纯唯美 | 中文字幕+乱码+中文字幕一区 | 一出一进一爽一粗一大视频 | 国产一区二区视频在线观看免费 | 天天干天天看 | 91看片网| 欧美在线观看视频 | 欧美性黄色 | 日本三级aaa | 精品一区三区 | 国产成人精品女人久久久 | 爱情岛论坛成人av | 一二区免费视频 | 老司机av影院| 亚洲一区在线免费 | 欧美1区2区 | 天堂资源地址在线 | 中文在线国产 | 亚洲色图偷 | 黄网站欧美内射 | 久久人人妻人人人人妻性色av | 玖玖网 | 国产69视频在线观看 | 亚洲乱熟女一区二区 | 日本少妇bbwbbw精品 | 极品尤物魔鬼身材啪啪仙踪林 | 日本一区二区三区在线看 | www.青青操| 国产中文欧美日韩在线 | 在线人成 | 久久久久无码国产精品一区李宗瑞 | 韩国成人免费视频 | 黄色特级视频 | 91国产在线看 | 国产二区三区 | aav在线 | 天堂资源 | 欧美国产日韩视频 | 久久对白 | 国产激情小视频 | 日韩色图视频 | 国产一区二区三区四区五区六区 | 国产一区二区三区色淫影院 | 深夜视频在线观看免费 | 影音先锋成人 | 亚洲最新av网址 | 九九精品在线视频 | 午夜日韩精品 | 日韩精品一二三四区 | 中文字幕蜜臀 | 国产网站免费在线观看 | 色五丁香 | 四川话毛片少妇免费看 | 天堂在线观看 | 美脚の诱脚舐め脚 | 蜜桃免费av | 色婷婷网 | 色婷婷综合久久久中文字幕 | www.日日干 | 亚洲无人区码一码二码三码 | 国产主播一区二区三区 | 夜夜骚网站 |