本帖最后由 Alden 于 2023-3-16 10:39 编辑
#技术资源#
FreeModbus简介 FreeMODBUS是一个奥地利人写的Modbus协议。它是一个针对嵌入式应用的一个免费(自由)的通用MODBUS协议的移植。Modbus是一个工业制造环境中应用的一个通用协议。Modbus通信协议栈包括两层:Modbus应用层协议,该层定义了数据模式和功能;另外一层是网络层。 FreeModbus协议对硬件的需求非常少——基本上任何具有串行接口,并且有一些能够容纳modbus数据帧的RAM的微控制器都足够了。 接下来基于其他的移植教程,将Freemodbus移植到APM32F030中,软件库基于极海SDK 《APM32F0xx_SDK_v1.7》 Freemodbus的源码可以直接在其官网:freemodbus官网 下载从机代码。 所需的文件只用modbus文件夹和demo里面BARE文件夹里的port文件。 实际使用中还需要对源文件做许多细节修改,可以直接使用修改好了的modbus进行接口移植。 参考来源:STM32 移植FreeModbus详细过程 将modbus的相关文件添加进APM32F030的例程中,即可进行下一步移植工作。 modbus通讯只需要使用一个串口和一个定时器,相关接口函数分别在portserial.c和porttimer.c文件中。 首先是portserial.c中串口的相关配置。 需要配置串口的初始化、中断处理、字节收发等。 串口初始化: - void USART1_Config(uint16_t buad)
- {
- GPIO_Config_T gpioConfig;
- USART_Config_T usartConfigStruct;
- /* Enable GPIO clock */
- RCM_EnableAHBPeriphClock(MINI_COM1_TX_GPIO_CLK | MINI_COM2_TX_GPIO_CLK);
- /* Enable COM1 or COM2 clock */
- RCM_EnableAPB2PeriphClock(MINI_COM1_CLK);
- RCM_EnableAPB2PeriphClock(MINI_COM2_CLK);
- /* Connect PXx to USARTx_Tx */
- GPIO_ConfigPinAF(MINI_COM1_TX_GPIO_PORT, MINI_COM1_TX_SOURCE, MINI_COM1_TX_AF);
- /* Connect PXx to USARRX_Rx */
- GPIO_ConfigPinAF(MINI_COM1_RX_GPIO_PORT, MINI_COM1_RX_SOURCE, MINI_COM1_RX_AF);
- /* Configure USART Tx as alternate function push-pull */
- gpioConfig.mode = GPIO_MODE_AF;
- gpioConfig.pin = MINI_COM1_TX_PIN;
- gpioConfig.speed = GPIO_SPEED_50MHz;
- gpioConfig.outtype = GPIO_OUT_TYPE_PP;
- gpioConfig.pupd = GPIO_PUPD_PU;
- GPIO_Config(MINI_COM1_TX_GPIO_PORT, &gpioConfig);
- /* Configure USART Rx as input floating */
- gpioConfig.pin = MINI_COM1_RX_PIN;
- GPIO_Config(MINI_COM1_RX_GPIO_PORT, &gpioConfig);
- /* MINI_USARTs configured as follow: */
- /* BaudRate = 115200 baud */
- usartConfigStruct.baudRate = buad;
- /* Receive and transmit enabled */
- usartConfigStruct.mode = USART_MODE_TX_RX;
- /* Hardware flow control disabled (RTS and CTS signals) */
- usartConfigStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
- /* No parity */
- usartConfigStruct.parity = USART_PARITY_NONE;
- /* One Stop Bit */
- usartConfigStruct.stopBits = USART_STOP_BIT_1;
- /* Word Length = 8 Bits */
- usartConfigStruct.wordLength = USART_WORD_LEN_8B;
- /* USART_Config */
- USART_Config(MINI_COM1, &usartConfigStruct);
- /* Enable USART_Interrupt_RXBNEIE */
- // USART_EnableInterrupt(MINI_COM1, USART_INT_RXBNEIE);
- NVIC_EnableIRQRequest(MINI_COM1_IRQn, 2);
- /* Enable USART */
- USART_Enable(MINI_COM1);
- }
中断处理:- void USART1_IRQHandler(void)
- {
- //发生接收中断
- if(USART_ReadStatusFlag(MINI_COM1, USART_FLAG_RXBNE) == SET)
- {
- prvvUARTRxISR(); //串口接收中断调用函数
- //清除中断标志位
- USART_ClearStatusFlag(USART1, USART_FLAG_RXBNE);
- }
-
- if(USART_ReadStatusFlag(MINI_COM1, USART_FLAG_OVRE) == SET)
- {
- prvvUARTRxISR(); //串口发送中断调用函数
- USART_ClearStatusFlag(USART1, USART_FLAG_OVRE);
- }
-
- //发生完成中断
- if(USART_ReadStatusFlag(MINI_COM1, USART_FLAG_TXC) == SET)
- {
- prvvUARTTxReadyISR();
- //清除中断标志
- USART_ClearStatusFlag(USART1, USART_FLAG_TXC);
- }
- }
portserial.c文件的收发处理
- vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
- {
- /* If xRXEnable enable serial receive interrupts. If xTxENable enable
- * transmitter empty interrupts.
- */
- if(xRxEnable == TRUE)
- {
- //UART中断使能
- USART_EnableInterrupt(MINI_COM1, USART_INT_RXBNEIE);
- }
- else
- {
- //禁止接收和接收中断
- USART_DisableInterrupt(MINI_COM1, USART_INT_RXBNEIE);
- }
- //STM32串口发送中断使能
- if(xTxEnable == TRUE)
- {
- //使能发送中断
- USART_EnableInterrupt(MINI_COM1, USART_INT_TXCIE);
- }
- else
- {
- //禁止发送中断
- USART_DisableInterrupt(MINI_COM1, USART_INT_TXCIE);
- }
- }
- BOOL
- xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
- {
-
- USART1_Config((uint16_t)ulBaudRate);
-
- return TRUE;
- }
- 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_TxData(USART1, 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.
- */
- *pucByte = USART_RxData(USART1);
-
- return TRUE;
- }
porttimer.c文件中需要配置一个定时器,定时器时基为50us。
TMR14初始化:
- void APM_MINI_TMR14_Init(uint16_t period)
- {
- TMR_TimeBase_T timeBaseConfig;
- /* Enable Clock */
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
- RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR14);
- /* Set clockDivision = 1 */
- timeBaseConfig.clockDivision = TMR_CKD_DIV1;
- /* Up-counter */
- timeBaseConfig.counterMode = TMR_COUNTER_MODE_UP;
- /* Set divider = 2399.So TMR1 clock freq ~= 48/(2400) = 20kHZ */
- timeBaseConfig.div = (2400-1) ;
- /* Set counter = 0xffff */
- timeBaseConfig.period = period;
- /* Repetition counter = 0x0 */
- // timeBaseConfig.repetitionCounter = 0;
- TMR_ConfigTimeBase(TMR14, &timeBaseConfig);
- /* Enable update interrupt*/
- // TMR_EnableInterrupt(TMR14, TMR_INT_UPDATE);
- NVIC_EnableIRQRequest(TMR14_IRQn, 2);
- /* Enable TMR14 */
- TMR_Enable(TMR14);
- }
TMR14中断函数:
- void TMR14_IRQHandler(void)
- {
- if (TMR_ReadIntFlag(TMR14, TMR_INT_FLAG_UPDATE) != RESET)
- {
- prvvTIMERExpiredISR();
- TMR_ClearIntFlag(TMR14, TMR_INT_FLAG_UPDATE);
- }
- }
porttimer.c文件接口配置。
- BOOL
- xMBPortTimersInit( USHORT usTim1Timerout50us )
- {
- APM_MINI_TMR14_Init(usTim1Timerout50us);
-
- return TRUE;
- }
- void vMBPortTimersEnable( )
- {
- /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */
- TMR_ClearIntFlag(TMR14, TMR_INT_FLAG_UPDATE);
- TMR_EnableInterrupt(TMR14, TMR_INT_UPDATE);
- TMR_SetCounter(TMR14,0x0000);
- TMR_Enable(TMR14);
- }
- void vMBPortTimersDisable( )
- {
- /* Disable any pending timers. */
-
- TMR_ClearIntFlag(TMR14, TMR_INT_FLAG_UPDATE);
- TMR_DisableInterrupt(TMR14, TMR_INT_UPDATE);
- TMR_SetCounter(TMR14,0x0000);
- TMR_Disable(TMR14);
- }
然后再定义各个模拟寄存器的地址和大小,补全补全输入寄存器操作函数、保持寄存器操作函数、线圈操作函数、离散寄存器函数
详细见prot.c文件。
然后完善main函数即可。
|