找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1942|回复: 11
收起左侧

STM32 Modbus RTU没有调通,请大家帮忙看下

[复制链接]
ID:686311 发表于 2021-10-27 10:08 | 显示全部楼层 |阅读模式
  1. #include "RS485.h"

  2. // 变量定义:
  3. uint8_t USART_TX_BUF[64];                                                        //串口数据发送缓存数组(最大可发送64字节数据)

  4. /*******************************************************************************
  5. 函数名称:Modbus协议CRC校验函数
  6. 输入参数:buf                                指向要校验的数据缓存区基址
  7. 输入参数:len                                要校验的字节数
  8. 返回参数:CRC                                校验结果
  9. 注意事项:无
  10. ********************************************************************************/
  11. static uint16_t CRC_16(uint8_t *buf,uint8_t len)
  12. {
  13.         uint16_t CRC16 = 0xFFFF;
  14.   uint8_t i, j;
  15.         
  16.   for (i = 0; i < len; i++)
  17.   {
  18.     CRC16 ^= buf[i] ;
  19.     for (j = 0; j < 8; j++)
  20.     {
  21.       if ((CRC16 & 0x0001) != 0){CRC16 = (CRC16>>1)^0xA001;}
  22.       else{CRC16 >>= 1;}
  23.     }
  24.    }
  25.     return CRC16;
  26. }


  27. /*******************************************************************************
  28. 函数名称:RS485数据缓存区初始化函数
  29. 输入参数:buf                 指向要初始化缓存区的基址
  30. 输入参数:data                要初始化的数值(一般初始化的值为0x00)
  31. 输入参数:len                        要初始化的字节长度
  32. 返回参数:无
  33. 注意事项:无
  34. ********************************************************************************/
  35. static void Arry_Init(uint8_t *buf,uint8_t data,uint8_t len)
  36. {
  37.         uint8_t i;                                                                                                                        //索引变量
  38.         for(i=0;i<len;i++)                                                                                        //执行相应次数的字节空间初始化
  39.         {
  40.                 buf[i] = data;                                                                                                //字节空间初始化
  41.         }
  42. }


  43. /*******************************************************************************
  44. 函数名称:RS485串口参数配置函数
  45. 输入参数:无
  46. 返回参数:无
  47. 注意事项:无
  48. ********************************************************************************/
  49. void RS485_USART_Config(void)
  50. {
  51.   GPIO_InitTypeDef  GPIO_InitStructure;                                                                                //定义GPIO外设初始化结构体
  52.         USART_InitTypeDef USART_InitStructure;                                                                        //定义USART外设初始化结构体
  53.         
  54.         USART_APBxClkCmd( USART_CLK, ENABLE );                                                                                //使能APB2高速USART1外设时钟
  55.         USART_GPIO_APBxClkCmd( USART_GPIO_CLK,ENABLE );                                                //使能APB2高速GPIOA外设时钟
  56.         RS485_GPIO_APBxClkCmd( RS485_GPIO_CLK,ENABLE );                                                //使能接收发送引脚时钟
  57.         
  58.         //配置发送引脚Tx
  59.         GPIO_InitStructure.GPIO_Pin = USART_TX_PIN;                                                                //配置GPIO端口
  60.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                                                //配置为复用推挽输出
  61.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                        //端口速度配置为50MHz
  62.         GPIO_Init( USART_TX_PORT,&GPIO_InitStructure );                                                //端口初始化
  63.         
  64.         //配置接收引脚Rx
  65.         GPIO_InitStructure.GPIO_Pin = USART_RX_PIN;                                                        //配置GPIO端口
  66.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;                //配置为浮空输入
  67.         GPIO_Init(USART_RX_PORT,&GPIO_InitStructure);                                                //端口初始化
  68.         
  69.         //配置接收或发送使能引脚
  70.         GPIO_InitStructure.GPIO_Pin = RS485_GPIO_PIN;                                                                //配置GPIO端口
  71.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                                                //配置为推挽输出
  72.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                                //端口速度配置为50MHz
  73.         GPIO_Init( RS485_GPIO_PORT,&GPIO_InitStructure );                                                //端口初始化
  74.         
  75.         //配置串口外设
  76.         USART_InitStructure.USART_Mode = USART_Mode_Tx;                                                                                                                                                //配置串口为发送模式
  77.   USART_InitStructure.USART_BaudRate = USART_BAUD;                                                                                                                                        //配置串口波特率
  78.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;                //配置串口硬件控制流
  79.         USART_InitStructure.USART_Parity = USART_Parity_No;                                                                                                                                //配置校验位为无校验
  80.         USART_InitStructure.USART_StopBits = USART_StopBits_1;                                                                                                                //配置串口为一个停止位
  81.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;                                                                                                //八位数据帧模式
  82.         USART_Init(USARTx, &USART_InitStructure);                                                                                                                                                                        //USART初始化
  83.         
  84.         USART_ClearFlag(USARTx, USART_FLAG_TC);                                                                        //清除发送完毕标志位TC
  85.         
  86.         USART_Cmd( USARTx,ENABLE );                                                                                                                        //使能串口
  87.         RS485_TXorRX_EN( TX_EN );                                                                                                                                //接收或发送使能引脚默认为接收状态
  88. }

  89. /*******************************************************************************
  90. 函数名称:RS485串口发送函数
  91. 输入参数:buf                                指向数据发送缓存区的首地址
  92. 输入参数:len                                指定发送的数据长度
  93. 返回参数:无
  94. 注意事项:无
  95. ********************************************************************************/
  96. void RS485_SendData(uint8_t *buf,uint8_t len)
  97. {
  98.         uint8_t i = 0;                                                                                                                                                                                                        //索引变量
  99.         
  100.         RS485_TXorRX_EN( TX_EN );                                                                                                                                                                //使能为发送模式
  101.         Delay_ms(3);
  102.         for(i=0;i<len;i++)                                                                                                                                                                                        //按照相应长度循环发送数据
  103.         {
  104.                 while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);                //检测是否发送完毕
  105.                 USART_SendData(USARTx,buf[i]);                                                                                                                                //将指向的数据发送
  106.         }
  107.         while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == RESET);                        //检测是否发送完毕                                                               
  108. }

  109. ///*******************************************************************************
  110. //函数名称:Modbus协议主机发送0x03(读寄存器)命令函数
  111. //输入参数:addr                                要发送命令的从机设备地址
  112. //输入参数:startable                要读取的从机寄存器起始地址                        
  113. //输入参数:len                                        要读取的寄存器个数
  114. //返回参数:无
  115. //注意事项:无
  116. //********************************************************************************/
  117. //void Modbus_Send_0x03Cmd(uint8_t addr,uint16_t startaddr,uint16_t len)
  118. //{
  119. //        if(len > 0x14){len = 0x14;}                                                                                                                //读取的寄存器个数只允许读20个,超出按最大20个读取(寄存器个数的最大值要根据接收缓存区的大小来决定,可人为定义寄存器个数的最大值)
  120. //        USART_TX_BUF[0] = addr;                                                                                                                                //获取从机设备地址
  121. //        USART_TX_BUF[1] = 0x03;                                                                                                                                //获取读寄存器功能码(0x03)
  122. //        USART_TX_BUF[2] = (uint8_t)(startaddr>>8);                                                //获取寄存器基址高字节
  123. //        USART_TX_BUF[3] = (uint8_t)(startaddr&0xFF);                                        //获取寄存器基址低字节
  124. //        USART_TX_BUF[4] = (uint8_t)(len>>8);                                                                        //获取读取寄存器个数高字节
  125. //        USART_TX_BUF[5] = (uint8_t)(len&0xFF);                                                                //获取读取寄存器个数低字节
  126. //        ((uint16_t)*(USART_TX_BUF+6)) = CRC_16(USART_TX_BUF,6);//获取发送数据的CRC校验结果
  127. //        RS485_SendData(USART_TX_BUF,8);                                                                                                //发送读寄存器功能命令
  128. //        USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE);                                //发送完毕,开串口接收中断
  129. //}

  130. /*******************************************************************************
  131. 函数名称:Modbus协议主机发送0x06(写单个寄存器)命令函数
  132. 输入参数:addr                                要发送命令的从机设备地址
  133. 输入参数:startable                要发送的从机寄存器起始地址        
  134. 输入参数:Data                                要写入的数据
  135. 返回参数:无
  136. 注意事项:无
  137. ********************************************************************************/
  138. void Modbus_Send_0x06Cmd(uint8_t addr,uint16_t startaddr,uint16_t Data)
  139. {
  140.         unsigned short temp;
  141.         
  142.         USART_TX_BUF[0] = addr;                                                                                                                                        //获取从机设备地址
  143.         USART_TX_BUF[1] = 0x06;                                                                                                                                        //获取读寄存器功能码(0x06)
  144.         USART_TX_BUF[2] = (uint8_t)(startaddr>>8);                                                        //获取寄存器基址高字节
  145.         USART_TX_BUF[3] = (uint8_t)(startaddr&0xFF);                                                //获取寄存器基址低字节
  146.         USART_TX_BUF[4] = (uint8_t)(Data>>8);                                                                                //获取写入数据的高字节
  147.         USART_TX_BUF[5] = (uint8_t)(Data&0xFF);                                                                        //获取写入数据的低字节
  148.         temp = CRC_16( USART_TX_BUF,6 );
  149.         USART_TX_BUF[6] = (uint8_t)(temp&0xFF);
  150.         USART_TX_BUF[7] = (uint8_t)(temp>>8);
  151.         RS485_SendData(USART_TX_BUF,8);                                                                                                        //发送读寄存器功能命令
  152. }

  153. ///*******************************************************************************
  154. //函数名称:Modbus协议主机发送0x10(写多个寄存器)命令函数
  155. //输入参数:addr                                要发送命令的从机设备地址
  156. //输入参数:startable                要写入的从机寄存器起始地址        (范围:0~64)
  157. //输入参数:len                                        要写入的寄存器个数                                        (范围:0~255)
  158. //输入参数:buf                                        指向要发送的数据缓存区
  159. //返回参数:无
  160. //注意事项:无
  161. //********************************************************************************/
  162. //void Modbus_Send_0x10Cmd(uint8_t addr,uint16_t startaddr,uint16_t len,uint16_t *buf)
  163. //{
  164. //        uint8_t i = 0;                                                                                                                                                                //索引变量
  165. //        
  166. //        USART_TX_BUF[0] = addr;                                                                                                                                //获取从机设备地址                                                                                                
  167. //        USART_TX_BUF[1] = 0x10;                                                                                                                                //获取写多个寄存器功能码(0x10)
  168. //        USART_TX_BUF[2] = (uint8_t)(startaddr>>8);                                                //获取寄存器基址高字节
  169. //        USART_TX_BUF[3] = (uint8_t)(startaddr&0xFF);                                        //获取寄存器基址低字节
  170. //        USART_TX_BUF[4] = (uint8_t)(len>>8);                                                                        //获取写入数据寄存器个数高字节
  171. //        USART_TX_BUF[5] = (len&0xFF);                                                                                                        //获取写入数据寄存器个数低字节
  172. //        USART_TX_BUF[6] = (uint8_t)(len*2);                                                                                //获取数据的总字节数
  173. //        for(i=0;i<USART_TX_BUF[5];i++)                                                                                                //循环获取要发送的数据
  174. //        {
  175. //                USART_TX_BUF[7+(i*2)] = (uint8_t)(buf[i]>>8);
  176. //                USART_TX_BUF[8+(i*2)] = (uint8_t)(buf[i]&0xFF);
  177. //        }
  178. //        ((uint16_t)(USART_TX_BUF+(7+USART_TX_BUF[6]))) = CRC_16(USART_TX_BUF,(7+USART_TX_BUF[6]));        //获取发送数据的CRC校验结果
  179. //        RS485_SendData(USART_TX_BUF,(9+USART_TX_BUF[6]));                        //发送写多个寄存器功能命令
  180. //}




  181. #include "stm32f10x.h"
  182. #include "RS485.h"
  183. #include "Delay.h"

  184. void GPIO_Cofing( void );

  185. /*******************************************************************************
  186. 函数名称:主函数
  187. 输入参数:无
  188. 返回参数:无
  189. 注意事项:无
  190. ********************************************************************************/
  191. int main(void)
  192. {        
  193.         Delay_Init();
  194.         RS485_USART_Config();
  195.         GPIO_Cofing();
  196.         while(1)
  197.         {
  198.                 Modbus_Send_0x06Cmd(0x01,0x2000,0x0001);                //发送电机正转信号
  199.                 Delay_ms(20000);
  200. //                Modbus_Send_0x06Cmd(0x01,0x2001,0x0002);                //发送电机正转信号
  201. //                Delay_ms(1000);
  202.         }
  203. }


  204. void GPIO_Cofing( void )
  205. {
  206.         GPIO_InitTypeDef  GPIO_InitStructure;                                                                                //定义GPIO外设初始化结构体
  207.         
  208.         RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA,ENABLE );
  209.         GPIO_InitStructure.GPIO_Mode         = GPIO_Mode_Out_PP;
  210.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  211.         GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_6;
  212.         GPIO_Init( GPIOA, &GPIO_InitStructure );
  213.         
  214.         GPIO_SetBits( GPIOA, GPIO_Pin_6 );
  215.         Delay_ms(3000);
  216. }


