[APM32F0] APM32F030移植freemodbus

[复制链接]
1766|8
 楼主| Alden 发表于 2023-3-16 10:39 | 显示全部楼层 |阅读模式
本帖最后由 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官网 下载从机代码。
2e778cfebd41a25635978cc04816b57.png
933c2ea621f9609937cb0ea90e5e25e.png
所需的文件只用modbus文件夹和demo里面BARE文件夹里的port文件。
实际使用中还需要对源文件做许多细节修改,可以直接使用修改好了的modbus进行接口移植。
参考来源:STM32 移植FreeModbus详细过程
将modbus的相关文件添加进APM32F030的例程中,即可进行下一步移植工作。
modbus通讯只需要使用一个串口和一个定时器,相关接口函数分别在portserial.c和porttimer.c文件中。
首先是portserial.c中串口的相关配置。
需要配置串口的初始化、中断处理、字节收发等。
串口初始化:
  1. void USART1_Config(uint16_t buad)
  2. {
  3.    GPIO_Config_T gpioConfig;
  4.     USART_Config_T usartConfigStruct;

  5.     /* Enable GPIO clock */
  6.     RCM_EnableAHBPeriphClock(MINI_COM1_TX_GPIO_CLK  | MINI_COM2_TX_GPIO_CLK);

  7.     /* Enable COM1 or COM2 clock */
  8.     RCM_EnableAPB2PeriphClock(MINI_COM1_CLK);
  9.     RCM_EnableAPB2PeriphClock(MINI_COM2_CLK);

  10.     /* Connect PXx to USARTx_Tx */
  11.     GPIO_ConfigPinAF(MINI_COM1_TX_GPIO_PORT, MINI_COM1_TX_SOURCE, MINI_COM1_TX_AF);

  12.     /* Connect PXx to USARRX_Rx */
  13.     GPIO_ConfigPinAF(MINI_COM1_RX_GPIO_PORT, MINI_COM1_RX_SOURCE, MINI_COM1_RX_AF);

  14.     /* Configure USART Tx as alternate function push-pull */
  15.     gpioConfig.mode = GPIO_MODE_AF;
  16.     gpioConfig.pin = MINI_COM1_TX_PIN;
  17.     gpioConfig.speed = GPIO_SPEED_50MHz;
  18.     gpioConfig.outtype = GPIO_OUT_TYPE_PP;
  19.     gpioConfig.pupd = GPIO_PUPD_PU;
  20.     GPIO_Config(MINI_COM1_TX_GPIO_PORT, &gpioConfig);

  21.     /* Configure USART Rx as input floating */
  22.     gpioConfig.pin  = MINI_COM1_RX_PIN;
  23.     GPIO_Config(MINI_COM1_RX_GPIO_PORT, &gpioConfig);

  24.     /* MINI_USARTs configured as follow: */
  25.     /* BaudRate = 115200 baud */
  26.     usartConfigStruct.baudRate = buad;
  27.     /* Receive and transmit enabled */
  28.     usartConfigStruct.mode     = USART_MODE_TX_RX;
  29.     /* Hardware flow control disabled (RTS and CTS signals) */
  30.     usartConfigStruct.hardwareFlowCtrl = USART_FLOW_CTRL_NONE;
  31.     /* No parity */
  32.     usartConfigStruct.parity   = USART_PARITY_NONE;
  33.     /* One Stop Bit */
  34.     usartConfigStruct.stopBits =  USART_STOP_BIT_1;
  35.     /* Word Length = 8 Bits */
  36.     usartConfigStruct.wordLength = USART_WORD_LEN_8B;
  37.     /* USART_Config */
  38.     USART_Config(MINI_COM1, &usartConfigStruct);

  39.     /* Enable USART_Interrupt_RXBNEIE */
  40. //  USART_EnableInterrupt(MINI_COM1, USART_INT_RXBNEIE);

  41.     NVIC_EnableIRQRequest(MINI_COM1_IRQn, 2);

  42.     /* Enable USART */
  43.     USART_Enable(MINI_COM1);

  44. }
