添加文件
- 獲取原始free modbus library(官網)
- 將...\freemodbus-v1.5.0\demo\BARE中的所有文件復制到...\freemodbus-v1.5.0\modbus中,修改demo.c文件名為user_mb_app.c
- 將...\freemodbus-v1.5.0\modbus中的所有.c文件全部添加到項目中
- 在項目路徑中添加所有.c、.h文件路徑
添加完成后項目結構圖:
移植修改
需要修改的文件:
- port.h:補全開關總中斷的宏定義、宏定義串口和定時器
#define ENTER_CRITICAL_SECTION( ) __set_PRIMASK(1); //關閉中斷 #define EXIT_CRITICAL_SECTION( ) __set_PRIMASK(0); //開啟中斷
- portserial.c:補全串口相關函數(串口中斷使能選擇、串口初始化、發送1字節、接收1字節、串口中斷服務函數)
- 注意事項:
- 使能中斷:發送中斷應使用TC而非TXE,否則可能會出現最后一個字節不能成功發送的情況。此外由於是用485發送,所以在使能中斷時,應同時轉換485收發轉換引腳。使能中斷前,應判斷對應的標志位是否為1,為1則清除該標志位。
- 串口初始化:初始化前用USART_DeInit重置寄存器;引腳初始化(GPIO)->串口初始化(USART)->中斷初始化(NVIC);參數中的ucPORT和eParity都應該忽略。
- 發送1字節:不用循環等待發送完成,因為已經有發送完成中斷了
- 串口中斷服務函數:在stm32f0xx_it.c中添加USART3_4_IRQHandler函數,跳轉到本文件中的prvvModbusUARTISR函數。
-
1 /* 2 * FreeModbus Libary: BARE Port 3 * Copyright (C) 2006 Christian Walter <wolti@sil.at> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * File: $Id: portserial.c,v 1.1 2006/08/22 21:35:13 wolti Exp $ 20 */ 21 22 #include "port.h" 23 24 /* ----------------------- Modbus includes ----------------------------------*/ 25 #include "mb.h" 26 #include "mbport.h" 27 28 /* ----------------------- static functions ---------------------------------*/ 29 static void prvvUARTTxReadyISR( void ); 30 static void prvvUARTRxISR( void ); 31 32 #define MODBUS_SEND() (GPIO_SetBits(MODBUS_USART_CTRL_PORT, MODBUS_USART_CTRL_PIN)) 33 #define MODBUS_RECIEVE() (GPIO_ResetBits(MODBUS_USART_CTRL_PORT, MODBUS_USART_CTRL_PIN)) 34 35 /* ----------------------- Start implementation -----------------------------*/ 36 void 37 vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ) 38 { 39 /* If xRXEnable enable serial receive interrupts. If xTxENable enable 40 * transmitter empty interrupts. 41 */ 42 if(xRxEnable==TRUE) { 43 MODBUS_RECIEVE(); 44 if(USART_GetFlagStatus(MODBUS_USART, USART_FLAG_RXNE) == SET) { 45 USART_ClearFlag(MODBUS_USART, USART_FLAG_RXNE); 46 } 47 USART_ITConfig(MODBUS_USART, USART_IT_RXNE, ENABLE); 48 } else if(xRxEnable == FALSE) { 49 MODBUS_SEND(); 50 USART_ITConfig(MODBUS_USART, USART_IT_RXNE, DISABLE); 51 } 52 53 if(xTxEnable==TRUE) { 54 MODBUS_SEND(); 55 if(USART_GetFlagStatus(MODBUS_USART, USART_FLAG_TC) == SET) { 56 USART_ClearFlag(MODBUS_USART, USART_FLAG_TC); 57 } 58 USART_ITConfig(MODBUS_USART, USART_IT_TC, ENABLE); 59 } else if(xTxEnable == FALSE) { 60 MODBUS_RECIEVE(); 61 USART_ITConfig(MODBUS_USART, USART_IT_TC, DISABLE); 62 } 63 } 64 65 BOOL 66 xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) 67 { 68 /*****************************引腳初始化*************************************/ 69 GPIO_InitTypeDef GPIO_InitStructure; 70 71 //時鍾使能 72 RCC_AHBPeriphClockCmd(MODBUS_USART_TX_CLK | MODBUS_USART_RX_CLK | MODBUS_USART_CTRL_CLK, ENABLE); 73 MODBUS_USART_CLK_INIT(MODBUS_USART_CLK, ENABLE); 74 75 //復用功能定義 76 GPIO_PinAFConfig(MODBUS_USART_TX_PORT, MODBUS_USART_TX_SOURCE, MODBUS_USART_TX_AF); 77 GPIO_PinAFConfig(MODBUS_USART_RX_PORT, MODBUS_USART_RX_SOURCE, MODBUS_USART_RX_AF); 78 79 //引腳功能定義 80 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; 81 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 82 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; 83 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_Level_3; //50MHz 84 85 //TX 86 GPIO_InitStructure.GPIO_Pin = MODBUS_USART_TX_PIN; 87 GPIO_Init(MODBUS_USART_TX_PORT, &GPIO_InitStructure); 88 89 //RX 90 GPIO_InitStructure.GPIO_Pin = MODBUS_USART_RX_PIN; 91 GPIO_Init(MODBUS_USART_RX_PORT, &GPIO_InitStructure); 92 93 //CTRL 94 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 95 GPIO_InitStructure.GPIO_Pin = MODBUS_USART_CTRL_PIN; 96 GPIO_Init(MODBUS_USART_CTRL_PORT, &GPIO_InitStructure); 97 MODBUS_RECIEVE(); //接收模式 98 99 /*****************************串口初始化*************************************/ 100 USART_InitTypeDef USART_InitStructure; 101 102 USART_InitStructure.USART_BaudRate = ulBaudRate; 103 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 104 USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; 105 USART_InitStructure.USART_Parity = USART_Parity_No; 106 USART_InitStructure.USART_StopBits = USART_StopBits_1; 107 USART_InitStructure.USART_WordLength = USART_WordLength_8b; 108 109 USART_Init(MODBUS_USART, &USART_InitStructure); 110 USART_Cmd(MODBUS_USART, ENABLE); 111 vMBPortSerialEnable(FALSE, FALSE); 112 113 /*****************************中斷初始化*************************************/ 114 NVIC_InitTypeDef NVIC_InitStructure; 115 116 NVIC_InitStructure.NVIC_IRQChannel = USART3_4_IRQn; 117 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 118 NVIC_InitStructure.NVIC_IRQChannelPriority = 1; 119 120 NVIC_Init(&NVIC_InitStructure); 121 122 return TRUE; 123 } 124 125 BOOL 126 xMBPortSerialPutByte( CHAR ucByte ) 127 { 128 /* Put a byte in the UARTs transmit buffer. This function is called 129 * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been 130 * called. */ 131 MODBUS_USART->TDR = ucByte; //此處不用等待發送完畢(TC),因為有發送完成中斷 132 return TRUE; 133 } 134 135 BOOL 136 xMBPortSerialGetByte( CHAR * pucByte ) 137 { 138 /* Return the byte in the UARTs receive buffer. This function is called 139 * by the protocol stack after pxMBFrameCBByteReceived( ) has been called. 140 */ 141 *pucByte = MODBUS_USART->RDR; 142 return TRUE; 143 } 144 145 /* Create an interrupt handler for the transmit buffer empty interrupt 146 * (or an equivalent) for your target processor. This function should then 147 * call pxMBFrameCBTransmitterEmpty( ) which tells the protocol stack that 148 * a new character can be sent. The protocol stack will then call 149 * xMBPortSerialPutByte( ) to send the character. 150 */ 151 static void prvvUARTTxReadyISR( void ) 152 { 153 pxMBFrameCBTransmitterEmpty( ); 154 } 155 156 /* Create an interrupt handler for the receive interrupt for your target 157 * processor. This function should then call pxMBFrameCBByteReceived( ). The 158 * protocol stack will then call xMBPortSerialGetByte( ) to retrieve the 159 * character. 160 */ 161 static void prvvUARTRxISR( void ) 162 { 163 pxMBFrameCBByteReceived( ); 164 } 165 166 void prvvModbusUARTISR( void ) 167 { 168 if(USART_GetITStatus(MODBUS_USART, USART_IT_TC) == SET) { 169 prvvUARTTxReadyISR(); 170 USART_ClearITPendingBit(MODBUS_USART, USART_IT_TC); 171 } 172 173 if(USART_GetITStatus(MODBUS_USART, USART_IT_RXNE) == SET) { 174 prvvUARTRxISR(); 175 USART_ClearITPendingBit(MODBUS_USART, USART_IT_RXNE); 176 } 177 }
- 注意事項:
- porttimer.c:補全定時器相關函數(定時器初始化、定時器使能、定時器關閉使能、定時器中斷服務函數)
- 注意事項:
- 初始化:初始化前應用TIM_DeInit函數重置寄存器值;初始化后要清標志位
- 定時器使能:要先關中斷、關定時器,然后清標志位、重置計數器,最后開中斷、開定時器
- 中斷服務函數:要先判斷中斷標志位,再清標志位、進入操作部分。
-
1 /* 2 * FreeModbus Libary: BARE Port 3 * Copyright (C) 2006 Christian Walter <wolti@sil.at> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2.1 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 * 19 * File: $Id: porttimer.c,v 1.1 2006/08/22 21:35:13 wolti Exp $ 20 */ 21 22 /* ----------------------- Platform includes --------------------------------*/ 23 #include "port.h" 24 25 /* ----------------------- Modbus includes ----------------------------------*/ 26 #include "mb.h" 27 #include "mbport.h" 28 29 /* ----------------------- static functions ---------------------------------*/ 30 static void prvvTIMERExpiredISR( void ); 31 32 /* ----------------------- Start implementation -----------------------------*/ 33 BOOL 34 xMBPortTimersInit( USHORT usTim1Timerout50us ) 35 { 36 /***************************定時器初始化*************************************/ 37 TIM_TimeBaseInitTypeDef TIM_InitStructure; 38 39 TIM_DeInit(MODBUS_TIM); 40 MODBUS_TIM_CLK_INIT(MODBUS_TIM_CLK, ENABLE); 41 TIM_InitStructure.TIM_ClockDivision = TIM_CKD_DIV1; 42 TIM_InitStructure.TIM_CounterMode = TIM_CounterMode_Up; 43 TIM_InitStructure.TIM_Period = usTim1Timerout50us - 1; 44 TIM_InitStructure.TIM_Prescaler = 2400 - 1; //48MHz/20kHz=2400 45 TIM_InitStructure.TIM_RepetitionCounter = 0; 46 47 TIM_TimeBaseInit(MODBUS_TIM, &TIM_InitStructure); 48 TIM_ClearFlag(MODBUS_TIM, TIM_FLAG_Update); 49 TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, ENABLE); 50 TIM_Cmd(MODBUS_TIM, DISABLE); 51 52 /*****************************中斷初始化*************************************/ 53 NVIC_InitTypeDef NVIC_InitStructure; 54 55 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; 56 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 57 NVIC_InitStructure.NVIC_IRQChannelPriority = 0; 58 59 NVIC_Init(&NVIC_InitStructure); 60 61 return TRUE; 62 } 63 64 65 inline void 66 vMBPortTimersEnable( ) 67 { 68 /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */ 69 TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, DISABLE); 70 TIM_Cmd(MODBUS_TIM, DISABLE); 71 TIM_ClearITPendingBit(MODBUS_TIM, TIM_IT_Update); 72 TIM_ClearFlag(MODBUS_TIM, TIM_FLAG_Update); 73 TIM_SetCounter(MODBUS_TIM, 0); 74 TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, ENABLE); 75 TIM_Cmd(MODBUS_TIM, ENABLE); 76 } 77 78 inline void 79 vMBPortTimersDisable( ) 80 { 81 /* Disable any pending timers. */ 82 TIM_ITConfig(MODBUS_TIM, TIM_IT_Update, DISABLE); 83 TIM_Cmd(MODBUS_TIM, DISABLE); 84 } 85 86 /* Create an ISR which is called whenever the timer has expired. This function 87 * must then call pxMBPortCBTimerExpired( ) to notify the protocol stack that 88 * the timer has expired. 89 */ 90 static void prvvTIMERExpiredISR( void ) 91 { 92 ( void )pxMBPortCBTimerExpired( ); 93 } 94 95 void prvvModbusTIMISR( void ) 96 { 97 if(TIM_GetITStatus(MODBUS_TIM, TIM_IT_Update) == SET) { 98 TIM_ClearITPendingBit(MODBUS_TIM, TIM_IT_Update); 99 prvvTIMERExpiredISR(); 100 } 101 }
- 注意事項:
- user_mb_app.h:定義各模擬寄存器地址
- 注意事項:
- 每個寄存器固定長度16位(2字節)
- 寄存器地址:從機內部定義的寄存器地址,要對尋址用的寄存器地址+1【Modbus標准協議規定】。即:從機內部定義的寄存器地址,必須大於1;對於寄存器1-16,尋址時通過0-15來尋址(如:查詢寄存器1的值時,指令中的寄存器地址為00 00)。
- 換句話說,就是:從機程序中定義寄存器地址為1-16時,文檔中的寄存器地址要寫成0-15。
- 注意事項:
- user_mb_app.c:補全輸入寄存器操作函數、保持寄存器操作函數(操作方式可參見...\freemodbus-v1.5.0\demo\ATSAM3S\demo.c),將main分解為modbus初始化函數和modbus進程函數,添加結構體與模擬寄存器之間的數據交互函數。
- 注意事項:
- eMBInit初始化:僅需更改地址和波特率。
- user_mb_app函數中不要用循環(本身就會被應用到主程序中的while(1)中)
-
1 /* ----------------------- Modbus includes ----------------------------------*/ 2 #include "mb.h" 3 #include "mbport.h" 4 #include "user_mb_app.h" 5 6 /* ----------------------- Defines ------------------------------------------*/ 7 #define REG_INPUT_START ((uint16_t)0x0000) 8 #define REG_INPUT_NREGS 25 9 #define REG_HOLD_START ((uint16_t)0x0000) 10 #define REG_HOLD_NREGS 30 11 12 /* ----------------------- Static variables ---------------------------------*/ 13 static USHORT usRegInputStart = REG_INPUT_START; 14 static USHORT usRegInputBuf[REG_INPUT_NREGS]; 15 static USHORT usRegHoldStart = REG_HOLD_START; 16 static USHORT usRegHoldBuf[REG_HOLD_NREGS]; 17 extern uint8_t g_Meter_Data[]; 18 extern uint8_t g_Check_Data[]; 19 /* ----------------------- Start implementation -----------------------------*/ 20 /****************************************************************************** 21 ** 函數名稱: mb_Modbus_Init 22 ** 功能描述: modbus初始化 23 ** 入口參數: 無 24 ** 返 回 值: 無 25 ** 26 ** 作 者: Cage 27 ** 日 期: 2018年3月9日 28 **----------------------------------------------------------------------------- 29 ******************************************************************************/ 30 void mb_Modbus_Init(void) { 31 32 uint8_t address = dio_Get_DIP_Value(); //獲取撥碼開關信息,獲得本機地址 33 ( void )eMBInit( MB_RTU, address, 0, 9600, MB_PAR_NONE ); 34 35 /* Enable the Modbus Protocol Stack. */ 36 ( void )eMBEnable( ); 37 } 38 39 40 /****************************************************************************** 41 ** 函數名稱: user_mb_app 42 ** 功能描述: modbus進程函數 43 ** 入口參數: 無 44 ** 返 回 值: 無 45 ** 46 ** 作 者: Cage 47 ** 日 期: 2018年3月13日 48 **----------------------------------------------------------------------------- 49 ******************************************************************************/ 50 void user_mb_app( void ) 51 { 52 53 ( void )eMBPoll( ); 54 55 } 56 57 58 /****************************************************************************** 59 ** 函數名稱: _mb_Fresh_Input_Reg 60 ** 功能描述: 將計量數據結構體中的數據刷新到Modbus模擬寄存器中 61 ** 入口參數: 無 62 ** 返 回 值: 無 63 ** 64 ** 作 者: Cage 65 ** 日 期: 2018年3月13日 66 **----------------------------------------------------------------------------- 67 ******************************************************************************/ 68 static void _mb_Fresh_Input_Reg(void) { 69 uint8_t i; 70 USHORT *pmeter_data = (USHORT*)g_Meter_Data; 71 for(i = 0; i<REG_INPUT_NREGS; i++) { 72 usRegInputBuf[i] = *pmeter_data++; 73 } 74 } 75 76 77 /****************************************************************************** 78 ** 函數名稱: _mb_Fresh_Check_Struct 79 ** 功能描述: 將Modbus模擬寄存器中的數據刷新到校表數據結構體 80 ** 入口參數: 無 81 ** 返 回 值: 無 82 ** 83 ** 作 者: Cage 84 ** 日 期: 2018年3月13日 85 **----------------------------------------------------------------------------- 86 ******************************************************************************/ 87 static void _mb_Fresh_Check_Struct(void) { 88 uint8_t i; 89 USHORT *pcheck_data = (USHORT*)g_Check_Data; 90 for(i = 0; i<REG_HOLD_NREGS; i++) { 91 *pcheck_data++ = usRegHoldBuf[i]; 92 } 93 } 94 95 96 //讀輸入寄存器 97 eMBErrorCode 98 eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs ) 99 { 100 eMBErrorCode eStatus = MB_ENOERR; 101 int iRegIndex; 102 103 if( ( usAddress >= REG_INPUT_START ) 104 && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) ) 105 { 106 _mb_Fresh_Input_Reg(); //將計量數據結構體中的數據刷新到Modbus模擬寄存器中 107 iRegIndex = ( int )( usAddress - usRegInputStart ); 108 while( usNRegs > 0 ) 109 { 110 *pucRegBuffer++ = 111 ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 ); 112 *pucRegBuffer++ = 113 ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF ); 114 iRegIndex++; 115 usNRegs--; 116 } 117 } 118 else 119 { 120 eStatus = MB_ENOREG; 121 } 122 123 return eStatus; 124 } 125 126 //寫保持寄存器--未定義 127 eMBErrorCode 128 eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, 129 eMBRegisterMode eMode ) 130 { 131 eMBErrorCode eStatus = MB_ENOERR; 132 int iRegIndex; 133 134 if( ( usAddress >= REG_HOLD_START ) 135 && ( usAddress + usNRegs <= REG_HOLD_START + REG_HOLD_NREGS ) ) 136 { 137 iRegIndex = ( int )( usAddress - usRegHoldStart ); 138 if(eMode == MB_REG_WRITE) { 139 while( usNRegs > 0 ) 140 { 141 usRegHoldBuf[iRegIndex] = *pucRegBuffer++ << 8; 142 usRegHoldBuf[iRegIndex] |= *pucRegBuffer++; 143 iRegIndex++; 144 usNRegs--; 145 } 146 } 147 _mb_Fresh_Check_Struct(); //將Modbus模擬寄存器中的數據刷新到校表數據結構體 148 } 149 else 150 { 151 eStatus = MB_ENOREG; 152 } 153 154 return eStatus; 155 } 156 157 /*********************************不使用的功能*********************************/ 158 eMBErrorCode 159 eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, 160 eMBRegisterMode eMode ) 161 { 162 return MB_ENOREG; 163 } 164 165 eMBErrorCode 166 eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete ) 167 { 168 return MB_ENOREG; 169 }
- mb.c:在eMBPoll函數中,EV_EXECUTE狀態下,准備好發送后,手動發送第一個字節,啟動發送
-
1 case EV_EXECUTE: 2 ucFunctionCode = ucMBFrame[MB_PDU_FUNC_OFF]; 3 eException = MB_EX_ILLEGAL_FUNCTION; 4 for( i = 0; i < MB_FUNC_HANDLERS_MAX; i++ ) 5 { 6 /* No more function handlers registered. Abort. */ 7 if( xFuncHandlers[i].ucFunctionCode == 0 ) 8 { 9 break; 10 } 11 else if( xFuncHandlers[i].ucFunctionCode == ucFunctionCode ) 12 { 13 eException = xFuncHandlers[i].pxHandler( ucMBFrame, &usLength ); 14 break; 15 } 16 } 17 18 /* If the request was not sent to the broadcast address we 19 * return a reply. */ 20 if( ucRcvAddress != MB_ADDRESS_BROADCAST ) 21 { 22 if( eException != MB_EX_NONE ) 23 { 24 /* An exception occured. Build an error frame. */ 25 usLength = 0; 26 ucMBFrame[usLength++] = ( UCHAR )( ucFunctionCode | MB_FUNC_ERROR ); 27 ucMBFrame[usLength++] = eException; 28 } 29 if( ( eMBCurrentMode == MB_ASCII ) && MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS ) 30 { 31 vMBPortTimersDelay( MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS ); 32 } 33 eStatus = peMBFrameSendCur( ucMBAddress, ucMBFrame, usLength ); 34 /*發送數組准備完畢,串口切換到了發送狀態,但TC標志位為0,不能自動開始發送*/ 35 if( eStatus == MB_ENOERR ) 36 { 37 xMBRTUTransmitFSM(); //發送第一個字節,啟動發送 38 } 39 } 40 break;
-
調試
- 串口收到數據后,無限進入中斷
- 現象:仿真時,一直進入中斷服務函數,不作任何處理后跳出;如此反復進入中斷服務函數。
- 判斷:ORE標志位未清除。RXNEIE中斷使能包括RXNE標志位和ORE標志位,中斷服務函數中只判斷、處理了RXNE標志位。
- 處理:在portserial.c的中斷服務函數prvvModbusUARTISR中,加入USART_IT_ORE標志位的判斷與處理【注:stm32f072庫函數中的USART_IT_ORE標志位定義錯誤,需要修改】
- 結果:問題解決
- Modbus收到數據后不響應
- 現象:跟蹤發現,Modbus協議一直進行到“串口發送”之前都是正常的,可是之后卻沒有發送
- 原因:上一次發送最后一個字節時,發送中斷中清除了TC標志位;切換到發送狀態、使能TCIE后,TC標志位為0,無法啟動發送。
- 解決方案:
- TXE+TC發送:
- 中斷使能函數:切換為發送狀態時,使能TXE中斷而非TC中斷(由TXE啟動發送,TXE永不手動清零)
- 中斷服務函數:TXE啟動發送后,將中斷使能由TXE改為TC,之后由TC判斷發送完成、清TC標志位
- 手動啟動:切換為發送狀態后,手動啟動發送(發送第一個字節)
- TXE+TC發送:
- 處理:選擇了方案2,問題解決。
仿真跟蹤--Modbus數據處理流程(RTU)
- modbus poll主進程(eMBPoll)獲取消息狀態,執行指令
- 數據接收:串口中斷接收數據(數據存入ucRTUBuf數組)->超過3.5us沒有收到數據->判斷一串數據接收完畢->將“接收完畢”消息添加到消息隊列
- 數據處理:
- eMBPoll獲取到“接收完畢”消息,令ucMBFrame指針指向ucRTUBuf數組的第1位(命令字),獲取地址位和數據長度(不含地址位和校驗位的長度),將“執行”消息添加到消息隊列
- eMBPoll獲取到“執行”消息,通過ucMBFrame中的命令字,進行對應的操作(比如:04--讀輸入寄存器),將要發回的數據存入ucMBFrame(不含地址位和校驗位)
- 將ucMBFrame中的數據加上地址位后計算校驗位,將地址位和校驗位存入ucRTUBuf數組,將發送狀態標志由空閑轉為發送,串口狀態轉為發送
- --至此發送數組(ucRTUBuf)和串口狀態都已經准備完畢,但沒有發送指令
- 【添加】手動發送發送數組的第一個字節,啟動發送
- 數據發送:通過串口將發送數組逐字節發送。