#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我是官网下载的 别的文件没有动 请问错误出在哪里了 感谢各位大佬给解答
一周热门 更多>