找回密码
 立即注册
查看: 90|回复: 3

ADC_DMA采集影响Modbus RTU通讯

[复制链接]
  • 打卡等级:偶尔看看III
  • 打卡总天数:35
  • 最近打卡:2025-07-15 16:41:25

8

主题

8

回帖

210

积分

中级会员

积分
210
发表于 2025-7-3 19:22:24 | 显示全部楼层 |阅读模式
大家好,最近在做Modbus RTU通讯的时候遇到一个奇怪的问题,就是串口数据会受到ADC_DMA处理的影响。

  1. Modbus.h
  2. //MODBUS全局头文件
  3. #ifndef _MODBUS_H
  4. #define _MODBUS_H        
  5. #include "config.h"
  6. //====================================================GLOBAL=全局定义===以下所有都是公用定义============================================================================================
  7. //--------------------------MODBUS全局标志宏定义-----------------------------------------------------------------------------------------------------------------------------------------
  8. #define Baudrate4   9600                                                                                                                                                                                //uart4波特率定义
  9. //------------------------定义上位机需要的各种数据类型地址范围---------------------------------------------------------------------------------------------------------------------------
  10. /*************************************************************************************************************************************************************************************
  11. 线圈寄存器:00001-09999       1字节
  12. 输入寄存器:10001-19999       1字节
  13. 保持寄存器:40001-49999
  14. u16: 40001-41000              2字节      共1000个数据
  15. u32: 41001-42000              4字节      共500个数据
  16. f32: 42001-43000              4字节      共1249个数据
  17. ****************************************************************************************************************************************************************************/
  18. //--------------定义上位机需要的各种数据类型范围-对应标准Modbus地址保持型寄存器4区(40001-49999)-----------------------------------------------------------------------------
  19. #define limit_int_lower        0                                                                                                                                                                   //定义整型变量地址下限
  20. #define limit_int_upper      999                                                                                                                                                                   //定义整型变量地址上限
  21. #define limit_long_lower    1000                                                                                                                                                                   //定义长整型变量地址下限
  22. #define limit_long_upper    1998                                                                                                                                                                   //定义长整型变量地址上限
  23. #define limit_float_lower   2000                                                                                                                                                                   //定义浮点型变量地址下限
  24. #define limit_float_upper   2998                                                                                                                                                                   //定义浮点型变量地址上限
  25. #define limit_DB_lower      3000                                                                                                                                                                   //定义混合区变量地址下限
  26. #define limit_DB_upper      3998                                                                                                                                                                   //定义混合区变量地址上限
  27. //修改以下参数值要注意发送缓冲区send[]的大小,例如整型数据num_int=200,则缓冲区send[]至少要定义为400
  28. #define num_int 250                                                                                                                                                          //整型变量数量上限 1249        250  字
  29. #define num_long 50                                                                                                                                                                //长整型变量数量上限 624       双字   注意如果数组定义数量少于使用的数量会造成未知错误
  30. #define num_float 150                                                                                                                                                              //浮点型变量上限 1249          浮点
  31. //定义1区开关量输入信号对应的avr中字节数组的大小(1个字节对应8个开关量输入状态)
  32. #define num_DI 20                                                                                                                                                           //1区变量数量上限 20                字节
  33. //定义0区开关量输入信号对应的avr中字节数组的大小(1个字节对应8个开关量线圈状态)
  34. #define num_DO 20                                                                                                                                                                 //0区变量数量上限 20                字节
  35. //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  36. #define num_0x 20                                                                                                                                                               //定义0区数据库上限
  37. #define num_1x 20                                                                                                                                                       //定义1区数据库上限                        
  38. #define num_4x 40                                                                                                                                                       //定义4区数据库上限
  39. #define num_Saddr 10                                                                                                                                                    //定义地址寄存器中有8个元素   
  40. //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  41. //#define code_key_off 11
  42. //#define code_key_on  22
  43. //-------------------------MODBUS对应地址在AVR中定义的数组---------------------------------------------------------------------------------------------------------------------------------------
  44. extern u8 xdata DI_input[num_DI];                                                                                                                                                       //读离散输入状态--寄存器地址10001-19999--位操作--单个位或多个位
  45. extern u8 xdata DO_output[num_DO];                                                                                                                                                                 //读/写线圈状态--寄存器地址00001-09999--位操作--单个位或多个位
  46. //通过读功能码“03”读单个或多个寄存器,通过写功能码"06“写单个,”10”写多个,对应地址40001-49999进行操作
  47. extern u16 xdata data_int[num_int];                                                                                                                                            //整型int:  40001-40999           2字节      共1000个数据
  48. extern u32 xdata data_long[num_long];                                                                                                                                          //长整型long: 41000-41999         4字节      共500个数据
  49. extern f32 xdata data_float[num_float];                                                                                                                                       //浮点型float:42000-42999         4字节      共500个数据
  50. //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  51. //----------------------------------------------------------MODBUS对应地址在AVR中定义的数组------------------------------------------------------------------------------------------------------
  52. //--------------------------------------------------------------存放CRC输出的高低值---------------------------------------------------------------------------------------------------------------
  53. extern u8 xdata MODBUS_CRC_data_Lo;                                                                                                                                     //crc16 校验,CRC高8位和低8位定义
  54. extern u8 xdata MODBUS_CRC_data_Hi;                                                                                                                                     //crc16 校验,CRC高8位和低8位定义
  55. //-------------------------------------------------------为了数据解析存放联合体变量数据-----------------------------------------------------------------------------------------------------------
  56. //----------------------------------------------------------------定义modbus结构体---------------------------------------------------------------------------------------------------------------                      --
  57. typedef struct
  58. {
  59.     u16   Myadd;                                                                                                                    //本设备的地址
  60.         u16   Baudrate;                                                                                                                                                                                                //波特率               
  61.         u16          Timer_Reload;                                                                                                                                                                                        //定时器重装值(用于生成波特率)
  62.        
  63.         u16   Timeout;                                                                                                                  //MODbus的数据断续时间                      
  64.     u8    Recount;                                                                                                                  //MODbus端口已经收到的数据个数
  65.     u8    Timerun;                                                                                                                  //MODbus定时器是否计时的标志
  66.     u8    Reflag;                                                                                                                   //收到一帧数据的标志
  67. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------      
  68.     u16  Saddr;                                                                                                                     //用于存放地址寄存器首地址;
  69.     u16   num_data;                                                                                                                       //读写数据个数 注意:这里由于要调用指针所以要把数据类型设置统一改为u16
  70.     u16   num_byte;                                                                                                                       //用于存放寄存器的字节总数 注意:这里由于要调用指针所以要把数据类型设置统一改为u16
  71.     u8   addr_data;                                                                                                                       //用来记录发送的数据地址变量
  72.    
  73.         u8   mindex;                                                                                                                           //modbus通讯,用来存放寄存器数组序号(索引读写数组的序号)
  74.     u8   mbit;                                                                                                                      //modbus通讯,从来存放寄存器位标号   (索引读写字节的某一位)
  75.     u8   mvalue;                                                                                                                           //modbus通讯,用来存放某一位变量值    (1或0)
  76.     s16  index_STR;                                                                                                                 //开始地址索引
  77.     s16  index_END;                                                                                                                 //结束地址索引      
  78. //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  79.         u8          flag_DIR;                                                                                                                                                                                  //串口B 485方向寄存器设置为接收
  80.         u16  inc_usart;                                                                                                                                                                                 //串口B延时计时
  81.         u8   modbus_1ms;                                                                                                                                                                                       //1ms标志
  82.         u8   TxSendFlag;                                                                                                                                                                                        //串口4写完成标志
  83.         u8         DmaTxFlag;                                                                                                                                                                                                //DMA串口写标志
  84.         u8         DmaRxFlag;                                                                                                                                                                                                //DMA串口读标志
  85.         u16  RX_TimeOut;                                                                                                                                                                                        //串口读取超时标志
  86.         u16  RX_Cnt;                                                                                                                                                                                            //接收计数
  87. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------       
  88.         u16 flag_remote;                                                                                                                                                                                        //远程通讯标志
  89.         u32 inc_remote;                                                                                                                                                                                                //记录远程通讯计时
  90. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  91.     u8  Sendbuf[256];                                                                                                                //MODbus发送缓冲区
  92.         u8  Rcbuf[256];                                                                                                                       //MODBUS接收缓冲区
  93. }MODBUS_RTU;
  94. extern MODBUS_RTU xdata MODBUS_STR_modbus4;                                                                                                                       //声明一个MODBUS实例 4                                                                     
  95. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  96. //extern void CRC16(u8 dat[],u8 lenth);                                                                                                                                         //计算法CRC16校验函数 dat[]为接收校验数组的首地址,lenth进行校验数组的长度
  97. extern void MODBUS_CRC16(u8 *Pushdata, u8 length);                                                                                                                  //查表法CRC16校验函数 *Pushdata 为接收校验数据/数组的首地址,lenth进行校验数据/数组的长度
  98. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  99. extern void MODBUS_Set_Array_Bit(u8 Array[],u8 Index,u8 Bit,u8 Value);                                                                                                                   //写入数组某元素的第几位的位状态
  100. extern u8 MODBUS_Get_Array_Bit(u8 Array[],u8 Index,u8 Bit);                                                                                                                     //获得数组某元素的第几位的位状态
  101. //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  102. //-----------------------------------------数据解析的转换函数------------------------------------------------------------------------------------------------------------------------------------                                                                                                                                               
  103. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  104. extern void Modbus_fun3(MODBUS_RTU *MODBUS_STR_modbus,void (*UART_DMA_Transmit)(u8*,u16));                                                                                //Modbus进行通讯的03功能码
  105. #endif