中断处理:
  1. void USART1_IRQHandler(void)
  2. {
  3.   //发生接收中断
  4.   if(USART_ReadStatusFlag(MINI_COM1, USART_FLAG_RXBNE) == SET)
  5.   {

  6.     prvvUARTRxISR(); //串口接收中断调用函数
  7.     //清除中断标志位   
  8.     USART_ClearStatusFlag(USART1, USART_FLAG_RXBNE);   
  9.   }
  10.         
  11.         if(USART_ReadStatusFlag(MINI_COM1, USART_FLAG_OVRE) == SET)
  12.   {  
  13.                                 prvvUARTRxISR();         //串口发送中断调用函数
  14.      USART_ClearStatusFlag(USART1, USART_FLAG_OVRE);

  15.   }
  16.   
  17.   //发生完成中断
  18.   if(USART_ReadStatusFlag(MINI_COM1, USART_FLAG_TXC)  == SET)
  19.   {
  20.     prvvUARTTxReadyISR();
  21.     //清除中断标志
  22.     USART_ClearStatusFlag(USART1, USART_FLAG_TXC);
  23.   }
  24. }
portserial.c文件的收发处理
  1. vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
  2. {
  3.     /* If xRXEnable enable serial receive interrupts. If xTxENable enable
  4.      * transmitter empty interrupts.
  5.      */
  6.         if(xRxEnable == TRUE)
  7.         {
  8.                 //UART中断使能
  9.                 USART_EnableInterrupt(MINI_COM1, USART_INT_RXBNEIE);
  10.         }
  11.         else
  12.         {
  13.           //禁止接收和接收中断
  14.                 USART_DisableInterrupt(MINI_COM1, USART_INT_RXBNEIE);
  15.         }
  16.   //STM32串口发送中断使能
  17.         if(xTxEnable == TRUE)
  18.         {
  19.           //使能发送中断
  20.                 USART_EnableInterrupt(MINI_COM1, USART_INT_TXCIE);
  21.         }
  22.         else
  23.         {
  24.     //禁止发送中断
  25.                 USART_DisableInterrupt(MINI_COM1, USART_INT_TXCIE);
  26.         }
  27. }

  28. BOOL
  29. xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
  30. {
  31.         
  32.   USART1_Config((uint16_t)ulBaudRate);  
  33.         
  34.         return TRUE;
  35. }

  36. BOOL
  37. xMBPortSerialPutByte( CHAR ucByte )
  38. {
  39.     /* Put a byte in the UARTs transmit buffer. This function is called
  40.      * by the protocol stack if pxMBFrameCBTransmitterEmpty( ) has been
  41.      * called. */
  42.         USART_TxData(USART1, ucByte); //发送一个字节
  43.         
  44.         return TRUE;
  45. }

  46. BOOL
  47. xMBPortSerialGetByte( CHAR * pucByte )
  48. {
  49.     /* Return the byte in the UARTs receive buffer. This function is called
  50.      * by the protocol stack after pxMBFrameCBByteReceived( ) has been called.
  51.      */
  52.   *pucByte = USART_RxData(USART1);
  53.         
  54.         return TRUE;
  55. }
porttimer.c文件中需要配置一个定时器,定时器时基为50us。
TMR14初始化:
  1. void APM_MINI_TMR14_Init(uint16_t period)
  2. {
  3.     TMR_TimeBase_T  timeBaseConfig;

  4.     /* Enable Clock */
  5.     RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
  6.     RCM_EnableAPB1PeriphClock(RCM_APB1_PERIPH_TMR14);

  7.     /* Set clockDivision = 1 */
  8.     timeBaseConfig.clockDivision =  TMR_CKD_DIV1;
  9.     /* Up-counter */
  10.     timeBaseConfig.counterMode =  TMR_COUNTER_MODE_UP;
  11.     /* Set divider = 2399.So TMR1 clock freq ~= 48/(2400) = 20kHZ */
  12.     timeBaseConfig.div = (2400-1) ;
  13.     /* Set counter = 0xffff */
  14.     timeBaseConfig.period = period;
  15.     /* Repetition counter = 0x0 */
  16.    // timeBaseConfig.repetitionCounter =  0;

  17.     TMR_ConfigTimeBase(TMR14, &timeBaseConfig);

  18.     /* Enable update interrupt*/
  19.   //  TMR_EnableInterrupt(TMR14, TMR_INT_UPDATE);
  20.     NVIC_EnableIRQRequest(TMR14_IRQn, 2);

  21.     /*  Enable TMR14  */
  22.     TMR_Enable(TMR14);
  23. }
