基於STM32F767通過STM32CubeMX實現ModbusTCP讀多爲寄存器操作(後續)
由於上篇着重介紹了實現功能的代碼,以至於我沒有和大家講清楚FreeModbus應該怎麼移植,在此先抱歉浪費大家時間了。
接下來我要開始實操怎麼成功移植Freemodbus在STM32上(以下方法可以滿足所有STM32設備)
實驗準備:去FreeModbus官網下載Modbus的源碼包,鏈接直接放上:Freemodbus官網
懶人直接點擊Github鏈接:FreeModbus源碼
3、很多人移植這個modbus時出現了加上modbus相關代碼時就ping不同的情況,其實是在modbus源碼中出現了死循環,如下所示處:
我的解決方案是使能串口後添加printf函數打印串口的代碼在串口文件中,這個死循環即可跳出。
之後就能成功ping通板子,操作modbus了
以下是具體操作:
一、實驗步驟
1、找到下載包內demo/STR71XTCP/Port文件夾,單獨拿出來放到ModbusPort文件夾下。
2、找到下載包內modbus文件夾拿出來,放到可以ping通的STM32項目裏,如圖:
3、打開STM32CubeMX,創建項目,使能LWIP和ETH和串口下載到開發板,並保證可以ping通
一定要串口一定要串口一定要串口,保證mosbus源碼不會死循環
4、添加串口的目的是讓文章開頭所說的地方的printf函數有輸出的地方,使Mosbus不會因爲死循環導致循序卡死
所以我們需要在串口程序部分添加串口用printf函數輸出的功能代碼
/* USER CODE BEGIN 0 */
/******************printf函數*********************/
#include "stdio.h"
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
/*************************************************/
/* USER CODE END 0 */
5、將之前下載的MosbusPort和modbus內的文件加到工程裏,其中需要加的文件有
6、點擊目標選項
7、在選項卡C/C++下的包含路徑添加modbus相關頭文件所在路徑
添加完成後有兩種情況,需要添加如下代碼
eMBTCPInit( 0 ); //初始化ModbusTCP
eMBEnable(); //使能Modbus
eMBPoll(); //輪詢Modbus(該條添加在主循環中)
A.使用了操作系統,則在freertos.c文件下添加如下代碼
B.沒有使能操作系統,添加在main.c文件添加如下代碼
8、新建ModbusCB.c文件,放在Modbus目錄下,實現各個功能,這裏只實現的保持寄存器功能(博主是懶狗,其他請大家照葫蘆畫瓢)
#include "mb.h"
uint16_t R[15];
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
static uint8_t flag = 0;
// flag == 0 ? GPIO_SetBits(GPIOC,GPIO_PIN_1) : GPIO_ResetBits(GPIOC,GPIO_PIN_1); //modify by alan
flag==0 ? HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET) : HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
flag ^= 1;
return eStatus;
}
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
eMBErrorCode eStatus = MB_ENOERR;
static uint8_t flag = 0;
int i=0;
//flag == 0 ? GPIO_SetBits(GPIOC,GPIO_PIN_2) : GPIO_ResetBits(GPIOC,GPIO_PIN_2); //modify by alan
flag==0 ? HAL_GPIO_WritePin(GPIOC, GPIO_PIN_2, GPIO_PIN_SET) : HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
flag ^= 1;
/*the following code is just for the testing the function of reading register
author: Alan
*/
R[0]=56;
R[1]=78;
R[2]=12;
R[3]=34;
for(i=0;i<usNRegs;i++)
{
*pucRegBuffer=R[i+usAddress-1]>>8;
pucRegBuffer++;
*pucRegBuffer=R[i+usAddress-1]&0xff;
pucRegBuffer++;
}
return eStatus;
}
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
static uint8_t flag = 0;
//flag == 0 ? GPIO_SetBits(GPIOC,GPIO_PIN_3) : GPIO_ResetBits(GPIOC,GPIO_PIN_6); //modify by alan
flag==0 ? HAL_GPIO_WritePin(GPIOC, GPIO_PIN_3, GPIO_PIN_SET) : HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET);
flag ^= 1;
return MB_ENOREG;
}
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
static uint8_t flag = 0;
//flag == 0 ? GPIO_SetBits(GPIOC,GPIO_PIN_4) : GPIO_ResetBits(GPIOC,GPIO_PIN_7); //modify by alan
flag==0 ? HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_SET) : HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
flag ^= 1;
return MB_ENOREG;
}
此時程序基本完成,編譯下載
二、實驗結果
1.下載完成後先測試能不能ping通,得到下圖即可
2.打開任何可以使用的mosbus測試工具,注意,本次實驗爲從站設計,所以測試工具設置爲主站
填寫好開發板IP地址和端口號
點擊連接,等下方出現連接成功提示
點擊讀保持寄存器(功能碼03)得到如下效果
如上圖,根據ModbusBC.c中設置的R[0]~R[4]的內容分別爲56,78,12,34,讀取後內存相應位置也變成了對應的數字,實驗成功
接下來分析一下發送和返回報文,由圖可知
發送報文TX:00 00 00 00 00 06 01 03 00 00 00 10
前6位位MBAP報文頭:00(Hi) 00(Lo) 00 00(協議標識,0000爲使能modbus) 00 06(報文長度6位)
後6位爲modbus報文:01(從機地址) 03(功能碼) 00 00(起始地址) 00 10(寄存器數量)
由上圖可知,我設定的起始地址爲0,長度爲16,該數字爲10進制,報文內爲16進制,所以長度爲十進制的16就變爲十六進制的10.
接收報文RX:00 00 00 00 00 23 01 03 20 00 38 00 4e 00 0c 00 22 00 00 00 00…
前6位位MBAP報文頭:00(Hi) 00(Lo) 00 00(協議標識,0000爲使能modbus) 00 23(報文長度23位)
後爲modbus報文:01(從機地址) 03(功能碼) 20(寄存器內容長度) 00 38(等於十進制的56)00 4e(等於十進制的78) 00 0c(等於十進制的12) 00 22(等於十進制的34) 00 00 00 00 00
之後全爲00,表示其他寄存器值爲0
實驗結束,打完收工!!!!
Good Game!!!!!!
以上內容歡迎大家轉載引用,標明出處即可!!!!!