[活动专区] 【AT-START-F407测评】+MODBUS测试

[复制链接]
 楼主| aple0807 发表于 2021-1-25 19:58 | 显示全部楼层 |阅读模式
本帖最后由 aple0807 于 2021-1-25 20:23 编辑

今天测试下工作中最常用的通信协议-modbus。

管脚配置:
  1. static gpio_init_cfg_type gpio_cfg[] =
  2. {
  3.     //UART1
  4.     {GPIOA, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_9},  //u1-TX
  5.     {GPIOA, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_10},  //u1-RX
  6.     //ADC
  7.     {GPIOA, GPIO_Mode_IN_ANALOG, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_0},  //ADC
  8.     //LED
  9.     {GPIOD, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_13 | GPIO_Pins_14 | GPIO_Pins_15}, //LED
  10.     {GPIOD, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0,  GPIO_Pins_15}, //LED-PWM
  11.     //UART8
  12.     {GPIOE, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_1},  //u8-TX
  13.     {GPIOE, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_0},  //u8-RX
  14.     //UART6
  15.     {GPIOC, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_6},  //u6-TX
  16.     {GPIOC, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_7},  //u6-RX
  17.     //SPI1
  18.     {GPIOA, GPIO_Mode_AF_PP, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_5 | GPIO_Pins_7},  //SPI1-SCK MOSI
  19.     {GPIOA, GPIO_Mode_IN_PU, GPIO_MaxSpeed_50MHz, 0, GPIO_Pins_6},  //SPI1-MISO
  20.     {GPIOA, GPIO_Mode_OUT_PP, GPIO_MaxSpeed_50MHz, 1, GPIO_Pins_15},  //SPI1-SS
  21. };

  22.     for(index=0; index < sizeof(gpio_cfg)/sizeof(gpio_init_cfg_type);index++)
  23.     {
  24.         GPIO_InitType GPIO_InitStructure;
  25.         
  26.         GPIO_InitStructure.GPIO_Mode = gpio_cfg[index].mode;
  27.         GPIO_InitStructure.GPIO_MaxSpeed = gpio_cfg[index].speed;
  28.         GPIO_InitStructure.GPIO_Pins = gpio_cfg[index].pin;
  29.         GPIO_Init(gpio_cfg[index].port, &GPIO_InitStructure);
  30.         
  31.         if((gpio_cfg[index].mode == GPIO_Mode_OUT_OD) || (gpio_cfg[index].mode == GPIO_Mode_OUT_PP))
  32.         {
  33.             if(gpio_cfg[index].val_init)
  34.             {
  35.                 GPIO_SetBits(gpio_cfg[index].port, gpio_cfg[index].pin);
  36.             }
  37.             else
  38.             {
  39.                 GPIO_ResetBits(gpio_cfg[index].port, gpio_cfg[index].pin);
  40.             }
  41.         }
  42.     }
      