复制代码
这里定义了一个结构体来存放Modbus所有通讯数据,这样做是为了以后方便移植。

  1. Modbus.c
  2. //MODBUS全局变量
  3. #include "..\..\comm\STC32G.h"
  4. #include "stdio.h"
  5. #include "intrins.h"
  6. #include <string.h>
  7. #include "MODBUS.H"                                                          //串口通讯全局头文件                                                       //
  8. #include "config.h"
  9. #include "method.h"
  10. #include "IO.h"
  11. //================================================MODBUS全局变量====================================================================================================================================
  12. //-----------------------------------------------为了数据解析存放联合体变量数据----------------------------------------------------------------------------------------------------------------------
  13. u8 xdata MODBUS_CRC_data_Lo;                                                                      //存储CRC16校验校验值的低8位数据
  14. u8 xdata MODBUS_CRC_data_Hi;                                                                      //存储CRC16校验校验值的高8位数据
  15. u16 flag_modbus=0;       
  16. //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  17. u8 xdata DI_input[num_DI]={0};                                               //存储离散输入状态--寄存器地址10001-19999--位操作--单个位或多个位
  18. u8 xdata DO_output[num_DO]={0};                                                 //存储读/写线圈状态--寄存器地址00001-09999--位操作--单个位或多个位
  19. //------------------------------通过读功能码“03”读单个或多个寄存器,通过写功能码"06“写单个,”10”写多个,对应地址40001-49999进行操作-------------------------------------------------------------------
  20. u16 xdata data_int[num_int];                                               //存储整型 int:  40001-40999             2字节      共1000个数据
  21. u32 xdata data_long[num_long];                                               //存储长整型 long: 41000-41999           4字节      共500个数据
  22. f32 xdata data_float[num_float];                                              //存储浮点型 float:42000-42999           4字节      共500个数据
  23. //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  24. //u8 MODBUS_DB_0X[num_0x]={0};                                                        //定义0区数据库
  25. //u8 MODBUS_DB_1X[num_1x]={0};                                           //定义1区数据库
  26. //u8 xdata MODBUS_DB_4X[num_4x]={0};                                     //定义4区数据库
  27. //DB xdata MODBUS_DB1;                                            //定义数据区
  28. MODBUS_RTU xdata MODBUS_STR_modbus4;                                 //声明一个MODBUS实例 4
  29. //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  30. u16 xdata MODBUS_Saddr[num_Saddr]={0,2,4,8,12,14,18,22};                  //定义地址寄存器
  31. //==================================================================================================================================================================================================
  32. //---------------------------查表法计算CRC16的数据表高字节--------------------------------------------------------------------------------------------------------------------------------------------
  33. const u8  auchCRCHi[] = {
  34.     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  35.     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  36.     0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  37.     0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  38.     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  39.     0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
  40.     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  41.     0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  42.     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  43.     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  44.     0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  45.     0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  46.     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  47.     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  48.     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  49.     0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
  50.     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  51.     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  52.     0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  53.     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  54.     0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
  55.     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
  56.     0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
  57.     0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
  58.     0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
  59.     0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
  60. };
  61. //------------------------------查表法计算CRC16的数据表低字节---------------------------------------------------------------------------------------------------------------------------------------
  62. const u8  auchCRCLo[] = {
  63.     0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
  64.     0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
  65.     0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
  66.     0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
  67.     0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
  68.     0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
  69.     0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
  70.     0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
  71.     0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
  72.     0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
  73.     0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
  74.     0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
  75.     0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
  76.     0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
  77.     0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
  78.     0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
  79.     0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
  80.     0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
  81.     0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
  82.     0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
  83.     0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
  84.     0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
  85.     0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
  86.     0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
  87.     0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
  88.     0x43, 0x83, 0x41, 0x81, 0x80, 0x40
  89. };
  90. /***************************************************************************************************************************************************************************************************
  91. 函数名称: void MODBUS_CRC16(u8 *Pushdata, u8 length)
  92. 功能描述:  计算中*Pushdata数据/数组所有元素的CRC16结果 (采用查表法)
  93. 参数说明: *Pushdata参与计算CRC的数组,length数组的长度
  94. 返回说明: u8 CRC_data_Lo CRC数据的低位,u8 CRC_data_Hi CRC数据的高位位
  95. 特殊说明:
  96. 备    注:
  97. 修改时间:2020-12-14
  98. ***************************************************************************************************************************************************************************************************/
  99. void MODBUS_CRC16(u8 *Pushdata, u8 length)
  100. {
  101.     u8 uchCRCHi = 0xFF;
  102.     u8 uchCRCLo = 0xFF;
  103.     u8 uIndex;
  104.     //unsigned int CRC=0xFFFF;
  105.     while (length--)
  106.     {
  107. uIndex = uchCRCHi^*Pushdata++;
  108.         uchCRCHi = uchCRCLo^auchCRCHi[uIndex];
  109.         uchCRCLo = auchCRCLo[uIndex];
  110.     }
  111.     //CRC=(uchCRCHi << 8 | uchCRCLo);
  112.     MODBUS_CRC_data_Lo=uchCRCLo;
  113.     MODBUS_CRC_data_Hi=uchCRCHi;
  114. }
  115. /***************************************************************************************************************************************************************************************************
  116. 函数名称: vMODBUS_RTU *MODBUS_STR_modbusoid Modbus_fun3(MODBUS_RTU *MODBUS_STR_modbus,void (*UART_DMA_Transmit)(u8*,u16),u8 *pData, u16 Size)
  117. 功能描述:  Modbus进行通讯的03功能码
  118. 参数说明: MODBUS_RTU *MODBUS_STR_modbus结构体,UART_DMA_Transmit串口发送函数
  119. 返回说明:
  120. 特殊说明:
  121. 备    注:
  122. 修改时间:2024-07-23
  123. ***************************************************************************************************************************************************************************************************/
  124. void Modbus_fun3(MODBUS_RTU *MODBUS_STR_modbus,void (*UART_DMA_Transmit)(u8*,u16))                                                                                                            //读继电器输出的当前状 态功能码:“03”;
  125. {
  126.     u8 i=0,j=0;   
  127.        
  128.     MODBUS_STR_modbus->Saddr=MODBUS_STR_modbus->Rcbuf[2]*256+MODBUS_STR_modbus->Rcbuf[3];                                                                                                  //计算出要读取的4X数据寄存器首地址(4X寄存器的地址是Modbus地址的2倍关系);
  129.     MODBUS_STR_modbus->Sendbuf[0]=MODBUS_STR_modbus->Myadd;                                                                                                                                                       //站号
  130.        
  131.         MODBUS_STR_modbus->Sendbuf[1]=3;                                                                                                                                                                                           //功能码
  132.     MODBUS_STR_modbus->addr_data=3;                                                                                                                                                                                                //返回的数据从第三个数组位开始放数据
  133. //----------------------------------------读取整型变量数据-40001-40999------------------------------------------------------------------------------------------------------------------------------
  134.     if(MODBUS_STR_modbus->Saddr>=limit_int_lower&&MODBUS_STR_modbus->Saddr<=limit_int_upper)                                                                                            //判断读取的数据是否在整型地址范围内在MODBUSB.H 下限:40001上限:42499
  135.     {
  136.         MODBUS_STR_modbus->num_data=MODBUS_STR_modbus->Rcbuf[4]*256+MODBUS_STR_modbus->Rcbuf[5];                                                                                 //读取寄存数个数(数据存储在接收数组usart_rx_bufB中)
  137.         MODBUS_STR_modbus->num_byte=2*MODBUS_STR_modbus->num_data;                                                                                                              //返回寄存器字节数数量(1个整型数据有2个字节)
  138.         MODBUS_STR_modbus->Sendbuf[2]=MODBUS_STR_modbus->num_byte;                                                                                                                //返回字节总数
  139.         for(i=0;i<MODBUS_STR_modbus->num_data;i++)                                                                                                       //读取指定的整型数据到发送寄存器sendB[]中
  140.         {
  141.             trans_int_byte(data_int[MODBUS_STR_modbus->Saddr-limit_int_lower+i]);                                                                                   //读取整型寄存中的数据转换成2字节数组(读取的首地址-下限+偏移量)
  142.                                                                                                                                                                                                                                                                                 //trans_int_byte()是把整型变量数组data_int[]转换成二字节数组ui2_byte
  143.             for(j=0;j<2;j++)
  144.             {
  145.                 MODBUS_STR_modbus->Sendbuf[MODBUS_STR_modbus->addr_data]=ui2_byte[j];                                                                                                //把整型数据转换过来的字节数组赋给发送寄存器
  146.                 MODBUS_STR_modbus->addr_data++;                                                                                                     //数据存储偏移量+1
  147.             }
  148.         }
  149.     }
  150. //------------------------------读取长整型变量数据--41000-41999--------------------------------------------------------------------------------------------------------------------------           
  151.     else if(MODBUS_STR_modbus->Saddr>=limit_long_lower&&MODBUS_STR_modbus->Saddr<=limit_long_upper)                                                                 //判断读取的数据是否在长整型地址范围内在MODBUSB.H 下限:41000上限:41999
  152.     {
  153.         MODBUS_STR_modbus->num_data=(MODBUS_STR_modbus->Rcbuf[4]*256+MODBUS_STR_modbus->Rcbuf[5])/2;                                                                         //读取寄存数个数 (“/2”modbus发送长整型数据占2个字 )
  154.         MODBUS_STR_modbus->num_byte=4*MODBUS_STR_modbus->num_data;                                                                                                                      //返回寄存字节数数量(1个长整型数据有4个字节),
  155.         MODBUS_STR_modbus->Sendbuf[2]=MODBUS_STR_modbus->num_byte;                                                                                                                         //返回字节总数
  156.         for(i=0;i<MODBUS_STR_modbus->num_data;i++)                                                                                                                 //读取长整型数据到发送寄存器sendB[]中
  157.         {
  158.             trans_long_byte(data_long[(MODBUS_STR_modbus->Saddr-limit_long_lower)/2+i]);                                                                                              //读取长整型寄存中的数据转换成4字节数组       长整型数组索引=(当前地址-起始地址)/2    上位机每两个字构成一个长整型变量的地址
  159.                                                                                                                                                                                                                                                                                 //((读取的首地址-下限)/2+偏移量)
  160.             for(j=0;j<4;j++)
  161.             {
  162.                 MODBUS_STR_modbus->Sendbuf[MODBUS_STR_modbus->addr_data]=ui4_byte[j];                                                                                                    //把长整型数据转换过来的字节数组赋给发送寄存器
  163.                 MODBUS_STR_modbus->addr_data++;                                                                                                     //数据存储偏移量+1
  164.             }
  165.         }
  166.     }
  167. //-------------------------------读取浮点型变量数据--42000-42999-------------------------------------------------------------------------------------------------------------------------
  168.     else if(MODBUS_STR_modbus->Saddr>=limit_float_lower&&MODBUS_STR_modbus->Saddr<=limit_float_upper)                                                                          //判断读取的数据是否在 浮点整型地址范围内在MODBUSB.H 下限:42000上限:42999
  169.     {
  170.         MODBUS_STR_modbus->num_data=(MODBUS_STR_modbus->Rcbuf[4]*256+MODBUS_STR_modbus->Rcbuf[5])/2;                                                                         //读取寄存数个数 (“/2”modbus发送浮点型数据占2个字 )
  171.         MODBUS_STR_modbus->num_byte=4*MODBUS_STR_modbus->num_data;                                                                                                                          //返回寄存字节数数量(1个浮点型数据有4个字节)
  172.         MODBUS_STR_modbus->Sendbuf[2]=MODBUS_STR_modbus->num_byte;                                                                                                                             //返回字节总数
  173.         for(i=0;i<MODBUS_STR_modbus->num_data;i++)                                                                                                                   //读取浮点数据到发送寄存器
  174.         {
  175.             trans_float_byte(data_float[(MODBUS_STR_modbus->Saddr-limit_float_lower)/2+i]);                                                                                                //读取浮点数寄存中的数据转换成4字节数组         浮点数组索引=(当前地址-起始地址)/2     上位机每两个字构成一个浮点变量的地址
  176.                        
  177.                         for(j=0;j<4;j++)
  178.             {
  179.                 MODBUS_STR_modbus->Sendbuf[MODBUS_STR_modbus->addr_data]=ui4_byte[j];                                                                                                    //把长整型数据转换过来的字节数组赋给发送寄存器                               
  180.                                 MODBUS_STR_modbus->addr_data++;                                                                                                     //数据存储偏移量+1
  181.             }
  182.         }
  183.     }
  184. //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  185.     if(MODBUS_STR_modbus->Saddr>=limit_int_lower&&MODBUS_STR_modbus->Saddr<=limit_float_upper)                                                         //如果在地址范围内     40001-42999
  186.     {
  187.         MODBUS_CRC16(MODBUS_STR_modbus->Sendbuf,MODBUS_STR_modbus->addr_data);                                                                      //CRC校验函数;(sendB要计算的数据,addr_data要计算的个数)
  188.         MODBUS_STR_modbus->Sendbuf[MODBUS_STR_modbus->addr_data]=MODBUS_CRC_data_Hi;                                                                //装载CRC高位
  189.         MODBUS_STR_modbus->addr_data++;                                                                                                                                                            //地址便宜量+1
  190.         MODBUS_STR_modbus->Sendbuf[MODBUS_STR_modbus->addr_data]=MODBUS_CRC_data_Lo;                                                                //装载CRC低位
  191.         MODBUS_STR_modbus->addr_data++;                                                                                                                                                             //地址便宜量+1
  192.                
  193.                 UART_DMA_Transmit(MODBUS_STR_modbus->Sendbuf,MODBUS_STR_modbus->addr_data);                                                                                                                //这里发送的字节数为当前函数中的结构变量(不能使用参数传递过来的结构体变量值)
  194.         }
  195. }
