第一个关于STM32的MODBUS协议例子 功能码03

梦里梦外; 2022-11-03 04:09 93阅读 0赞

这两天一直在有关于modbus协议的传输,没有想到会这般困难,原谅我是一个新手。具体的modbus协议,网上很多了,我就不多说了,直接发出来。
第一部分

  1. u8 receiveOK_flag = 0;
  2. int main(void)
  3. {
  4. delay_init(); //延时函数初始化
  5. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  6. uart_init(115200);
  7. LED_Init();//LED初始化
  8. while(1)
  9. {
  10. if( receiveOK_flag ) //一帧数据接收完成后开始处理数据
  11. {
  12. DisposeReceive(); //处理modbus通信
  13. receiveOK_flag = 0;
  14. }
  15. delay_ms(10);
  16. }
  17. }

第二部分

  1. void DisposeReceive( void )
  2. {
  3. u16 CRC16 = 0, CRC16Temp = 0;
  4. if(receiveOK_flag)
  5. {
  6. delay_ms(10);
  7. if( USART_RX_BUF[0] == SlaveID ) //地址等于本机地址 地址范围:1 - 32
  8. {
  9. CRC16 = CRC_Compute(USART_RX_BUF,USART_RX_CNT-2);//计算所接收数据的CRC; //CRC校验 低字节在前 高字节在后 高字节为报文最后一个字节
  10. CRC16Temp = USART_RX_BUF[USART_RX_CNT-1]|(((u16)USART_RX_BUF[USART_RX_CNT-2])<<8);
  11. if( CRC16 != CRC16Temp )
  12. {
  13. err = 4; //CRC校验错误
  14. }
  15. StartRegAddr = ( u16 )( USART_RX_BUF[2] << 8 ) | USART_RX_BUF[3];
  16. if( StartRegAddr > (HoldRegStartAddr + HoldRegCount - 1) )
  17. {
  18. err = 2; //起始地址不在规定范围内 00 - 07 1 - 8号通道
  19. }
  20. if( err == 0 )
  21. {
  22. switch( USART_RX_BUF[1] ) //功能码
  23. {
  24. case 3: //读多个寄存器
  25. {
  26. Modbus_03_Slave();
  27. break;
  28. }
  29. case 6: //写单个寄存器
  30. {
  31. Modbus_06_Slave();
  32. break;
  33. }
  34. case 16: //写多个寄存器
  35. {
  36. Modbus_16_Slave();
  37. break;
  38. }
  39. default:
  40. {
  41. err = 1; //不支持该功能码
  42. break;
  43. }
  44. }
  45. }
  46. USART_RX_CNT=0;//接收计数器清零
  47. USART_RX_BUF[USART_REC_LEN]=0;
  48. if( err > 0 )
  49. {
  50. SendBuf[0] = USART_RX_BUF[0];
  51. SendBuf[1] = USART_RX_BUF[1] | 0x80;
  52. SendBuf[2] = err; //发送错误代码
  53. CRC16Temp = CRC_Compute( SendBuf, 3 ); //计算CRC校验值
  54. SendBuf[3] = CRC16Temp & 0xFF; //CRC低位
  55. SendBuf[4] = ( CRC16Temp >> 8 ); //CRC高位
  56. usart_SendData( SendBuf, 5 );
  57. err = 0; //发送完数据后清除错误标志
  58. }
  59. }
  60. }
  61. }
  62. void Modbus_03_Slave( void )
  63. {
  64. u16 RegNum = 0;
  65. u16 CRC16Temp = 0;
  66. u8 i = 0;
  67. RegNum = ( u16 )( USART_RX_BUF[4] << 8 ) | USART_RX_BUF[5]; //获取寄存器数量
  68. if( ( StartRegAddr + RegNum ) <= (HoldRegStartAddr + HoldRegCount) ) //寄存器地址+寄存器数量 在规定范围内 <=8
  69. {
  70. SendBuf[0] = USART_RX_BUF[0]; //地址
  71. SendBuf[1] = USART_RX_BUF[1]; //功能码
  72. SendBuf[2] = RegNum * 2; //返回字节数量
  73. for( i = 0; i < RegNum; i++ ) //循环读取保持寄存器内的值
  74. {
  75. SendBuf[3 + i * 2] = HoldReg[StartRegAddr * 2 + i * 2];
  76. SendBuf[4 + i * 2] = HoldReg[StartRegAddr * 2 + i * 2 + 1];
  77. }
  78. CRC16Temp = CRC_Compute( SendBuf, RegNum * 2 + 3 ); //获取CRC校验值
  79. SendBuf[RegNum * 2 + 3] = CRC16Temp & 0xFF; //CRC低位
  80. SendBuf[RegNum * 2 + 4] = ( CRC16Temp >> 8 ); //CRC高位
  81. usart_SendData( SendBuf, RegNum * 2 + 5 );
  82. }
  83. else
  84. {
  85. err = 3; //寄存器数量不在规定范围内
  86. }
  87. }

第三部分

  1. void USART1_IRQHandler( void )
  2. {
  3. u8 tem = 0;
  4. if( USART_GetITStatus( USART1, USART_IT_RXNE ) != RESET ) //接收中断
  5. {
  6. tem = USART_ReceiveData( USART1 );
  7. if(USART_RX_CNT<USART_REC_LEN)
  8. {
  9. USART_RX_BUF[USART_RX_CNT]=tem;
  10. USART_RX_CNT++;
  11. }
  12. receiveOK_flag = 1; //置位数据接收完成标志位
  13. USART_ClearITPendingBit( USART1, USART_IT_RXNE );
  14. USART_ClearFlag(USART1,USART_FLAG_RXNE);
  15. }

第四部分
在这里插入图片描述

在这里插入图片描述
最后:想说的就是,我自己一开始看着还挺简单,然后做的时候出现很多问题,这边多次发送报错,那边发生不回复,还有发错一次,之后再发正确命令,无反应等等。还好解决了,如果需要例程,可以看看链接,就是这个的全部内容。
https://download.csdn.net/download/weixin\_45075787/15483014

发表评论

表情:
评论列表 (有 0 条评论,93人围观)

还没有评论,来说两句吧...

相关阅读

    相关 STM32经典例子

    本文以STM32F103R6为测试单片机 我们经常使用单片机完成一些工作,今天我写出的几个较为经典的例子希望能够帮助大家更好的认识单片机,更好的掌握STM32单片机的工作原理