测试开通两个通道,一路主机-UART6,一路从机-UART8。
协议解析用现成的库,只需要编写底层数据收发文件。
  1. #include "sys_ext.h"
  2. #include "os_obj.h"
  3. #include "mbapp.h"

  4. #define mbPORT                       USART6
  5. #define mbURT_IRQn                   USART6_IRQn
  6. #define mbISR                        USART6_IRQHandler
  7. #define RCU_USART                    RCC_APB2PERIPH_USART6
  8. #define RCU_USARTRST                 RCC_APB2PERIPH_USART6
  9. #define mbObj                        mb.obj06
  10. #define mbCmdBuff                    mb.CmdBuff06

  11. static volatile uint8_t alDir;

  12. //RS485 Dir-Pin
  13. #define mbRxEnable()  
  14. #define mbTxEnable()  

  15. static void mbswTimerEnable(void);

  16. static void mbEnable(uint8_t xRxEnable, uint8_t xTxEnable);
  17. static void mbDataSend(void);

  18. #include "mb_fun.h"

  19. /*****************************************************************************//*!
  20. *
  21. * [url=home.php?mod=space&uid=247401]@brief[/url]   port.
  22. * [url=home.php?mod=space&uid=72445]@[/url] Pass/ Fail criteria: none
  23. *****************************************************************************/
  24. static void mb_port_pin_cfg(void)
  25. {
  26.     intx_disable();

  27.     RCC_APB2PeriphClockCmd(RCU_USART, ENABLE);
  28.     RCC_APB2PeriphResetCmd(RCU_USARTRST, ENABLE);
  29.     RCC_APB2PeriphResetCmd(RCU_USARTRST, DISABLE);

  30.     intx_enable();
  31. }

  32. /*****************************************************************************//*!
  33. *
  34. * [url=home.php?mod=space&uid=247401]@brief[/url]   RTU timer enable.
  35. * [url=home.php?mod=space&uid=72445]@[/url] Pass/ Fail criteria: none
  36. *****************************************************************************/
  37. __STATIC_INLINE void mbswTimerEnable(void)
  38. {
  39.     mbObj.bRtuTimerOn = 1;
  40.     mbObj.RtuTimerCnt = 0;
  41. }

  42. /*****************************************************************************//*!
  43. * @brief UART0 RX interrupt routine.
  44. * @brief   Uart interrupt.
  45. *
  46. * @ Pass/ Fail criteria: none
  47. *****************************************************************************/

  48. void mbISR()
  49. {
  50.     volatile uint32_t IntSt;
  51.     volatile uint8_t Data;

  52.     mbObj.TimeOutCnt = 0;

  53.     IntSt = mbPORT->STS;

  54.     if (IntSt & USART_STS_RDNE)
  55.     {
  56.         Data = mbPORT->DT;

  57.         mbObj.RunSt.bits.PortSt = 1;

  58.         if (MB_RX_RCVEND == mbObj.RcvSt)
  59.             return;

  60.         if (mbObj.SndSt != MB_TX_IDLE)
  61.             return;

  62.         mbObj.RcvSt = MB_RX_RCV;                                                    //指示正在接收数据
  63.         mbswTimerEnable();

  64.         if (mbObj.RcvCnt >= MB_BUFF_SIZE)
  65.             return;                                                                  //指针越界检查

  66.         if ((IntSt & (USART_STS_PERR | USART_STS_FERR | USART_STS_ORERR)) != 0)   //帧错误 //只读,由硬件管理
  67.         {
  68.             if (mbObj.RcvCnt >= 1)
  69.             {
  70.                 mbObj.ErrSt.bits.ErrHal = 1;
  71.             }
  72.         }

  73.         mbObj.AduBuff[mbObj.RcvCnt++] = Data;

  74.     }
  75.     else if ((mbObj.SndSize <= mbObj.SndCnt) && (IntSt & USART_STS_TRAC))
  76.     {
  77.         mbObj.SndSt = MB_TX_IDLE;                                               //发送结束   
  78.         if (mbObj.RunSt.bits.MasterMode)                                         //主机进入接收等待状态
  79.         {
  80.             mbObj.RcvSt = MB_RX_WAIT;
  81.         }
  82.         mbEnable(ENABLE, DISABLE);
  83.     }
  84.     else if (IntSt & USART_STS_TDE)
  85.     {
  86.         if (mbObj.SndSize > mbObj.SndCnt)
  87.         {
  88.             mbPORT->DT = mbObj.AduBuff[mbObj.SndCnt++];
  89.         }
  90.         else                                  //写缓冲区结束
  91.         {
  92.             mbPORT->CTRL1 &= ~((uint32_t)(USART_CTRL1_TDEIEN));
  93.             mbPORT->CTRL1 |= (uint32_t)(USART_CTRL1_TRACIEN);
  94.         }
  95.     }
  96.     else
  97.     {

  98.     }
  99.    
  100.     cpu_data_sync();
  101. }

  102. /*****************************************************************************//*!
  103. *
  104. * @brief   mb object init.
  105. *
  106. * @ Pass/ Fail criteria: none
  107. *****************************************************************************/

  108. static void mbObjInit(mb_mode_type mbMode)
  109. {

  110.     mb_obj_init(&mbObj);
  111.     mbObj.AduSend = &mbDataSend;

  112.     mbObj.RunSt.bits.RTUMode = 1;

  113.     mbObj.Fun.Slave.RegCoilsCB = &eMBRegCoilsCB;
  114.     mbObj.Fun.Slave.RegDiscreteCB = &eMBRegDiscreteCB;
  115.     mbObj.Fun.Slave.RegHoldingCB = &eMBRegHoldingCB;
  116.     mbObj.Fun.Slave.RegInputCB = &eMBRegInputCB;

  117.     mmb_cmd_buff_init(&mbObj, mbCmdBuff, 32, 16);
  118.     mbObj.Fun.Master.ErrCnt = 0;

  119.     mbObj.api = &mb_fun;
  120.    
  121.     //SLAVE FUNCTION INIT
  122.     if (MB_RTU_SLAVE == mbMode)
  123.     {

  124.     }
  125.     else
  126.     {
  127.         //MASER FUNCTION INIT
  128.         mbObj.RunSt.bits.MasterMode = 1;

  129.     }
  130. }

  131. /*****************************************************************************//*!
  132. * @brief           com modle init .
  133. *
  134. * @ Pass/ Fail criteria: none
  135. *****************************************************************************/

  136. void mb06_Init(mb_mode_type mbMode, uint32_t ulBaudRate, mb_parity_type eParity)
  137. {

  138.     uint32_t usTimerT35_50us;
  139.     USART_InitType cfg;

  140.     mb_port_pin_cfg();
  141.     mbObjInit(mbMode);

  142.     cfg.USART_BaudRate = ulBaudRate;
  143.     cfg.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  144.     cfg.USART_HardwareFlowControl = 0;

  145.     if (MB_PAR_NONE == eParity)
  146.     {
  147.         cfg.USART_Parity = USART_Parity_No;
  148.         cfg.USART_StopBits = USART_StopBits_2;
  149.         cfg.USART_WordLength = USART_WordLength_8b;
  150.     }
  151.     else if (MB_PAR_NONE_1S == eParity)
  152.     {
  153.         cfg.USART_Parity = USART_Parity_No;
  154.         cfg.USART_StopBits = USART_StopBits_1;
  155.         cfg.USART_WordLength = USART_WordLength_8b;  
  156.     }
  157.     else if (MB_PAR_ODD == eParity)
  158.     {
  159.         cfg.USART_Parity = USART_Parity_Odd;
  160.         cfg.USART_StopBits = USART_StopBits_1;
  161.         cfg.USART_WordLength = USART_WordLength_9b;
  162.     }
  163.     else
  164.     {
  165.         cfg.USART_Parity = USART_Parity_Even;
  166.         cfg.USART_StopBits = USART_StopBits_1;
  167.         cfg.USART_WordLength = USART_WordLength_9b;
  168.     }

  169.     if (ulBaudRate > 19200)
  170.     {
  171.         usTimerT35_50us = 35; /* 1800us. */
  172.         mbObj.RtuTimerSv = 3;
  173.     }
  174.     else
  175.     {
  176.         usTimerT35_50us = (7UL * 220000UL) / (2UL * ulBaudRate);
  177.         mbObj.RtuTimerSv = usTimerT35_50us / 20 + 2;
  178.     }

  179.     USART_Init(mbPORT, &cfg);

  180.     USART_Cmd(mbPORT, ENABLE);

  181.     nvic_irq_set(mbURT_IRQn, 0x0F, 1);

  182.     mbEnable(ENABLE, DISABLE);
  183. }

  184. /*****************************************************************************//*!
  185. *
  186. * @brief   Uart En or Dis.
  187. * @ Pass/ Fail criteria: none
  188. *****************************************************************************/

  189. static void mbEnable(uint8_t xRxEnable, uint8_t xTxEnable)
  190. {
  191.     volatile uint8_t u8Temp;

  192.     if (xRxEnable)
  193.     {
  194.         mbRxEnable();


  195.         mbPORT->CTRL1 &= ~((uint32_t)USART_CTRL1_TDEIEN | USART_CTRL1_TRACIEN);
  196.         mbPORT->CTRL1 |= (uint32_t)USART_CTRL1_REN | USART_CTRL1_UEN;

  197.         u8Temp = mbPORT->DT;
  198.         while ((mbPORT->STS & (USART_STS_RDNE | USART_STS_ORERR)) != 0)
  199.         {
  200.             u8Temp = mbPORT->DT;
  201.             __DSB();
  202.         }

  203.         mbPORT->CTRL1 |= USART_CTRL1_RDNEIEN;
  204.     }
  205.     else if (xTxEnable)
  206.     {
  207.         mbPORT->CTRL1 &= ~((uint32_t)USART_CTRL1_RDNEIEN | USART_CTRL1_REN);

  208.         mbPORT->CTRL1 |= (uint32_t)USART_CTRL1_TEN | USART_CTRL1_UEN;
  209.         mbTxEnable();

  210.         mbPORT->DT = mbObj.AduBuff[mbObj.SndCnt++];
  211.         mbPORT->CTRL1 |= (uint32_t)(USART_CTRL1_TDEIEN);
  212.     }
  213.     else
  214.     {

  215.     }
  216. }

  217. /*****************************************************************************//*!
  218. *
  219. * @brief   Send data.
  220. *
  221. * @ Pass/ Fail criteria: none
  222. *****************************************************************************/
  223. void mbDataSend(void)
  224. {
  225.     mbEnable(DISABLE, ENABLE);
  226. }