复制代码
这里把Modbus 03代码做成了函数,通过把对应串口的结构体数据传递进来可以获取解析的数据。这里为了精简显示只贴了03功能码。

  1. Modbus4.c
复制代码
这里是用串口4进通讯的,串口4接收通过DMA进行了收取数据到MODBUS_STR_modbus4.Rcbuf中。然后调用“Modbus.c”中的03功能吗,来进行数据的解析,并通过DMA把发送缓冲“MODBUS_STR_modbus.Sendbuf”中的数据发送出去。
  1. ADC_MEASURE.h
  2. #ifndef _ADC_MEASURE_H
  3. #define _ADC_MEASURE_H
  4. //#define ADC_Num 32                                                                                                 //ADC采集的次数上限
  5. #define ADC_DAQ_Num 5                                                                                               //DAQ采集的个数
  6. #define ADC_REF 2500                                                                                                                //ADC的电压基准   电源电压基准VCC=3300 外部基准Vref=2500(默认)       
  7. #define ADC_on  1                                                                                                                        //ADC结果使能                               
  8. #define ADC_off 0                                                                                                                        //ADC结果失效
  9. #define ADC_Channel_Mask   0x8F                                                                                                //ADC通道屏蔽                                
  10. #define ADC_Channal_Offset 0x01                                                                                                //ADC通道端口偏移,从通道14开始作为通道0 (~0x01)=0xFE (1111 1110)
  11. #define input_pressure        (DI_input[0]&(1<<5))                                                                //管道压力超压标志 DI05
  12. //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  13. #define        ADC_CH                2                        /* 1~16, ADC转换通道数, 需同步修改 DMA_ADC_CHSW 转换通道 */
  14. //#define        ADC_DATA        8                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=2 */
  15. //#define        ADC_DATA        12                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=4 */
  16. //#define        ADC_DATA        20                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=8 */
  17. //#define        ADC_DATA        36                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=16 */
  18. //#define        ADC_DATA        68                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=32 */
  19. //#define        ADC_DATA        132                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=64 */
  20. //#define        ADC_DATA        260                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=128 */
  21. #define        ADC_DATA                516                        /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=256 */
  22. //#define        DMA_ADDR        0x800                /* DMA数据存放地址 */
  23. //#define        DMA_ADDR        0x1400                /* DMA数据存放地址 */
  24. //-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  25. typedef struct                                                                                                                                          
  26. {   
  27.     u8 channel;                                                                                       //AD当前通道   
  28.     u8 time_channel;                                                                                       //AD采集通道(上限)
  29.     u8 flag_meas;                                                                                    //单次测量完成(0-正在采集,1-采集完成)         
  30.     u16 inc_meas;                                                                                //AD采集次数的累加变量
  31.     u16 time_meas;                                                                                     //AD采集总次数(求平均值)
  32.     u16 ADC_data[ADC_DAQ_Num];                                                                       //存放AD单次采集的值
  33.         u16        ADC_1ms;                                                                                                                        //ADC 1ms时间到达       
  34.         u16 inc_ADC_ms;                                                                                                                        //ADC ms计时       
  35.         u16 inc_pressure;                                                                                                                //ADC超压计时                       
  36.     u16 time_pressure;                                                                                                                //ACC超压时间设定               
  37.         u16 flag_pressure;                                                                                                                //管道超压连锁 0-超压检测禁用,1-超压检测使能
  38.         u16 flag_Low_Pressure;                                                                                                        //管道欠压缺药连锁 0-欠压检测禁用,1-欠压检测使能
  39.         u16 state_pressure;                                                                                                                //管道压力状态 0-管道压力正常,1-管道压力超压,2-管道压力欠压                                       
  40. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  41.         f32 value_Low_Pressure;                                                                                                        //管道欠压值kPa
  42.         u32 time_Low_Pressure;                                                                                                        //管道欠压检测设定时间
  43.         u32 inc_Low_Pressure;                                                                                                        //管道欠压检测计时时间                                         
  44. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------       
  45.         f32 voldata[ADC_DAQ_Num];                                                                         //把每个通道单次采集的值装入数组中
  46.     f32 sum_voldata[ADC_DAQ_Num];                                                                        //把每个通道采集多次的值累加后放入数组中(为了求平局值)
  47. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  48.     f32 avg_voldata[ADC_DAQ_Num];                                                                        //用来存放每个通道实际电压的平均值
  49.     f32 value[ADC_DAQ_Num];                                                                           //用来存放实际电压转换的工程量
  50.     f32 vol_upper[ADC_DAQ_Num];                                                                            //用来存放电压对应的上限值
  51.     f32 vol_lower[ADC_DAQ_Num];                                                                            //用来存放电压对应的下限值
  52.     f32 value_upper[ADC_DAQ_Num];                                                                        //用来存放工程量的上限
  53.     f32 value_lower[ADC_DAQ_Num];                                                                        //用来存放工程量的下限
  54.     f32 value_comp_upper[ADC_DAQ_Num];                                                                             //用来存放比较值的高值 (大于此值,输出一个状态)
  55.     f32 value_comp_lower[ADC_DAQ_Num];                                                                             //用来存放比较值的低值 (小于此值,输出一个状态)
  56. }ADC_VAR;                                               
  57. extern ADC_VAR xdata ADCA_STR_VAR;                                                                                   //声明一个ADC模块结构体实例变量
  58. extern u8 xdata DmaBuffer[ADC_CH][ADC_DATA];                                                                //定义DMA缓冲
  59. //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  60. extern void ADC_Init(void);                                                                                                        //ADC初始化                               
  61. extern void ADC_Meas(void);                                                                                                        //ADC采集处理
  62. extern void ADC_check_pressure(void);                                                                                //ADC压力检测               
  63. #endif
