600 lines
16 KiB
C
600 lines
16 KiB
C
#include "modbus_485.h"
|
||
|
||
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_tx = 0;
|
||
TRANS_PROCESS st_flag = TRANSPARENT_WAIT;
|
||
|
||
|
||
void parse_scom_485(st_scom *scom)
|
||
{
|
||
if ((scom == &scom2_rs485) && (scom->rx_flag == TRUE))
|
||
{
|
||
scom->rx_flag = FALSE;
|
||
if ((scom->rx_buff[0] == 0xff) && (scom->rx_buff[1] == 0xff) && (scom->rx_buff[scom->rx_len - 1] == 0xaa))
|
||
{
|
||
vTaskDelay(10);
|
||
HAL_UART_Transmit(&huart2, scom->rx_buff, scom->rx_len, 0xFFFF);
|
||
}
|
||
scom->rx_len = 0;
|
||
}
|
||
}
|
||
|
||
void transparent_tim(void)
|
||
{
|
||
switch (sig_trans)
|
||
{
|
||
case TRANS_NONE:
|
||
{}
|
||
break;
|
||
|
||
case TRANS_HART_TO_PC:
|
||
{
|
||
trans_hart2pc();
|
||
}
|
||
break;
|
||
|
||
case TRANS_PC_TO_HART:
|
||
{
|
||
trans_pc2hart();
|
||
}
|
||
break;
|
||
|
||
case TRANS_BLE_TO_PC:
|
||
{
|
||
trans_ble2pc();
|
||
}
|
||
break;
|
||
|
||
case TRANS_PC_TO_BLE:
|
||
{
|
||
trans_pc2ble();
|
||
}
|
||
break;
|
||
|
||
case TRANS_MODBUS_PC_TO_SIG:
|
||
{
|
||
trans_modbus_pc2sig();
|
||
}
|
||
break;
|
||
|
||
case TRANS_MODBUS_SIG_TO_SLAVE:
|
||
{
|
||
trans_modbus_sig2slave();
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
void trans_hart2pc(void)
|
||
{
|
||
//来自HART设备的数据是否接收完成
|
||
if (scom1_hart.rx_flag == TRUE)
|
||
{
|
||
scom1_hart.rx_flag = FALSE;
|
||
|
||
//接收到的数据是否符合HART数据报,符合则写入485的tx,准备发送至上位机
|
||
if ((scom1_hart.rx_buff[0] == 0xff) && (scom1_hart.rx_buff[1] == 0xff) && (scom1_hart.rx_buff[scom1_hart.rx_len - 1] == 0xAA))
|
||
{
|
||
memcpy(scom2_rs485.tx_buff, scom1_hart.rx_buff, scom1_hart.rx_len);
|
||
scom2_rs485.tx_len = scom1_hart.rx_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);
|
||
}
|
||
|
||
//清空缓存区,等待新的数据
|
||
memset(scom1_hart.rx_buff, 0, scom1_hart.rx_len);
|
||
scom1_hart.rx_len = 0;
|
||
}
|
||
}
|
||
|
||
void trans_pc2hart(void)
|
||
{
|
||
if (scom2_rs485.rx_flag == TRUE)
|
||
{
|
||
scom2_rs485.rx_flag = FALSE;
|
||
|
||
if ((scom2_rs485.rx_buff[0] == 0xff) && (scom2_rs485.rx_buff[1] == 0xff) && (scom2_rs485.rx_buff[scom2_rs485.rx_len - 1] == 0xaa))
|
||
{
|
||
//接收到的数据是否符合HART数据报,符合则写入HART的tx,准备发送至HART设备
|
||
memcpy(scom1_hart.tx_buff, scom2_rs485.rx_buff, scom2_rs485.rx_len);
|
||
scom1_hart.tx_len = scom2_rs485.rx_len;
|
||
scom1_hart.tx_flag = TRUE;
|
||
}
|
||
|
||
//来自上位机的数据是否准备完毕
|
||
if (scom1_hart.tx_flag == TRUE)
|
||
{
|
||
scom1_hart.tx_flag = FALSE;
|
||
HART_RTS(RTS_ON);
|
||
|
||
wu_delay_us(10000);
|
||
|
||
//将tx中的数据发送至HART设备
|
||
HAL_UART_Transmit_DMA(&huart1, scom1_hart.tx_buff, scom1_hart.tx_len);
|
||
|
||
}
|
||
|
||
//清空缓存区,等待新的数据
|
||
memset(scom2_rs485.rx_buff, 0, scom2_rs485.rx_len);
|
||
scom2_rs485.rx_len = 0;
|
||
}
|
||
}
|
||
|
||
void trans_ble2pc(void)
|
||
{
|
||
if( ble_init() == 0 ) return;
|
||
|
||
if (scom6_ble.rx_flag == TRUE)
|
||
{
|
||
scom6_ble.rx_flag = FALSE;
|
||
|
||
//将接收到的数据存入485的tx,准备发送至上位机
|
||
memcpy(scom2_rs485.tx_buff, scom6_ble.rx_buff, scom6_ble.rx_len);
|
||
scom2_rs485.tx_len = scom6_ble.rx_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);
|
||
}
|
||
|
||
//清空缓存区,等待新的数据
|
||
memset(scom6_ble.rx_buff, 0, scom6_ble.rx_len);
|
||
scom6_ble.rx_len = 0;
|
||
}
|
||
}
|
||
|
||
void trans_pc2ble(void)
|
||
{
|
||
if (scom2_rs485.rx_flag == TRUE)
|
||
{
|
||
scom2_rs485.rx_flag = FALSE;
|
||
|
||
//将接收到的数据存入BLE的tx,准备发送至蓝牙设备
|
||
memcpy(scom6_ble.tx_buff, scom2_rs485.rx_buff, scom2_rs485.rx_len);
|
||
scom6_ble.tx_len = scom2_rs485.rx_len;
|
||
scom6_ble.tx_flag = TRUE;
|
||
|
||
//来自上位机的数据是否准备完毕
|
||
if (scom6_ble.tx_flag == TRUE)
|
||
{
|
||
scom6_ble.tx_flag = FALSE;
|
||
|
||
//将tx中的数据发送至蓝牙设备
|
||
HAL_UART_Transmit_DMA(&huart6, scom6_ble.tx_buff, scom6_ble.tx_len);
|
||
}
|
||
|
||
//清空缓存区,等待新的数据
|
||
memset(scom2_rs485.rx_buff, 0, scom2_rs485.rx_len);
|
||
scom2_rs485.rx_len = 0;
|
||
}
|
||
}
|
||
|
||
void trans_modbus_pc2sig(void)
|
||
{
|
||
if (scom2_rs485.rx_flag == TRUE)
|
||
{
|
||
scom2_rs485.rx_flag = FALSE;
|
||
|
||
modbus_process_rtu();
|
||
|
||
if(scom2_rs485.tx_flag == TRUE)
|
||
{
|
||
scom2_rs485.tx_flag = FALSE;
|
||
|
||
//将数据发送至上位机
|
||
HAL_UART_Transmit_DMA(&huart2, scom2_rs485.tx_buff, scom2_rs485.tx_len);
|
||
}
|
||
|
||
//清空缓存区,等待新的数据
|
||
memset(scom2_rs485.rx_buff, 0, scom2_rs485.rx_len);
|
||
scom2_rs485.rx_len = 0;
|
||
}
|
||
}
|
||
|
||
uint8_t sig2slave_step = 0;
|
||
uint8_t sig2slave_data_length_total = 0;
|
||
uint8_t buffer_size_temp = BUFFER_SIZE;
|
||
void trans_modbus_sig2slave(void)
|
||
{
|
||
if (scom2_rs485.rx_flag == TRUE)
|
||
{
|
||
scom2_rs485.rx_flag = FALSE;
|
||
|
||
switch (sig2slave_step)
|
||
{
|
||
case 0:
|
||
{
|
||
//进入此处说明已经接收完成一部分数据,重新开始超时计时,发送标志复位
|
||
mod_master.tx_flag = TX_NONE;
|
||
sig2slave_current_tick = 0;
|
||
|
||
//记录第一次接收到的数据长度
|
||
sig2slave_data_length_total = scom2_rs485.rx_len;
|
||
|
||
//修改剩余buff长度,继续接收
|
||
buffer_size_temp -= scom2_rs485.rx_len;
|
||
HAL_UART_Receive_DMA(&huart2, scom2_rs485.rx_buff + sig2slave_data_length_total, buffer_size_temp);
|
||
|
||
sig2slave_step++;
|
||
}
|
||
break;
|
||
|
||
case 1:
|
||
{
|
||
//超时时间内再次收到数据,重新开始超时计时
|
||
sig2slave_current_tick = 0;
|
||
|
||
//本次收到的数据长度
|
||
uint8_t sig2slave_data_length_temp = buffer_size_temp - __HAL_DMA_GET_COUNTER(huart2.hdmarx);
|
||
|
||
//累计收到的数据长度
|
||
sig2slave_data_length_total += sig2slave_data_length_temp;
|
||
scom2_rs485.rx_len = sig2slave_data_length_total;
|
||
|
||
if(scom2_rs485.rx_len < BUFFER_SIZE)
|
||
{
|
||
//继续接收
|
||
buffer_size_temp -= sig2slave_data_length_temp;
|
||
HAL_UART_Receive_DMA(&huart2, scom2_rs485.rx_buff + sig2slave_data_length_total, buffer_size_temp);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case 2:
|
||
{
|
||
if(mod_master.rx_error_message != RX_ERROR_TIMEOUT)
|
||
{
|
||
//进入此处说明收到了数据,并且超时计时期间内未收到新的数据
|
||
modbus_rtu_master_analysis();
|
||
}
|
||
else
|
||
{
|
||
strcpy(mod_master.result_display, "ERROR: TIMEOUT");
|
||
}
|
||
//在屏幕上显示 mod_master.result_display 字符串
|
||
lv_label_set_text(guider_ui.screen_modbus_trx_value_Rx, mod_master.result_display);
|
||
|
||
//处理完成后复位相关参数
|
||
sig2slave_step = 0;
|
||
sig_trans = TRANS_NONE;
|
||
memset(scom2_rs485.rx_buff, 0, scom2_rs485.rx_len);
|
||
scom2_rs485.rx_len = 0;
|
||
sig2slave_data_length_total = 0;
|
||
buffer_size_temp = BUFFER_SIZE;
|
||
|
||
HAL_UART_Receive_DMA(&huart2, scom2_rs485.rx_buff, BUFFER_SIZE);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
void trans_start_capture(void)
|
||
{
|
||
uint8_t data_len1 = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx);
|
||
uint8_t data_len2 = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart2.hdmarx);
|
||
uint8_t data_len6 = BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart6.hdmarx);
|
||
|
||
if( (1 <= data_len1 )&&( data_len1 <= 3) )
|
||
{
|
||
if(tabdata.hart_enable)
|
||
{
|
||
if (st_flag == TRANSPARENT_WAIT)
|
||
{
|
||
st_flag = TRANSPARENT_RECIEVE_START;
|
||
tick_start = xTaskGetTickCountFromISR();
|
||
}
|
||
}
|
||
}
|
||
|
||
if( (1 <= data_len2 )&&( data_len2 <= 3) )
|
||
{
|
||
if(tabdata.bluetooth_enable)
|
||
{
|
||
if (st_flag == TRANSPARENT_WAIT)
|
||
{
|
||
st_flag = TRANSPARENT_RECIEVE_START;
|
||
tick_start = xTaskGetTickCountFromISR();
|
||
}
|
||
}
|
||
}
|
||
|
||
if( (1 <= data_len6 )&&( data_len6 <= 3) )
|
||
{
|
||
if(tabdata.hart_enable||tabdata.bluetooth_enable||tabdata.modbus_enable)
|
||
{
|
||
if (st_flag == TRANSPARENT_WAIT)
|
||
{
|
||
st_flag = TRANSPARENT_RECIEVE_START;
|
||
tick_start = xTaskGetTickCountFromISR();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
uint8_t trans_enable_check(st_scom *scom)
|
||
{
|
||
uint8_t result = 0;
|
||
|
||
if( scom == &scom1_hart )
|
||
{
|
||
if(tabdata.hart_enable)
|
||
{
|
||
result = 1;
|
||
sig_trans = TRANS_HART_TO_PC;
|
||
}
|
||
}
|
||
|
||
if( scom == &scom6_ble )
|
||
{
|
||
if(tabdata.bluetooth_enable)
|
||
{
|
||
result = 1;
|
||
sig_trans = TRANS_BLE_TO_PC;
|
||
}
|
||
}
|
||
|
||
if( scom == &scom2_rs485 )
|
||
{
|
||
if(tabdata.hart_enable)
|
||
{
|
||
result = 1;
|
||
sig_trans = TRANS_PC_TO_HART;
|
||
}
|
||
else if(tabdata.bluetooth_enable)
|
||
{
|
||
result = 1;
|
||
sig_trans = TRANS_PC_TO_BLE;
|
||
}
|
||
else if(tabdata.modbus_enable)
|
||
{
|
||
result = 1;
|
||
|
||
switch (tabdata.modbus_type)
|
||
{
|
||
case SIG_SLAVE:
|
||
{
|
||
sig_trans = TRANS_MODBUS_PC_TO_SIG;
|
||
}
|
||
break;
|
||
|
||
case SIG_MASTER:
|
||
{
|
||
sig_trans = TRANS_MODBUS_SIG_TO_SLAVE;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
//处理modbus寄存器值的更新与写入
|
||
void modbus_registers_update(void)
|
||
{
|
||
//线圈寄存器
|
||
modbus_reg_update_coil();
|
||
|
||
//离散状态寄存器
|
||
modbus_reg_update_dis();
|
||
|
||
//保持寄存器
|
||
modbus_reg_update_hold();
|
||
|
||
//输入寄存器
|
||
modbus_reg_update_input();
|
||
}
|
||
|
||
//线圈寄存器,读写
|
||
void modbus_reg_update_coil(void)
|
||
{
|
||
if( (get_coil_val(COIL_ADDR_ON_OFF) != menu_data.io_on2off)&&(get_coil_val(COIL_ADDR_ON_OFF) < 2) )
|
||
{
|
||
//进入此处说明线圈寄存器的值被上位机修改
|
||
if( menu_data.scr_now == SCREEN_MAIN )
|
||
{
|
||
//只有在主界面时,修改内容才生效
|
||
menu_data.io_on2off = get_coil_val(COIL_ADDR_ON_OFF);
|
||
io_on2off_status();
|
||
}
|
||
else
|
||
{
|
||
//拒绝修改内容
|
||
set_coil_val(COIL_ADDR_ON_OFF, menu_data.io_on2off);
|
||
}
|
||
}
|
||
|
||
if( (get_coil_val(COIL_ADDR_LIGHT) != tabdata.item3_page0_lightflag)&&(get_coil_val(COIL_ADDR_LIGHT) < 2) )
|
||
{
|
||
//进入此处说明线圈寄存器的值被上位机修改
|
||
tabdata.item3_page0_lightflag = get_coil_val(COIL_ADDR_LIGHT);
|
||
if(tabdata.item3_page0_lightflag)
|
||
{
|
||
LIGHT_ON;
|
||
}
|
||
else
|
||
{
|
||
LIGHT_OFF;
|
||
}
|
||
}
|
||
|
||
if( (get_coil_val(COIL_ADDR_CONFIG_SAVE) == 1)&&(tabdata.item3_page0_saveflag == 0) )
|
||
{
|
||
if( (menu_data.scr_now == SCREEN_SETTING)&&(tabdata.item3_page0_resetflag != 1) )
|
||
{
|
||
//当前处于设置界面,并且未处于重置过程中,执行保存
|
||
tabdata.item3_page0_saveflag = 1;
|
||
}
|
||
else
|
||
{
|
||
//拒绝修改
|
||
set_coil_val(COIL_ADDR_CONFIG_SAVE, 0);
|
||
}
|
||
}
|
||
|
||
if( (get_coil_val(COIL_ADDR_CONFIG_RESET) == 1)&&(tabdata.item3_page0_resetflag == 0) )
|
||
{
|
||
if( (menu_data.scr_now == SCREEN_SETTING)&&(tabdata.item3_page0_saveflag != 1) )
|
||
{
|
||
//当前处于设置界面,并且未处于保存过程中,执行复位
|
||
tabdata.item3_page0_resetflag = 1;
|
||
}
|
||
else
|
||
{
|
||
//拒绝修改
|
||
set_coil_val(COIL_ADDR_CONFIG_RESET, 0);
|
||
}
|
||
}
|
||
|
||
if( get_coil_val(COIL_ADDR_SCREEN_SWITCH) != ( (uint8_t)menu_data.scr_now - 1 ) )
|
||
{
|
||
switch (menu_data.scr_now)
|
||
{
|
||
case SCREEN_INIT:
|
||
{
|
||
//拒绝修改,开机动画视作主界面
|
||
set_coil_val(COIL_ADDR_SCREEN_SWITCH, 0);
|
||
}
|
||
break;
|
||
|
||
case SCREEN_MAIN:
|
||
{
|
||
//切换至设置界面;
|
||
scr_setting_recover();
|
||
lv_scr_load(guider_ui.screen_setting);
|
||
lv_obj_clear_flag(guider_ui.screen_setting, LV_OBJ_FLAG_HIDDEN);
|
||
|
||
//隐藏主界面对象
|
||
lv_obj_add_flag(guider_ui.screen_main, LV_OBJ_FLAG_HIDDEN);
|
||
|
||
menu_data.scr_now = SCREEN_SETTING; //当前界面为详细设置菜单
|
||
set_coil_val(COIL_ADDR_SCREEN_SWITCH, 1);
|
||
}
|
||
break;
|
||
|
||
case SCREEN_SETTING:
|
||
{
|
||
//切换至主界面;
|
||
//加载主界面
|
||
if(!scr_main_set_flag)
|
||
{
|
||
scr_main_set_flag = 1;
|
||
setup_scr_screen_main(&guider_ui);
|
||
delay_cnt(200); //不加延时有概率卡死
|
||
}
|
||
scr_main_recover();
|
||
lv_scr_load(guider_ui.screen_main);
|
||
lv_obj_clear_flag(guider_ui.screen_main, LV_OBJ_FLAG_HIDDEN);
|
||
|
||
//隐藏设置界面对象
|
||
lv_obj_add_flag(guider_ui.screen_setting, LV_OBJ_FLAG_HIDDEN);
|
||
|
||
menu_data.scr_now = SCREEN_MAIN;
|
||
set_coil_val(COIL_ADDR_SCREEN_SWITCH, 0);
|
||
}
|
||
break;
|
||
|
||
default:
|
||
{
|
||
//拒绝修改,其他界面视作设置界面
|
||
set_coil_val(COIL_ADDR_SCREEN_SWITCH, 1);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
|
||
//离散输入寄存器,上位机只读
|
||
void modbus_reg_update_dis(void)
|
||
{}
|
||
|
||
//保持寄存器,读写
|
||
uint16_t work_mode_pv = 0;
|
||
void modbus_reg_update_hold(void)
|
||
{
|
||
work_mode_pv = 1 + (uint16_t)menu_data.input_mode_type + (menu_data.io_mode == IO_OUTPUT) * 15;
|
||
if( HoldReg[HOLD_ADDR_SET_WORK_MODE] != work_mode_pv )
|
||
{
|
||
if(menu_data.scr_now == SCREEN_MAIN)
|
||
{
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
//输入寄存器,上位机只读
|
||
void modbus_reg_update_input(void)
|
||
{}
|
||
|
||
void set_coil_val(uint8_t addr, uint8_t bit_val)
|
||
{
|
||
if( (addr > COIL_ADD_MAX)||(bit_val > 1) ) return;
|
||
addr -= COIL_ADD_MIN;
|
||
if( addr > 200 ) return;
|
||
|
||
uint8_t pcoil = addr / 8; //数组的第几个元素, 0-7
|
||
uint8_t pbit = addr % 8; //元素的第几位, 0-7
|
||
uint8_t fac = 0; //辅助计算的因子
|
||
|
||
switch (bit_val)
|
||
{
|
||
case 0:
|
||
{
|
||
fac = ~(1 << pbit);
|
||
CoilState[pcoil] &= fac;
|
||
}
|
||
break;
|
||
|
||
case 1:
|
||
{
|
||
fac = 1 << pbit;
|
||
CoilState[pcoil] |= fac;
|
||
}
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
|
||
uint8_t get_coil_val(uint8_t addr)
|
||
{
|
||
if( addr > COIL_ADD_MAX ) return 99;
|
||
addr -= COIL_ADD_MIN;
|
||
if( addr > 200 ) return 99;
|
||
|
||
uint8_t result = 0;
|
||
uint8_t pcoil = addr / 8; //数组的第几个元素, 0-7
|
||
uint8_t pbit = addr % 8; //元素的第几位, 0-7
|
||
|
||
result = 0x01 & (CoilState[pcoil] >> pbit);
|
||
|
||
return result;
|
||
}
|
||
|
||
|