標(biāo)題:
我的ModBus主機-調(diào)度篇
[打印本頁]
作者:
qinlu123
時間:
2021-11-15 13:29
標(biāo)題:
我的ModBus主機-調(diào)度篇
開始本篇之前我想先談一下為什么要把一個ModBus主機分成4篇來寫,一是代碼的分層理念,隨著工作時間的增長以及工作的深入你會發(fā)現(xiàn)分層是那么的至關(guān)重要不僅僅是代碼的可讀性更重要的是更方便的維護(hù)。初期寫代碼一個文件中甚至一個函數(shù)中既有功能代碼又有底層代碼,當(dāng)增刪功能或者平臺移植的時候都不知道去哪里哭,分層也許在初期會增加代碼量顯得很麻煩但是當(dāng)你的架構(gòu)建立起來之后會變得十分方便,解決問題得心應(yīng)手。操作系統(tǒng)幫你做好了底層的分層和軟件層面的任務(wù)調(diào)度,但是應(yīng)用層面依然需要個人來做好。分層理念需要時時有處處有。二是ModBus的一對多特性,當(dāng)一個主機任務(wù)讀取某個從機的數(shù)據(jù)并等待從機應(yīng)答時,必須保證別的主機任務(wù)不要來動ModBus總線,如果有個不長眼的主機任務(wù)過來咔咔操作了總線那么之前等待從機應(yīng)答的任務(wù)就崩潰了。可能有人說了等待應(yīng)答的時候我直接while死等不就行了,直接斷了別的主機任務(wù)的念想,當(dāng)然這樣是可以解決問題的不過要是某個從機不在線就會導(dǎo)致整個系統(tǒng)卡死一段時間,要是你用了操作系統(tǒng)還好如果是裸機那就非常影響用戶體驗并且會使其他任務(wù)比如刷屏按鍵出現(xiàn)一些莫名其妙的問題,我們都知道人的新陳代謝越快身體越強壯,同樣任務(wù)輪詢越快系統(tǒng)也越強壯。無論你使用操作系統(tǒng)還是裸機都要避免使用阻塞式的寫法。所以我們才大費周章分4層來解決一個ModBus主機問題。本篇調(diào)度篇內(nèi)容很少但是整個ModBus主機系統(tǒng)的重中之重。
我們先來看代碼。
#ifndef __RS485_H
#define __RS485_H
#include "Header.h"
#include "THP.h"
#include "EPC.h"
#include "Delay.h"
extern uint16_t RS485BusSilentTime1;
void RS485Device1Init(void);
void RS485Device1Handle(void);
#endif
復(fù)制代碼
#include "RS485Device.h"
uint16_t RS485BusSilentTime1;
void RS485Device1Init(void)
{
THPInit();
EPCInit();
}
static uint8_t TaskHandle(uint8_t En, uint8_t (*Task)(void*), void *Dev, uint8_t *BusTake, uint8_t TaskID, uint16_t *DelayTime)
{
if((En!=0) && ((*BusTake==0)||(*BusTake==TaskID)))
{
if(Task(Dev) != 0)
{
/*釋放總線*/
*BusTake = 0;
Set_Delay_Time(10,DelayTime);
}
else
{
/*占用總線*/
*BusTake = TaskID;
return 1;
}
}
return 0;
}
void RS485Device1Handle(void)
{
static uint8_t BusTake=0;
if(CheckDelay(&RS485BusSilentTime1) == 0)
{
if(TaskHandle(EPC1.S_P_En,SetPreVal,&EPC1,&BusTake,1,&RS485BusSilentTime1) != 0)
{
return;
}
if(TaskHandle(THP1.Enable,ReadTHP,&THP1,&BusTake,2,&RS485BusSilentTime1) != 0)
{
return;
}
if(TaskHandle(EPC1.R_En,ReadEPC,&EPC1,&BusTake,3,&RS485BusSilentTime1) != 0)
{
return;
}
}
}
復(fù)制代碼
通過代碼可以看到該層引用了任務(wù)篇創(chuàng)建的"THP.h"和"EPC.h",在這里我們要對三個主機任務(wù)進(jìn)行調(diào)度。
首先來看函數(shù)“
static uint8_t TaskHandle(uint8_t En, uint8_t (
Task)(void
), void *Dev, uint8_t *BusTake, uint8_t TaskID, uint16_t *DelayTime)
”;
該函數(shù)參數(shù)比較多,分別為任務(wù)使能信號(uint8_t En)、任務(wù)主體(uint8_t (
Task)(void
))、設(shè)備名稱(void *Dev)、是誰在使用總線(uint8_t *BusTake)、任務(wù)編號(uint8_t TaskID)、總線靜默時間控制(uint16_t *DelayTime);
該函數(shù)邏輯很簡單,就是判斷任務(wù)使能信號是否置位了并查看總線被哪個任務(wù)占用,若總線空閑或者被自己占用就去占用總線去執(zhí)行任務(wù)主體函數(shù),若任務(wù)主體函數(shù)返回0說明正在等待從機應(yīng)答接著占用總線并返回1告知調(diào)度器我還沒用完,否則說明任務(wù)完成了釋放總線并給總線插入10ms的靜默時間然后返回0告訴調(diào)度器我完事了讓別人來吧。
函數(shù)“
void RS485Device1Handle(void)
”就是最終的調(diào)度器它在main函數(shù)的while循環(huán)中被執(zhí)行,它首先實現(xiàn)10ms的總線靜默然后挨個詢問主機任務(wù)的當(dāng)前狀態(tài)并滿足他們的需求。
至此,我的ModBus主機就完結(jié)了。
作者:
jxcrgt35
時間:
2021-11-20 09:49
謝謝分享,能否提供一些關(guān)于分層的思想的文章,學(xué)習(xí)。
作者:
海陽螃蟹
時間:
2022-2-16 21:05
謝謝分享,能否提供一些關(guān)于分層的思想的文章,學(xué)習(xí)。
作者:
alangada
時間:
2022-3-9 08:33
mark,標(biāo)記學(xué)習(xí)下
作者:
63451141
時間:
2022-3-21 22:25
mark,標(biāo)記學(xué)習(xí)下
作者:
大漠落日
時間:
2022-5-7 14:38
上的操作系統(tǒng)?
作者:
lihuaxu66
時間:
2022-5-20 12:10
謝謝分享,能否提供一些關(guān)于分層的思想的文章,學(xué)習(xí)
作者:
sindycn
時間:
2022-12-11 15:36
mark,標(biāo)記學(xué)習(xí)下
作者:
liixaofei5
時間:
2023-4-16 09:43
,標(biāo)記學(xué)習(xí)一下,感謝分享
作者:
qhp777
時間:
2023-5-12 16:42
mark,標(biāo)記學(xué)習(xí)下
作者:
ngyl
時間:
2023-8-6 14:58
moubus在工作中我遇到了,也看了大概的基本原理,但程序?qū)懖怀鰜,借鑒一下樓主的
作者:
jxcrgt35
時間:
2023-8-15 14:34
思路清晰,程序扎實
作者:
qinlu123
時間:
2024-10-30 16:59
大漠落日 發(fā)表于 2022-5-7 14:38
上的操作系統(tǒng)?
裸機,我自己的框架
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1