复制代码
这里同样定义了一个结构体来存放ADC相关的数据。

  1. ADC_MEASURE.c
  2. /*
  3. 说明:        ADC采集通通道为0-通道14(P06),1-通道13(P05)
  4.                 ADC数据格式为右对齐
  5.                 ADC每次采集速度为1ms
  6.                 ADC采集10次时,电压、电流波动大概±5mV左右,电流(通道2)长时间测试可能会超时,偶尔会超出这个值。
  7.                 ADC采集为100次时,电压、电流波动都在±1mV左右。
  8. */
  9. #include "..\..\comm\STC32G.h"
  10. #include "config.h"
  11. #include "intrins.h"
  12. #include "stdio.h"
  13. #include "ADC_MEASURE.h"
  14. #include "method.h"
  15. #include "MODBUS.H"
  16. #include "IO.h"
  17. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  18. //------------------------------------------------------------------------------------------------------变量定义-----------------------------------------------------------------------------------------------
  19. ADC_VAR xdata ADCA_STR_VAR;                                                                                                                                            //输出结构体变量   
  20. //u8 xdata DmaBuffer[ADC_CH][ADC_DATA] _at_ DMA_ADDR;
  21. u8 xdata DmaBuffer[ADC_CH][ADC_DATA];                                                                                                                                        //定义DMA缓冲               
  22. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  23. void ADC_DMA_GetValue(void);                                                                                                                                                        //从DMA获取ADC平均值       
  24. void ADC_Data_Porcess(void);                                                                                                                                                        //ADC 数据处理
  25. void ADC_Quantity_Process(void);                                                                                                                                                //ADC 工程量处理
  26. void ADC_Rstart(void);                                                                                                                                                                        //ADC 重新运行一次ADC转换
  27. void DMA_Config(void);
  28. //====================================================================================================================================================================================================
  29. // 函数: void ADC_STR_Init(void)
  30. // 描述: ADC结构体变量初始化
  31. // 参数: none.
  32. // 返回: none.
  33. // 版本: VER1.0
  34. // 日期: 2025-2-24
  35. // 备注:
  36. //====================================================================================================================================================================================================
  37. void ADC_STR_Init(void)
  38. {       
  39.         u16 i=0;       
  40. //---------------------------------------------------------------------------变量初始化-------------------------------------------------------------------------------------------------------------------------
  41.     ADCA_STR_VAR.inc_meas=0;                                                                                                                                      //AD采集次数的累加变量
  42.     ADCA_STR_VAR.time_meas=10000;                                                                                                                            //AD采集总次数(求平均值10)  ADC_Num 32  //ADC采集的次数上限
  43.     ADCA_STR_VAR.channel=0;                                                                                                                                      //AD当前通道
  44.     ADCA_STR_VAR.time_channel=2;                                                                                                                                 //AD采集通道上限(当前为2个通道)
  45.         ADCA_STR_VAR.flag_meas=0;                                                                                                                                    //单次测量完成(0-正在采集,1-采集完成)  
  46.     ADCA_STR_VAR.ADC_1ms=0;                                                                                                                                                                //ADC 1ms时间到达                       
  47.         ADCA_STR_VAR.inc_ADC_ms=0;                                                                                                                                                        //ADC ms 计时       
  48.         ADCA_STR_VAR.inc_pressure=0;                                                                                                                                                //ACC超压计时       
  49.         ADCA_STR_VAR.time_pressure=500;                                                                                                                                                //ACC超压时间设定
  50.         ADCA_STR_VAR.flag_pressure=0;                                                                                                                                                //管道超压连锁        0-禁用        1-使能
  51. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  52.         ADCA_STR_VAR.flag_Low_Pressure=0;                                                                                                                                        //管道欠压连锁        0-禁用        1-使能        
  53.         ADCA_STR_VAR.value_Low_Pressure=100;                                                                                                                                //管道欠压值kPa
  54.         ADCA_STR_VAR.time_Low_Pressure=60000;                                                                                                                                //管道欠压检测设定时间(60s)
  55.         ADCA_STR_VAR.inc_Low_Pressure=0;                                                                                                                                        //管道欠压检测计时时间       
  56. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  57.     for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.ADC_data[i]=0;                                                                                                //记录单词ADC准换值                       
  58.         for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.voldata[i]=0;                                                                                                //记录瞬时电压值
  59.         for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.sum_voldata[i]=0;                                                                                        //记录电压累计值
  60. //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------       
  61.         for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.avg_voldata[i]=0;                                                                         //用来存放每个通道实际电压的平均值
  62.     for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.value[i]=0;                                                                            //用来存放实际电压转换的工程量
  63.     for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.vol_upper[i]=2500;                                                                      //用来存放电压对应的上限值
  64.     for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.vol_lower[i]=0;                                                                                //用来存放电压对应的下限值
  65.     for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.value_upper[i]=1000;                                                                           //用来存放工程量的上限
  66.     for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.value_lower[i]=0;                                                                        //用来存放工程量的下限
  67.     ADCA_STR_VAR.value_comp_upper[0]=300;                                                                                                                             //用来存放比较值的高值 (大于此值,输出一个状态)
  68.     ADCA_STR_VAR.value_comp_upper[1]=400;                                                                                                                             //用来存放比较值的高值 (大于此值,输出一个状态)
  69.     ADCA_STR_VAR.value_comp_upper[2]=550;                                                                                                                             //用来存放比较值的高值 (大于此值,输出一个状态)
  70.     ADCA_STR_VAR.value_comp_upper[3]=400;                                                                                                                             //用来存放比较值的高值 (大于此值,输出一个状态)
  71.     ADCA_STR_VAR.value_comp_upper[4]=400;                                                                                                                             //用来存放比较值的高值 (大于此值,输出一个状态)                                                   
  72. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------   
  73.     ADCA_STR_VAR.value_comp_lower[0]=200;                                                                                                                    //用来存放比较值下限值1      
  74.     ADCA_STR_VAR.value_comp_lower[1]=250;                                                                                                                    //用来存放比较值下限值2
  75.     ADCA_STR_VAR.value_comp_lower[2]=150;                                                                                                                    //用来存放比较值下限值3     
  76.     ADCA_STR_VAR.value_comp_lower[3]=150;                                                                                                                    //用来存放比较值下限值4
  77.     ADCA_STR_VAR.value_comp_lower[4]=150;                                                                                                                    //用来存放比较值下限值5
  78. }
  79. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  80. //====================================================================================================================================================================================================
  81. // 函数: void ADC_Init(void)
  82. // 描述: ADC初始化设置
  83. // 参数: none.
  84. // 返回: none.
  85. // 版本: VER1.0
  86. // 日期: 2025-2-24
  87. // 备注:
  88. //====================================================================================================================================================================================================
  89. void ADC_Init(void)                                                                       
  90. {
  91. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  92.         ADC_STR_Init();                                                                                                                                                                                //ADC结构变量初始化
  93. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------       
  94.         P0M0&=~(1<<6);                                                                                                                                                                                //P0.6作为电压输出口        高组输入
  95.         P0M1|=(1<<6);                                                                                                                                                                                //P0.6
  96.         P0M0&=~(1<<5);                                                                                                                                                                             //P0.5作为电压输出口        高组输入
  97.         P0M1|=(1<<5);                                                                                                                                                                                //P0.5
  98.        
  99.         //P0M0=0x00;                                                                                                                                                                                //P0.6作为电压输出口        高组输入
  100.         //P0M1=0x40;                                                                                                                                                                                //P0.6       
  101.         //P0M0=0x00;                                                                                                                                                                                //P0.5作为电压输出口        高组输入
  102.         //P0M1=0x20;                                                                                                                                                                                //P0.5       
  103.        
  104.         P0_PullUp_DIS(PIN_6);                                                                                                                                                                //关闭P06上拉
  105.         P0_PullUp_DIS(PIN_5);                                                                                                                                                                //关闭P05上拉       
  106. //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  107.         //ADCTIM=0x3f;                                                                                                                                                                                //                                                               
  108.         //ADC保持时间2,模拟采样时间32
  109.         SetBits(ADCTIM,CSHOLD0|SMPDUTY4|SMPDUTY3|SMPDUTY2|SMPDUTY1|SMPDUTY0);                                                                //ADC保持时间2,模拟采样时间32
  110.         ADC_RES=0;                                                                                                                                                                                          //ADC数据寄存器清零
  111.         ADC_RESL=0;                                                                                                                                                                                        //ADC低位寄存器清零                       
  112.         //设置ADC工作频率Sysclk/2/16
  113.         ADCCFG=0x2f;                                                                                                                                                                                //设置ADC数据格式为右对齐                       
  114.         ADC_CONTR=(~(ADCA_STR_VAR.channel+ADC_Channal_Offset));                                                                                                //选择P06为采集通道14
  115.         //ADC_CONTR=0x0E;                                                                                                                                                                        //选择P06为采集通道14
  116.         //ADC_CONTR=0x0D;                                                                                                                                                                        //选择P05为采集通道13   
  117.         ADC_POWER=1;                                                                                                                                                                                //ADC电源使能
  118.         delay_ms(2);                                                                                                                                                                                //延时2ms,等待ADC上电稳定       
  119.         //EADC=1;                                                                                                                                                                                                //ADC中断使能
  120.         //ADC_START=1;                                                                                                                                                                                //进行一次ADC转换
  121.        
  122.         DMA_Config();
  123. }
  124. //=====================================================================================================================================================================================================
  125. // 函数: void DMA_Config(void)
  126. // 描述: ADC DMA 功能配置.
  127. // 参数: none.
  128. // 返回: none.
  129. // 版本: V1.0, 2025-5-6
  130. //=====================================================================================================================================================================================================
  131. void DMA_Config(void)
  132. {
  133.         DMA_ADC_STA = 0x00;
  134.         DMA_ADC_CFG = 0x80;                //bit7 1:Enable Interrupt
  135.         DMA_ADC_RXAH = (u8)((u16)&DmaBuffer>> 8);        //ADC转换数据存储地址
  136.         DMA_ADC_RXAL = (u8)((u16)&DmaBuffer);
  137. //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------       
  138.         //DMA_ADC_CFG2 = 0x08;        //每个通道ADC转换次数:2
  139.         //DMA_ADC_CFG2 = 0x09;        //每个通道ADC转换次数:4
  140.         //DMA_ADC_CFG2 = 0x0A;        //每个通道ADC转换次数:8
  141.         //DMA_ADC_CFG2 = 0x0B;        //每个通道ADC转换次数:16
  142.        
  143.         //DMA_ADC_CFG2 = 0x0C;        //每个通道ADC转换次数:32
  144.         //DMA_ADC_CFG2 = 0x0D;        //每个通道ADC转换次数:64
  145.         //DMA_ADC_CFG2 = 0x0E;        //每个通道ADC转换次数:128
  146.         DMA_ADC_CFG2 = 0x0F;        //每个通道ADC转换次数:256
  147.        
  148.         DMA_ADC_CHSW0 = 0x00;        //ADC通道使能寄存器 ADC7~ADC0
  149.         DMA_ADC_CHSW1 = 0x60;        //ADC通道使能寄存器 ADC15~ADC8 使能14,13通道
  150.         //DMA_ADC_CHSW1 = 0x40;        //ADC通道使能寄存器 ADC15~ADC8 使能14通道
  151.         DMA_ADC_CR = 0xc0;                //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
  152. }
  153. //=========================================================================================================================================================================================================
  154. // 函数: void ADC_DMA_Interrupt (void) interrupt 48
  155. // 描述: ADC DMA中断函数
  156. // 参数: none.
  157. // 返回: none.
  158. // 版本: VER1.0
  159. // 日期: 2025-5-6
  160. // 备注:
  161. //=======================================================================================================================================================================================================
  162. void ADC_DMA_Interrupt(void) interrupt DMA_ADC_VECTOR
  163. {
  164.         DMA_ADC_STA = 0;                                                                                        //DMA_ADC 中断标志清零
  165.         ADCA_STR_VAR.flag_meas=1;                                                                        //ADC数据处理标志=1
  166. }
  167. //====================================================================================================================================================================================================
  168. // 函数: void ADC_Isr() interrupt 5
  169. // 描述: ADC中断处理
  170. // 参数: none.
  171. // 返回: none.
  172. // 版本: VER1.0
  173. // 日期: 2025-2-24
  174. // 备注:
  175. //====================================================================================================================================================================================================
  176. /*
  177. void ADC_Isr() interrupt 5
  178. {
  179.         ADC_FLAG=0;                                                                                                                                                                                        //清除中断标志
  180.         ADCA_STR_VAR.ADC_data=(ADC_RES<<8)+ADC_RESL;                                                                                                                //读取ADC采集数据(数据右对齐)
  181. //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------               
  182.         ADCA_STR_VAR.flag_meas=1;                                                                                                                                      //电压采集完成标志=1准备进行电压处理   
  183.         //ADC_Meas();                                                                                                                                                                                //ADC数据处理
  184. }       
  185. */
  186. //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  187. //====================================================================================================================================================================================================
  188. // 函数: void ADC_Meas(void)       
  189. // 描述: ADC测量处理
  190. // 参数: none.
  191. // 返回: none.
  192. // 版本: VER1.0
  193. // 日期: 2025-2-24
  194. // 备注:
  195. //====================================================================================================================================================================================================
  196. void ADC_Meas(void)                                                                                                                                                                                        //ADC测量处理
  197. {
  198.         if(ADCA_STR_VAR.ADC_1ms)                                                                                                                                                                //判断如果1ms时间到达       
  199.         {
  200.                 ADCA_STR_VAR.ADC_1ms=0;                                                                                                                                                                //1ms清零        10                                                                                                                                                                                               
  201.                 if(++ADCA_STR_VAR.inc_ADC_ms>=10)
  202.                 {               
  203.                         ADCA_STR_VAR.inc_ADC_ms=0;
  204.                         if(ADCA_STR_VAR.flag_meas)                                                                                                                                                       
  205.                         {       
  206.                                 ADCA_STR_VAR.flag_meas=0;                                                                                                                                            //复位电压采集完成标志=0         
  207. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  208.                                 ADC_DMA_GetValue();                                                                                                                                                                //从DMA获取ADC平局值
  209.                                 ADC_Data_Porcess();                                                                                                                                                                //数据处理
  210. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  211.                                 DMA_ADC_CR=0xc0;                                                                                                                                                                //重新启动一次ADC_DMA采集 bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA       
  212.                         }       
  213.                 }
  214.         }
  215. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------                     
  216. }
  217. //====================================================================================================================================================================================================
  218. // 函数: void ADC_DMA_GetValue(void)
  219. // 描述: 从ADC_DMA寄存器中获取数据
  220. // 参数: none.
  221. // 返回: none.
  222. // 版本: VER1.0
  223. // 日期: 2025-5-6
  224. // 备注:
  225. //====================================================================================================================================================================================================
  226. void ADC_DMA_GetValue(void)                                                                                                                                                                                //ADC测量处理
  227. {       
  228.         //ADCA_STR_VAR.ADC_data[0]=((u16)DmaBuffer[0][ADC_DATA-2]<<8)+DmaBuffer[0][ADC_DATA-1];                                                //读取ADC采集平均数据(数据右对齐)管道压力通道14
  229. //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------       
  230.         ADCA_STR_VAR.ADC_data[0]=((u16)DmaBuffer[1][ADC_DATA-2]<<8)+DmaBuffer[1][ADC_DATA-1];                                                //读取ADC采集平均数据(数据右对齐)管道压力通道14       
  231.         ADCA_STR_VAR.ADC_data[1]=((u16)DmaBuffer[0][ADC_DATA-2]<<8)+DmaBuffer[0][ADC_DATA-1];                                                //读取ADC采集平均数据(数据右对齐)模拟量控制通道13                       
  232. }
  233. //====================================================================================================================================================================================================
  234. // 函数: void ADC_Data_Porcess(void)       
  235. // 描述: ADC数据处理
  236. // 参数: none.
  237. // 返回: none.
  238. // 版本: VER1.0
  239. // 日期: 2025-4-16
  240. // 备注:
  241. //====================================================================================================================================================================================================
  242. void ADC_Data_Porcess(void)
  243. {
  244.         ADCA_STR_VAR.avg_voldata[0]=(unsigned long)ADCA_STR_VAR.ADC_data[0]*ADC_REF/4096;           //计算单次电压值mV(外部2.5V基准) 管道压力通道14
  245.         ADCA_STR_VAR.avg_voldata[1]=(unsigned long)ADCA_STR_VAR.ADC_data[1]*ADC_REF/4096;           //计算单次电压值mV(外部2.5V基准) 模拟量控制通道13       
  246. //------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  247.         ADCA_STR_VAR.value[0]=(ADCA_STR_VAR.avg_voldata[0]-ADCA_STR_VAR.vol_lower[0])*((ADCA_STR_VAR.value_upper[0]-ADCA_STR_VAR.value_lower[0])/(ADCA_STR_VAR.vol_upper[0]-ADCA_STR_VAR.vol_lower[0]))+ADCA_STR_VAR.value_lower[0];    //计算物理量值
  248.         ADCA_STR_VAR.value[1]=(ADCA_STR_VAR.avg_voldata[1]-ADCA_STR_VAR.vol_lower[1])*((ADCA_STR_VAR.value_upper[1]-ADCA_STR_VAR.value_lower[1])/(ADCA_STR_VAR.vol_upper[1]-ADCA_STR_VAR.vol_lower[1]))+ADCA_STR_VAR.value_lower[1];    //计算物理量值
  249. }       
  250. //====================================================================================================================================================================================================
  251. // 函数: void ADC_Rstart(void)       
  252. // 描述: 重新运行一次ADC转换
  253. // 参数: none.
  254. // 返回: none.
  255. // 版本: VER1.0
  256. // 日期: 2025-4-16
  257. // 备注:
  258. //====================================================================================================================================================================================================
  259. //void ADC_Rstart(void)                                                                                                                                                                                                                                    //重新运行一次ADC转换
  260. //{
  261. //        ADC_CONTR=ADC_Channel_Mask&(~(ADCA_STR_VAR.channel+ADC_Channal_Offset));                                                                                                                    //设置当前采集通道                                                                                                                       
  262. //        _nop_(); _nop_();                                                                                                                                                                                                                                        //插入空周期稳定一会儿
  263. //        ADC_START=1;                                                                                                                                                                                                                                                //进行一次ADC转换
  264. //}       
  265.        
