社区导航

 

搜索
查看: 221|回复: 0

[原创] 【 XMC4800 Relax EtherCAT Kit测评】+上手DAVE,Modbus总线综合应用

[复制链接]

279

TA的帖子

0

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2019-2-1 20:43 | 显示全部楼层 |阅读模式
马上过年了,祝愿各位坛友猪年快乐,猪事顺利!

前面已经利用DAVE软件完成了多数基本部件的应用,由于本人之前一直使用的DAVE版本是4.3.2版本,有好多例程不能跑,例如基于XMC4700的modbus应用,为此重新下载了4.4.2版本,本次分享一下modbus的综合应用。在APP中,没有专门的Modbus总线应用。这里直接使用的是英飞凌提供的软件例程:MODBUS_RTU_MODE_XMC47。
这个应用中英飞凌已经把相关的移植做好了,我们只要对应配置即可。所使用的是freemodbus-1.5.0,这个协议栈是为从站应用设计的,不能作为主站使用。
对于freemodbus的移植应用,需要建立port文件夹,其实移植主要涉及2个硬件资源,一个是串口资源,一个是定时资源,分别是对应modbus协议栈运行时所需的通道和超时处理。另外就是对于4类寄存器(离散输入,输入寄存器、线圈输出、保持寄存器)的处理函数要有自己编写。
image001.png
本次,我在MODBUS_RTU_MODE_XMC47例程的基础上,分别对4类寄存器进行了测试,主要包括:
1.    按钮对离散输入量,
2.    PWM频率值对应输入寄存器,
3.    用来设置PWM的频率,
4.    读取ADC转换的值,作为保持寄存器数值。
在使用之前,我们需要定义4类寄存器的地址和有效数量。
image002.png
之后在单片机程序中定义4类数组,分别对应4类寄存器。
image003.jpg
然后依次编写相关寄存器的读写操作函数,把数据写入到缓冲区或者从缓冲区中读入,这里缓冲区与UART交互,完成modbus总线协议栈的底层数据交换。
image004.jpg
image005.jpg
image006.jpg
image007.jpg
而我们的应用需要在原来例程的基础上再添加2个IO模块,对应LED;添加ADC模块,对应读取ADC的值,并且写入到保持寄存器3中,另外添加PWM程序,将输入寄存器的值与PWM频率设置值对接。相应的操作可以看之前我的帖子,这里不再赘述。其中ADC的转换值采用了轮训的方式,直接读取,而没有采用中断方式,后续再优化。
image008.png
所有配置完成后,依次编写相关的处理程序。
1,led处理函数如下,通过读取线圈输出值,来判断是否点亮或者关闭对应的LED。
image009.png
2.PWM中,我们引用了compare匹配模式,产生了一个呼吸灯,然后配置呼吸灯的频率。
image010.png
3.ADC直接去读的转换结果。在程序中我们还另外设置了固定数值,以及自加数值,用来检测modbus的应用。
image011.jpg
5.    另外,例程原本程序是读取离散输入的按钮值。具体可以看代码。
之后,编译下载程序,使用modscan32软件依次添加4类寄存器的操作面板,具体截图如下。
输入寄存器的操作:
image012.jpg
保持寄存器的操作:
image013.jpg
离散输入寄存器:
image014.jpg
线圈寄存器:
image015.jpg
最终一张全家福,看看各个窗口数据:
image016.jpg
最后相关的代码,这里主要贴出main函数代码:


  1. /****************************************************************
  2. * HEADER FILES
  3. ***************************************************************/
  4. #include <DAVE.h>
  5. #include "port.h"
  6. #include "mbutils.h"
  7. #include "mb.h"

  8. /****************************************************************
  9. * MACROS AND DEFINES
  10. ***************************************************************/
  11. /* Input Register Definition (16 bit; Read-Only) */
  12. /* Input Register Start Address */
  13. #define REG_INPUT_START_ADDR 1U
  14. /* No of Input Registers*/
  15. #define REG_INPUT_COUNT 4U

  16. /* Holding Register Definition (16 bit; Read-Write) */
  17. /* Holding Register Start Address */
  18. #define REG_HOLDING_START_ADDR 10U
  19. /* No of Holding Registers */
  20. #define REG_HOLDING_COUNT 130U

  21. /* Coil Register Definition (1 bit; Read-Write) */
  22. /* Coil Register Start Address */
  23. #define REG_COILS_START_ADDR 1000U
  24. /* No of Coil Registers*/
  25. #define REG_COILS_COUNT 16U

  26. /* Discrete Inputs Definition (1 bit; Read-Only) */
  27. /* Discrete Inputs Start Address */
  28. #define REG_DISC_START_ADDR 2000U
  29. /* No of Discrete Inputs */
  30. #define REG_DISC_COUNT 16U

  31. /****************************************************************
  32. * LOCAL DATA
  33. ***************************************************************/
  34. /* Allocate buffer for Input Register (16bit; Read-Only) */
  35. static uint16_t reg_input_buffer[REG_INPUT_COUNT];
  36. /* Allocate buffer for Holding Register (16bit; Read-Write) */
  37. static uint16_t reg_holding_buffer[REG_HOLDING_COUNT];
  38. /* Allocate buffer for discrete input register (1bit; Read-Only) */
  39. static uint8_t reg_discrete_input_buffer[ (((uint16_t)REG_DISC_COUNT-1U) / 8U) + 1U];
  40. /* Allocate buffer for coil register (1bit; Read-Write) */
  41. static uint8_t reg_coils_buffers[ (((uint16_t)REG_COILS_COUNT-1U) / 8U) + 1U];

  42. /****************************************************************
  43. * API PROTOTYPES
  44. ***************************************************************/
  45. void readbuttons(void);
  46. void Rx_Cb(void);
  47. void Tx_Cb(void);
  48. void setleds(void);
  49. void setPWM_feq(void);

  50. /****************************************************************
  51. * API IMPLEMENTATION
  52. ***************************************************************/
  53. /**
  54. * @eMBRegInputCB
  55. *
  56. * Callback function called by the protocol stack for reading the 16bit value of input
  57. * register(s)
  58. *
  59. * @input :  - buffer  : Pointer to a buffer which is used to return the
  60. *                        current value of the modbus input registers to the stack.
  61. *           - address : Starting address of the registers.
  62. *           - count   : Number of registers to be returned.
  63. *
  64. * @output : - buffer  : Buffer which is updated with the modbus input registers.
  65. *
  66. * [url=home.php?mod=space&uid=784970]@return[/url] : MB_ENOERR if success
  67. *           MB_ENOREG if failure (illegal register access)
  68. *
  69. * */
  70. eMBErrorCode eMBRegInputCB( uint8_t *buffer, uint16_t address, uint16_t count )
  71. {
  72.   eMBErrorCode status = MB_ENOERR;
  73.   uint16_t     register_index;

  74.   if (( address >= (uint16_t)REG_INPUT_START_ADDR )
  75.      && ( (uint16_t)(address + count) <= (uint16_t)(REG_INPUT_START_ADDR + REG_INPUT_COUNT) ))
  76.   {
  77.     register_index = ( uint16_t )( address - REG_INPUT_START_ADDR );
  78.     while( count > 0U )
  79.     {
  80.       /* Pass current register values to the protocol stack. */
  81.       *buffer = ( uint8_t )( reg_input_buffer[register_index] >> 8 );
  82.       buffer++;
  83.       *buffer = ( uint8_t )( reg_input_buffer[register_index] & 0xFFU );
  84.       buffer++;
  85.       register_index++;
  86.       count--;
  87.     }
  88.   }
  89.   else
  90.   {
  91.     status = MB_ENOREG;
  92.   }
  93.   return status;
  94. }

  95. /**
  96. * @eMBRegHoldingCB
  97. *
  98. * Callback function called by the protocol stack for reading/writing the 16bit value of
  99. * holding register(s)
  100. *
  101. * @input :  - buffer  : Pointer to a buffer which is used to exchange (read/write)
  102. *                       current value of the modbus holding registers with the protocol stack.
  103. *           - address : Starting address of the register(s).
  104. *           - count   : Number of registers to be exchanged (read/write).
  105. *           - mode    : MB_REG_WRITE Protocol stack is writing input register(s).
  106. *                       MB_REG_READ  Protocol stack is reading input register(s).
  107. *
  108. * @output : - buffer  : Buffer which is updated with the modbus holding registers.
  109. *
  110. * @return:  MB_ENOERR if success
  111. *           MB_ENOREG if failure (illegal register access)
  112. *
  113. * */
  114. eMBErrorCode eMBRegHoldingCB( uint8_t *buffer, uint16_t address, uint16_t count, eMBRegisterMode mode )
  115. {
  116.   eMBErrorCode status = MB_ENOERR;
  117.   uint16_t register_index;

  118.   if ( ( address >= REG_HOLDING_START_ADDR ) &&
  119.      ( (uint16_t)(address + count) <= (uint16_t)(REG_HOLDING_START_ADDR + REG_HOLDING_COUNT)) )
  120.   {
  121.     register_index = ( uint16_t )( address - REG_HOLDING_START_ADDR );
  122.     switch ( mode )
  123.     {
  124.       /* Pass current register values to the protocol stack. */
  125.       case MB_REG_READ:
  126.         while( count > 0U )
  127.         {
  128.           *buffer = (uint8_t)( reg_holding_buffer[register_index] >> 8 );
  129.           buffer++;
  130.           *buffer = (uint8_t)( reg_holding_buffer[register_index] & 0xFFU );
  131.           buffer++;
  132.           register_index++;
  133.           count--;
  134.         }
  135.         break;
  136.       /* Update current register values with new values from the
  137.        * protocol stack. */
  138.       case MB_REG_WRITE:
  139.         while( count > 0U )
  140.         {
  141.           reg_holding_buffer[register_index] = (uint16_t)((uint16_t)*buffer << 8);
  142.           buffer++;
  143.           reg_holding_buffer[register_index] |= *buffer;
  144.           buffer++;
  145.           register_index++;
  146.           count--;
  147.         }
  148.         break;
  149.       default:
  150.         status = MB_ENOREG;
  151.         break;
  152.     }
  153.   }
  154.   else
  155.   {
  156.       status = MB_ENOREG;
  157.   }
  158.   return status;
  159. }

  160. /**
  161. * @eMBRegCoilsCB
  162. *
  163. * Callback function called by the protocol stack for reading/writing the 1bit value of coil register(s)
  164. *
  165. * @input :  - buffer  : Pointer to a buffer which is used to exchange (read/write)
  166. *                       current value of the modbus coil regitser(s) with the protocol stack.
  167. *           - address : Starting address of the register(s).
  168. *           - count   : Number of registers bits to be exchanged (read/write).
  169. *           - mode    : MB_REG_WRITE Protocol stack is writing coil register(s).
  170. *                       MB_REG_READ  Protocol stack is reading coil register(s).
  171. *
  172. * @output : - buffer  : Buffer which is updated with the modbus coil register(s).
  173. *
  174. * @return:  MB_ENOERR if success
  175. *           MB_ENOREG if failure (illegal register access)
  176. *
  177. * */
  178. eMBErrorCode eMBRegCoilsCB( uint8_t *buffer, uint16_t address, uint16_t count, eMBRegisterMode mode )
  179. {
  180.   eMBErrorCode status = MB_ENOERR;
  181.   int16_t signed_count = (int16_t)count;
  182.   uint16_t bit_offset;

  183.   /* Check if we have registers mapped at this block. */
  184.   if( ( address >= REG_COILS_START_ADDR ) &&
  185.       ( (uint16_t)(address + count) <= (uint16_t)(REG_COILS_START_ADDR + REG_COILS_COUNT)) )
  186.   {
  187.     bit_offset = ( uint16_t )( address - REG_COILS_START_ADDR );
  188.     switch ( mode )
  189.     {
  190.       /* Read current values and pass to protocol stack. */
  191.       case MB_REG_READ:
  192.         while( signed_count > 0 )
  193.         {
  194.           if (signed_count > 8)
  195.           {
  196.             *buffer = xMBUtilGetBits( reg_coils_buffers, bit_offset, 8U);
  197.           }
  198.           else
  199.           {
  200.             *buffer = xMBUtilGetBits( reg_coils_buffers, bit_offset, (uint8_t)signed_count);
  201.           }
  202.           buffer++;
  203.           signed_count -= 8;
  204.           bit_offset += 8U;
  205.         }
  206.         break;
  207.       /* Update current register values. */
  208.       case MB_REG_WRITE:
  209.         while( signed_count > 0 )
  210.         {
  211.           if (signed_count > 8)
  212.           {
  213.             xMBUtilSetBits( reg_coils_buffers, bit_offset, 8U, *buffer );
  214.           }
  215.           else
  216.           {
  217.             xMBUtilSetBits( reg_coils_buffers, bit_offset, (uint8_t)signed_count, *buffer );
  218.           }
  219.           buffer++;
  220.           signed_count -= 8;
  221.           bit_offset += (uint8_t)8;
  222.         }
  223.         break;
  224.       default:
  225.         status = MB_ENOREG;
  226.         break;
  227.     }
  228.   }
  229.   else
  230.   {
  231.     status = MB_ENOREG;
  232.   }
  233.   return status;
  234. }

  235. /**
  236. * @eMBRegDiscreteCB
  237. *
  238. * Callback function called by the protocol stack for reading the 1bit value of discrete register(s)
  239. *
  240. * @input :  - buffer  : Pointer to a buffer which is used to return the
  241. *                       current value of the modbus discrete registers to the stack.
  242. *           - address : Starting address of the registers.
  243. *           - count   : Number of register bits to be returned.
  244. *
  245. * @output : - buffer  : Buffer which is updated with the modbus discrete registers.
  246. *
  247. * @return : MB_ENOERR if success
  248. *           MB_ENOREG if failure (illegal register access)
  249. *
  250. * */
  251. eMBErrorCode eMBRegDiscreteCB( uint8_t *buffer, uint16_t address, uint16_t count )
  252. {
  253.   eMBErrorCode status = MB_ENOERR;
  254.   int16_t signed_count = (int16_t)count;
  255.   uint16_t bit_offset;

  256.   /* Check if we have registers mapped at this block. */
  257.   if( ( address >= REG_DISC_START_ADDR ) &&
  258.     ( (uint16_t)(address + count) <= (uint16_t)(REG_DISC_START_ADDR + REG_DISC_COUNT)) )
  259.   {
  260.     bit_offset = (uint16_t)( address - REG_DISC_START_ADDR );
  261.     while( signed_count > 0 )
  262.     {
  263.       if (signed_count > 8)
  264.       {
  265.          *buffer = xMBUtilGetBits( reg_discrete_input_buffer, bit_offset, 8U );
  266.       }
  267.       else
  268.       {
  269.          *buffer = xMBUtilGetBits( reg_discrete_input_buffer, bit_offset, (uint8_t)signed_count);
  270.       }
  271.       buffer++;
  272.       signed_count -= 8;
  273.       bit_offset += (uint8_t)8;
  274.     }
  275.   }
  276.   else
  277.   {
  278.     status = MB_ENOREG;
  279.   }
  280.   return status;
  281. }

  282. /**
  283. * @readbuttons
  284. *
  285. * Checks state of button1 and button2 and
  286. * sets bit0 and bit1 of discrete input registers accordingly
  287. *
  288. * @input :  none
  289. *
  290. * @output : none
  291. *
  292. * @return : none
  293. *
  294. * */
  295. void readbuttons(void)
  296. {
  297.     /* Read input of button 1 and store inside bit 0 of discrete input registers */
  298.     if (XMC_GPIO_GetInput(P15_13))
  299.     {
  300.       xMBUtilSetBits( reg_discrete_input_buffer, 0U, 1U, 1U );    /* Set bit 0 to 1b. */
  301.     }
  302.     else
  303.     {
  304.       xMBUtilSetBits( reg_discrete_input_buffer, 0U, 1U, 0U );    /* Set bit 0 to 0b. */
  305.     }

  306.     /* Read input of button 2 and store inside bit 1 of discrete input registers */
  307.     if (XMC_GPIO_GetInput(P15_12))
  308.     {
  309.       xMBUtilSetBits( reg_discrete_input_buffer, 1U, 1U, 1U );    /* Set bit 1 to 1b. */
  310.     }
  311.     else
  312.     {
  313.       xMBUtilSetBits( reg_discrete_input_buffer, 1U, 1U, 0U );    /* Set bit 1 to 0b. */
  314.     }
  315. }

  316. void setleds(){

  317.         if((reg_coils_buffers[0]&0x01)!=0){           //check buffer[0] bit0 is 1.
  318.                 DIGITAL_IO_SetOutputHigh(&LED_1);
  319.         }
  320.         else{
  321.                 DIGITAL_IO_SetOutputLow(&LED_1);
  322.         }

  323.         if((reg_coils_buffers[0]&0x02)!=0){           //check buffer[0] bit1 is 1.
  324.                 DIGITAL_IO_SetOutputHigh(&LED_0);
  325.         }
  326.         else{
  327.                 DIGITAL_IO_SetOutputLow(&LED_0);
  328.         }
  329. }

  330. void setPWM_feq(){

  331.         PWM_SetFreq(&PWM_0,(uint32_t)reg_holding_buffer[0]);
  332. }

  333. void PWM_handler(){
  334.         static uint32_t duty = (uint32_t)100;
  335.         static bool decrement_duty = (bool)false;

  336.           if(decrement_duty != false)
  337.           {
  338.             //Decrement the duty cycle until it reaches 1%
  339.             duty -= (uint32_t)100;
  340.             // Once the duty has reached 1% flag status is changed to Increment
  341.             if (duty <= (uint32_t)100)
  342.              {
  343.                 decrement_duty = false;
  344.              }
  345.           }
  346.           else
  347.           {
  348.             // Increment the duty cycle until it reaches 100%
  349.             duty += (uint32_t)100;
  350.             // Once the duty has reached 100% flag status is changed to decrement
  351.             if (duty >= (uint32_t)10000)
  352.             {
  353.              decrement_duty = true;
  354.             }
  355.           }
  356.           // Sets the duty cycle of the PWM
  357.           PWM_SetDutyCycle(&PWM_0,duty);

  358.           // Clear the compare match interrupt.
  359.           PWM_ClearEvent(&PWM_0,PWM_INTERRUPT_COMPAREMATCH );

  360. }


  361. void Adc_Measurement(){
  362.         reg_input_buffer[2] = ADC_MEASUREMENT_GetResult(&ADC_MEASUREMENT_Channel_A);
  363. }


  364. /**
  365. * @brief
  366. *
  367. * Initialize Modbus RTU or ASCII mode, baudrate and device address. Enables the
  368. * modbus stack.
  369. *
  370. *
  371. * */
  372. int32_t main(void)
  373. {
  374.   /*Initialize DAVE */
  375.   if(DAVE_Init() == DAVE_STATUS_FAILURE)
  376.   {
  377.     /* Placeholder for error handler code.*/
  378.     XMC_DEBUG(("DAVE APPs initialization failed\n"));
  379.     while(1U)
  380.     {
  381.         /* do nothing */
  382.     }
  383.   }

  384.   /* INITIALIZE BUTTON1 ON PORT 5.13 FOR INPUT */
  385.   /* Set mode to input tristate */
  386.   XMC_GPIO_SetMode(P15_13, XMC_GPIO_MODE_INPUT_TRISTATE);
  387.   /* Enable digital input. Only needed because P15.13 is an analog port */
  388.   XMC_GPIO_EnableDigitalInput(P15_13);
  389.   /* INITIALIZE BUTTON2 ON PORT 5.12 FOR INPUT */
  390.   /* Set mode to input tristate */
  391.   XMC_GPIO_SetMode(P15_12, XMC_GPIO_MODE_INPUT_TRISTATE);
  392.   /* Enable digital input. Only needed because P15.12 is an analog port */
  393.   XMC_GPIO_EnableDigitalInput(P15_12);


  394.   PWM_Start(&PWM_0);
  395.   ADC_MEASUREMENT_StartConversion(&ADC_MEASUREMENT_0);


  396.   /* Set FIFO trigger limits */
  397.   UART_SetRXFIFOTriggerLimit (&UART_0, (uint32_t)0);
  398.   UART_SetTXFIFOTriggerLimit (&UART_0, (uint32_t)1);

  399.   /* Register UART_0 interface for modbus usage */
  400.   MB_register_UART(&UART_0);

  401.   /* Initialization of modbus in RTU mode */
  402.   (void)eMBInit( MB_RTU,            /*eMode (MB_ASCII or MB_RTU*/
  403.                    (uint8_t)0x0A,     /*ucSlaveAddress*/
  404.                    (uint8_t)0,        /*ignored*/
  405.                    (uint8_t)19200,    /*ulBaudRate*/
  406.                    (eMBParity)0         /*ignored*/
  407.                  );
  408.   /*Enable modbus protocol stack.*/
  409.   (void)eMBEnable();

  410.   /* Initialise the discrete input registers with zero's and one's
  411.    * for demonstration purpose within this example. */
  412.   xMBUtilSetBits( reg_discrete_input_buffer, (uint16_t)2, (uint8_t)2, (uint8_t)3 );    /* Set bit 2:3 to 11b. */
  413.   xMBUtilSetBits( reg_discrete_input_buffer, (uint16_t)8, (uint8_t)1, (uint8_t)1 );    /* Set bit 8 to 1b. */

  414.   /* Modbus polling loop waiting for an Event*/
  415.   for( ;; )
  416.   {
  417.     /* Process modbus protocol stack */
  418.     (void)eMBPoll();

  419.     /* Change values inside local register banks for demonstration purpose*/
  420.     reg_input_buffer[0]++;
  421.     reg_input_buffer[1]=12345;
  422.     readbuttons();
  423.     setleds();
  424.     setPWM_feq();
  425.     Adc_Measurement();
  426.   }
  427. }

  428. /* Callback handler of UART receiving */
  429. void Rx_Cb(void)
  430. {
  431.   MB_RxHandler();
  432. }

  433. /* Callback handler of UART transmitting */
  434. void Tx_Cb(void)
  435. {
  436.   MB_TxHandler();
  437. }

复制代码





此内容由EEWORLD论坛网友flyword原创,如需转载或用于商业用途需征得作者同意并注明出处




此帖出自工控电子论坛


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2019-2-23 00:01 , Processed in 0.091248 second(s), 20 queries , Gzip On, MemCache On.

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