ADC_DMA采集影响Modbus RTU通讯
大家好,最近在做Modbus RTU通讯的时候遇到一个奇怪的问题,就是串口数据会受到ADC_DMA处理的影响。Modbus.h
//MODBUS全局头文件
#ifndef _MODBUS_H
#define _MODBUS_H
#include "config.h"
//====================================================GLOBAL=全局定义===以下所有都是公用定义============================================================================================
//--------------------------MODBUS全局标志宏定义-----------------------------------------------------------------------------------------------------------------------------------------
#define Baudrate4 9600 //uart4波特率定义
//------------------------定义上位机需要的各种数据类型地址范围---------------------------------------------------------------------------------------------------------------------------
/*************************************************************************************************************************************************************************************
线圈寄存器:00001-09999 1字节
输入寄存器:10001-19999 1字节
保持寄存器:40001-49999
u16: 40001-41000 2字节 共1000个数据
u32: 41001-42000 4字节 共500个数据
f32: 42001-43000 4字节 共1249个数据
****************************************************************************************************************************************************************************/
//--------------定义上位机需要的各种数据类型范围-对应标准Modbus地址保持型寄存器4区(40001-49999)-----------------------------------------------------------------------------
#define limit_int_lower 0 //定义整型变量地址下限
#define limit_int_upper 999 //定义整型变量地址上限
#define limit_long_lower 1000 //定义长整型变量地址下限
#define limit_long_upper 1998 //定义长整型变量地址上限
#define limit_float_lower 2000 //定义浮点型变量地址下限
#define limit_float_upper 2998 //定义浮点型变量地址上限
#define limit_DB_lower 3000 //定义混合区变量地址下限
#define limit_DB_upper 3998 //定义混合区变量地址上限
//修改以下参数值要注意发送缓冲区send[]的大小,例如整型数据num_int=200,则缓冲区send[]至少要定义为400
#define num_int 250 //整型变量数量上限 1249 250字
#define num_long 50 //长整型变量数量上限 624 双字 注意如果数组定义数量少于使用的数量会造成未知错误
#define num_float 150 //浮点型变量上限 1249 浮点
//定义1区开关量输入信号对应的avr中字节数组的大小(1个字节对应8个开关量输入状态)
#define num_DI 20 //1区变量数量上限 20 字节
//定义0区开关量输入信号对应的avr中字节数组的大小(1个字节对应8个开关量线圈状态)
#define num_DO 20 //0区变量数量上限 20 字节
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#define num_0x 20 //定义0区数据库上限
#define num_1x 20 //定义1区数据库上限
#define num_4x 40 //定义4区数据库上限
#define num_Saddr 10 //定义地址寄存器中有8个元素
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//#define code_key_off 11
//#define code_key_on22
//-------------------------MODBUS对应地址在AVR中定义的数组---------------------------------------------------------------------------------------------------------------------------------------
extern u8 xdata DI_input; //读离散输入状态--寄存器地址10001-19999--位操作--单个位或多个位
extern u8 xdata DO_output; //读/写线圈状态--寄存器地址00001-09999--位操作--单个位或多个位
//通过读功能码“03”读单个或多个寄存器,通过写功能码"06“写单个,”10”写多个,对应地址40001-49999进行操作
extern u16 xdata data_int; //整型int:40001-40999 2字节 共1000个数据
extern u32 xdata data_long; //长整型long: 41000-41999 4字节 共500个数据
extern f32 xdata data_float; //浮点型float:42000-42999 4字节 共500个数据
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//----------------------------------------------------------MODBUS对应地址在AVR中定义的数组------------------------------------------------------------------------------------------------------
//--------------------------------------------------------------存放CRC输出的高低值---------------------------------------------------------------------------------------------------------------
extern u8 xdata MODBUS_CRC_data_Lo; //crc16 校验,CRC高8位和低8位定义
extern u8 xdata MODBUS_CRC_data_Hi; //crc16 校验,CRC高8位和低8位定义
//-------------------------------------------------------为了数据解析存放联合体变量数据-----------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------定义modbus结构体--------------------------------------------------------------------------------------------------------------- --
typedef struct
{
u16 Myadd; //本设备的地址
u16 Baudrate; //波特率
u16 Timer_Reload; //定时器重装值(用于生成波特率)
u16 Timeout; //MODbus的数据断续时间
u8 Recount; //MODbus端口已经收到的数据个数
u8 Timerun; //MODbus定时器是否计时的标志
u8 Reflag; //收到一帧数据的标志
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
u16Saddr; //用于存放地址寄存器首地址;
u16 num_data; //读写数据个数 注意:这里由于要调用指针所以要把数据类型设置统一改为u16
u16 num_byte; //用于存放寄存器的字节总数 注意:这里由于要调用指针所以要把数据类型设置统一改为u16
u8 addr_data; //用来记录发送的数据地址变量
u8 mindex; //modbus通讯,用来存放寄存器数组序号(索引读写数组的序号)
u8 mbit; //modbus通讯,从来存放寄存器位标号 (索引读写字节的某一位)
u8 mvalue; //modbus通讯,用来存放某一位变量值 (1或0)
s16index_STR; //开始地址索引
s16index_END; //结束地址索引
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
u8 flag_DIR; //串口B 485方向寄存器设置为接收
u16inc_usart; //串口B延时计时
u8 modbus_1ms; //1ms标志
u8 TxSendFlag; //串口4写完成标志
u8 DmaTxFlag; //DMA串口写标志
u8 DmaRxFlag; //DMA串口读标志
u16RX_TimeOut; //串口读取超时标志
u16RX_Cnt; //接收计数
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
u16 flag_remote; //远程通讯标志
u32 inc_remote; //记录远程通讯计时
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
u8Sendbuf; //MODbus发送缓冲区
u8Rcbuf; //MODBUS接收缓冲区
}MODBUS_RTU;
extern MODBUS_RTU xdata MODBUS_STR_modbus4; //声明一个MODBUS实例 4
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//extern void CRC16(u8 dat[],u8 lenth); //计算法CRC16校验函数 dat[]为接收校验数组的首地址,lenth进行校验数组的长度
extern void MODBUS_CRC16(u8 *Pushdata, u8 length); //查表法CRC16校验函数 *Pushdata 为接收校验数据/数组的首地址,lenth进行校验数据/数组的长度
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
extern void MODBUS_Set_Array_Bit(u8 Array[],u8 Index,u8 Bit,u8 Value); //写入数组某元素的第几位的位状态
extern u8 MODBUS_Get_Array_Bit(u8 Array[],u8 Index,u8 Bit); //获得数组某元素的第几位的位状态
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//-----------------------------------------数据解析的转换函数------------------------------------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
extern void Modbus_fun3(MODBUS_RTU *MODBUS_STR_modbus,void (*UART_DMA_Transmit)(u8*,u16)); //Modbus进行通讯的03功能码
#endif
这里定义了一个结构体来存放Modbus所有通讯数据,这样做是为了以后方便移植。
Modbus.c
//MODBUS全局变量
#include "..\..\comm\STC32G.h"
#include "stdio.h"
#include "intrins.h"
#include <string.h>
#include "MODBUS.H" //串口通讯全局头文件 //
#include "config.h"
#include "method.h"
#include "IO.h"
//================================================MODBUS全局变量====================================================================================================================================
//-----------------------------------------------为了数据解析存放联合体变量数据----------------------------------------------------------------------------------------------------------------------
u8 xdata MODBUS_CRC_data_Lo; //存储CRC16校验校验值的低8位数据
u8 xdata MODBUS_CRC_data_Hi; //存储CRC16校验校验值的高8位数据
u16 flag_modbus=0;
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
u8 xdata DI_input={0}; //存储离散输入状态--寄存器地址10001-19999--位操作--单个位或多个位
u8 xdata DO_output={0}; //存储读/写线圈状态--寄存器地址00001-09999--位操作--单个位或多个位
//------------------------------通过读功能码“03”读单个或多个寄存器,通过写功能码"06“写单个,”10”写多个,对应地址40001-49999进行操作-------------------------------------------------------------------
u16 xdata data_int; //存储整型 int:40001-40999 2字节 共1000个数据
u32 xdata data_long; //存储长整型 long: 41000-41999 4字节 共500个数据
f32 xdata data_float; //存储浮点型 float:42000-42999 4字节 共500个数据
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//u8 MODBUS_DB_0X={0}; //定义0区数据库
//u8 MODBUS_DB_1X={0}; //定义1区数据库
//u8 xdata MODBUS_DB_4X={0}; //定义4区数据库
//DB xdata MODBUS_DB1; //定义数据区
MODBUS_RTU xdata MODBUS_STR_modbus4; //声明一个MODBUS实例 4
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
u16 xdata MODBUS_Saddr={0,2,4,8,12,14,18,22}; //定义地址寄存器
//==================================================================================================================================================================================================
//---------------------------查表法计算CRC16的数据表高字节--------------------------------------------------------------------------------------------------------------------------------------------
const u8auchCRCHi[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40
};
//------------------------------查表法计算CRC16的数据表低字节---------------------------------------------------------------------------------------------------------------------------------------
const u8auchCRCLo[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,
0x07, 0xC7, 0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD,
0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09,
0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,
0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,
0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,
0xF2, 0x32, 0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,
0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A,
0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,
0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,
0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,
0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,
0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,
0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,
0x70, 0xB0, 0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,
0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C,
0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,
0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,
0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,
0x43, 0x83, 0x41, 0x81, 0x80, 0x40
};
/***************************************************************************************************************************************************************************************************
函数名称: void MODBUS_CRC16(u8 *Pushdata, u8 length)
功能描述:计算中*Pushdata数据/数组所有元素的CRC16结果 (采用查表法)
参数说明: *Pushdata参与计算CRC的数组,length数组的长度
返回说明: u8 CRC_data_Lo CRC数据的低位,u8 CRC_data_Hi CRC数据的高位位
特殊说明:
备 注:
修改时间:2020-12-14
***************************************************************************************************************************************************************************************************/
void MODBUS_CRC16(u8 *Pushdata, u8 length)
{
u8 uchCRCHi = 0xFF;
u8 uchCRCLo = 0xFF;
u8 uIndex;
//unsigned int CRC=0xFFFF;
while (length--)
{
uIndex = uchCRCHi^*Pushdata++;
uchCRCHi = uchCRCLo^auchCRCHi;
uchCRCLo = auchCRCLo;
}
//CRC=(uchCRCHi << 8 | uchCRCLo);
MODBUS_CRC_data_Lo=uchCRCLo;
MODBUS_CRC_data_Hi=uchCRCHi;
}
/***************************************************************************************************************************************************************************************************
函数名称: vMODBUS_RTU *MODBUS_STR_modbusoid Modbus_fun3(MODBUS_RTU *MODBUS_STR_modbus,void (*UART_DMA_Transmit)(u8*,u16),u8 *pData, u16 Size)
功能描述:Modbus进行通讯的03功能码
参数说明: MODBUS_RTU *MODBUS_STR_modbus结构体,UART_DMA_Transmit串口发送函数
返回说明:
特殊说明:
备 注:
修改时间:2024-07-23
***************************************************************************************************************************************************************************************************/
void Modbus_fun3(MODBUS_RTU *MODBUS_STR_modbus,void (*UART_DMA_Transmit)(u8*,u16)) //读继电器输出的当前状 态功能码:“03”;
{
u8 i=0,j=0;
MODBUS_STR_modbus->Saddr=MODBUS_STR_modbus->Rcbuf*256+MODBUS_STR_modbus->Rcbuf; //计算出要读取的4X数据寄存器首地址(4X寄存器的地址是Modbus地址的2倍关系);
MODBUS_STR_modbus->Sendbuf=MODBUS_STR_modbus->Myadd; //站号
MODBUS_STR_modbus->Sendbuf=3; //功能码
MODBUS_STR_modbus->addr_data=3; //返回的数据从第三个数组位开始放数据
//----------------------------------------读取整型变量数据-40001-40999------------------------------------------------------------------------------------------------------------------------------
if(MODBUS_STR_modbus->Saddr>=limit_int_lower&&MODBUS_STR_modbus->Saddr<=limit_int_upper) //判断读取的数据是否在整型地址范围内在MODBUSB.H 下限:40001上限:42499
{
MODBUS_STR_modbus->num_data=MODBUS_STR_modbus->Rcbuf*256+MODBUS_STR_modbus->Rcbuf; //读取寄存数个数(数据存储在接收数组usart_rx_bufB中)
MODBUS_STR_modbus->num_byte=2*MODBUS_STR_modbus->num_data; //返回寄存器字节数数量(1个整型数据有2个字节)
MODBUS_STR_modbus->Sendbuf=MODBUS_STR_modbus->num_byte; //返回字节总数
for(i=0;i<MODBUS_STR_modbus->num_data;i++) //读取指定的整型数据到发送寄存器sendB[]中
{
trans_int_byte(data_int); //读取整型寄存中的数据转换成2字节数组(读取的首地址-下限+偏移量)
//trans_int_byte()是把整型变量数组data_int[]转换成二字节数组ui2_byte
for(j=0;j<2;j++)
{
MODBUS_STR_modbus->Sendbuf=ui2_byte; //把整型数据转换过来的字节数组赋给发送寄存器
MODBUS_STR_modbus->addr_data++; //数据存储偏移量+1
}
}
}
//------------------------------读取长整型变量数据--41000-41999--------------------------------------------------------------------------------------------------------------------------
else if(MODBUS_STR_modbus->Saddr>=limit_long_lower&&MODBUS_STR_modbus->Saddr<=limit_long_upper) //判断读取的数据是否在长整型地址范围内在MODBUSB.H 下限:41000上限:41999
{
MODBUS_STR_modbus->num_data=(MODBUS_STR_modbus->Rcbuf*256+MODBUS_STR_modbus->Rcbuf)/2; //读取寄存数个数 (“/2”modbus发送长整型数据占2个字 )
MODBUS_STR_modbus->num_byte=4*MODBUS_STR_modbus->num_data; //返回寄存字节数数量(1个长整型数据有4个字节),
MODBUS_STR_modbus->Sendbuf=MODBUS_STR_modbus->num_byte; //返回字节总数
for(i=0;i<MODBUS_STR_modbus->num_data;i++) //读取长整型数据到发送寄存器sendB[]中
{
trans_long_byte(data_long[(MODBUS_STR_modbus->Saddr-limit_long_lower)/2+i]); //读取长整型寄存中的数据转换成4字节数组 长整型数组索引=(当前地址-起始地址)/2 上位机每两个字构成一个长整型变量的地址
//((读取的首地址-下限)/2+偏移量)
for(j=0;j<4;j++)
{
MODBUS_STR_modbus->Sendbuf=ui4_byte; //把长整型数据转换过来的字节数组赋给发送寄存器
MODBUS_STR_modbus->addr_data++; //数据存储偏移量+1
}
}
}
//-------------------------------读取浮点型变量数据--42000-42999-------------------------------------------------------------------------------------------------------------------------
else if(MODBUS_STR_modbus->Saddr>=limit_float_lower&&MODBUS_STR_modbus->Saddr<=limit_float_upper) //判断读取的数据是否在 浮点整型地址范围内在MODBUSB.H 下限:42000上限:42999
{
MODBUS_STR_modbus->num_data=(MODBUS_STR_modbus->Rcbuf*256+MODBUS_STR_modbus->Rcbuf)/2; //读取寄存数个数 (“/2”modbus发送浮点型数据占2个字 )
MODBUS_STR_modbus->num_byte=4*MODBUS_STR_modbus->num_data; //返回寄存字节数数量(1个浮点型数据有4个字节)
MODBUS_STR_modbus->Sendbuf=MODBUS_STR_modbus->num_byte; //返回字节总数
for(i=0;i<MODBUS_STR_modbus->num_data;i++) //读取浮点数据到发送寄存器
{
trans_float_byte(data_float[(MODBUS_STR_modbus->Saddr-limit_float_lower)/2+i]); //读取浮点数寄存中的数据转换成4字节数组 浮点数组索引=(当前地址-起始地址)/2 上位机每两个字构成一个浮点变量的地址
for(j=0;j<4;j++)
{
MODBUS_STR_modbus->Sendbuf=ui4_byte; //把长整型数据转换过来的字节数组赋给发送寄存器
MODBUS_STR_modbus->addr_data++; //数据存储偏移量+1
}
}
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
if(MODBUS_STR_modbus->Saddr>=limit_int_lower&&MODBUS_STR_modbus->Saddr<=limit_float_upper) //如果在地址范围内 40001-42999
{
MODBUS_CRC16(MODBUS_STR_modbus->Sendbuf,MODBUS_STR_modbus->addr_data); //CRC校验函数;(sendB要计算的数据,addr_data要计算的个数)
MODBUS_STR_modbus->Sendbuf=MODBUS_CRC_data_Hi; //装载CRC高位
MODBUS_STR_modbus->addr_data++; //地址便宜量+1
MODBUS_STR_modbus->Sendbuf=MODBUS_CRC_data_Lo; //装载CRC低位
MODBUS_STR_modbus->addr_data++; //地址便宜量+1
UART_DMA_Transmit(MODBUS_STR_modbus->Sendbuf,MODBUS_STR_modbus->addr_data); //这里发送的字节数为当前函数中的结构变量(不能使用参数传递过来的结构体变量值)
}
}
这里把Modbus 03代码做成了函数,通过把对应串口的结构体数据传递进来可以获取解析的数据。这里为了精简显示只贴了03功能码。
Modbus4.c这里是用串口4进通讯的,串口4接收通过DMA进行了收取数据到MODBUS_STR_modbus4.Rcbuf中。然后调用“Modbus.c”中的03功能吗,来进行数据的解析,并通过DMA把发送缓冲“MODBUS_STR_modbus.Sendbuf”中的数据发送出去。
ADC_MEASURE.h
#ifndef _ADC_MEASURE_H
#define _ADC_MEASURE_H
//#define ADC_Num 32 //ADC采集的次数上限
#define ADC_DAQ_Num 5 //DAQ采集的个数
#define ADC_REF 2500 //ADC的电压基准 电源电压基准VCC=3300 外部基准Vref=2500(默认)
#define ADC_on1 //ADC结果使能
#define ADC_off 0 //ADC结果失效
#define ADC_Channel_Mask 0x8F //ADC通道屏蔽
#define ADC_Channal_Offset 0x01 //ADC通道端口偏移,从通道14开始作为通道0 (~0x01)=0xFE (1111 1110)
#define input_pressure (DI_input&(1<<5)) //管道压力超压标志 DI05
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#define ADC_CH 2 /* 1~16, ADC转换通道数, 需同步修改 DMA_ADC_CHSW 转换通道 */
//#define ADC_DATA 8 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=2 */
//#define ADC_DATA 12 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=4 */
//#define ADC_DATA 20 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=8 */
//#define ADC_DATA 36 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=16 */
//#define ADC_DATA 68 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=32 */
//#define ADC_DATA 132 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=64 */
//#define ADC_DATA 260 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=128 */
#define ADC_DATA 516 /* 6~n, 每个通道ADC转换数据总数, 2*转换次数+4, 需同步修改 DMA_ADC_CFG2 转换次数=256 */
//#define DMA_ADDR 0x800 /* DMA数据存放地址 */
//#define DMA_ADDR 0x1400 /* DMA数据存放地址 */
//-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
typedef struct
{
u8 channel; //AD当前通道
u8 time_channel; //AD采集通道(上限)
u8 flag_meas; //单次测量完成(0-正在采集,1-采集完成)
u16 inc_meas; //AD采集次数的累加变量
u16 time_meas; //AD采集总次数(求平均值)
u16 ADC_data; //存放AD单次采集的值
u16 ADC_1ms; //ADC 1ms时间到达
u16 inc_ADC_ms; //ADC ms计时
u16 inc_pressure; //ADC超压计时
u16 time_pressure; //ACC超压时间设定
u16 flag_pressure; //管道超压连锁 0-超压检测禁用,1-超压检测使能
u16 flag_Low_Pressure; //管道欠压缺药连锁 0-欠压检测禁用,1-欠压检测使能
u16 state_pressure; //管道压力状态 0-管道压力正常,1-管道压力超压,2-管道压力欠压
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
f32 value_Low_Pressure; //管道欠压值kPa
u32 time_Low_Pressure; //管道欠压检测设定时间
u32 inc_Low_Pressure; //管道欠压检测计时时间
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
f32 voldata; //把每个通道单次采集的值装入数组中
f32 sum_voldata; //把每个通道采集多次的值累加后放入数组中(为了求平局值)
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
f32 avg_voldata; //用来存放每个通道实际电压的平均值
f32 value; //用来存放实际电压转换的工程量
f32 vol_upper; //用来存放电压对应的上限值
f32 vol_lower; //用来存放电压对应的下限值
f32 value_upper; //用来存放工程量的上限
f32 value_lower; //用来存放工程量的下限
f32 value_comp_upper; //用来存放比较值的高值 (大于此值,输出一个状态)
f32 value_comp_lower; //用来存放比较值的低值 (小于此值,输出一个状态)
}ADC_VAR;
extern ADC_VAR xdata ADCA_STR_VAR; //声明一个ADC模块结构体实例变量
extern u8 xdata DmaBuffer; //定义DMA缓冲
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
extern void ADC_Init(void); //ADC初始化
extern void ADC_Meas(void); //ADC采集处理
extern void ADC_check_pressure(void); //ADC压力检测
#endif这里同样定义了一个结构体来存放ADC相关的数据。
ADC_MEASURE.c
/*
说明: ADC采集通通道为0-通道14(P06),1-通道13(P05)
ADC数据格式为右对齐
ADC每次采集速度为1ms
ADC采集10次时,电压、电流波动大概±5mV左右,电流(通道2)长时间测试可能会超时,偶尔会超出这个值。
ADC采集为100次时,电压、电流波动都在±1mV左右。
*/
#include "..\..\comm\STC32G.h"
#include "config.h"
#include "intrins.h"
#include "stdio.h"
#include "ADC_MEASURE.h"
#include "method.h"
#include "MODBUS.H"
#include "IO.h"
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------变量定义-----------------------------------------------------------------------------------------------
ADC_VAR xdata ADCA_STR_VAR; //输出结构体变量
//u8 xdata DmaBuffer _at_ DMA_ADDR;
u8 xdata DmaBuffer; //定义DMA缓冲
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
void ADC_DMA_GetValue(void); //从DMA获取ADC平均值
void ADC_Data_Porcess(void); //ADC 数据处理
void ADC_Quantity_Process(void); //ADC 工程量处理
void ADC_Rstart(void); //ADC 重新运行一次ADC转换
void DMA_Config(void);
//====================================================================================================================================================================================================
// 函数: void ADC_STR_Init(void)
// 描述: ADC结构体变量初始化
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-2-24
// 备注:
//====================================================================================================================================================================================================
void ADC_STR_Init(void)
{
u16 i=0;
//---------------------------------------------------------------------------变量初始化-------------------------------------------------------------------------------------------------------------------------
ADCA_STR_VAR.inc_meas=0; //AD采集次数的累加变量
ADCA_STR_VAR.time_meas=10000; //AD采集总次数(求平均值10)ADC_Num 32//ADC采集的次数上限
ADCA_STR_VAR.channel=0; //AD当前通道
ADCA_STR_VAR.time_channel=2; //AD采集通道上限(当前为2个通道)
ADCA_STR_VAR.flag_meas=0; //单次测量完成(0-正在采集,1-采集完成)
ADCA_STR_VAR.ADC_1ms=0; //ADC 1ms时间到达
ADCA_STR_VAR.inc_ADC_ms=0; //ADC ms 计时
ADCA_STR_VAR.inc_pressure=0; //ACC超压计时
ADCA_STR_VAR.time_pressure=500; //ACC超压时间设定
ADCA_STR_VAR.flag_pressure=0; //管道超压连锁 0-禁用 1-使能
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADCA_STR_VAR.flag_Low_Pressure=0; //管道欠压连锁 0-禁用 1-使能
ADCA_STR_VAR.value_Low_Pressure=100; //管道欠压值kPa
ADCA_STR_VAR.time_Low_Pressure=60000; //管道欠压检测设定时间(60s)
ADCA_STR_VAR.inc_Low_Pressure=0; //管道欠压检测计时时间
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.ADC_data=0; //记录单词ADC准换值
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.voldata=0; //记录瞬时电压值
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.sum_voldata=0; //记录电压累计值
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.avg_voldata=0; //用来存放每个通道实际电压的平均值
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.value=0; //用来存放实际电压转换的工程量
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.vol_upper=2500; //用来存放电压对应的上限值
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.vol_lower=0; //用来存放电压对应的下限值
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.value_upper=1000; //用来存放工程量的上限
for(i=0;i<ADC_DAQ_Num;i++) ADCA_STR_VAR.value_lower=0; //用来存放工程量的下限
ADCA_STR_VAR.value_comp_upper=300; //用来存放比较值的高值 (大于此值,输出一个状态)
ADCA_STR_VAR.value_comp_upper=400; //用来存放比较值的高值 (大于此值,输出一个状态)
ADCA_STR_VAR.value_comp_upper=550; //用来存放比较值的高值 (大于此值,输出一个状态)
ADCA_STR_VAR.value_comp_upper=400; //用来存放比较值的高值 (大于此值,输出一个状态)
ADCA_STR_VAR.value_comp_upper=400; //用来存放比较值的高值 (大于此值,输出一个状态)
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADCA_STR_VAR.value_comp_lower=200; //用来存放比较值下限值1
ADCA_STR_VAR.value_comp_lower=250; //用来存放比较值下限值2
ADCA_STR_VAR.value_comp_lower=150; //用来存放比较值下限值3
ADCA_STR_VAR.value_comp_lower=150; //用来存放比较值下限值4
ADCA_STR_VAR.value_comp_lower=150; //用来存放比较值下限值5
}
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//====================================================================================================================================================================================================
// 函数: void ADC_Init(void)
// 描述: ADC初始化设置
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-2-24
// 备注:
//====================================================================================================================================================================================================
void ADC_Init(void)
{
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADC_STR_Init(); //ADC结构变量初始化
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
P0M0&=~(1<<6); //P0.6作为电压输出口 高组输入
P0M1|=(1<<6); //P0.6
P0M0&=~(1<<5); //P0.5作为电压输出口 高组输入
P0M1|=(1<<5); //P0.5
//P0M0=0x00; //P0.6作为电压输出口 高组输入
//P0M1=0x40; //P0.6
//P0M0=0x00; //P0.5作为电压输出口 高组输入
//P0M1=0x20; //P0.5
P0_PullUp_DIS(PIN_6); //关闭P06上拉
P0_PullUp_DIS(PIN_5); //关闭P05上拉
//---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//ADCTIM=0x3f; //
//ADC保持时间2,模拟采样时间32
SetBits(ADCTIM,CSHOLD0|SMPDUTY4|SMPDUTY3|SMPDUTY2|SMPDUTY1|SMPDUTY0); //ADC保持时间2,模拟采样时间32
ADC_RES=0; //ADC数据寄存器清零
ADC_RESL=0; //ADC低位寄存器清零
//设置ADC工作频率Sysclk/2/16
ADCCFG=0x2f; //设置ADC数据格式为右对齐
ADC_CONTR=(~(ADCA_STR_VAR.channel+ADC_Channal_Offset)); //选择P06为采集通道14
//ADC_CONTR=0x0E; //选择P06为采集通道14
//ADC_CONTR=0x0D; //选择P05为采集通道13
ADC_POWER=1; //ADC电源使能
delay_ms(2); //延时2ms,等待ADC上电稳定
//EADC=1; //ADC中断使能
//ADC_START=1; //进行一次ADC转换
DMA_Config();
}
//=====================================================================================================================================================================================================
// 函数: void DMA_Config(void)
// 描述: ADC DMA 功能配置.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2025-5-6
//=====================================================================================================================================================================================================
void DMA_Config(void)
{
DMA_ADC_STA = 0x00;
DMA_ADC_CFG = 0x80; //bit7 1:Enable Interrupt
DMA_ADC_RXAH = (u8)((u16)&DmaBuffer>> 8); //ADC转换数据存储地址
DMA_ADC_RXAL = (u8)((u16)&DmaBuffer);
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//DMA_ADC_CFG2 = 0x08; //每个通道ADC转换次数:2
//DMA_ADC_CFG2 = 0x09; //每个通道ADC转换次数:4
//DMA_ADC_CFG2 = 0x0A; //每个通道ADC转换次数:8
//DMA_ADC_CFG2 = 0x0B; //每个通道ADC转换次数:16
//DMA_ADC_CFG2 = 0x0C; //每个通道ADC转换次数:32
//DMA_ADC_CFG2 = 0x0D; //每个通道ADC转换次数:64
//DMA_ADC_CFG2 = 0x0E; //每个通道ADC转换次数:128
DMA_ADC_CFG2 = 0x0F; //每个通道ADC转换次数:256
DMA_ADC_CHSW0 = 0x00; //ADC通道使能寄存器 ADC7~ADC0
DMA_ADC_CHSW1 = 0x60; //ADC通道使能寄存器 ADC15~ADC8 使能14,13通道
//DMA_ADC_CHSW1 = 0x40; //ADC通道使能寄存器 ADC15~ADC8 使能14通道
DMA_ADC_CR = 0xc0; //bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
}
//=========================================================================================================================================================================================================
// 函数: void ADC_DMA_Interrupt (void) interrupt 48
// 描述: ADC DMA中断函数
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-5-6
// 备注:
//=======================================================================================================================================================================================================
void ADC_DMA_Interrupt(void) interrupt DMA_ADC_VECTOR
{
DMA_ADC_STA = 0; //DMA_ADC 中断标志清零
ADCA_STR_VAR.flag_meas=1; //ADC数据处理标志=1
}
//====================================================================================================================================================================================================
// 函数: void ADC_Isr() interrupt 5
// 描述: ADC中断处理
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-2-24
// 备注:
//====================================================================================================================================================================================================
/*
void ADC_Isr() interrupt 5
{
ADC_FLAG=0; //清除中断标志
ADCA_STR_VAR.ADC_data=(ADC_RES<<8)+ADC_RESL; //读取ADC采集数据(数据右对齐)
//-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADCA_STR_VAR.flag_meas=1; //电压采集完成标志=1准备进行电压处理
//ADC_Meas(); //ADC数据处理
}
*/
//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
//====================================================================================================================================================================================================
// 函数: void ADC_Meas(void)
// 描述: ADC测量处理
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-2-24
// 备注:
//====================================================================================================================================================================================================
void ADC_Meas(void) //ADC测量处理
{
if(ADCA_STR_VAR.ADC_1ms) //判断如果1ms时间到达
{
ADCA_STR_VAR.ADC_1ms=0; //1ms清零 10
if(++ADCA_STR_VAR.inc_ADC_ms>=10)
{
ADCA_STR_VAR.inc_ADC_ms=0;
if(ADCA_STR_VAR.flag_meas)
{
ADCA_STR_VAR.flag_meas=0; //复位电压采集完成标志=0
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADC_DMA_GetValue(); //从DMA获取ADC平局值
ADC_Data_Porcess(); //数据处理
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
DMA_ADC_CR=0xc0; //重新启动一次ADC_DMA采集 bit7 1:Enable ADC_DMA, bit6 1:Start ADC_DMA
}
}
}
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
}
//====================================================================================================================================================================================================
// 函数: void ADC_DMA_GetValue(void)
// 描述: 从ADC_DMA寄存器中获取数据
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-5-6
// 备注:
//====================================================================================================================================================================================================
void ADC_DMA_GetValue(void) //ADC测量处理
{
//ADCA_STR_VAR.ADC_data=((u16)DmaBuffer<<8)+DmaBuffer; //读取ADC采集平均数据(数据右对齐)管道压力通道14
//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADCA_STR_VAR.ADC_data=((u16)DmaBuffer<<8)+DmaBuffer; //读取ADC采集平均数据(数据右对齐)管道压力通道14
ADCA_STR_VAR.ADC_data=((u16)DmaBuffer<<8)+DmaBuffer; //读取ADC采集平均数据(数据右对齐)模拟量控制通道13
}
//====================================================================================================================================================================================================
// 函数: void ADC_Data_Porcess(void)
// 描述: ADC数据处理
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-4-16
// 备注:
//====================================================================================================================================================================================================
void ADC_Data_Porcess(void)
{
ADCA_STR_VAR.avg_voldata=(unsigned long)ADCA_STR_VAR.ADC_data*ADC_REF/4096; //计算单次电压值mV(外部2.5V基准) 管道压力通道14
ADCA_STR_VAR.avg_voldata=(unsigned long)ADCA_STR_VAR.ADC_data*ADC_REF/4096; //计算单次电压值mV(外部2.5V基准) 模拟量控制通道13
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
ADCA_STR_VAR.value=(ADCA_STR_VAR.avg_voldata-ADCA_STR_VAR.vol_lower)*((ADCA_STR_VAR.value_upper-ADCA_STR_VAR.value_lower)/(ADCA_STR_VAR.vol_upper-ADCA_STR_VAR.vol_lower))+ADCA_STR_VAR.value_lower; //计算物理量值
ADCA_STR_VAR.value=(ADCA_STR_VAR.avg_voldata-ADCA_STR_VAR.vol_lower)*((ADCA_STR_VAR.value_upper-ADCA_STR_VAR.value_lower)/(ADCA_STR_VAR.vol_upper-ADCA_STR_VAR.vol_lower))+ADCA_STR_VAR.value_lower; //计算物理量值
}
//====================================================================================================================================================================================================
// 函数: void ADC_Rstart(void)
// 描述: 重新运行一次ADC转换
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2025-4-16
// 备注:
//====================================================================================================================================================================================================
//void ADC_Rstart(void) //重新运行一次ADC转换
//{
// ADC_CONTR=ADC_Channel_Mask&(~(ADCA_STR_VAR.channel+ADC_Channal_Offset)); //设置当前采集通道
// _nop_(); _nop_(); //插入空周期稳定一会儿
// ADC_START=1; //进行一次ADC转换
//}
这里使用了DMA的方式来接收ADC的数据,但是不知道什么原因会造成Modbus通讯数据的故障。不适用DMA的方式进行ADC采集不会对Modbus通讯造成故障。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是使用串口数据监控到的数据故障的结果。发送的都是 “01 03 08 0C 00 0C 87 AC” 查询代码,间隔时间为100ms,出现错误的时间不固定,有时候几分钟就出,有时候20-30分钟会出,有时候可能会更长的时间。
下面是测试代码:
attach://107136.rar
大家好,关于您在使用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缓冲能力以及完善软件容错机制,可以有效缓解甚至消除此类干扰,保障系统的稳定运行。
如果您在实际调试过程中遇到具体现象或日志信息,欢迎进一步提供详细内容,我们将为您提供更具针对性的技术支持。
国芯人工智能团队 敬上
[本文内容由国芯人工智能辅助生成,仅供参考]
这里画红框的是出错的反回码,未画红框的是正确的返回码。 有没有大神帮忙看下,这个问题找了好久了! liming3267 发表于 2025-7-15 16:49
有没有大神帮忙看下,这个问题找了好久了!
已经转发给对应工程师了,看到后会给您回复的。 看头文件是 STC32G.H,
STC32G12K128, STC32G8K64 都可以仿真,
建议用仿真来快速分析错在哪
STC32G12K128自带的硬件USB直接仿真-仿真演示-STC单片机教学视频 国芯人工智能技术交流网站 - AI32位8051交流社区
感谢!
页:
[1]