复制代码
这里使用了DMA的方式来接收ADC的数据,但是不知道什么原因会造成Modbus通讯数据的故障。不适用DMA的方式进行ADC采集不会对Modbus通讯造成故障。

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是使用串口数据监控到的数据故障的结果。发送的都是 “01 03 08 0C 00 0C 87 AC” 查询代码,间隔时间为100ms,出现错误的时间不固定,有时候几分钟就出,有时候20-30分钟会出,有时候可能会更长的时间。
1.png              2.png

下面是测试代码:
Modbus DMA_ADC功能测试 2025-7-3-10.rar (256.76 KB, 下载次数: 2)
https://www.stcaimcu.com/forum.php?mod=attachment&aid=MTA3MTM2fGIwNjk2MTBmfDE3NTI2MzE4ODd8MHw%3D



回复

使用道具 举报 送花

3

主题

385

回帖

-519

积分

等待验证会员

积分
-519
发表于 2025-7-3 19:23:00 | 显示全部楼层
大家好,关于您在使用Modbus RTU通信时遇到的串口数据受ADCDMA处理影响的问题,我们非常理解您的困扰。以下是我们对这一问题的专业分析及建议。

首先,从系统架构的角度来看,ADC(模数转换)与UART(通用异步收发传输器)作为嵌入式系统中常见的外设模块,通常由不同的DMA(直接内存访问)通道进行数据传输。当ADC通过DMA采集数据时,如果未合理配置DMA优先级或资源分配,确实可能对其他外设(如UART)的数据传输造成干扰,尤其是在高负载或实时性要求较高的场景下。

