找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 10439|回复: 14
收起左侧

在STM32F103 C8T6上采用MODBUS协议实现开关量输入输出采集

  [复制链接]
ID:68438 发表于 2017-12-19 15:29 | 显示全部楼层 |阅读模式
采用MODBUS协议实现开关量输入输出采集的程序,希望对大家有用,下载使用的时候记得回复哦

本例程是采用 MODBUS 协议实现的,为了实现 MODBUS 协议,我们移植了一个叫FREE MODBUS协议栈。关于 FREE MODBUS协议栈,在这里就不做介绍了,
   在阅读例程之前,请大家先学习下标准 MODBUS协议,不然你无法了解功能代码的使用。
接下来我给大家介绍如何在串口调试软件中用MODBUS协议命令点亮从机
板子上的LED灯以及读取板子上按键的状态。
在这个例程的工程文件夹下找一个名为:ECOMV280的文件夹,打开后有一个“ECOM串口助手  V2.80.exe”的软件和好多说明资料,请先阅读下软件的使用方法。等你熟悉了调试软件的使用后,就可以连接板子进行调试了,调试板子前你首先要准备一个 RS485转 RS232的转换器,不然没有办法跟电脑连接。  
操作说明:
1、  通讯参数设置:           
0.jpg 0.jpg
注意:发送命令的时候一定要按照上图设置,数据按 HEX格式发送,最后还要用CRC校验。   
设置完了以后直接在数据输入框中填写发送的命令就行,CRC 校验码用户
不用管,在发送数据时,软件会自动在后面加上的。
3、  接收窗口设置:
0.jpg
注意:终端一定要设置成 HEX显示,否则看不到返回的 代码。
4、  数字量输入采集指令:(采集板子上2个按键的状态)
发送:01 02 00 00 00 02 38 0B   十六进制
0.jpg 0.png
备注:如果没有板子按键按下,收到 01 02 01 00 A1 88
           板子上按键KEY1按下,收到01 02 01 01 60 48
           板子上按键KEY2按下,收到01 02 01 02 20 49
           注意:发送时在数据框中只填入红色部分数据,蓝色部分为 CRC校验,软件自动添加。
读取的数据是一个字节,转化为二进制为 8 个位 0000  0000 我们的 3 个
按键的状态对应为:KEY1对应D0位,KEY2对应D1位。
如果按键按下对应的位为 1,如果按键没有按下对应的位为0。
5、  数字量输出控制指令:(控制板子上2个LED灯)
发送:01 0F 00 00 00 02 01 00 8F 57   十六进制
0.jpg
         接收:01 0F 00 00 00 02 15 CA     十六进制
写入的一个字节数据转换成二进制为 8个位 0000 0000,LED1对应DO,
LED2对应D1。 “1”表示点亮LED, “0”表示熄灭LED,
例如发送:01 0F 00 00 00 02 01 01 4E 97 表示点亮LED1.
       发送:01 0F 00 00 00 02 01 02 0E 96 表示点亮LED2
发送:01 0F 00 00 00 02 01 00 8F 57 表示熄灭所有LED
注意:发送时在数据框中只填入红色部分数据,蓝色部分为CRC校验,软件自动添加
好了,这个例程的应用操作说明就先介绍到这里,祝福大家能操作成功。
0.jpg 0.jpg