RTU定时使用软件定时器,这样可以避免硬件资源不足,方便添加多通道。
  1. /**
  2.   * @brief  app timer isr
  3.   * @param  None
  4.   * @retval None
  5.   */
  6. void AdcInsertedHandle(void);

  7. void app_timer_isr(void)
  8. {
  9.     APP_TIM->STS = 0;   
  10.    
  11.     sys_st.u_tick++;

  12.     AdcInsertedHandle();
  13.    
  14.     if(com.obj01.fun)
  15.         com.obj01.fun->timer_handle();
  16.    
  17.     if(mb.obj08.api)
  18.         mb.obj08.api->rtu_timer_run();
  19.             
  20.     if(mb.obj06.api)
  21.         mb.obj06.api->rtu_timer_run();
  22.    
  23.     cpu_data_sync();
  24. }

modbus任务配置两条静态处理命令,分别为读取8字和写8字。
根据测试平均每秒执行指令30+次。        
  1.         
  2. void modbus_task (void const *argument)
  3. {
  4.     mb_obj_init(&mb.obj08);

  5.     //从机配置
  6.     mb08_Init(MB_RTU_SLAVE, mb_baud_tab[MB_BAUD_19200], MB_PAR_NONE);
  7.     mb.obj08.SlaveId = 1;
  8.     mb.obj08.os_event_send = mb_os_send;
  9.     mb.obj08.os_rtu_end_event = 1;
  10.     mb.obj08.os_timeout_event = 2;
  11.    
  12.     mb_obj_init(&mb.obj06);

  13.     //主机配置
  14.     mb06_Init(MB_RTU_MASTER, mb_baud_tab[MB_BAUD_19200], MB_PAR_NONE);
  15.     mb.obj06.SlaveId = 1;
  16.     mb.obj06.RtuRcvendDelaySet = 3;
  17.     mb.obj06.rcv_end_handle_comp = rcv_end_handle_comp;
  18.     mb.obj06.os_event_send = mb_os_send;
  19.     mb.obj06.os_rtu_end_event = 1;
  20.     mb.obj06.os_timeout_event = 2;
  21.    
  22.     mb.obj06.api->stc_cmd_req(0, 1, FUN_CODE_WRITE_MULTIPLE_REG, mb_tst.pv_w, 0, 8, 0);
  23.     mb.obj06.api->stc_cmd_req(0, 1, FUN_CODE_READ_REG, mb_tst.pv_r, 0, 8, 0);
  24.    
  25.     //任务处理
  26.     for(;;)
  27.     {
  28.         osSignalWait(0, ms_ticks(100));
  29.         
  30.         mb_poll(&mb.obj08);
  31.         
  32.         mb_poll(&mb.obj06);
  33.     }
  34. }
mblink.jpg
mbtest.png


附上测试工程,IAR8.40版以上可用
software.rar (9.11 MB, 下载次数: 261)


caizhiwei 发表于 2021-1-25 21:22 | 显示全部楼层
牛啊,感谢分享!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

77

主题

326

帖子

2

粉丝
快速回复 返回顶部 返回列表