更新:

1、modbus主站各种形式的数据发送功能完成;
2、发送和接收过程中出现的错误进行了记录;
This commit is contained in:
吴俊潮 2025-05-16 17:05:28 +08:00
parent af6d6fd969
commit f92b4a15f7
18 changed files with 17815 additions and 21128 deletions

View File

@ -116,7 +116,7 @@ typedef struct
uint8_t bluetooth_enable; //蓝牙透传使能
uint8_t modbus_enable; //MODBUS使能
SIG_MODBUS_TYPE modbus_type; //SIG在modbus中作为主或从
uint16_t modbus_timeout_period; //SIG作为主设备时等待从设备响应的超时时间上限ms
uint8_t modbus_master_send_flag; //发送标志
//ITEMS_3
uint8_t item3_page0_lightflag; //照明状态标志0熄灭1开启

View File

@ -24,6 +24,7 @@
#include "SIG24130.h"
#include "modbus_485.h"
#include "modbus_rtu.h"
#include "modbus_rtu_master.h"
extern osThreadId task_lcdHandle;
extern osThreadId task_menuHandle;

View File

@ -286,6 +286,18 @@ uint8_t init_set_bar(uint8_t start, uint8_t end, uint16_t interval)
void scr_main_run(void)
{
//modbus主站功能测试
if(tabdata.modbus_master_send_flag == 1)
{
tabdata.modbus_enable = 1;
tabdata.modbus_type = SIG_MASTER;
tabdata.modbus_master_send_flag = 0;
modbus_rtu_master_load();
modbus_rtu_master_send();
}
//实时更新设定值
sig_sv_update(); //不做延时,尽快响应

View File

@ -47,7 +47,7 @@ void tab_data_init(void)
tabdata.bluetooth_enable = 0; //HART默认使能状态
tabdata.modbus_enable = 0; //HART默认使能状态
tabdata.modbus_type = SIG_SLAVE; //SIG默认作为从设备
tabdata.modbus_timeout_period = 1000; //默认超时时间为1000ms
tabdata.modbus_master_send_flag = 0; //触发发送后置1发送完成后置0
//ITEMS_3部分内容位于EERPOM读取
tabdata.item3_page0_lightflag = 0; //照明状态标志0熄灭1开启
@ -592,6 +592,14 @@ void scr_setting_run(void) //详细设置界面
//处理复位事件
deal_data_reset();
if(tabdata.modbus_master_send_flag == 1)
{
tabdata.modbus_master_send_flag = 0;
modbus_rtu_master_load();
modbus_rtu_master_send();
}
}
//执行保存功能

View File

@ -847,6 +847,9 @@ void my_inits_gather(void)
// lv_demo_benchmark(); //lv_conf.h, line:761
setup_ui(&guider_ui); // 初始化UI设置与加载初始界面
events_init(&guider_ui); // 初始化事件
//MODBUS主站初始化
modbus_rtu_master_init();
}

View File