复制代码

STM32 MODBUS.7z

474.52 KB, 下载次数: 25

回复

使用道具 举报

ID:123289 发表于 2021-10-28 09:49 | 显示全部楼层
如何才算调通了呢?
回复

使用道具 举报

ID:686311 发表于 2021-10-28 13:37 | 显示全部楼层
yzwzfyz 发表于 2021-10-28 09:49
如何才算调通了呢?

无刷电机没有反应,程序有发送电机正转指令   Modbus_Send_0x06Cmd(0x01,0x2000,0x0001);               
回复

使用道具 举报

ID:123289 发表于 2021-10-29 09:49 | 显示全部楼层
硬件图呢,程序有发送电机正转指令,已发到什么地方了呢?如果证明被电机收到了呢?
回复

使用道具 举报

ID:686311 发表于 2021-10-29 10:24 | 显示全部楼层
Modbus RTU通讯发给发到驱动器,驱动器外购的,目前只是写驱动器字节,没有读取,是不是要读取?但读取数据也没有用

V2.pdf

119.93 KB, 下载次数: 14

回复

使用道具 举报

ID:686311 发表于 2021-10-29 10:41 | 显示全部楼层
yzwzfyz 发表于 2021-10-29 09:49
硬件图呢,程序有发送电机正转指令,已发到什么地方了呢?如果证明被电机收到了呢?

