#include "stm32f4xx.h"
#include "./usart/bsp_rs232_usart.h"
#include "./modbus/include/mb.h"
#include "./modbus/include/mbutils.h"
#include "./modbus/include/mbport.h"
#include "./usart/bsp_rs232_usart.h"
/* ----------------------- Defines ------------------------------------------*/
/*线圈状态寄存器*/
#define REG_COILS_START 0x0000
#define REG_COILS_SIZE 8
/*线圈状态输入寄存器*/
#define REG_DISCRETE_START 0x0000
#define REG_DISCRETE_SIZE 8
/*保持寄存器*/
#define REG_HOLDING_START 0x0000
#define REG_HOLDING_NREGS 8
/*输入寄存器*/
#define REG_INPUT_START 0x0000
#define REG_INPUT_NREGS 1
/* USER CODE END PV */
/* Private function prototypes ------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* USER CODE BEGIN 0 */
/*定义线圈状态寄存器的地址起始值和存储数组*/
uint8_t ucRegCoilsStart = REG_HOLDING_START;
uint8_t ucRegCoilsBuf[REG_COILS_SIZE / 8];
/*定义线圈输入状态寄存器的地址起始值和存储数组*/
uint8_t ucRegDiscreteStart = REG_HOLDING_START;
uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE / 8];
/*定义输入寄存器的地址起始值和存储数组*/
uint16_t usRegInputStart = REG_INPUT_START;
uint16_t usRegInputBuf[REG_INPUT_NREGS];
//保持寄存器起始地址
#define REG_HOLDING_START 0x0000
//保持寄存器数量
#define REG_HOLDING_NREGS 8
//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS]
= {0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
uint8_t Rxflag=0;
uint8_t ucTemp;
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
eMBErrorCode eStatus;
eStatus = eMBInit( MB_RTU, 0x01, 0X01, 115200, MB_PAR_NONE );
eMBInit( MB_RTU, 0x01,1, 115200, MB_PAR_NONE );
/* Enable the Modbus Protocol Stack. */
//eStatus = eMBEnable( );
eMBEnable( );
while(1)
{
eMBPoll( );
}
}
/**
* @brief 输入寄存器处理函数,输入寄存器可读,但不可写。
* @param pucRegBuffer 返回数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* @retval eStatus 寄存器状态
*/
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
eMBErrorCode eStatus = MB_ENOERR;
int16_t iRegIndex;
//查询是否在寄存器范围内
//为了避免警告,修改为有符号整数
if( ( (int16_t)usAddress >= REG_INPUT_START )
&& ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
{
//获得操作偏移量,本次操作起始地址-输入寄存器的初始地址
iRegIndex = ( int16_t )( usAddress - REG_INPUT_START );
//逐个赋值
while( usNRegs > 0 )
{
//赋值高字节
*pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] >> 8 );
//赋值低字节
*pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] & 0xFF );
//偏移量增加
iRegIndex++;
//被操作寄存器数量递减
usNRegs--;
}
}
else
{
//返回错误状态,无寄存器
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* @brief 保持寄存器处理函数,保持寄存器可读,可读可写
* @param pucRegBuffer 读操作时--返回数据指针,写操作时--输入数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* eMode 操作方式,读或者写
* @retval eStatus 寄存器状态
*/
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
eMBRegisterMode eMode )
{
//错误状态
eMBErrorCode eStatus = MB_ENOERR;
//偏移量
int16_t iRegIndex;
//判断寄存器是不是在范围内
if( ( (int16_t)usAddress >= REG_HOLDING_START )
&& ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
{
//计算偏移量
iRegIndex = ( int16_t )( usAddress - REG_HOLDING_START );
switch ( eMode )
{
//读处理函数
case MB_REG_READ:
while( usNRegs > 0 )
{
*pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 );
*pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF );
iRegIndex++;
usNRegs--;
}
break;
//写处理函数
case MB_REG_WRITE:
while( usNRegs > 0 )
{
usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
iRegIndex++;
usNRegs--;
}
break;
}
}
else
{
//返回错误状态
eStatus = MB_ENOREG;
}
return eStatus;
}
/**
* @brief 线圈寄存器处理函数,线圈寄存器可读,可读可写
* @param pucRegBuffer 读操作---返回数据指针,写操作--返回数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* eMode 操作方式,读或者写
* @retval eStatus 寄存器状态
*/
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
eMBRegisterMode eMode )
{
//错误状态
eMBErrorCode eStatus = MB_ENOERR;
//寄存器个数
int16_t iNCoils = ( int16_t )usNCoils;
//寄存器偏移量
int16_t usBitOffset;
//检查寄存器是否在指定范围内
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;
}
/**
* @brief 开关输入寄存器处理函数,开关输入寄存器,可读
* @param pucRegBuffer 读操作---返回数据指针,写操作--返回数据指针
* usAddress 寄存器起始地址
* usNRegs 寄存器长度
* eMode 操作方式,读或者写
* @retval eStatus 寄存器状态
*/
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
//错误状态
eMBErrorCode eStatus = MB_ENOERR;
//操作寄存器个数
int16_t iNDiscrete = ( int16_t )usNDiscrete;
//偏移量
uint16_t usBitOffset;
//判断寄存器时候再制定范围内
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;
}
/* USER CODE END 4 */
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d
", file, line) */
/* USER CODE END 6 */
}
下面是port timer.c
/* ----------------------- Platform includes --------------------------------*/
#include "./modbus/port.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "./modbus/include/mb.h"
#include "./modbus/include/mbport.h"
#include "stm32f4xx.h"
/* ----------------------- static functions ---------------------------------*/
void prvvTIMERExpiredISR( void );
/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{ //使用TIM4 180MHz
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
//
uint16_t PrescalerValue = 0;
//使能定时器4时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
/*
3.5个字符时间区分不同的帧,即接收到的两个字符之间时间间隔小于3.5个字符
时间时认为是同一个帧的,如果间隔大于3.5个字符时间则认为是不同帧的
在一般的串口通信中,发送1个字符需要:1位起始位,8位数据位,1位校验位(可无),
1位停止位,总共 1+8+1+1 = 11位,3.5个字符时间就是 3.5 * 11 = 38.5位,
假如波特率是9600,那么传输1位的时间是1000/9600 = 0.10416667(ms) ,
这样,3.5个字符时间就大约是 4 ms ,即定时器需要的中断时间
*/
// 这个就是预分频系数9000/180M = 0.00005,即每50us计数值加1
//50us x 100 = 5ms,即5ms中断一次
TIM_TimeBaseStructure.TIM_Period = (uint16_t) usTim1Timerout50us-1;
TIM_TimeBaseStructure.TIM_Prescaler =(9000 - 1);
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);
//预装载使能
TIM_ARRPreloadConfig(TIM4, ENABLE);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//定时器4中断优先级
NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//清除溢出中断标志位
TIM_ClearITPendingBit(TIM4,TIM_IT_Update);
//定时器4溢出中断关闭
TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE);
//定时器4禁能
TIM_Cmd(TIM4, DISABLE);
return TRUE;
}
void vMBPortTimersEnable( )
{
/* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);
//设定定时器4的初始值
TIM_SetCounter(TIM4,0);
//定时器4启动
TIM_Cmd(TIM4, ENABLE);
}
void vMBPortTimersDisable( )
{
/* Disable any pending timers. */
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
TIM_ITConfig(TIM4, TIM_IT_Update, DISABLE);
TIM_SetCounter(TIM4,0);
//关闭定时器4
TIM_Cmd(TIM4, DISABLE);
}
/* Create an ISR which is called whenever the timer has expired. This function
* must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that
* the timer has expired.
*/
void prvvTIMERExpiredISR( void )
{
( void )pxMBPortCBTimerExpired( );
}
下面是portserial.c
#include "./modbus/port.h"
#include "./usart/bsp_rs232_usart.h"
/* ----------------------- Modbus includes ----------------------------------*/
#include "./modbus/include/mb.h"
#include "./modbus/include/mbport.h"
/* ----------------------- static functions ---------------------------------*/
void prvvUARTTxReadyISR( void );
void prvvUARTRxISR( void );
/* ----------------------- Start implementation -----------------------------*/
/**
* @brief 串口初始化
* @param ucPORT 串口号
* ulBaudRate 波特率
* ucDataBits 数据位
* eParity 校验位
* @retval None
*/
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
(void)ucPORT; //不修改串口
(void)ucDataBits; //不修改数据位长度
(void)eParity; //不修改校验格式
/* 使能 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_Init(RS232_USART, &USART_InitStructure);
USART_Cmd(RS232_USART, ENABLE); //使能USART2
USART_ITConfig(RS232_USART,USART_IT_RXNE, ENABLE); /*配置串口接收中断*/
//=====================中断初始化======================================
//设置NVIC优先级分组为Group2:0-3抢占式优先级,0-3的响应式优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = RS232_USART_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
return TRUE;
}
/**
* @brief 控制接收和发送状态
* @param xRxEnable 接收使能、
* xTxEnable 发送使能
* @retval None
*/
void
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{
if(xRxEnable)
{
//使能接收和接收中断
USART_ITConfig(RS232_USART, USART_IT_RXNE, ENABLE);;
}
else
{
USART_ITConfig(RS232_USART, USART_IT_RXNE, DISABLE);
}
if(xTxEnable)
{
//使能发送完成中断
USART_ITConfig(RS232_USART, USART_IT_TXE, ENABLE);
}
else
{
//禁止发送完成中断
USART_ITConfig(RS232_USART, USART_IT_TXE, DISABLE);
}
/* If xRXEnable enable serial receive interrupts.
If xTxENable enable transmitter empty interrupts.
如果XRX启用启用串行接收中断。
如果XTX启用使发射器空中断。
*/
}
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.
在UART传输缓冲区中放置一个字节。
如果调用了pxMBFrameCBTransmitterEmpty(),则协议栈调用此函数*/
//发送数据
USART_SendData(RS232_USART, ucByte);
return TRUE;
}
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.
*返回UART接收缓冲区中的字节。此函数在调用pxMBFrameCBByteRecei.()之后由协议栈调用。
*/
*pucByte = USART_ReceiveData(RS232_USART);
return TRUE;
}
/* Create an interrupt handler for the transmit buffer empty interrupt
* (or an equivalent) for your target processor. This function should then
* call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that
* a new character can be sent. The protocol stack will then call
* xMBPortSerialPutByte( ) to send the character.
*为目标处理器的传输缓冲区空中断(或等效中断)创建一个中断处理程序。
*然后这个函数应该调用pxMBFrameCBTransmitterEmpty(),
*它告诉协议栈可以发送一个新字符。
*然后,协议栈将调用XMbPosialPutPoType()来发送字符。
*/
void prvvUARTTxReadyISR( void )
{
//mb.c eMBInit函数中
//pxMBFrameCBTransmitterEmpty = xMBRTUTransmitFSM
//发送状态机
pxMBFrameCBTransmitterEmpty( );
}
/* Create an interrupt handler for the receive interrupt for your target
* processor. This function should then call pxMBFrameCBByteReceived( ). The
* protocol stack will then call xMBPortSerialGetByte( ) to retrieve the
* character.
*/
/*FreeModbus协议栈通过串口中断接收一帧数据,用户需在串口接收中断中回调prvvUARTRxISR()函数;
prvvUARTRxISR()函数:*/
void prvvUARTRxISR( void )
{
//mb.c eMBInit函数中
//pxMBFrameCBByteReceived = xMBRTUReceiveFSM
//接收状态机
pxMBFrameCBByteReceived( );
}
void USART1_IRQHandler(void)
{
//发生接收中断
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
prvvUARTRxISR();
//清除中断标志位
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
}
//发生完成中断
if(USART_GetITStatus(USART1, USART_IT_TC) == SET)
{
prvvUARTTxReadyISR();
//清除中断标志
USART_ClearITPendingBit(USART1, USART_IT_TC);
}
}
freemodbus我是官网下载的 别的文件没有动 请问错误出在哪里了 感谢各位大佬给解答
一周热门 更多>