@ -65,11 +65,19 @@ void duty_tim6(void)
input_500ms_flag = 1;
}
if(sig2slave_step == 1)
//发送完成 或者 已经接收到一部分数据之后开始计时
if( (sig2slave_step == 1)||(mod_master.tx_flag == TX_OK) )
{
sig2slave_current_tick++;
if(sig2slave_current_tick > tabdata.modbus_timeout_period)
if(sig2slave_current_tick > mod_master.timeout)
{
if(sig2slave_step == 0)
{
//进入此处说明发送成功后未收到任何数据
mod_master.rx_error_message = RX_ERROR_TIMEOUT;
mod_master.tx_flag = TX_NONE;
}
HAL_UART_DMAStop(&huart2);
__HAL_UART_CLEAR_IDLEFLAG(&huart2);

View File

@ -14,18 +14,13 @@ typedef enum
extern uint32_t tick_start;
extern uint32_t tick_middle;
extern uint32_t tick_end;
extern uint32_t trans_log_rx;
//extern uint32_t trans_log_rx;
extern uint32_t trans_log_tx;
extern uint8_t sig2slave_step;
extern TRANS_PROCESS st_flag;
void parse_scom_485(st_scom *scom);
//PC <---SIG---> HART/BLUETOOTH/MODBUS
//BLE将接收完成的BLE数据发送至上位机将来自上位机的BLE数据装载至comhart_tx
//HART将接收完成的HART的数据发送至上位机将来自上位机的HART数据装载至comhart_tx
void transparent_485(st_scom *scom);
//透传DMA发送与发送回调组合使用
void transparent_tim(void);

View File

@ -9,10 +9,10 @@
#define ReadDisInputState 0x02 //读取输入状态
#define ReadHoldReg 0x03 //读取保持寄存器
#define ReadInputReg 0x04 //读取输入寄存器
#define WriteSingleCoil 0x05 //强制写单线圈输出状态
#define WriteSingleReg 0x06 //预设()单寄存器
#define WriteMultiCoil 0x0F //强制写多线圈输出状态
#define WriteMultiReg 0x10 //预设()多寄存器
#define WriteSingleCoil 0x05 //写单个线圈寄存器
#define WriteSingleReg 0x06 //写单个保持寄存器
#define WriteMultiCoil 0x0F //写多个线圈寄存器
#define WriteMultiReg 0x10 //写多个保持寄存器
#define COIL_ADD_MIN 0x00
#define COIL_ADD_MAX 0x64
@ -63,6 +63,7 @@ extern uint8_t DisState [(MAX_DIS_NUM + 7) / 8];
extern uint16_t InputReg[MAX_INPUT_REG_NUM];
extern uint16_t HoldReg[MAX_HOLD_REG_NUM];
extern Var_Reg SamVarReg;
extern eMBException ex_message;
//MODBUS_RTU
void modbus_analysis_rtu(uint8_t * upRxdbuf, uint16_t wRxdLen);

View File

@ -0,0 +1,68 @@
#ifndef __MODBUS_RTU_MASTER_H
#define __MODBUS_RTU_MASTER_H
#include "apps_gather.h"
#include "modbus_rtu.h"
#define TX_BUFF_MAX 128
#define TX_DATA_MAX 100
#define RX_BUFF_MAX 128
#define TX_NONE 0x00 //没有需要发送的数据
#define TX_WAITING 0x01 //数据准备完成,等待发送
#define TX_OK 0x02 //发送完成
#define RX_NONE 0x00 //没有接收到数据
#define RX_WAITING 0x01 //等待接收
#define RX_OK 0x02 //接收完成
typedef enum
{
RX_ERROR_NONE = 0, //数据接收未出现错误
RX_ERROR_TIMEOUT, //接收数据超时
RX_ERROR_OVERFLOW, //接收到的数据超出缓存区
RX_ERROR_WRONG_ID //接收到的设备ID与目标ID不符
}ERROR_NESSAGE_RX;
typedef enum
{
TX_ERROR_NONE = 0, //数据发送未出现错误
TX_ERROR_WRONG_CMD, //命令字错误
TX_ERROR_COIL_NUM, //写多个线圈时,线圈数量或字节数错误
TX_ERROR_HOLDREG_NUM //写保持寄存器时,寄存器数量或字节数错误
}ERROR_NESSAGE_TX;
typedef struct
{
uint8_t target_id; //目标ID从设备识别号、地址
uint8_t command_code; //命令字
uint16_t start_address; //起始地址
uint16_t register_num; //线圈、寄存器数量
uint16_t crc16; //MODBUS_CRC16校验码
uint8_t byte_num; //需要写入的线圈、保持寄存器字节数
uint8_t data_tx_value8[TX_DATA_MAX]; //需要写入的数值,8位
uint16_t data_tx_value16[TX_DATA_MAX]; //需要写入的数值,16位
uint8_t data_tx[TX_BUFF_MAX]; //存放完整的发送数据报
uint8_t data_rx[RX_BUFF_MAX]; //存放完整的接收数据报
uint8_t data_tx_len; //发送的数据报长度
uint8_t data_rx_len; //接收到的数据报长度
ERROR_NESSAGE_RX rx_error_message; //接收过程中的错误信息
ERROR_NESSAGE_TX tx_error_message; //发送过程中的错误信息
uint16_t timeout; //超时、等待时间
uint8_t rx_flag; //接收标志位
uint8_t tx_flag; //发送标志位
}MODBUS_MASTER;
extern MODBUS_MASTER mod_master;
void modbus_rtu_master_init(void);
void modbus_rtu_master_load(void);
void modbus_rtu_master_send(void);
void modbus_rtu_master_analysis(void);
#endif

View File

@ -3,19 +3,10 @@
uint32_t tick_start = 0;
uint32_t tick_middle = 0;
uint32_t tick_end = 0;
uint32_t trans_log_rx = 0;
//uint32_t trans_log_rx = 0;
uint32_t trans_log_tx = 0;
TRANS_PROCESS st_flag = TRANSPARENT_WAIT;
//static void scom_485_send(UART_HandleTypeDef *huart, char *str)
//{
// RS485_RW(RS485_WR);
// vTaskDelay(10);
// printf("\r\n");
// usart_printf(huart, "rs485 receive:[%s]\r\n", str);
// printf("printf test_data:[%s]\r\n", str);
// RS485_RW(RS485_RD);
//}
void parse_scom_485(st_scom *scom)
{
@ -24,89 +15,13 @@ void parse_scom_485(st_scom *scom)
scom->rx_flag = FALSE;
if ((scom->rx_buff[0] == 0xff) && (scom->rx_buff[1] == 0xff) && (scom->rx_buff[scom->rx_len - 1] == 0xaa))
{
// scom_485_send(&huart2, scom->rx_buff);
//RS485_RW(RS485_WR);
vTaskDelay(10);
HAL_UART_Transmit(&huart2, scom->rx_buff, scom->rx_len, 0xFFFF);
//RS485_RW(RS485_RD);
}
scom->rx_len = 0;
}
}
void transparent_485(st_scom *scom)
{
if(scom != &scom2_rs485) return;
//来自上位机的数据是否接收完成
if(scom->rx_flag == TRUE)
{
scom->rx_flag = FALSE;
// switch (sig_trans)
// {
// case TRANS_HART:
// {
// if ((scom->rx_buff[0] == 0xff) && (scom->rx_buff[1] == 0xff) && (scom->rx_buff[scom->rx_len - 1] == 0xaa))
// {
// //接收到的数据是否符合HART数据报符合则写入HART的tx准备发送至HART设备
// memcpy(scom1_hart.tx_buff, scom->rx_buff, sizeof(scom->rx_buff));
// scom1_hart.tx_flag = TRUE;
// }
// }
// break;
// case TRANS_BLUETOOTH:
// {
// //将接收到的数据存入BLE的tx准备发送至蓝牙设备
// memcpy(scom6_ble.tx_buff, scom->rx_buff, sizeof(scom->rx_buff));
// scom6_ble.tx_flag = TRUE;
// }
// break;
// case TRANS_MODBUS:
// {
// modbus_process_rtu();
// }
// break;
// case TRANS_NONE:
// {}
// break;
// default:
// break;
// }
//清空缓存区,等待新的数据
memset(scom->rx_buff, 0, sizeof(scom->rx_buff));
scom->rx_len = 0;
}
//数据是否准备完成
if( (scom->tx_flag == TRUE) && (sig_trans != TRANS_NONE) )
{
scom->tx_flag = FALSE;
//vTaskDelay(10);
wu_delay_us(1000);
//将数据发送至上位机
HAL_UART_Transmit(&huart2, scom->tx_buff, scom->tx_len, 0xFFFF);
//清空缓存区,等待新的数据
memset(scom->tx_buff, 0, sizeof(scom->tx_buff));
scom->tx_len = 0;
//HAL_UART_Transmit_IT(&huart2, scom->tx_buff, scom->tx_len);
xTaskResumeFromISR(task_lcdHandle);
xTaskResumeFromISR(task_menuHandle);
screen_suspend_flag = 0;
}
}
void transparent_tim(void)
{
switch (sig_trans)
@ -306,7 +221,9 @@ void trans_modbus_sig2slave(void)
{
case 0:
{
//进入此处说明已经接收完成一部分数据,开始超时计时
//进入此处说明已经接收完成一部分数据,重新开始超时计时,发送标志复位
mod_master.tx_flag = TX_NONE;
sig2slave_current_tick = 0;
//记录第一次接收到的数据长度
sig2slave_data_length_total = scom2_rs485.rx_len;
@ -342,9 +259,18 @@ void trans_modbus_sig2slave(void)
case 2:
{
//进入此处说明超时计时结束,对接收到的数据进行处理
if(mod_master.rx_error_message != RX_ERROR_TIMEOUT)
{
//进入此处说明收到了数据,并且超时计时期间内未收到新的数据
modbus_rtu_master_analysis();
//如果接收到的数据没有错误,则清空相关数据,否则保留
if(mod_master.rx_error_message == RX_ERROR_NONE)
{
modbus_rtu_master_init();
}
}
//数据处理完成
sig2slave_step = 0;
sig_trans = TRANS_NONE;
memset(scom2_rs485.rx_buff, 0, scom2_rs485.rx_len);

View File

@ -6,6 +6,7 @@ uint16_t InputReg[MAX_INPUT_REG_NUM] = {0x0000,0x0000,0x0000,0x0000}; //输入
uint16_t HoldReg[MAX_HOLD_REG_NUM] = {0, 0,0,0x00C8}; //保持寄存器
Var_Reg SamVarReg;
eMBException ex_message = MB_EX_NONE; //从设备返回的异常信息
/*******************************************************************************
Modbus_Analysis

View File

@ -0,0 +1,221 @@
#include "modbus_rtu_master.h"
MODBUS_MASTER mod_master;
void modbus_rtu_master_init(void)
{
mod_master.target_id = 0x00;
mod_master.command_code = 0x00;
mod_master.start_address = 0x0000;
mod_master.register_num = 0x0000;
mod_master.crc16 = 0x0000;
mod_master.byte_num = 0;
memset(mod_master.data_tx_value8, 0, TX_DATA_MAX);
memset(mod_master.data_tx_value16, 0, TX_DATA_MAX);
memset(mod_master.data_tx, 0, TX_BUFF_MAX);
memset(mod_master.data_rx, 0, RX_BUFF_MAX);
mod_master.data_tx_len = 0;
mod_master.data_rx_len = 0;
mod_master.rx_error_message = RX_ERROR_NONE;
mod_master.tx_error_message = TX_ERROR_NONE;
mod_master.timeout = 1000;
mod_master.rx_flag = RX_NONE;
mod_master.tx_flag = TX_NONE;
}
void modbus_rtu_master_load(void)
{
mod_master.data_tx[0] = mod_master.target_id;
mod_master.data_tx[1] = mod_master.command_code;
memset(mod_master.data_rx, 0, sizeof(mod_master.data_rx));
switch (mod_master.data_tx[1])
{
//读四种寄存器的格式一致
case ReadCoilState:
{
//注释break直接向下穿透
}
//break;
case ReadDisInputState:
{
//注释break直接向下穿透
}
//break;
case ReadHoldReg:
{
//注释break直接向下穿透
}
//break;
case ReadInputReg:
{
mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8);
mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF);
mod_master.data_tx[4] = (uint8_t)(mod_master.register_num >> 8);
mod_master.data_tx[5] = (uint8_t)(mod_master.register_num & 0x00FF);
mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 6);
mod_master.data_tx[6] = (uint8_t)(mod_master.crc16 & 0x00FF);
mod_master.data_tx[7] = (uint8_t)(mod_master.crc16 >> 8);
mod_master.data_tx_len = 8;
}
break;
case WriteSingleCoil:
{
mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8);
mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF);
mod_master.data_tx[4] = (uint8_t)(mod_master.data_tx_value8[0] >> 8);
mod_master.data_tx[5] = (uint8_t)(mod_master.data_tx_value8[0] & 0x00FF);
mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 6);
mod_master.data_tx[6] = (uint8_t)(mod_master.crc16 & 0x00FF);
mod_master.data_tx[7] = (uint8_t)(mod_master.crc16 >> 8);
mod_master.data_tx_len = 8;
}
break;
case WriteSingleReg:
{
mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8);
mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF);
mod_master.data_tx[4] = (uint8_t)(mod_master.data_tx_value16[0] >> 8);
mod_master.data_tx[5] = (uint8_t)(mod_master.data_tx_value16[0] & 0x00FF);
mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 6);
mod_master.data_tx[6] = (uint8_t)(mod_master.crc16 & 0x00FF);
mod_master.data_tx[7] = (uint8_t)(mod_master.crc16 >> 8);
mod_master.data_tx_len = 8;
}
break;
case WriteMultiCoil:
{
if( mod_master.register_num % 8 )
{
//线圈数量不为8的倍数时字节数 == (线圈数量/8 + 1
if( (mod_master.register_num/8 + 1) != mod_master.byte_num )
{
mod_master.tx_error_message = TX_ERROR_COIL_NUM;
return;
}
}
else
{
//线圈数量为8的倍数时字节数 == 线圈数量/8
if( (mod_master.register_num/8) != mod_master.byte_num )
{
mod_master.tx_error_message = TX_ERROR_COIL_NUM;
return;
}
}
mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8);
mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF);
mod_master.data_tx[4] = (uint8_t)(mod_master.register_num >> 8);
mod_master.data_tx[5] = (uint8_t)(mod_master.register_num & 0x00FF);
mod_master.data_tx[6] = mod_master.byte_num;
for(uint8_t i = 1; i <= mod_master.byte_num; i++ )
{
mod_master.data_tx[6 + i] = mod_master.data_tx_value8[i - 1];
}
mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 7 + mod_master.byte_num);
mod_master.data_tx[7 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 & 0x00FF);
mod_master.data_tx[8 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 >> 8);
mod_master.data_tx_len = 8 + mod_master.byte_num + 1;
}
break;
case WriteMultiReg:
{
if( (mod_master.register_num * 2) != mod_master.byte_num )
{
//字节数 == (寄存器数量*2
mod_master.tx_error_message = TX_ERROR_HOLDREG_NUM;
return;
}
mod_master.data_tx[2] = (uint8_t)(mod_master.start_address >> 8);
mod_master.data_tx[3] = (uint8_t)(mod_master.start_address & 0x00FF);
mod_master.data_tx[4] = (uint8_t)(mod_master.register_num >> 8);
mod_master.data_tx[5] = (uint8_t)(mod_master.register_num & 0x00FF);
mod_master.data_tx[6] = mod_master.byte_num;
for(uint8_t i = 1; i <= mod_master.byte_num; i++ )
{
mod_master.data_tx[6 + i] = mod_master.data_tx_value16[ (i - 1)/2 ] >> ( 8*(i%2) );
}
mod_master.crc16 = ModbusCRC16(mod_master.data_tx, 7 + mod_master.byte_num);
mod_master.data_tx[7 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 & 0x00FF);
mod_master.data_tx[8 + mod_master.byte_num] = (uint8_t)(mod_master.crc16 >> 8);
mod_master.data_tx_len = 8 + mod_master.byte_num + 1;
}
break;
default:
{
mod_master.tx_error_message = TX_ERROR_WRONG_CMD;
}
break;
}
}
void modbus_rtu_master_send(void)
{
if(mod_master.tx_error_message == TX_ERROR_NONE)
{
mod_master.rx_flag = TX_WAITING;
//将准备好的数据发送至从设备
memcpy(scom2_rs485.tx_buff, mod_master.data_tx, mod_master.data_tx_len);
scom2_rs485.tx_len = mod_master.data_tx_len;
scom2_rs485.tx_flag = TRUE;
if(scom2_rs485.tx_flag == TRUE)
{
scom2_rs485.tx_flag = FALSE;
//将数据发送至上位机
HAL_UART_Transmit_DMA(&huart2, scom2_rs485.tx_buff, scom2_rs485.tx_len);
}
//在发送回调中判断发送是否完成
sig_trans = TRANS_MODBUS_SIG_TO_SLAVE;
}
}
void modbus_rtu_master_analysis(void)
{
if(scom2_rs485.rx_len > RX_BUFF_MAX)
{
mod_master.rx_error_message = RX_ERROR_OVERFLOW;
return;
}
mod_master.data_rx_len = scom2_rs485.rx_len;
memcpy(mod_master.data_rx, scom2_rs485.rx_buff, mod_master.data_rx_len);
if(mod_master.data_rx[0] != mod_master.target_id)
{
mod_master.rx_error_message = RX_ERROR_WRONG_ID;
return;
}
if(mod_master.data_rx[1] <= 0x80)
{
//收到的是正常响应
}
else
{
//收到的是异常响应
ex_message = (eMBException)mod_master.data_rx[2];
}
mod_master.rx_flag = RX_OK;
}

View File

@ -46,7 +46,7 @@ extern UART_HandleTypeDef huart6;
#define RX_DMA_ENABLE 1
#define BUFFER_SIZE 255
#define BUFFER_SIZE 128
typedef struct
{

View File

@ -465,9 +465,37 @@ void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
scom2_rs485.tx_len = 0;
//开启对应的DMA
if(sig_trans == TRANS_HART_TO_PC) HAL_UART_Receive_DMA(&huart1, scom1_hart.rx_buff, BUFFER_SIZE);
if(sig_trans == TRANS_BLE_TO_PC) HAL_UART_Receive_DMA(&huart6, scom6_ble.rx_buff, BUFFER_SIZE);
if(sig_trans == TRANS_MODBUS_PC_TO_SIG) HAL_UART_Receive_DMA(&huart2, scom2_rs485.rx_buff, BUFFER_SIZE);
switch (sig_trans)
{
case TRANS_HART_TO_PC:
{
HAL_UART_Receive_DMA(&huart1, scom1_hart.rx_buff, BUFFER_SIZE);
}
break;
case TRANS_BLE_TO_PC:
{
HAL_UART_Receive_DMA(&huart6, scom6_ble.rx_buff, BUFFER_SIZE);
}
break;
case TRANS_MODBUS_PC_TO_SIG:
{
HAL_UART_Receive_DMA(&huart2, scom2_rs485.rx_buff, BUFFER_SIZE);
}
break;
case TRANS_MODBUS_SIG_TO_SLAVE:
{
mod_master.tx_flag = TX_OK;
HAL_UART_Receive_DMA(&huart2, scom2_rs485.rx_buff, BUFFER_SIZE);
sig2slave_current_tick = 0;
}
break;
default:
break;
}
}
if(huart == &huart6)

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -760,6 +760,11 @@
<FileType>1</FileType>
<FilePath>..\App\MODBUS\Src\modbus_rtu.c</FilePath>
</File>
<File>
<FileName>modbus_rtu_master.c</FileName>
<FileType>1</FileType>
<FilePath>..\App\MODBUS\Src\modbus_rtu_master.c</FilePath>
</File>
</Files>
</Group>
<Group>

File diff suppressed because it is too large Load Diff