?? mbmaster.c
字號:
/****************************************Copyright (c)**************************************************
** 廣州周立功單片機發展有限公司
** 研 究 所
** 產品一部
**
** http://www.zlgmcu.com
**
**--------------文件信息--------------------------------------------------------------------------------
**文 件 名: MBMaster.c
**創 建 人: 周立山
**最后修改日期: 2005年7月29日
**描 述: MODBUS RTU 協議棧
**
**--------------歷史版本信息----------------------------------------------------------------------------
** 創建人: 周立山
** 版 本: 1.0a
** 日 期: 2005年7月29日
** 描 述: 原始版本
**
**------------------------------------------------------------------------------------------------------
** 修改人:
** 版 本:
** 日 期:
** 描 述:
**
**--------------當前版本修訂------------------------------------------------------------------------------
** 修改人:
** 日 期:
** 描 述:
**
**------------------------------------------------------------------------------------------------------
********************************************************************************************************/
#include "config.h"
#define ERR_ADRRESS 0xff // 設備地址無效
#define ERR_PARAMETER 0xfe // 輸入參數無效出錯
#define ERR_TIMEOUT 0xfd // 沒應答超時出錯
#define ERR_FRAME 0xfc // 接收到的幀出錯(CRC出錯)
#define ERR_NON 0x00 // 正常返回
extern FUNCTION_PACK_PDU FunPDUPackHanlde[MAX_FUNCTION];
extern FUNCTION_DATA_HANDLE FunParRepAndStData[MAX_FUNCTION];
uint16 Modbus_CRC16(uint8 *Buff_addr,uint16 len);
void SendResponse(uint8 *buff,uint16 len);
uint8 ADUBuffer[256];
extern g_WaitN10mS;
#ifdef UCOSII
OS_EVENT *mb_handle_event_ptr;
OS_EVENT *mb_reply_event_ptr;
OS_EVENT *mb_idle_event_ptr;
#endif
MASTER_INFORMATION MB_Master;
//********************************************************************************************************
// 函數名稱:MBSlaveIni
// 輸入參數:無
// 輸出參數:無
// 功能描述:MODBUS從機初始化
//********************************************************************************************************
void MBMasterIni(void)
{
MB_Master.Status = MB_MASTER_IDLE; // 主機空閑
ADUData.Address = 0;
ADUData.ADUBuffPtr = ADUBuffer;
ADUData.ADULength = 0;
ADUData.EndT15 = FALSE;
ADUData.FrameOK = FALSE;
PDUData.PDUBuffPtr = NULL;
#ifdef UCOSII
mb_idle_event_ptr = OSSemCreate(1); // MODBUS主機空閑信號量
mb_handle_event_ptr = OSSemCreate(0); // MODBUS處理信號量
mb_reply_event_ptr = OSMboxCreate((void *)0); // MODBUS處理應答消息
#endif
}
//******************************************************************************************
// 函數名稱:ModbusPoll
// 輸入參數:NodeID,節點ID(設備地址)
// FunctionCode,功能代碼
// ParameterPtr,參數入口
// 輸出參數:err,指令執行狀態
// 功能描述:
//******************************************************************************************
uint8 ModbusPoll(uint8 NodeID,uint8 FunctionCode,void *ParameterPtr)
{
uint8 i,err;
ADUData.Address = NodeID;
for(i=0;i<MAX_FUNCTION;i++) // 查打有效的功能代碼
{ if(FunPDUPackHanlde[i].Code==FunctionCode) // 查找功能代碼處理函數
{
#ifdef UCOSII
OSSemPend(mb_idle_event_ptr,0,&err); // 等待可以操作MODBUS主機的一個信號量
#else
if(MB_Master.Status!=(uint8)MB_MASTER_IDLE)
return (uint8)MB_MASTER_BUSY; // 無效指令返回
#endif
PDUData.PDUBuffPtr = ADUData.ADUBuffPtr+1; // 設置PDU起始指針
FunPDUPackHanlde[i].Function(ParameterPtr); // 調用功能代碼處理函數
PDUData.FrameOK = TRUE; // 請求幀準備就緒
MB_Master.ParPtr = ParameterPtr; // 請求參數結構指針
#ifdef UCOSII
OSSemPost(mb_handle_event_ptr); // 發報信號量,使MODBUS服務任務處理傳輸
err = *(uint8 *)OSMboxPend(mb_reply_event_ptr,0,&err); // 等待執行完成
#else
do
{
err = IdleModbus();
}while(MB_Master.Status==(uint8)MB_MASTER_BUSY);
#endif
return err; // 無效指令返回
}
}
return (uint8)MB_FUN_NOT_DEF;
}
//******************************************************************************************
// 函數名稱:ParseReponseAndStoreData
// 輸入參數:無
// 輸出參數:無
// 功能描述:解析應答幀,并保存數據
//******************************************************************************************
uint8 ParseReponseAndStoreData(void)
{
uint8 i,err;
err = MB_FUN_NOT_DEF;
for(i=0;i<MAX_FUNCTION;i++)
if(FunParRepAndStData[i].Code==PDUData.FunctionCode) // 查找功能代碼處理函數
{
if(PDUData.PDUBuffPtr[0]&0x80) // 異常產生
{ err = PDUData.PDUBuffPtr[1];}
else
{ err = MB_NO_ERR;
FunParRepAndStData[i].Function(PDUData.PDUBuffPtr,MB_Master.ParPtr); // 調用功能代碼處理函數
}
break;
}
return err;// 未定義功能碼
}
//******************************************************************************************
// 函數名稱:CheckModbusMessage
// 輸入參數:無
// 輸出參數:ADU描述符
// 功能描述:檢查是否有需要發送的的幀
//******************************************************************************************
ADU_CONTROL *CheckModbusMessage(void)
{
uint16 CRC16;
uint8 *ADUPtr;
if(PDUData.FrameOK == TRUE) // 請求幀的PDU是否準備就緒
{
PDUData.FrameOK = FALSE; // 清PDU是否準備就緒標志,當接收到有效的PDU后將被再次置1
ADUPtr = ADUData.ADUBuffPtr;
ADUPtr[0] = ADUData.Address; // 設置ADU地址(節點)
CRC16 = Modbus_CRC16(ADUPtr,PDUData.PDULength+1); // 求CRC16值
ADUPtr[PDUData.PDULength+1] = CRC16; // 設置CRC16值
ADUPtr[PDUData.PDULength+2] = CRC16>>8;
ADUData.ADULength=PDUData.PDULength+3; // ADU長度等于PDU長度加1個地址和2個CRC字符
ADUData.FrameOK = TRUE; // 標記ADU請求幀準備就緒
return (ADU_CONTROL *) &ADUData;
}
else
return NULL;
}
//******************************************************************************************
// 函數名稱:IdleModbus
// 輸入參數:無
// 輸出參數:MODBUS主機狀態
// 功能描述:
//******************************************************************************************
uint8 IdleModbus(void)
{
static uint8 err;
static uint8 modbus_state=0;
#ifdef UCOSII
OSSemPend(mb_handle_event_ptr,0,&err);
#endif
err = MB_MASTER_BUSY;
switch ( modbus_state )
{
case 0:
/******************************************************************/
/* CHECK FOR THE NEXT MESSAGE TO SEND */
/* 檢查需要發送的消息,并發送請求幀 */
/******************************************************************/
if ( CheckModbusMessage() )
{
/******************************************************************/
/* SEND THE POLL */
/* 發送請求幀 */
/******************************************************************/
SendResponse(ADUData.ADUBuffPtr,ADUData.ADULength);// 發送幀
ADUData.FrameOK = FALSE;
ADUData.ADULength = 0;
Waite10mS(MB_POLL_TIMEOUT); // 命令應答計時
modbus_state++;
}
else
err = MB_MASTER_IDLE; // 沒有功能代碼需傳輸
break;
case 1:
/******************************************************************/
/* GET THE PACKET AND MAKE SURE IT IS COMPLETE */
/******************************************************************/
if ( PDUData.FrameOK ) // 成功接收PDU幀
{
/******************************************************************/
/* PARSE THE RESPONSE AND STORE THE DATA */
/* 解析應等幀,并儲存數據 */
/******************************************************************/
err = ParseReponseAndStoreData();
PDUData.FrameOK = FALSE;
Waite10mS(MB_POLL_DELAY);
#ifdef UCOSII
OSMboxPost(mb_reply_event_ptr,&err);
#endif
modbus_state++;
break;
}
/******************************************************************/
/* IF NO RESPONSE RECEIVED TIME OUT AND SEND NEXT POLL */
/******************************************************************/
if (g_TimeEnd)
{
modbus_state = 0;
MB_Master.Status = MB_MASTER_IDLE; // 主機空閑
err = MB_RESPONSE_TIME_OUT;
#ifdef UCOSII
OSMboxPost(mb_reply_event_ptr,&err);
#endif
}
break;
case 2:
/******************************************************************/
/* POLL DELAY */
/* 輪循延時 */
/******************************************************************/
if (g_TimeEnd)
{
modbus_state=0;
MB_Master.Status = MB_MASTER_IDLE; // 主機空閑
}
default:
break;
}
#ifdef UCOSII
if(MB_Master.Status == MB_MASTER_IDLE)
OSSemPost(mb_idle_event_ptr);
#endif
return err;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -