基於STM32F767通過STM32CubeMX實現ModbusTCP從站(後續)

基於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!!!!!!

以上內容歡迎大家轉載引用,標明出處即可!!!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章