大家好,最近在做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_on 22
- //-------------------------MODBUS对应地址在AVR中定义的数组---------------------------------------------------------------------------------------------------------------------------------------
- extern u8 xdata DI_input[num_DI]; //读离散输入状态--寄存器地址10001-19999--位操作--单个位或多个位
- extern u8 xdata DO_output[num_DO]; //读/写线圈状态--寄存器地址00001-09999--位操作--单个位或多个位
- //通过读功能码“03”读单个或多个寄存器,通过写功能码"06“写单个,”10”写多个,对应地址40001-49999进行操作
- extern u16 xdata data_int[num_int]; //整型int: 40001-40999 2字节 共1000个数据
- extern u32 xdata data_long[num_long]; //长整型long: 41000-41999 4字节 共500个数据
- extern f32 xdata data_float[num_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; //收到一帧数据的标志
- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- u16 Saddr; //用于存放地址寄存器首地址;
- u16 num_data; //读写数据个数 注意:这里由于要调用指针所以要把数据类型设置统一改为u16
- u16 num_byte; //用于存放寄存器的字节总数 注意:这里由于要调用指针所以要把数据类型设置统一改为u16
- u8 addr_data; //用来记录发送的数据地址变量
-
- u8 mindex; //modbus通讯,用来存放寄存器数组序号(索引读写数组的序号)
- u8 mbit; //modbus通讯,从来存放寄存器位标号 (索引读写字节的某一位)
- u8 mvalue; //modbus通讯,用来存放某一位变量值 (1或0)
- s16 index_STR; //开始地址索引
- s16 index_END; //结束地址索引
- //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- u8 flag_DIR; //串口B 485方向寄存器设置为接收
- u16 inc_usart; //串口B延时计时
- u8 modbus_1ms; //1ms标志
- u8 TxSendFlag; //串口4写完成标志
- u8 DmaTxFlag; //DMA串口写标志
- u8 DmaRxFlag; //DMA串口读标志
- u16 RX_TimeOut; //串口读取超时标志
- u16 RX_Cnt; //接收计数
- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- u16 flag_remote; //远程通讯标志
- u32 inc_remote; //记录远程通讯计时
- //----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- u8 Sendbuf[256]; //MODbus发送缓冲区
- u8 Rcbuf[256]; //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[num_DI]={0}; //存储离散输入状态--寄存器地址10001-19999--位操作--单个位或多个位
- u8 xdata DO_output[num_DO]={0}; //存储读/写线圈状态--寄存器地址00001-09999--位操作--单个位或多个位
- //------------------------------通过读功能码“03”读单个或多个寄存器,通过写功能码"06“写单个,”10”写多个,对应地址40001-49999进行操作-------------------------------------------------------------------
- u16 xdata data_int[num_int]; //存储整型 int: 40001-40999 2字节 共1000个数据
- u32 xdata data_long[num_long]; //存储长整型 long: 41000-41999 4字节 共500个数据
- f32 xdata data_float[num_float]; //存储浮点型 float:42000-42999 4字节 共500个数据
- //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- //u8 MODBUS_DB_0X[num_0x]={0}; //定义0区数据库
- //u8 MODBUS_DB_1X[num_1x]={0}; //定义1区数据库
- //u8 xdata MODBUS_DB_4X[num_4x]={0}; //定义4区数据库
- //DB xdata MODBUS_DB1; //定义数据区
-
- MODBUS_RTU xdata MODBUS_STR_modbus4; //声明一个MODBUS实例 4
- //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- u16 xdata MODBUS_Saddr[num_Saddr]={0,2,4,8,12,14,18,22}; //定义地址寄存器
- //==================================================================================================================================================================================================
- //---------------------------查表法计算CRC16的数据表高字节--------------------------------------------------------------------------------------------------------------------------------------------
- const u8 auchCRCHi[] = {
- 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 u8 auchCRCLo[] = {
- 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[uIndex];
- uchCRCLo = auchCRCLo[uIndex];
- }
- //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[2]*256+MODBUS_STR_modbus->Rcbuf[3]; //计算出要读取的4X数据寄存器首地址(4X寄存器的地址是Modbus地址的2倍关系);
- MODBUS_STR_modbus->Sendbuf[0]=MODBUS_STR_modbus->Myadd; //站号
-
- MODBUS_STR_modbus->Sendbuf[1]=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[4]*256+MODBUS_STR_modbus->Rcbuf[5]; //读取寄存数个数(数据存储在接收数组usart_rx_bufB中)
- MODBUS_STR_modbus->num_byte=2*MODBUS_STR_modbus->num_data; //返回寄存器字节数数量(1个整型数据有2个字节)
- MODBUS_STR_modbus->Sendbuf[2]=MODBUS_STR_modbus->num_byte; //返回字节总数
- for(i=0;i<MODBUS_STR_modbus->num_data;i++) //读取指定的整型数据到发送寄存器sendB[]中
- {
- trans_int_byte(data_int[MODBUS_STR_modbus->Saddr-limit_int_lower+i]); //读取整型寄存中的数据转换成2字节数组(读取的首地址-下限+偏移量)
- //trans_int_byte()是把整型变量数组data_int[]转换成二字节数组ui2_byte
- for(j=0;j<2;j++)
- {
- MODBUS_STR_modbus->Sendbuf[MODBUS_STR_modbus->addr_data]=ui2_byte[j]; //把整型数据转换过来的字节数组赋给发送寄存器
- 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[4]*256+MODBUS_STR_modbus->Rcbuf[5])/2; //读取寄存数个数 (“/2”modbus发送长整型数据占2个字 )
- MODBUS_STR_modbus->num_byte=4*MODBUS_STR_modbus->num_data; //返回寄存字节数数量(1个长整型数据有4个字节),
- MODBUS_STR_modbus->Sendbuf[2]=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[MODBUS_STR_modbus->addr_data]=ui4_byte[j]; //把长整型数据转换过来的字节数组赋给发送寄存器
- 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[4]*256+MODBUS_STR_modbus->Rcbuf[5])/2; //读取寄存数个数 (“/2”modbus发送浮点型数据占2个字 )
- MODBUS_STR_modbus->num_byte=4*MODBUS_STR_modbus->num_data; //返回寄存字节数数量(1个浮点型数据有4个字节)
- MODBUS_STR_modbus->Sendbuf[2]=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[MODBUS_STR_modbus->addr_data]=ui4_byte[j]; //把长整型数据转换过来的字节数组赋给发送寄存器
- 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_STR_modbus->addr_data]=MODBUS_CRC_data_Hi; //装载CRC高位
- MODBUS_STR_modbus->addr_data++; //地址便宜量+1
- MODBUS_STR_modbus->Sendbuf[MODBUS_STR_modbus->addr_data]=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功能码。
复制代码 这里是用串口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_on 1 //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[0]&(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[ADC_DAQ_Num]; //存放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[ADC_DAQ_Num]; //把每个通道单次采集的值装入数组中
- f32 sum_voldata[ADC_DAQ_Num]; //把每个通道采集多次的值累加后放入数组中(为了求平局值)
- //-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- f32 avg_voldata[ADC_DAQ_Num]; //用来存放每个通道实际电压的平均值
- f32 value[ADC_DAQ_Num]; //用来存放实际电压转换的工程量
- f32 vol_upper[ADC_DAQ_Num]; //用来存放电压对应的上限值
- f32 vol_lower[ADC_DAQ_Num]; //用来存放电压对应的下限值
- f32 value_upper[ADC_DAQ_Num]; //用来存放工程量的上限
- f32 value_lower[ADC_DAQ_Num]; //用来存放工程量的下限
- f32 value_comp_upper[ADC_DAQ_Num]; //用来存放比较值的高值 (大于此值,输出一个状态)
- f32 value_comp_lower[ADC_DAQ_Num]; //用来存放比较值的低值 (小于此值,输出一个状态)
- }ADC_VAR;
- extern ADC_VAR xdata ADCA_STR_VAR; //声明一个ADC模块结构体实例变量
- extern u8 xdata DmaBuffer[ADC_CH][ADC_DATA]; //定义DMA缓冲
- //---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- extern void ADC_Init(void); //ADC初始化
- extern void ADC_Meas(void); //ADC采集处理
- extern void ADC_check_pressure(void); //ADC压力检测
-
- #endif
复制代码
这里同样定义了一个结构体来存放ADC相关的数据。
复制代码 这里使用了DMA的方式来接收ADC的数据,但是不知道什么原因会造成Modbus通讯数据的故障。不适用DMA的方式进行ADC采集不会对Modbus通讯造成故障。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是使用串口数据监控到的数据故障的结果。发送的都是 “01 03 08 0C 00 0C 87 AC” 查询代码,间隔时间为100ms,出现错误的时间不固定,有时候几分钟就出,有时候20-30分钟会出,有时候可能会更长的时间。
下面是测试代码:
Modbus DMA_ADC功能测试 2025-7-3-10.rar
(256.76 KB, 下载次数: 2)
https://www.stcaimcu.com/forum.php?mod=attachment&aid=MTA3MTM2fGIwNjk2MTBmfDE3NTI2MzE4ODd8MHw%3D
|