久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4053|回復: 6
打印 上一主題 下一主題
收起左側

我的ModBus主機-任務篇

  [復制鏈接]
跳轉到指定樓層
樓主
ID:446156 發表于 2021-11-15 13:27 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
任務篇是建立在協議篇之上的。以我的項目為例,我有兩個從機設備,一個是EPC(控制器控制電磁閥開度使電磁閥出口處的氣壓保持恒定)需要主機設定出口處氣壓和定時讀取出口處實際氣壓;另一個是溫濕壓傳感器變送器需要定時讀取溫濕度壓數據。
我的理念是不管主機掛載幾個從機設備,而是主機有幾個任務。以上文為例,主機一共有三個任務,一是設定EPC出口處氣壓(寫保持寄存器);二是讀取EPC出口處氣壓(讀輸入寄存器);三是讀取溫濕壓數據(讀輸入寄存器)。我們首先要建立這三個任務。我們根據從機名稱來創建4個文件分別是"EPC.c"、"EPC.h"、"THP.c"和"THP.h"。按照慣例我們先來看"EPC.h"和"THP.h"。
  1. #ifndef __EPC_H
  2. #define __EPC_H

  3. #include "Header.h"
  4. #include "UartDebug.h"
  5. #include "Modbus_Master.h"
  6. #include "Delay.h"

  7. struct EpcPre
  8. {
  9.         struct ModbusMasterDevice *MMD;
  10.         uint8_t DeviceAddr;
  11.         int16_t P_Fb,P_Sta;
  12.         uint16_t Pset;
  13.         uint8_t S_P_En,R_En;
  14.         uint8_t DataUpdate;
  15.         uint8_t SetSuccess;
  16. };

  17. extern struct EpcPre EPC1;

  18. void EPCInit(void);
  19. uint8_t ReadEPC(void *Para);
  20. void ReadEPFEnable(struct EpcPre *EPF);
  21. uint8_t SetPreVal(void *Para);
  22. void SetPreValEnable(struct EpcPre *EPC,uint16_t Pre);

  23. #endif
復制代碼
  1. #ifndef __THP_H
  2. #define __THP_H

  3. #include "Header.h"
  4. #include "UartDebug.h"
  5. #include "Modbus_Master.h"
  6. #include "Delay.h"

  7. struct TemHumPre
  8. {
  9.         struct ModbusMasterDevice *MMD;
  10.         uint8_t DeviceAddr;
  11.         float AirTemp;
  12.         float AirHun;
  13.         float AirPre;
  14.         uint8_t Enable;
  15.         uint8_t DataUpdate;
  16. };

  17. extern struct TemHumPre THP1;

  18. void THPInit(void);
  19. uint8_t ReadTHP(void *Para);
  20. void ReadTHPEnable(struct TemHumPre *THP);

  21. #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沒有相對應得任務所以也就沒有該標志。
接下來我們來看具體得任務實現。
  1. #include "EPC.h"

  2. struct EpcPre EPC1;

  3. void EPCInit(void)
  4. {
  5.         EPC1.MMD = &MMDPort1;
  6.         EPC1.DeviceAddr = 0x01;
  7. }
  8. uint8_t ReadEPC(void *Para)
  9. {
  10.         struct EpcPre *EPC;
  11.        
  12.         EPC = (struct EpcPre *)Para;
  13.         if(ReadHoldInputReg(EPC->MMD,EPC->DeviceAddr,0x04,0,4) != 0)
  14.         {
  15.                 if(EPC->MMD->RIR_Update)
  16.                 {
  17.                         EPC->MMD->RIR_Update = 0;
  18.                         EPC->DataUpdate = 1;
  19.                         EPC->P_Fb = EPC->MMD->Input_Reg[0];
  20.                         EPC->P_Sta = EPC->MMD->Input_Reg[1];
  21.                 }
  22.                 EPC->R_En = 0;
  23.                 return 1;
  24.         }
  25.         return 0;
  26. }
  27. void ReadEPFEnable(struct EpcPre *EPC)
  28. {
  29.         EPC->R_En = 1;
  30. }
  31. uint8_t SetPreVal(void *Para)
  32. {
  33.         struct EpcPre *EPC;
  34.        
  35.         EPC = (struct EpcPre *)Para;
  36.         if(WriteHoldReg(EPC->MMD,EPC->DeviceAddr,0,1,&EPC->Pset) != 0)
  37.         {
  38.                 if(EPC->MMD->WHR_Success)
  39.                 {
  40.                         EPC->MMD->WHR_Success = 0;
  41.                         EPC->SetSuccess = 1;
  42.                 }
  43.                 EPC->S_P_En = 0;
  44.                 return 1;
  45.         }
  46.         return 0;
  47. }
  48. void SetPreValEnable(struct EpcPre *EPC,uint16_t Pre)
  49. {
  50.         EPC->S_P_En = 1;
  51.         EPC->Pset = Pre;
  52. }