stm32单片机源程序如下:
  1. #include "stm32f10x.h"
  2. #include "sys.h"
  3. //#include "usart.h"
  4. #include "led.h"   /*------添加了IO控制端口的头文件------*/
  5. #include "mb.h"
  6. #include "mbutils.h"

  7. //输入寄存器起始地址
  8. #define REG_INPUT_START       0x0000
  9. //输入寄存器数量
  10. #define REG_INPUT_NREGS       8
  11. //保持寄存器起始地址
  12. #define REG_HOLDING_START     0x0000
  13. //保持寄存器数量
  14. #define REG_HOLDING_NREGS     8

  15. //线圈起始地址
  16. #define REG_COILS_START       0x0000
  17. //线圈数量
  18. #define REG_COILS_SIZE        16

  19. //开关寄存器起始地址
  20. #define REG_DISCRETE_START    0x0000
  21. //开关寄存器数量
  22. #define REG_DISCRETE_SIZE     16


  23. /* Private variables ---------------------------------------------------------*/
  24. //输入寄存器内容
  25. uint16_t usRegInputBuf[REG_INPUT_NREGS] = {0x0ed6,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007};
  26. //寄存器起始地址
  27. uint16_t usRegInputStart = REG_INPUT_START;

  28. //保持寄存器内容
  29. uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] = {0x0ed6,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
  30. //保持寄存器起始地址
  31. uint16_t usRegHoldingStart = REG_HOLDING_START;

  32. //线圈状态                                                                                                                        
  33. uint8_t ucRegCoilsBuf[REG_COILS_SIZE / 8] = {0x03,0x00};  //0x03表示2个LED全亮,这是刚复位后的状态。
  34. //开关输入状态
  35. uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE / 8] = {0x00,0x00};

  36. void LED_Poll(void);
  37. void Button_Poll(void);


  38. int main(void)
  39. {        
  40.    LED_Config(); //--------LED端口初始化-------------
  41.    Button_Config();        //-----按键端口初始化------------
  42.   eMBInit(MB_RTU, 0x02, 0x01, 9600, MB_PAR_NONE); //初始化 RTU模式 从机地址为1 USART1 9600 无校验  
  43.   eMBEnable(); //启动FreeModbus
  44.   while(1)
  45.         {
  46.                 eMBPoll();
  47.                 LED_Poll();
  48.                 Button_Poll();
  49.         }
  50. }


  51. void LED_Poll(void)
  52. {
  53.   uint8_t LED_Status;
  54.   LED_Status = ucRegCoilsBuf[0];
  55.   if(LED_Status & 0x01) {LED1_ON;} else {LED1_OFF;}
  56.   if(LED_Status & 0x02) {LED2_ON;} else {LED2_OFF;}
  57.   //if(LED_Status & 0x04) {LED3_ON;} else {LED3_OFF;}
  58. }

  59. void Button_Poll(void)
  60. {
  61.   
  62.   uint8_t Button_Status = 0x00;  
  63.   BUTTON1_READ()?(Button_Status &=~ 0x01):(Button_Status |= 0x01);
  64.   BUTTON2_READ()?(Button_Status &=~ 0x02):(Button_Status |= 0x02);
  65.   //BUTTON3_READ()?(Button_Status &=~ 0x04):(Button_Status |= 0x04);   
  66.   ucRegDiscreteBuf[0] = Button_Status;
  67. }
  68. /**
  69.   * @brief  输入寄存器处理函数,输入寄存器可读,但不可写。
  70.   * @param  pucRegBuffer  返回数据指针
  71.   *         usAddress     寄存器起始地址
  72.   *         usNRegs       寄存器长度
  73.   * @retval eStatus       寄存器状态
  74.   */
  75. eMBErrorCode
  76. eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
  77. {
  78.   eMBErrorCode    eStatus = MB_ENOERR;
  79.   int16_t         iRegIndex;
  80.   
  81.   //查询是否在寄存器范围内
  82.   //为了避免警告,修改为有符号整数
  83.   if( ( (int16_t)usAddress >= REG_INPUT_START ) \
  84.         && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
  85.   {
  86.     //获得操作偏移量,本次操作起始地址-输入寄存器的初始地址
  87.     iRegIndex = ( int16_t )( usAddress - usRegInputStart );
  88.     //逐个赋值
  89.     while( usNRegs > 0 )
  90.     {
  91.       //赋值高字节
  92.       *pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] >> 8 );
  93.       //赋值低字节
  94.       *pucRegBuffer++ = ( uint8_t )( usRegInputBuf[iRegIndex] & 0xFF );
  95.       //偏移量增加
  96.       iRegIndex++;
  97.       //被操作寄存器数量递减
  98.       usNRegs--;
  99.     }
  100.   }
  101.   else
  102.   {
  103.     //返回错误状态,无寄存器  
  104.     eStatus = MB_ENOREG;
  105.   }

  106.   return eStatus;
  107. }

  108. /**
  109.   * @brief  保持寄存器处理函数,保持寄存器可读,可读可写
  110.   * @param  pucRegBuffer  读操作时--返回数据指针,写操作时--输入数据指针
  111.   *         usAddress     寄存器起始地址
  112.   *         usNRegs       寄存器长度
  113.   *         eMode         操作方式,读或者写
  114.   * @retval eStatus       寄存器状态
  115.   */
  116. eMBErrorCode
  117. eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs,
  118.                  eMBRegisterMode eMode )
  119. {
  120.   //错误状态
  121.   eMBErrorCode    eStatus = MB_ENOERR;
  122.   //偏移量
  123.   int16_t         iRegIndex;
  124.   
  125.   //判断寄存器是不是在范围内
  126.   if( ( (int16_t)usAddress >= REG_HOLDING_START ) \
  127.      && ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
  128.   {
  129.     //计算偏移量
  130.     iRegIndex = ( int16_t )( usAddress - usRegHoldingStart );
  131.    
  132.     switch ( eMode )
  133.     {
  134.       //读处理函数  
  135.       case MB_REG_READ:
  136.         while( usNRegs > 0 )
  137.         {
  138.           *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] >> 8 );
  139.           *pucRegBuffer++ = ( uint8_t )( usRegHoldingBuf[iRegIndex] & 0xFF );
  140.           iRegIndex++;
  141.           usNRegs--;
  142.         }
  143.         break;

  144.       //写处理函数
  145.       case MB_REG_WRITE:
  146.         while( usNRegs > 0 )
  147.         {
  148.           usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
  149.           usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
  150.           iRegIndex++;
  151.           usNRegs--;
  152.         }
  153.         break;
  154.      }
  155.   }
  156.   else
  157.   {
  158.     //返回错误状态
  159.     eStatus = MB_ENOREG;
  160.   }
  161.   
  162.   return eStatus;
  163. }


  164. /**
  165.   * @brief  线圈寄存器处理函数,线圈寄存器可读,可读可写
  166.   * @param  pucRegBuffer  读操作---返回数据指针,写操作--返回数据指针
  167.   *         usAddress     寄存器起始地址
  168.   *         usNRegs       寄存器长度
  169.   *         eMode         操作方式,读或者写
  170.   * @retval eStatus       寄存器状态
  171.   */
  172. eMBErrorCode
  173. eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
  174.                eMBRegisterMode eMode )
  175. {
  176.   //错误状态
  177.   eMBErrorCode    eStatus = MB_ENOERR;
  178.   //寄存器个数
  179.   int16_t         iNCoils = ( int16_t )usNCoils;
  180.   //寄存器偏移量
  181.   int16_t         usBitOffset;

  182.   //检查寄存器是否在指定范围内
  183.   if( ( (int16_t)usAddress >= REG_COILS_START ) &&
  184.         ( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) )
  185.   {
  186.     //计算寄存器偏移量
  187.     usBitOffset = ( int16_t )( usAddress - REG_COILS_START );
  188.     switch ( eMode )
  189.     {
  190.       //读操作
  191.       case MB_REG_READ:
  192.         while( iNCoils > 0 )
  193.         {
  194.           *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset,
  195.                                           ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) );
  196.           iNCoils -= 8;
  197.           usBitOffset += 8;
  198.         }
  199.         break;

  200.       //写操作
  201.       case MB_REG_WRITE:
  202.         while( iNCoils > 0 )
  203.         {
  204.           xMBUtilSetBits( ucRegCoilsBuf, usBitOffset,
  205.                         ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ),
  206.                         *pucRegBuffer++ );
  207.           iNCoils -= 8;
  208.         }
  209.         break;
  210.     }

  211.   }
  212.   else
  213.   {
  214.     eStatus = MB_ENOREG;
  215.   }
  216.   return eStatus;
  217. }

  218. eMBErrorCode
  219. eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
  220. {
  221. ……………………

  222. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:

ECOMV280调试软件.zip

1.46 MB, 下载次数: 160, 下载积分: 黑币 -5

1

采用MODBUS协议实现开关量输入输出采集例程说明.pdf

237.43 KB, 下载次数: 203, 下载积分: 黑币 -5

2

多块板子利用485总线 采用MODBUS协议实现开关量采集与控制采集.zip

403.35 KB, 下载次数: 294, 下载积分: 黑币 -5

3

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:368549 发表于 2018-7-10 11:20 | 显示全部楼层
来看看,学习学习
回复

使用道具 举报

ID:122622 发表于 2018-12-20 21:47 | 显示全部楼层
正在学习485转开关量,参考一下,在此感谢楼主的辛勤劳动。
回复

使用道具 举报

ID:122622 发表于 2018-12-20 21:50 | 显示全部楼层
参考一下,谢谢楼主。
回复

使用道具 举报

ID:354798 发表于 2019-4-11 14:45 | 显示全部楼层
好的,希望对我们有用
回复

使用道具 举报

ID:160930 发表于 2019-5-24 16:29 | 显示全部楼层
谢谢分享。最近正好用得到
回复

使用道具 举报

ID:570893 发表于 2019-6-24 15:36 | 显示全部楼层
正在学习modbus,学习一下
回复

使用道具 举报

ID:284642 发表于 2020-2-5 21:55 | 显示全部楼层
感谢分享,希望对我有用
回复

使用道具 举报

ID:624009 发表于 2020-2-6 16:56 | 显示全部楼层
谢谢分享
回复

使用道具 举报

ID:108573 发表于 2020-2-9 10:26 | 显示全部楼层
工业最常用的通讯协议,学习一下
回复

使用道具 举报

ID:140644 发表于 2020-2-9 19:10 | 显示全部楼层
工业触摸屏怎么用
回复

使用道具 举报

ID:142383 发表于 2020-2-19 19:56 | 显示全部楼层
感谢楼主分享,正在学习STM32视频,下载学习。
回复

使用道具 举报

ID:605030 发表于 2021-3-19 15:23 | 显示全部楼层
这是个好东西,学习了
回复

使用道具 举报

ID:313601 发表于 2021-5-13 17:18 | 显示全部楼层
工业最常用的通讯协议,学习一下。
回复

使用道具 举报

ID:65633 发表于 2021-5-17 14:45 | 显示全部楼层
是一篇很好的学习资料
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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