1.準備模板
打開雅特力官網,也就是帶有LwIP的示例。
下載官方源碼:modbus
2.移植
我這里是在這里新建兩個文件夾,分別是modbus與port,這個任意,只需要將必要的文件加入項目即可。
將源碼中的modbus這些都移植過來,分別是實現,頭文件、以及tcp相關的文件。其余的就不需要了
port文件夾里為:源碼->demo->MCF5235TCP->port。
接下來將這些文件加入工程。加入頭文件
編譯后,發現有12個錯誤
3.依次解決:
1.打開mbconfig.h
確保,我是本來就這樣,所以可能就只有12個錯誤,如果不是這樣可能之前編譯的錯誤更多。
2.打開port.h
這里我就關閉tcp_debug了。
3.打開portevent.c
沒有定義,自己定義一下,然后這里的sys_mbox_ne()這個函數定義已經發生了改變。按照途中修改,后續報警的xMailBox加上&符號,
4.打開portother.c
刪掉多余的這個三個
編譯,發現還有五個錯誤
1.打開porttcp.c
報錯說沒有memcpy,那么我們加入頭文件
還有這個錯誤,我們ctrl+h尋找,發現定義在portother.c文件里
復制并放在port.h中:
2.突然又發現少個宏定義,很離譜,我之前移植的時候沒有少過
是這個宏
拷貝,并放到mbconfig.h文件中:
#ifndef MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
#define MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS ( 0 )
#endif
不過我記得我之前沒有這個問題。
再次編譯:
我出現了以下五個錯誤
我的main.c為:
/***************************************************************************** @file main.c* @version v2.0.6* @date 2022-03-11* @brief main program*************************************************************************** Copyright notice & Disclaimer** The software Board Support Package (BSP) that is made available to * download from Artery official website is the copyrighted work of Artery. * Artery authorizes customers to use, copy, and distribute the BSP * software and its related documentation for the purpose of design and * development in conjunction with Artery microcontrollers. Use of the * software is governed by this copyright notice and the following disclaimer.** THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.****************************************************************************/#include "at32f435_437_board.h"
#include "at32f435_437_clock.h"
#include "at32_emac.h"
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"#include "lwip/api.h"
#include "lwip/sys.h"
/*FreeModBus*/
#include "mb.h"
#include "mbutils.h"/* ----------------------- Defines ------------------------------------------*/
#define PROG "FreeModbus"//輸入寄存器起始地址
#define REG_INPUT_START 0x0000
//輸入寄存器數量
#define REG_INPUT_NREGS 8
//保持寄存器起始地址
#define REG_HOLDING_START 0x0000
//保持寄存器數量
#define REG_HOLDING_NREGS 8//線圈起始地址
#define REG_COILS_START 0x0000
//線圈數量
#define REG_COILS_SIZE 16//開關寄存器起始地址
#define REG_DISCRETE_START 0x0000
//開關寄存器數量
#define REG_DISCRETE_SIZE 16/* Private variables ---------------------------------------------------------*/
//輸入寄存器內容
uint16_t usRegInputBuf[REG_INPUT_NREGS] = {0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007};
//輸入寄存器起始地址
uint16_t usRegInputStart = REG_INPUT_START;//保持寄存器內容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] = {0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
//保持寄存器起始地址
uint16_t usRegHoldingStart = REG_HOLDING_START;//線圈狀態
uint8_t ucRegCoilsBuf[REG_COILS_SIZE / 8] = {0x0f,0x02};
//開關輸入狀態
uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE / 8] = {0x0f,0x02};
/** @addtogroup UTILITIES_examples* @{*//*開始任務*/
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);
/** @addtogroup FreeRTOS_demo* @{*/
extern void tcpip_stack_init(void);
extern void udpecho_init(void);
extern void tcpecho_init(void);TaskHandle_t network_handler;/* led3 task */
void network_task_function(void *pvParameters);/*** @brief main function.* @param none* @retval none*/
int main(void)
{nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);system_clock_config();/* init led2*/at32_led_init(LED2);/* init led3*/at32_led_init(LED3);/* init led4*/at32_led_init(LED4);/* init usart1 */uart_print_init(115200);/* enter critical */taskENTER_CRITICAL(); if(xTaskCreate((TaskFunction_t )network_task_function, (const char* )"Network_task", (uint16_t )512, (void* )NULL,(UBaseType_t )2,(TaskHandle_t* )&network_handler) != pdPASS){printf("Network task could not be created as there was insufficient heap memory remaining.\r\n");} else{printf("Network task was created successfully.\r\n");}/* exit critical */ taskEXIT_CRITICAL(); /* start scheduler */ vTaskStartScheduler(); }static void modbustcp_thread(void *arg)
{ LWIP_UNUSED_ARG(arg);eMBErrorCode xStatus;eMBTCPInit( MB_TCP_PORT_USE_DEFAULT );eMBEnable();while(1){eMBPoll();vTaskDelay(5);}/* An error occured. Maybe we can restart. */
// ( void )eMBDisable( );
// ( void )eMBClose( );//}
}void modbustcp_init(void)
{sys_thread_new("modbustcp_thread", modbustcp_thread, NULL, 512, 4);
}/* led3 task function */
void network_task_function(void *pvParameters)
{while(emac_system_init() == ERROR);tcpip_stack_init();modbustcp_init();taskENTER_CRITICAL(); //進入臨界區vTaskDelete(StartTask_Handler); //刪除開始任務taskEXIT_CRITICAL(); //退出臨界區
}/*** @}*/ /****************************************************************************
* 名 稱:eMBRegInputCB
* 功 能:讀取輸入寄存器,對應功能碼是 04 eMBFuncReadInputRegister
* 入口參數:pucRegBuffer: 數據緩存區,用于響應主機
* usAddress: 寄存器地址
* usNRegs: 要讀取的寄存器個數
* 出口參數:
* 注 意:上位機發來的 幀格式是: SlaveAddr(1 Byte)+FuncCode(1 Byte)
* +StartAddrHiByte(1 Byte)+StartAddrLoByte(1 Byte)
* +LenAddrHiByte(1 Byte)+LenAddrLoByte(1 Byte)+
* +CRCAddrHiByte(1 Byte)+CRCAddrLoByte(1 Byte)
* 3 區
****************************************************************************/
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{eMBErrorCode eStatus = MB_ENOERR;int iRegIndex;/* it already plus one in modbus function method. */usAddress--;if( ( usAddress >= REG_INPUT_START )&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ){iRegIndex = ( int )( usAddress - usRegInputStart );while( usNRegs > 0 ){*pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] >> 8 );*pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] & 0xFF );iRegIndex++;usNRegs--;}}else{eStatus = MB_ENOREG;}return eStatus;
}/****************************************************************************
* 名 稱:eMBRegHoldingCB
* 功 能:對應功能碼有:06 寫保持寄存器 eMBFuncWriteHoldingRegister
* 16 寫多個保持寄存器 eMBFuncWriteMultipleHoldingRegister
* 03 讀保持寄存器 eMBFuncReadHoldingRegister
* 23 讀寫多個保持寄存器 eMBFuncReadWriteMultipleHoldingRegister
* 入口參數:pucRegBuffer: 數據緩存區,用于響應主機
* usAddress: 寄存器地址
* usNRegs: 要讀寫的寄存器個數
* eMode: 功能碼
* 出口參數:
* 注 意:4 區
****************************************************************************/
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{eMBErrorCode eStatus = MB_ENOERR;int iRegIndex;/* it already plus one in modbus function method. */usAddress--;if((usAddress >= REG_HOLDING_START)&&\((usAddress+usNRegs) <= (REG_HOLDING_START + REG_HOLDING_NREGS))){iRegIndex = (int)(usAddress - usRegHoldingStart);switch(eMode){ case MB_REG_READ://讀 MB_REG_READ = 0while(usNRegs > 0){*pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] >> 8); *pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] & 0xFF); iRegIndex++;usNRegs--; } break;case MB_REG_WRITE://寫 MB_REG_WRITE = 0while(usNRegs > 0){ usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;iRegIndex++;usNRegs--;} }}else//錯誤{eStatus = MB_ENOREG;} return eStatus;
}extern void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,UCHAR ucValue );
extern UCHAR xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits );
/****************************************************************************
* 名 稱:eMBRegCoilsCB
* 功 能:對應功能碼有:01 讀線圈 eMBFuncReadCoils
* 05 寫線圈 eMBFuncWriteCoil
* 15 寫多個線圈 eMBFuncWriteMultipleCoils
* 入口參數:pucRegBuffer: 數據緩存區,用于響應主機
* usAddress: 線圈地址
* usNCoils: 要讀寫的線圈個數
* eMode: 功能碼
* 出口參數:
* 注 意:如繼電器
* 0 區
****************************************************************************/
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,eMBRegisterMode eMode )
{//錯誤狀態eMBErrorCode eStatus = MB_ENOERR;//寄存器個數int16_t iNCoils = ( int16_t )usNCoils;//寄存器偏移量int16_t usBitOffset;/* it already plus one in modbus function method. */usAddress--;//檢查寄存器是否在指定范圍內if( ( (int16_t)usAddress >= REG_COILS_START ) &&( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) ){//計算寄存器偏移量usBitOffset = ( int16_t )( usAddress - REG_COILS_START );switch ( eMode ){//讀操作case MB_REG_READ:while( iNCoils > 0 ){*pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset,( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) );iNCoils -= 8;usBitOffset += 8;}break;//寫操作case MB_REG_WRITE:while( iNCoils > 0 ){xMBUtilSetBits( ucRegCoilsBuf, usBitOffset,( uint8_t )( iNCoils > 8 ? 8 : iNCoils ),*pucRegBuffer++ );iNCoils -= 8;}break;}}else{eStatus = MB_ENOREG;}return eStatus;
}/****************************************************************************
* 名 稱:eMBRegDiscreteCB
* 功 能:讀取離散寄存器,對應功能碼有:02 讀離散寄存器 eMBFuncReadDiscreteInputs
* 入口參數:pucRegBuffer: 數據緩存區,用于響應主機
* usAddress: 寄存器地址
* usNDiscrete: 要讀取的寄存器個數
* 出口參數:
* 注 意:1 區
****************************************************************************/
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{//錯誤狀態eMBErrorCode eStatus = MB_ENOERR;//操作寄存器個數int16_t iNDiscrete = ( int16_t )usNDiscrete;//偏移量uint16_t usBitOffset;/* it already plus one in modbus function method. */usAddress--; //判斷寄存器時候再制定范圍內if( ( (int16_t)usAddress >= REG_DISCRETE_START ) &&( usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE ) ){//獲得偏移量usBitOffset = ( uint16_t )( usAddress - REG_DISCRETE_START );while( iNDiscrete > 0 ){*pucRegBuffer++ = xMBUtilGetBits( ucRegDiscreteBuf, usBitOffset,( uint8_t)( iNDiscrete > 8 ? 8 : iNDiscrete ) );iNDiscrete -= 8;usBitOffset += 8;}}else{eStatus = MB_ENOREG;}return eStatus;
}
/*** @}*/
? ? usAddress--;每一個都有這個是因為在modbus內部處理的時候,會將地址+1,從1開始。所以讀數組的時候,會出現問題。
現在再次編譯:
我們按照指示,打開mbutils.c
void __aeabi_assert(const char *expr, const char *file, int line) {// 打印斷言失敗信息(根據需要修改,如輸出到串口、LCD等)// 斷言失敗后的處理(如停機、復位等)while (1); // 死循環,防止程序繼續運行// 或調用復位函數(根據芯片型號,如 NVIC_SystemReset())
}
加入后,編譯通過,下載:
打開tcpip_stack_init();函數,發現綁定ip為172.31.96.101.我的eMBTCPInit( MB_TCP_PORT_USE_DEFAULT );為默認502.
發送數據:讀取8個數據:收到回應。