對modbus中的包含下的mbconfig.h進行編輯,把Ascii碼配置爲0,我們只用用RTU
1.可以新建一個STM32工程,我這裏是用的是例程串口232收發的例程,用的是串口2
2.主要先將freemodbus 1.5源碼中的modbus文件夾和演示文件夾裏的BARE文件複製到工程,然後添加文件到工程
3.配置串口使能函數vMBPortSerialEnable(BOOL xRxEnable,BOOL xTxEnable)
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
/* If xRXEnable enable serial receive interrupts. If xTxENable enable
* transmitter empty interrupts.
*/
/* If xRXEnable enable serial receive interrupts. If xTxENable enable
* transmitter empty interrupts.
*/
if(TRUE==xRxEnable)
{
USART_ITConfig(RS232_USART, USART_IT_RXNE, ENABLE);
}
else
{
USART_ITConfig(RS232_USART, USART_IT_RXNE, DISABLE);
}
if(TRUE==xTxEnable)
{
USART_ITConfig(RS232_USART, USART_IT_TXE, ENABLE);
}
else
{
USART_ITConfig(RS232_USART, USART_IT_TXE, DISABLE);
}
}
串口初始化函數xMBPortSerialInit(UCHAR ucPORT,ULONG ulBaudRate,UCHAR ucDataBits,eMBParity eParity)
可以將232串口初始化的例程複製到這個函數
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
(void)ucPORT; //不修改串口
(void)ucDataBits; //不修改數據長度
(void)eParity; //不修改格式
//////////////////////////////////////////////////////////////////////////////////////////////
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_AHB1PeriphClockCmd( RS232_USART_RX_GPIO_CLK|RS232_USART_TX_GPIO_CLK, ENABLE);
/*使用UART時鐘*/
RCC_APB1PeriphClockCmd(RS232_USART_CLK, ENABLE);
/*連接PXx到USARTx_Tx*/
GPIO_PinAFConfig(RS232_USART_RX_GPIO_PORT,RS232_USART_RX_SOURCE, RS232_USART_RX_AF);
/*連接PXx到USARTx_Rx*/
GPIO_PinAFConfig(RS232_USART_TX_GPIO_PORT,RS232_USART_TX_SOURCE,RS232_USART_TX_AF);
/*配置Tx引腳爲複用功能*/
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = RS232_USART_TX_PIN ;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(RS232_USART_TX_GPIO_PORT, &GPIO_InitStructure);
/*配置Rx引腳爲複用功能*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Pin = RS232_USART_RX_PIN;
GPIO_Init(RS232_USART_RX_GPIO_PORT, &GPIO_InitStructure);
/* 配置串口RS232_USART模式*/
USART_InitStructure.USART_BaudRate = RS232_USART_BAUDRATE;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(RS232_USART, &USART_InitStructure);
USART_ITConfig(RS232_USART, USART_IT_RXNE, ENABLE);
USART_Cmd(RS232_USART, ENABLE);
////////////////////////////////////////////////////////////////////////////////////////////////
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/*中斷初始化 */
//設置NVIC優先級分組爲Group2:0-3搶佔優先級,0-3的響應優先級
NVIC_InitStructure.NVIC_IRQChannel = RS232_USART_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
return TRUE;
}
注意:
1- 我這裏用的例程串口的.H文件的波特率RS232_USART_BAUDRATE,不是MODBUS初始化函數
eMBInit(MB_RTU,1,1,9600,MB_PAR_NONE);裏的波特率9600,而且最後返回TRUE
2- 當波特率大於19200時,usTimerT35_50us固定爲35us;否則
usTimerT35_50us =(7UL * 220000UL)/(2UL * ulBaudRate);
4.xMBPortSerialPutByte的作用是將字節數據送到串口。把正常用的串口發送拿過來就可以了
BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
/* Put a byte in the UARTs transmit buffer. This function is called
* by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
* called. */
USART_SendData(USART2, ucByte);
while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET){};
return TRUE;
}
5.xMBPortSerialGetByte的作用是從串口接收數據並且把數據傳給指定內存。
BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
/* Return the byte in the UARTs receive buffer. This function is called
* by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
*/
*pucByte = USART_ReceiveData(RS232_USART);
return TRUE;
}
6.配置中斷函數
void RS232_USART_IRQHandler(void)
{
if(USART_GetITStatus(RS232_USART, USART_IT_RXNE) == SET)
{
prvvUARTRxISR();
USART_ClearITPendingBit(RS232_USART, USART_IT_RXNE);
}
if(USART_GetITStatus(RS232_USART, USART_IT_TXE) == SET)
{
prvvUARTTxReadyISR();
}
}
注意:需要將這兩個函數void prvvUARTTxReadyISR(void);和void prvvUARTRxISR(void); 的靜態去掉,並在port.h裏聲明
才能在中斷文件裏引用
7.設置定時器初始化,使用的是TIM2
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
NVIC_InitTypeDef NVIC_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseStructure.TIM_Period = usTim1Timerout50us-1;
TIM_TimeBaseStructure.TIM_Prescaler = (9000 - 1);
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ARRPreloadConfig(TIM2, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
TIM_Cmd(TIM2, DISABLE);
return TRUE;
}
8.vMBPortTimersEnable()使能定時器函數
void
vMBPortTimersEnable( )
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
TIM_SetCounter(TIM2, 0);
TIM_Cmd(TIM2, ENABLE);
}
9.vMBPortTimersDisable()定時器失能(關閉)函數
void
vMBPortTimersDisable( )
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, DISABLE);
TIM_SetCounter(TIM2, 0);
//TIM_Cmd(TIM2, DISABLE);
}
10.配置定時器中斷函數
void TIM2_IRQHandler(void)
{
prvvTIMERExpiredISR();
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
注意:需要把static void prvvTIMERExpiredISR(void)函數的靜去掉,並且聲明在port.h裏才能在中斷文件裏引用
11.新建port.c文件,主要是定義開啓/關閉全局中斷函數
port.c
#include "stm32f4xx.h"
#include "port.h"
void EnterCriticalSection(void)
{
//看看這個函數的使用位置就知道他們是反過來的,Enter本來意思是進入,但他的位置表明其實應該關閉
//開啓全局中斷
__disable_irq();
}
void ExitCriticalSection(void)
{
//開啓全局中斷
__enable_irq();
}
注意:在mbrtu.c文件裏
看看這兩個函數的位置就知道,按照一般邏輯來說:
一,都是先關閉中斷,然後處理數據,再打開終端,
灣並且輸入是使能/打開的意思,EXIT是失能/關閉的意思
所以我覺得這兩個函數的位置是弄反的,所以我直接在兩個函數的具體實現裏調換過來。
12.新建一個modbus.c文件,複製demo.c裏的四個函數(的的的Modbus通信中,總共有四類的寄存器,開關輸入寄存器,線圈寄存器,保持寄存器和輸入寄存器)過來,然後自己實現
//這是.h文件的內容
#include "mb.h"
#include "stm32f4xx.h"
#include "bsp_led.h"
#include "relay.h"
#include "modbus.h"
#include "Timer5.h"
#include "mbrtu.h"
#include "main.h"
#include "bsp_SysTick.h"
#include "new.h"
/* -----------------------Slave Defines -------------------------------------*/
#define S_DISCRETE_INPUT_START 1
#define S_DISCRETE_INPUT_NDISCRETES 16
#define S_COIL_START 1
#define S_COIL_NCOILS 104
#define S_REG_INPUT_START 1
#define S_REG_INPUT_NREGS 100
#define S_REG_HOLDING_START 1
#define S_REG_HOLDING_NREGS 100
//從機模式:在保持寄存器中,各個地址對應得功能定義
#define S_HD_RESERVE 0 //保留
#define S_HD_CPU_USAGE_MAJOR 1 //當前CPU利用率的整數位
#define S_HD_CPU_USAGE_MINOR 2 //當前CPU利用率的小數位
//從機模式:在輸入寄存器中,各個地址對應的功能定義
#define S_IN_RESERVE 0 //保留
//從機模式:在線圈中,各個地址對應的功能定義
#define S_CO_RESERVE 2 //保留
//從機模式:在離散輸入中,各個地址對應的功能定義
#define S_DI_RESERVE 1 //保留
/*------------------------Slave mode use these variables----------------------*/
//////Slave mode:DiscreteInputs variables
USHORT usSDiscInStart = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
#endif
//Slave mode:Coils variables
USHORT usSCoilStart = S_COIL_START;
#if S_COIL_NCOILS%8
UCHAR ucSCoilBuf[S_COIL_NCOILS/8+1] ;
#else
UCHAR ucSCoilBuf[14] ;
#endif
//Slave mode:InputRegister variables
USHORT usSRegInStart = S_REG_INPUT_START;
USHORT usSRegInBuf[100];
//float usSRegInBuf[S_REG_INPUT_NREGS];
//Slave mode:HoldingRegister variables
USHORT usSRegHoldStart = S_REG_HOLDING_START;
USHORT usSRegHoldBuf[250] ;
下面是modbus.c的內容
/*------------------------Slave mode use these variables----------------------*/
//////Slave mode:DiscreteInputs variables
USHORT usSDiscInStart = S_DISCRETE_INPUT_START;
#if S_DISCRETE_INPUT_NDISCRETES%8
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8+1];
#else
UCHAR ucSDiscInBuf[S_DISCRETE_INPUT_NDISCRETES/8] ;
#endif
//Slave mode:Coils variables
USHORT usSCoilStart = S_COIL_START;
#if S_COIL_NCOILS%8
UCHAR ucSCoilBuf[S_COIL_NCOILS/8+1] ;
#else
UCHAR ucSCoilBuf[14] ;
#endif
//Slave mode:InputRegister variables
USHORT usSRegInStart = S_REG_INPUT_START;
USHORT usSRegInBuf[100];
//float usSRegInBuf[S_REG_INPUT_NREGS];
//Slave mode:HoldingRegister variables
USHORT usSRegHoldStart = S_REG_HOLDING_START;
USHORT usSRegHoldBuf[250] ;
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
USHORT * pusRegInputBuf;
UCHAR REG_INPUT_START;
UCHAR REG_INPUT_NREGS;
UCHAR usRegInStart;
pusRegInputBuf = usSRegInBuf;
REG_INPUT_START = S_REG_INPUT_START;
REG_INPUT_NREGS = S_REG_INPUT_NREGS;
usRegInStart = usSRegInStart;
if( ( usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegInStart );
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( unsigned char )( pusRegInputBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex;
USHORT * pusRegHoldingBuf;
UCHAR REG_HOLDING_START;
UCHAR REG_HOLDING_NREGS;
UCHAR usRegHoldStart;
pusRegHoldingBuf = usSRegHoldBuf;
REG_HOLDING_START = S_REG_HOLDING_START;
REG_HOLDING_NREGS = S_REG_HOLDING_NREGS;
usRegHoldStart = usSRegHoldStart;
if( ( usAddress >= REG_HOLDING_START ) &&
( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
{
iRegIndex = ( int )( usAddress - usRegHoldStart );
switch ( eMode )
{
/* Pass current register values to the protocol stack. */
case MB_REG_READ:
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( unsigned char )( pusRegHoldingBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
break;
/* Update current register values with new values from the
* protocol stack. */
case MB_REG_WRITE:
while( usNRegs > 0 )
{
pusRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
pusRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex , iRegBitIndex , iNReg;
iNReg = usNCoils / 8 + 1; //Õ¼ÓüĴæÆ÷ÊýÁ¿
if( ( usAddress >= S_COIL_START ) &&
( usAddress + usNCoils <= S_COIL_START + S_COIL_NCOILS ) )
{
iRegIndex = ( int )( usAddress - S_COIL_START ) / 8 ; //ÿ¸ö¼Ä´æÆ÷´æ8¸ö
iRegBitIndex = ( int )( usAddress - usSCoilStart ) % 8 ; //Ïà¶ÔÓڼĴæÆ÷ÄÚ²¿µÄλµØÖ·
switch ( eMode )
{
/* Pass current coil values to the protocol stack. */
case MB_REG_READ:
while( iNReg > 0 )
{
*pucRegBuffer++ = xMBUtilGetBits(&ucSCoilBuf[iRegIndex++] , iRegBitIndex , 8);
iNReg --;
}
pucRegBuffer --;
usNCoils = usNCoils % 8; //ÓàϵÄÏßȦÊý
*pucRegBuffer = *pucRegBuffer <<(8 - usNCoils); //¸ßλ²¹Áã
*pucRegBuffer = *pucRegBuffer >>(8 - usNCoils);
break;
/* Update current coil values with new values from the
* protocol stack. */
case MB_REG_WRITE:
while(iNReg > 1) //×îºóÃæÓàÏÂÀ´µÄÊýµ¥¶ÀËã
{
xMBUtilSetBits(&ucSCoilBuf[iRegIndex++] , iRegBitIndex , 8 , *pucRegBuffer++);
iNReg--;
}
usNCoils = usNCoils % 8; //ÓàϵÄÏßȦÊý
if (usNCoils != 0) //xMBUtilSetBits·½·¨ ÔÚ²Ù×÷λÊýÁ¿Îª0ʱ´æÔÚbug
{
xMBUtilSetBits(&ucSCoilBuf[iRegIndex++], iRegBitIndex, usNCoils,
*pucRegBuffer++);
}
break;
}
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
eMBErrorCode eStatus = MB_ENOERR;
int iRegIndex , iRegBitIndex , iNReg;
UCHAR * pucDiscreteInputBuf;
UCHAR DISCRETE_INPUT_START;
UCHAR DISCRETE_INPUT_NDISCRETES;
UCHAR usDiscreteInputStart;
iNReg = usNDiscrete / 8 + 1; //Õ¼ÓüĴæÆ÷ÊýÁ¿
pucDiscreteInputBuf = ucSDiscInBuf;
DISCRETE_INPUT_START = S_DISCRETE_INPUT_START;
DISCRETE_INPUT_NDISCRETES = S_DISCRETE_INPUT_NDISCRETES;
usDiscreteInputStart = usSDiscInStart;
pucDiscreteInputBuf[0]=0x07;
if( ( usAddress >= DISCRETE_INPUT_START )
&& ( usAddress + usNDiscrete <= DISCRETE_INPUT_START + DISCRETE_INPUT_NDISCRETES ) )
{
iRegIndex = ( int )( usAddress - usDiscreteInputStart ) / 8 ; //ÿ¸ö¼Ä´æÆ÷´æ8¸ö
iRegBitIndex = ( int )( usAddress - usDiscreteInputStart ) % 8 ; //Ïà¶ÔÓڼĴæÆ÷ÄÚ²¿µÄλµØÖ·
while( iNReg > 0 )
{
*pucRegBuffer++ = xMBUtilGetBits(&pucDiscreteInputBuf[iRegIndex++] , iRegBitIndex , 8);
iNReg --;
}
pucRegBuffer --;
usNDiscrete = usNDiscrete % 8; //ÓàϵÄÏßȦÊý
*pucRegBuffer = *pucRegBuffer <<(8 - usNDiscrete); //¸ßλ²¹Áã
*pucRegBuffer = *pucRegBuffer >>(8 - usNDiscrete);
}
else
{
eStatus = MB_ENOREG;
}
return eStatus;
}
13.在主函數裏初始化,然後使用輸入寄存器第一和第二個寄存器來測試
int main(void)
{
eMBInit(MB_RTU, 1, 1, 9600, MB_PAR_NONE);
eMBEnable();
test_data1.d=11;
while(1)
{
( void)eMBPoll();
test_data1.d =test_data1.d +0.001;
usSRegInBuf[0]=test_data1.value[3];
usSRegInBuf[0]=(usSRegInBuf[0]<<8)+test_data1.value[2];
usSRegInBuf[1]=test_data1.value[1];
usSRegInBuf[1]=(usSRegInBuf[1]<<8)+test_data1.value[0];
}
}
注意:TEST_DATA1是聯體數,不懂得可以百度
移植好的代碼鏈接:https://download.csdn.net/download/qq_22079023/10840362
我不知道怎麼直接把代碼放到這裏點擊就可以下載,有會的希望能告知一下!
如果對於freemodbus不瞭解的可以看看這個https://blog.csdn.net/liukais/article/details/73385328