一、问题原因分析

1. DMA通道冲突  
   在许多嵌入式平台中,多个外设共享相同的DMA控制器,而每个DMA通道具有不同的优先级。若ADC和UART使用了同一DMA通道或相近的优先级设置,可能会导致UART在接收或发送数据时被中断,从而引发数据丢失或误码。

2. CPU资源竞争  
   当ADC通过DMA进行高速数据采集时,虽然DMA本身不占用CPU资源,但如果ADC的DMA传输频繁触发中断(如每帧数据结束时),可能会间接影响到UART的中断响应时间,进而影响Modbus RTU的通信稳定性。

3. 波特率与时序匹配问题  
   Modbus RTU协议对通信时序有严格要求,特别是在帧间隔(Frame Interval)和字符间隔(Character Interval)方面。如果ADC DMA操作导致UART的接收缓冲区未能及时处理数据,可能导致帧解析错误,进而引发通信失败。

4. 硬件设计限制  
   某些MCU的UART和ADC可能共用部分硬件资源(如时钟源、引脚等)。若ADC采集频率过高,可能对UART的时钟稳定性产生一定影响,尤其在低功耗模式下更为明显。

二、解决方案建议

1. 优化DMA配置  
为ADC和UART分别分配独立的DMA通道,并设置合理的优先级。通常建议将UART的DMA请求优先级设为“高”或“中”,以确保其通信不受ADC采集的干扰。
若无法分配独立通道,可尝试调整DMA的仲裁策略,确保UART的DMA请求在ADC传输期间仍能获得足够的响应机会。