復制代碼
  1. #include "THP.h"

  2. struct TemHumPre THP1;

  3. void THPInit(void)
  4. {
  5.         THP1.MMD = &MMDPort1;
  6.         THP1.DeviceAddr = 0x03;
  7. }
  8. uint8_t ReadTHP(void *Para)
  9. {
  10.         struct TemHumPre *THP;
  11.        
  12.         THP = (struct TemHumPre*)Para;
  13.         if(ReadHoldInputReg(THP->MMD,THP->DeviceAddr,0x04,0,3) != 0)
  14.         {
  15.                 if(THP->MMD->RIR_Update)
  16.                 {
  17.                         THP->MMD->RIR_Update = 0;
  18.                         if(THP->MMD->Input_Reg[0] != 0xffff)
  19.                         {
  20.                                 THP->AirTemp = (float)(THP->MMD->Input_Reg[0]-10000)/10;
  21.                         }
  22.                         if(THP->MMD->Input_Reg[1] != 0xffff)
  23.                         {
  24.                                 THP->AirHun = (float)THP->MMD->Input_Reg[1]/10;
  25.                         }
  26.                         if(THP->MMD->Input_Reg[2] != 0xffff)
  27.                         {
  28.                                 THP->AirPre = (float)THP->MMD->Input_Reg[2]/10;
  29.                         }
  30.                 }
  31.                 THP->Enable = 0;
  32.                 return 1;
  33.         }
  34.         return 0;
  35. }
  36. void ReadTHPEnable(struct TemHumPre *THP)
  37. {
  38.         THP->Enable = 1;
  39. }
復制代碼
整體來看,每個任務都分為任務主體和任務使能兩個部分,任務主體由下一章要介紹的調度篇來調用,使能由用戶來調用,比如THP需要每隔1S讀取一次那么就使函數“void ReadTHPEnable(struct TemHumPre *THP)”每隔1S執行一次。
  1. static void Task_1000ms(void)
  2. {
  3.         ReadTHPEnable(&THP1);
  4. }
復制代碼
而EPC需要500ms讀取一次氣壓,則使函數“void ReadEPFEnable(struct EpcPre *EPC)”每隔500ms執行一次。
  1. static void Task_500ms(void)
  2. {
  3.         ReadEPFEnable(&EPC1);
  4. }
復制代碼
對于寫保持寄存器相關的任務我們可以順道把要寫的數據放在使能函數里,這樣可以使寫保持寄存器的任務主體函數更加簡潔。
下面我們需要著重講解一下任務主體的實現。
以讀取EPC氣壓為例,任務會首先執行函數“ReadHoldInputReg()”并判斷返回值,根據協議篇可以知道在等待從機應答的那段時間“ReadHoldInputReg()”會返回0,于是“ReadEPC()”也返回0告知上層函數目前正在等待從機應答;若“ReadHoldInputReg()”返回1則說明從機成功應答或者應答超時了,我們怎么知道到底是應答了還是超時了呢?這就需要讀取變量RIR_Update,若為1則說明應答成功我們就需要把讀到的數據進行保存和處理,RIR_Update也完成了它的使命所以將其置0,并將DataUpdate置1告知上層函數數據讀取成功。從機無論是應答還是超時都需要將R_En置0并返回1這點至關重要。
所有的任務必須嚴格按照該格式來實現,否則會影響上層的調度工作。
至此任務篇就介紹完畢了。





評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏5 分享淘帖 頂1 踩
回復

使用道具 舉報

沙發
ID:654585 發表于 2022-4-18 11:03 | 只看該作者
教程很好,學習學習,感謝!
回復

使用道具 舉報

板凳
ID:27536 發表于 2023-5-12 16:43 | 只看該作者
crc沒看到,
回復

使用道具 舉報

地板
ID:50577 發表于 2024-7-10 15:32 | 只看該作者
這是哪個系類單片機的呢
回復

使用道具 舉報

5#
ID:50577 發表于 2024-7-10 15:32 | 只看該作者
只是什么系列的單片機呢
回復

使用道具 舉報

6#
ID:446156 發表于 2024-10-30 16:58 | 只看該作者

CRC在協議篇里
回復

使用道具 舉報

7#
ID:446156 發表于 2024-10-30 16:59 | 只看該作者
linlin1 發表于 2024-7-10 15:32
只是什么系列的單片機呢

這些代碼不分單片機,底層應用層分離的只需要修改一點點接口代碼就行
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 色www精品视频在线观看 | 国产精品一区二区久久久久 | 色站综合| 青娱乐av| 精品国产一区二区在线 | 中文字幕福利 | 国产精品免费大片 | 日韩字幕一区 | 一级毛片色一级 | 91深夜福利视频 | 亚洲欧洲一区二区 | 视频一区在线 | 中文字幕二区三区 | 久青草影院 | 国产一级淫片a直接免费看 免费a网站 | 国产亚洲精品精品国产亚洲综合 | 国产99久久| 亚洲综合色自拍一区 | 69福利影院 | 成年人在线观看视频 | 欧美精品片 | 精品久久一| 9久久婷婷国产综合精品性色 | 欧美久久久 | 国产欧美一区二区精品忘忧草 | 国产精品视频免费看 | 黄色国产视频 | 天天综合网天天综合色 | 91大片 | 午夜影院在线观看视频 | 亚洲国产精品一区二区www | 欧美亚洲一级 | 久久久久久国产精品 | 一区二区三区欧美 | 成人国产在线观看 | 自拍偷拍亚洲视频 | 蜜桃黄网 | 成人免费网站视频 | 欧美久久久电影 | 91av导航| 91亚洲国产精品 |