任務篇是建立在協議篇之上的。以我的項目為例,我有兩個從機設備,一個是EPC(控制器控制電磁閥開度使電磁閥出口處的氣壓保持恒定)需要主機設定出口處氣壓和定時讀取出口處實際氣壓;另一個是溫濕壓傳感器變送器需要定時讀取溫濕度壓數據。
我的理念是不管主機掛載幾個從機設備,而是主機有幾個任務。以上文為例,主機一共有三個任務,一是設定EPC出口處氣壓(寫保持寄存器);二是讀取EPC出口處氣壓(讀輸入寄存器);三是讀取溫濕壓數據(讀輸入寄存器)。我們首先要建立這三個任務。我們根據從機名稱來創建4個文件分別是"EPC.c"、"EPC.h"、"THP.c"和"THP.h"。按照慣例我們先來看"EPC.h"和"THP.h"。
- #ifndef __EPC_H
- #define __EPC_H
- #include "Header.h"
- #include "UartDebug.h"
- #include "Modbus_Master.h"
- #include "Delay.h"
- struct EpcPre
- {
- struct ModbusMasterDevice *MMD;
- uint8_t DeviceAddr;
- int16_t P_Fb,P_Sta;
- uint16_t Pset;
- uint8_t S_P_En,R_En;
- uint8_t DataUpdate;
- uint8_t SetSuccess;
- };
- extern struct EpcPre EPC1;
- void EPCInit(void);
- uint8_t ReadEPC(void *Para);
- void ReadEPFEnable(struct EpcPre *EPF);
- uint8_t SetPreVal(void *Para);
- void SetPreValEnable(struct EpcPre *EPC,uint16_t Pre);
- #endif
復制代碼- #ifndef __THP_H
- #define __THP_H
- #include "Header.h"
- #include "UartDebug.h"
- #include "Modbus_Master.h"
- #include "Delay.h"
- struct TemHumPre
- {
- struct ModbusMasterDevice *MMD;
- uint8_t DeviceAddr;
- float AirTemp;
- float AirHun;
- float AirPre;
- uint8_t Enable;
- uint8_t DataUpdate;
- };
- extern struct TemHumPre THP1;
- void THPInit(void);
- uint8_t ReadTHP(void *Para);
- void ReadTHPEnable(struct TemHumPre *THP);
- #endif
復制代碼 這兩個文件非常相似,下面我們來詳細介紹一下。
略過頭文件我們來看從機結構體。
“struct ModbusMasterDevice *MMD;” 從機掛載到的ModBus主機;
“uint8_t DeviceAddr;” 從機的設備地址;
“int16_t P_Fb,P_Sta;” “float AirTemp;”“float AirHun;”“float AirPre;”數據區,根據從機的需求而定;
“uint8_t S_P_En,R_En;”“uint8_t Enable; ”任務的使能標志,可以看到因為EPC有兩個任務所以它有S_P_En和R_En兩個使能標志,而THP只有一個任務所以它只有一個Enable;
“uint8_t DataUpdate;”讀保持/輸入寄存器成功標志;
“uint8_t SetSuccess;”寫保持寄存器成功標志,THP沒有相對應得任務所以也就沒有該標志。
接下來我們來看具體得任務實現。
- #include "EPC.h"
- struct EpcPre EPC1;
- void EPCInit(void)
- {
- EPC1.MMD = &MMDPort1;
- EPC1.DeviceAddr = 0x01;
- }
- uint8_t ReadEPC(void *Para)
- {
- struct EpcPre *EPC;
-
- EPC = (struct EpcPre *)Para;
- if(ReadHoldInputReg(EPC->MMD,EPC->DeviceAddr,0x04,0,4) != 0)
- {
- if(EPC->MMD->RIR_Update)
- {
- EPC->MMD->RIR_Update = 0;
- EPC->DataUpdate = 1;
- EPC->P_Fb = EPC->MMD->Input_Reg[0];
- EPC->P_Sta = EPC->MMD->Input_Reg[1];
- }
- EPC->R_En = 0;
- return 1;
- }
- return 0;
- }
- void ReadEPFEnable(struct EpcPre *EPC)
- {
- EPC->R_En = 1;
- }
- uint8_t SetPreVal(void *Para)
- {
- struct EpcPre *EPC;
-
- EPC = (struct EpcPre *)Para;
- if(WriteHoldReg(EPC->MMD,EPC->DeviceAddr,0,1,&EPC->Pset) != 0)
- {
- if(EPC->MMD->WHR_Success)
- {
- EPC->MMD->WHR_Success = 0;
- EPC->SetSuccess = 1;
- }
- EPC->S_P_En = 0;
- return 1;
- }
- return 0;
- }
- void SetPreValEnable(struct EpcPre *EPC,uint16_t Pre)
- {
- EPC->S_P_En = 1;
- EPC->Pset = Pre;
- }
復制代碼- #include "THP.h"
- struct TemHumPre THP1;
- void THPInit(void)
- {
- THP1.MMD = &MMDPort1;
- THP1.DeviceAddr = 0x03;
- }
- uint8_t ReadTHP(void *Para)
- {
- struct TemHumPre *THP;
-
- THP = (struct TemHumPre*)Para;
- if(ReadHoldInputReg(THP->MMD,THP->DeviceAddr,0x04,0,3) != 0)
- {
- if(THP->MMD->RIR_Update)
- {
- THP->MMD->RIR_Update = 0;
- if(THP->MMD->Input_Reg[0] != 0xffff)
- {
- THP->AirTemp = (float)(THP->MMD->Input_Reg[0]-10000)/10;
- }
- if(THP->MMD->Input_Reg[1] != 0xffff)
- {
- THP->AirHun = (float)THP->MMD->Input_Reg[1]/10;
- }
- if(THP->MMD->Input_Reg[2] != 0xffff)
- {
- THP->AirPre = (float)THP->MMD->Input_Reg[2]/10;
- }
- }
- THP->Enable = 0;
- return 1;
- }
- return 0;
- }
- void ReadTHPEnable(struct TemHumPre *THP)
- {
- THP->Enable = 1;
- }
復制代碼 整體來看,每個任務都分為任務主體和任務使能兩個部分,任務主體由下一章要介紹的調度篇來調用,使能由用戶來調用,比如THP需要每隔1S讀取一次那么就使函數“void ReadTHPEnable(struct TemHumPre *THP)”每隔1S執行一次。
- static void Task_1000ms(void)
- {
- ReadTHPEnable(&THP1);
- }
復制代碼 而EPC需要500ms讀取一次氣壓,則使函數“void ReadEPFEnable(struct EpcPre *EPC)”每隔500ms執行一次。
- static void Task_500ms(void)
- {
- ReadEPFEnable(&EPC1);
- }
復制代碼 對于寫保持寄存器相關的任務我們可以順道把要寫的數據放在使能函數里,這樣可以使寫保持寄存器的任務主體函數更加簡潔。
下面我們需要著重講解一下任務主體的實現。
以讀取EPC氣壓為例,任務會首先執行函數“ReadHoldInputReg()”并判斷返回值,根據協議篇可以知道在等待從機應答的那段時間“ReadHoldInputReg()”會返回0,于是“ReadEPC()”也返回0告知上層函數目前正在等待從機應答;若“ReadHoldInputReg()”返回1則說明從機成功應答或者應答超時了,我們怎么知道到底是應答了還是超時了呢?這就需要讀取變量RIR_Update,若為1則說明應答成功我們就需要把讀到的數據進行保存和處理,RIR_Update也完成了它的使命所以將其置0,并將DataUpdate置1告知上層函數數據讀取成功。從機無論是應答還是超時都需要將R_En置0并返回1這點至關重要。
所有的任務必須嚴格按照該格式來實現,否則會影響上層的調度工作。
至此任務篇就介紹完畢了。
|