2. 减少ADC DMA中断频率  
如果ADC采集频率较高且不需要实时处理,可考虑降低采样率或采用双缓冲机制,避免频繁触发DMA中断,从而减少对UART的干扰。
使用DMA完成中断而非每帧中断,可以降低系统开销,提升整体效率。

3. 增加UART接收缓冲区大小  
增加UART接收缓冲区的长度,可以在ADC DMA操作期间暂存更多数据,防止因数据积压而导致丢包或解析错误。
同时,可结合软件定时器检测帧间隔,确保Modbus RTU的通信时序符合规范。

4. 检查时钟源稳定性  
确保ADC和UART所使用的时钟源稳定可靠,避免因时钟抖动或漂移导致通信异常。
如有必要,可启用外部晶振或使用更高精度的时钟源,以提升系统整体的可靠性。

5. 软件层面的容错处理  
在Modbus RTU协议实现中,增加错误校验机制(如CRC校验),并在接收到数据后进行完整性判断,防止因通信异常导致的逻辑错误。
对于关键数据,可设置重传机制,提高系统的鲁棒性。

三、总结

综上所述,ADCDMA采集对Modbus RTU通信的影响主要源于DMA资源竞争、CPU调度延迟及通信时序匹配等问题。通过合理配置DMA通道、优化ADC采集策略、增强UART缓冲能力以及完善软件容错机制,可以有效缓解甚至消除此类干扰,保障系统的稳定运行。

如果您在实际调试过程中遇到具体现象或日志信息,欢迎进一步提供详细内容,我们将为您提供更具针对性的技术支持。

国芯人工智能团队 敬上

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:35
  • 最近打卡:2025-07-15 16:41:25

8

主题

8

回帖

210

积分

中级会员

积分
210
发表于 2025-7-3 19:26:17 | 显示全部楼层
截图202507031924352623.jpg
这里画红框的是出错的反回码,未画红框的是正确的返回码。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:偶尔看看III
  • 打卡总天数:35
  • 最近打卡:2025-07-15 16:41:25

8

主题

8

回帖

210

积分

中级会员

积分
210
发表于 昨天 16:49 | 显示全部楼层
有没有大神帮忙看下,这个问题找了好久了!
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-7-16 10:11 , Processed in 0.120521 second(s), 69 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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