TMR14中断函数:
  1. void TMR14_IRQHandler(void)
  2. {
  3.             if (TMR_ReadIntFlag(TMR14, TMR_INT_FLAG_UPDATE)  != RESET)
  4.     {
  5.                                 prvvTIMERExpiredISR();
  6.              TMR_ClearIntFlag(TMR14, TMR_INT_FLAG_UPDATE);
  7.                 }
  8. }
porttimer.c文件接口配置。
  1. BOOL
  2. xMBPortTimersInit( USHORT usTim1Timerout50us )
  3. {
  4.   APM_MINI_TMR14_Init(usTim1Timerout50us);
  5.         
  6.         return TRUE;
  7. }


  8. void vMBPortTimersEnable(  )
  9. {
  10.     /* Enable the timer with the timeout passed to xMBPortTimersInit( ) */        
  11.            TMR_ClearIntFlag(TMR14, TMR_INT_FLAG_UPDATE);
  12.            TMR_EnableInterrupt(TMR14, TMR_INT_UPDATE);
  13.      TMR_SetCounter(TMR14,0x0000);
  14.            TMR_Enable(TMR14);
  15. }

  16. void vMBPortTimersDisable(  )
  17. {
  18.     /* Disable any pending timers. */
  19.         
  20.                  TMR_ClearIntFlag(TMR14, TMR_INT_FLAG_UPDATE);
  21.            TMR_DisableInterrupt(TMR14, TMR_INT_UPDATE);
  22.      TMR_SetCounter(TMR14,0x0000);
  23.            TMR_Disable(TMR14);
  24. }
然后再定义各个模拟寄存器的地址和大小,补全补全输入寄存器操作函数、保持寄存器操作函数、线圈操作函数、离散寄存器函数
详细见prot.c文件。
然后完善main函数即可。
  1. int main(void)
  2. {


  3.         eMBInit(MB_RTU, 0x01, 1, 9600, MB_PAR_NONE);  //初始化FreeModbus
  4.         eMBEnable();  //启动FreeModbus
  5.         while(1)
  6.         {
  7.                 (void)eMBPoll();  //查询数据帧
  8.         }
  9. }
程序移植完成后即可使用modbus工具测试,配置ModbusRTU的校验方式。
eadeefd1df22f3481ec6b2dad492cc1.png

然后就可以设置发送01 04 00 00 00 01,就会自动计算校验值发送出去,得到MCU回传的结果。 f8b745d486cd263011507d845717a68.png

APM32F0xx_SDK_v1.7-Freemodbus.zip (1.45 MB, 下载次数: 27) crc计算助手.zip (320.1 KB, 下载次数: 15) freemodbus-master1.6.zip (4.24 MB, 下载次数: 24)






tpgf 发表于 2023-4-10 14:30 | 显示全部楼层
FreeMODBUS 提供了RTU/ASCII 传输模式及TCP协议支持
nawu 发表于 2023-4-10 15:05 | 显示全部楼层
FreeModbus协议对硬件的需求非常少--基本上任何具有串行接口,并且有一些能够容纳modbus数据帧的RAM的微控制器都足够了。
aoyi 发表于 2023-4-10 15:27 | 显示全部楼层
实际的存储器需求决定于所使用的Modbus模块的多少
zljiu 发表于 2023-4-10 15:54 | 显示全部楼层
FreeModbus是基于消息队列的协议。协议通过检测相应的消息来完成对应功能
gwsan 发表于 2023-4-10 16:21 | 显示全部楼层
对于FreeModbus的软件部分,仅仅需要一个简单的事件队列
tfqi 发表于 2023-4-10 16:31 | 显示全部楼层
硬件上需要一个异步串行接口,能够支持接收缓冲区满和发送缓存区空中断
chenjun89 发表于 2023-4-10 19:44 来自手机 | 显示全部楼层
和标准modbus相比,有什么优势呢?
99288697 发表于 2024-10-28 07:52 来自手机 | 显示全部楼层
航顺的F030能移植吗?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

49

主题

116

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部