主控发给驱动器,驱动器外购的,目前只是往驱动器写字节,没有读取,是不是要读取?但读取数据也没有用
回复

使用道具 举报

ID:123289 发表于 2021-10-30 11:26 | 显示全部楼层
证明一下,驱动器收到了你发的指令,而且指令是正确的,符合驱动器手册上的要求。
回复

使用道具 举报

ID:686311 发表于 2021-11-2 19:08 | 显示全部楼层
yzwzfyz 发表于 2021-10-30 11:26
证明一下,驱动器收到了你发的指令,而且指令是正确的,符合驱动器手册上的要求。

问题找到了,正转运行指令改正转点动指令就可以了,好奇怪
回复

使用道具 举报

ID:883242 发表于 2021-11-2 19:28 | 显示全部楼层
zhijie327 发表于 2021-11-2 19:08
问题找到了,正转运行指令改正转点动指令就可以了,好奇怪

以后这样的问题可以用串口助手加USB转485先调通了,再写软件更快一些。
回复

使用道具 举报

ID:686311 发表于 2021-11-2 20:48 | 显示全部楼层
Hephaestus 发表于 2021-11-2 19:28
以后这样的问题可以用串口助手加USB转485先调通了,再写软件更快一些。

好的,谢谢!
回复

使用道具 举报

ID:165291 发表于 2022-1-13 11:48 | 显示全部楼层
这个是主站程序呗?请问用的什么型号的单片机?
回复

使用道具 举报

ID:31164 发表于 2022-2-12 10:11 | 显示全部楼层
timeabcd 发表于 2022-1-13 11:48
这个是主站程序呗?请问用的什么型号的单片机?

是的,STM32
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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