FluxDC/components/FluxUart/FluxUart.c
2025-04-28 17:49:47 +08:00

551 lines
19 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* @file FluxUart.c
* @brief 串口通讯实现源文件
*
* 用于串口通讯实现
*
* @author wang xiang en
* @date 2025-04-19
* @version 版本号
* @copyright 版权声明((C)2025, YUWELL MEDTECH Co.ltd
*/
#include <stdio.h>
#include "FluxUart.h"
#include "ui.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "FluxSD.h"
static const char *TAG = "UART TEST";
/* 通讯使用到的结构体 */
struct FluxMachineData FluxMachineData;
struct ModbusRTU_Frame flux_frame;
struct ModbusRTU_Frame breath_frame;
struct ModbusRTU_Frame flux_frame_start;
struct ModbusRTU_Frame2Reg flux_frame2Reg;
/*创建用于记录开始测量事件的事件组*/
EventGroupHandle_t start_state_event_group;
/* 用于进行CRC校验的数组 */
const unsigned char chCRCHTalbe[] =
{
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
};
/* 用于进行CRC校验的数组 */
const unsigned char chCRCLTalbe[] =
{
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
};
/**
* @brief CRC16 校验函数
*
* @param[in] pchMsg 输入的数据
* @param[in] wDataLen 数据长度
*
*/
unsigned short CRC16(unsigned char* pchMsg, unsigned short wDataLen)
{
unsigned char chCRCHi = 0xFF;
unsigned char chCRCLo = 0xFF;
unsigned short wIndex;
while(wDataLen--)
{
wIndex = chCRCLo ^ *pchMsg++ ;
chCRCLo = chCRCHi ^ chCRCHTalbe[wIndex];
chCRCHi = chCRCLTalbe[wIndex] ;
}
#if BIG_ENDIAN_USED
return((chCRCHi << 8) | chCRCLo) ;
#else
return((chCRCLo << 8) | chCRCHi) ;
#endif
}
/**
* @brief 串口1收发任务 (流量计服务函数)
*
* @param[in] arg not used
*
*/
void uart1_echoTask(void* arg)
{
/* Configure parameters of an UART driver,
* communication pins and install the driver */
uart_config_t uart_config = {
.baud_rate = ECHO_UART_BAUD_RATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
int intr_alloc_flags = 0;
ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM1, BUF_SIZE * 2, BUF_SIZE * 2, 0, NULL, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM1, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM1, ECHO_TEST_TXD1, ECHO_TEST_RXD1, ECHO_TEST_RTS, ECHO_TEST_CTS));
uint8_t *data = (uint8_t *) malloc(BUF_SIZE);
unsigned short crc;
flux_frame.ADDR = FLUX_ADDR;
flux_frame.FUNC = FLUX_FUNC_READ;
flux_frame.DATA[0] = 0x00;
flux_frame.DATA[1] = 0x01;
flux_frame.DATA[2] = 0x00;
flux_frame.DATA[3] = 0x02;
/*初始化启动命令帧内容*/
flux_frame_start.ADDR = FLUX_ADDR;
flux_frame_start.FUNC = FLUX_FUNC_SET_SINGLE;
flux_frame_start.DATA[0] = 0x00;
flux_frame_start.DATA[1] = 0x01;
flux_frame_start.DATA[2] = 0x00;
flux_frame_start.DATA[3] = 0x01;
float time = 0;
uint8_t bytes[4];
#if LOG_RECORD_ENABLE
WRITE_LOG_TO_SD("流量计任务初始化完毕");
#endif
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Read data from the UART
/*更新data*/
int len = uart_read_bytes(ECHO_UART_PORT_NUM1, data, (BUF_SIZE - 1), 20 / portTICK_PERIOD_MS);
// Write data back to the UART
//uart_write_bytes(ECHO_UART_PORT_NUM1, (const char *) data, len);
if (len)
{
data[len] = '\0';
for(int i=0;i<len;i++)
ESP_LOGI(TAG, "data[%d]:%02X", i, data[i]);
/* 检查测试是否完成 */
if ((data[20] == 0x01)&&(data[1]==0x03)&&data[4]==FLUX_MODE_TIMER)
{
/* 测试已完成 */
lv_obj_add_state(ui_pageFluxRead_checkboxUnfinished,LV_STATE_CHECKED);
/* 获取定时模式的时间 */
bytes[0] = data[10];
bytes[1] = data[9];
bytes[2] = data[8];
bytes[3] = data[7];
memcpy(&FluxMachineData.time, bytes, 4);
lv_label_set_text_fmt(ui_pageFluxRead_labelTimerPeriod,"%.2f",FluxMachineData.time);
/* 获取积分流量值 */
bytes[0] = data[46];
bytes[1] = data[45];
bytes[2] = data[44];
bytes[3] = data[43];
/* 获取积分流量值将单位转化为mL */
memcpy(&FluxMachineData.cumulativeVolume, bytes, 4);
FluxMachineData.cumulativeVolume = FluxMachineData.cumulativeVolume*1000;
lv_label_set_text_fmt(ui_pageFluxRead_labelCumulativeVolume,"%.2f",FluxMachineData.cumulativeVolume);
#if LOG_RECORD_ENABLE
WRITE_LOG_TO_SD("收到有效流量计数据,解析成功。");
#endif
/* 获取测试结果并写入到SD卡中 */
sdData.flux_test_result.current_test_result = FluxMachineData.cumulativeVolume/10.0;
sd_testData_write(is_test_mode_nom,sdData.flux_test_result.current_test_result);
if(is_test_mode_nom)
{
/* 若当前是NOM模式直接刷新结果在Nom的界面 */
RefreshResult();
}else{
/* 若当前是BS模式刷新结果在BS的界面 */
sdData.flux_test_result.test_result[currentTestRate] = sdData.flux_test_result.current_test_result;
/* 根据当前BS测试阶段刷新结果 */
switch (currentTestRate)
{
case BS_RATE_15BPM:
/* 如果当前测试挡位为15BPM刷新结果在BS界面的15BPM界面 */
lv_label_set_text_fmt(ui_pageHome_LabelRate15Result,"%.1f",sdData.flux_test_result.current_test_result);
break;
case BS_RATE_20BPM:
lv_label_set_text_fmt(ui_pageHome_LabelRate20Result,"%.1f",sdData.flux_test_result.current_test_result);
break;
case BS_RATE_25BPM:
lv_label_set_text_fmt(ui_pageHome_LabelRate25Result,"%.1f",sdData.flux_test_result.current_test_result);
break;
case BS_RATE_30BPM:
lv_label_set_text_fmt(ui_pageHome_LabelRate30Result,"%.1f",sdData.flux_test_result.current_test_result);
break;
case BS_RATE_35BPM:
lv_label_set_text_fmt(ui_pageHome_LabelRate35Result,"%.1f",sdData.flux_test_result.current_test_result);
break;
case BS_RATE_40BPM:
lv_label_set_text_fmt(ui_pageHome_LabelRate40Result,"%.1f",sdData.flux_test_result.current_test_result);
break;
default:
break;
}
/* 获取当前设备类型 */
uint16_t device_type = lv_dropdown_get_selected(ui_pageHome_DropdownTestTypeBS);
int32_t current_stage = lv_spinbox_get_value(ui_pageHome_spinboxStageBS);
float stage_volume = 0;
/* 判断测试结果是否合格 */
switch (device_type)
{
case Spirit3:
stage_volume = Spirit3_Volume[current_stage];
break;
case Spirit6:
stage_volume = Spirit6_Volume[current_stage];
break;
case YU_Lite8:
stage_volume = YULite8_Volume[current_stage];
break;
default:
break;
}
float stage_rate_volume = stage_volume/((currentTestRate+3.0)*5);
if((sdData.flux_test_result.current_test_result > stage_rate_volume * 1.15)|(sdData.flux_test_result.current_test_result < stage_rate_volume * 0.85))
{
/* 测试结果不合格刷新结果为X */
xEventGroupSetBits(g_bs_test_event_group,g_bs_test_event_group_bits[currentTestRate]);
}else{
/* 测试合格*/
xEventGroupClearBits(g_bs_test_event_group,g_bs_test_event_group_bits[currentTestRate]);
}
}
}else{
lv_obj_clear_state(ui_pageFluxRead_checkboxUnfinished,LV_STATE_CHECKED);
}
}
}
}
/**
* @brief 测试用任务函数
*
* @param[in] arg not used
*
*/
void test_task(void *arg)
{
start_state_event_group = xEventGroupCreate();
/*事件初始化*/
xEventGroupClearBits(start_state_event_group,START_TEST_EVENT_BIT);
int32_t timeS = 0;
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
if (xEventGroupGetBits(start_state_event_group)&START_TEST_EVENT_BIT)
{
/*开始测试*/
timeS = lv_spinbox_get_value(ui_pageFluxRead_spinboxTime);
/*下发启动测试指令*/
FLUX_TEST_START;
lv_label_set_text(ui_pageHome_labelStartTest,"Testing...");
vTaskDelay(timeS*1000/portTICK_PERIOD_MS);
lv_event_send(ui_pageFluxRead_buttonReadFlux,LV_EVENT_CLICKED,NULL);
lv_label_set_text(ui_pageHome_labelStartTest,"Test Complete!");
/*测试完毕后清空事件*/
xEventGroupClearBits(start_state_event_group,START_TEST_EVENT_BIT);
}
}
}
/**
* @brief 串口2收发任务 (呼吸模拟器)
*
* @param[in] arg not used
*
*/
void uart2_echoTask(void* arg)
{
/* Configure parameters of an UART driver,
* communication pins and install the driver */
uart_config_t uart_config = {
.baud_rate = ECHO_UART_BAUD_RATE,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
int intr_alloc_flags = 0;
ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM2, BUF_SIZE * 2, BUF_SIZE * 2, 0, NULL, intr_alloc_flags));
ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM2, &uart_config));
ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM2, ECHO_TEST_TXD2, ECHO_TEST_RXD2, ECHO_TEST_RTS, ECHO_TEST_CTS));
uint8_t *data = (uint8_t *) malloc(BUF_SIZE);
//ESP_LOGI("uart2_echoTask", "UART2 ECHO TEST: start test");
#if LOG_RECORD_ENABLE
WRITE_LOG_TO_SD("呼吸模拟器消息处理任务初始化完毕")
#endif
while (1)
{
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Read data from the UART
int len = uart_read_bytes(ECHO_UART_PORT_NUM2, data, (BUF_SIZE - 1), 20 / portTICK_PERIOD_MS);
// Write data back to the UART
uart_write_bytes(ECHO_UART_PORT_NUM2, (const char *) data, len);
//ESP_LOGI("uart2_echoTask", "Read %d bytes: '%s'", len, data);
}
}
/**
* @brief 封装03 06指令函数 单寄存器写、多寄存器读
*
* @param[in] uart_num 串口号
* @param[in] frame 需要发送的数据帧
*
*/
esp_err_t ModbusRTU_Send_0306(uart_port_t uart_num, struct ModbusRTU_Frame *frame)
{
unsigned short crc;
char text[64];
int res=0;
crc = CRC16((unsigned char *)frame, sizeof(frame->ADDR) + sizeof(frame->FUNC) + sizeof(frame->DATA));
frame->CRC[1] = (crc & 0xFF);
frame->CRC[0] = (crc >> 8);
res = uart_write_bytes(uart_num, (const char *)frame, sizeof(struct ModbusRTU_Frame)/sizeof(unsigned char));
if (res == -1)
{
return ESP_FAIL;
}
#if 1
sprintf(text,"%02X %02X %02X %02X %02X %02X %02X %02X",frame->ADDR,frame->FUNC,frame->DATA[0],frame->DATA[1],frame->DATA[2],frame->DATA[3],frame->CRC[0],frame->CRC[1]);
lv_textarea_add_text(ui_pageFluxDebug_textAreaContent,"Send:");
lv_textarea_add_text(ui_pageFluxDebug_textAreaContent,(char*)text);
lv_textarea_add_char(ui_pageFluxDebug_textAreaContent,'\n');
#if LOG_RECORD_ENABLE
WRITE_LOG_TO_SD("0306指令数据发送成功。");
WRITE_LOG_TO_SD(text);
#endif
#endif
return ESP_OK;
}
#if USART_USE_10_COMMAND
/**
* @brief 封装多寄存器写函数 0x10指令
*
* @param[in] uart_num 串口号
* @param[in] frame 需要发送的数据帧
*
*/
esp_err_t ModbusRTU_Send_0x10(uart_port_t uart_num, struct ModbusRTU_Frame2Reg *frame)
{
unsigned short crc;
//char text[64];
int res=0;
crc = CRC16((unsigned char *)frame, sizeof(frame->ADDR) + sizeof(frame->FUNC) + sizeof(frame->DATA)+\
sizeof(frame->regAddr) + sizeof(frame->regNum)+sizeof(frame->ByteNum));
frame->CRC[1] = (crc & 0xFF);
frame->CRC[0] = (crc >> 8);
ESP_LOGI("uart_write_bytes", "%02X %02X %02X %02X %02X %02X %02X %02X \n",\
frame->ADDR,frame->FUNC,frame->DATA[0],frame->DATA[1],frame->DATA[2],frame->DATA[3],frame->CRC[0],frame->CRC[1]);
res = uart_write_bytes(uart_num, (const char *)frame, sizeof(struct ModbusRTU_Frame2Reg)/sizeof(unsigned char));
if (res == -1)
{
return ESP_FAIL;
ESP_LOGI("uart_write_bytes", "uart_write_bytes fail");
}
ESP_LOGI("uart_write_bytes", "uart_write_bytes success");
return ESP_OK;
}
#endif
/**
* @brief 封装05指令修改单个寄存器开关量
*
* @param[in] uart_num 串口号
* @param[in] frame 需要发送的数据帧
*
*/
esp_err_t ModbusRTU_Send_0x05(uint32_t ADDR)
{
struct ModbusRTU_Frame frame;
unsigned short crc;
frame.ADDR = 0x01;
frame.FUNC = 0x05;
/* 寄存器所在地址 */
frame.DATA[0] = (ADDR >> 8);
frame.DATA[1] = (ADDR & 0xFF);
/* 启动命令 */
frame.DATA[2] = 0xFF;
frame.DATA[3] = 0x00;
crc = CRC16((unsigned char *)&frame, sizeof(frame.ADDR) + sizeof(frame.FUNC) + sizeof(frame.DATA));
frame.CRC[1] = (crc & 0xFF);
frame.CRC[0] = (crc >> 8);
int res = uart_write_bytes(ECHO_UART_PORT_NUM2, (const char *)&frame, sizeof(struct ModbusRTU_Frame)/sizeof(unsigned char));
if (res == -1)
{
return ESP_FAIL;
WRITE_LOG_TO_SD("05指令数据发送失败。");
ESP_LOGI("uart_write_bytes", "uart_write_bytes fail");
}
WRITE_LOG_TO_SD("05指令数据发送成功。");
return ESP_OK;
}
/**
* @brief 根据主界面内容刷新测试结果
*
*/
esp_err_t RefreshResult(void)
{
/* 获取当前测试次数 */
switch (lv_dropdown_get_selected(ui_pageFluxRead_dropdownPulseTimes))
{
case 0:
FluxMachineData.breathTimes = 10;
break;
case 1:
FluxMachineData.breathTimes = 20;
break;
case 2:
FluxMachineData.breathTimes = 30;
break;
default:
break;
}
/* 获取当前测试流量 */
float breathVolume = FluxMachineData.cumulativeVolume/FluxMachineData.breathTimes;
lv_label_set_text_fmt(ui_pageHome_labelTestVolume,"%.2f",breathVolume);
/*获取测试体积上下限*/
float testVolumeUpper = atoff(lv_label_get_text(ui_pageHome_labelNominalVolumeMax));
float testVolumeLower = atoff(lv_label_get_text(ui_pageHome_labelNominalVolumeMin));
/*根据测试结果判断是否合格*/
if (breathVolume > testVolumeUpper || breathVolume < testVolumeLower)
{
RESULT_FAULT;
if (breathVolume > testVolumeUpper )
{
lv_label_set_text(ui_pageHome_labelResultCompare,"High");
}else if (breathVolume < testVolumeLower)
{
lv_label_set_text(ui_pageHome_labelResultCompare,"Low");
}
}else{
RESULT_RIGHT;
lv_label_set_text(ui_pageHome_labelResultCompare,"Pass!");
}
#if LOG_RECORD_ENABLE
WRITE_LOG_TO_SD("结果判断刷新完毕");
#endif
return ESP_OK;
}