From 89b0708dfba62ab577b92c84d300733fadb27fa5 Mon Sep 17 00:00:00 2001 From: liumin Date: Sat, 5 Jul 2025 20:11:15 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 9 + MFC2AF5DEDB.tmp | 178 +++++ app/20250324植树车app.rar | Bin 0 -> 37063 bytes app/app_brake.c | 224 ++++++ app/app_brake.h | 58 ++ app/app_config.h | 39 + app/app_dependence.h | 90 +++ app/app_differential_drive.c | 932 ++++++++++++++++++++++ app/app_differential_drive.h | 84 ++ app/app_frm_monitor.c | 175 +++++ app/app_frm_monitor.h | 41 + app/app_frm_signal.c | 324 ++++++++ app/app_frm_signal.h | 47 ++ app/app_frm_timer.c | 165 ++++ app/app_frm_timer.h | 35 + app/app_light.c | 240 ++++++ app/app_light.h | 62 ++ app/app_param_manage.c | 464 +++++++++++ app/app_param_manage.h | 145 ++++ app/app_pid.c | 130 ++++ app/app_pid.h | 46 ++ app/app_power.c | 429 ++++++++++ app/app_power.h | 57 ++ app/app_request.c | 396 ++++++++++ app/app_request.h | 89 +++ app/app_temp.c | 285 +++++++ app/app_temp.h | 58 ++ app/app_test.c | 62 ++ app/app_test.h | 18 + app/app_ultrasonic.c | 83 ++ app/app_ultrasonic.h | 75 ++ app_brake.c | 127 +++ app_brake.h | 34 + crc16.h | 51 ++ interface.c | 70 ++ interface.h | 984 +++++++++++++++++++++++ interface_24c02.c | 428 ++++++++++ interface_24c02.h | 42 + interface_boot.c | 130 ++++ interface_boot.h | 69 ++ interface_btm.c | 99 +++ interface_btm.h | 19 + interface_can.c | 1422 ++++++++++++++++++++++++++++++++++ interface_can.h | 204 +++++ interface_config.h | 70 ++ interface_ethernet.c | 660 ++++++++++++++++ interface_ethernet.h | 121 +++ interface_gpio.c | 145 ++++ interface_gpio.h | 25 + interface_power.c | 139 ++++ interface_power.h | 115 +++ interface_uart.c | 471 +++++++++++ interface_uart.h | 157 ++++ interface_wdt.c | 48 ++ interface_wdt.h | 64 ++ main.c | 142 ++++ 56 files changed, 10876 insertions(+) create mode 100644 .gitignore create mode 100644 MFC2AF5DEDB.tmp create mode 100644 app/20250324植树车app.rar create mode 100644 app/app_brake.c create mode 100644 app/app_brake.h create mode 100644 app/app_config.h create mode 100644 app/app_dependence.h create mode 100644 app/app_differential_drive.c create mode 100644 app/app_differential_drive.h create mode 100644 app/app_frm_monitor.c create mode 100644 app/app_frm_monitor.h create mode 100644 app/app_frm_signal.c create mode 100644 app/app_frm_signal.h create mode 100644 app/app_frm_timer.c create mode 100644 app/app_frm_timer.h create mode 100644 app/app_light.c create mode 100644 app/app_light.h create mode 100644 app/app_param_manage.c create mode 100644 app/app_param_manage.h create mode 100644 app/app_pid.c create mode 100644 app/app_pid.h create mode 100644 app/app_power.c create mode 100644 app/app_power.h create mode 100644 app/app_request.c create mode 100644 app/app_request.h create mode 100644 app/app_temp.c create mode 100644 app/app_temp.h create mode 100644 app/app_test.c create mode 100644 app/app_test.h create mode 100644 app/app_ultrasonic.c create mode 100644 app/app_ultrasonic.h create mode 100644 app_brake.c create mode 100644 app_brake.h create mode 100644 crc16.h create mode 100644 interface.c create mode 100644 interface.h create mode 100644 interface_24c02.c create mode 100644 interface_24c02.h create mode 100644 interface_boot.c create mode 100644 interface_boot.h create mode 100644 interface_btm.c create mode 100644 interface_btm.h create mode 100644 interface_can.c create mode 100644 interface_can.h create mode 100644 interface_config.h create mode 100644 interface_ethernet.c create mode 100644 interface_ethernet.h create mode 100644 interface_gpio.c create mode 100644 interface_gpio.h create mode 100644 interface_power.c create mode 100644 interface_power.h create mode 100644 interface_uart.c create mode 100644 interface_uart.h create mode 100644 interface_wdt.c create mode 100644 interface_wdt.h create mode 100644 main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0b07df --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +# 忽略整个目录及其所有子文件和子目录 +/configs/ +/IAR/ +/IAR_Norflash/ +/SES/ +/configs/** +/IAR/** +/IAR_Norflash/** +/SES/** \ No newline at end of file diff --git a/MFC2AF5DEDB.tmp b/MFC2AF5DEDB.tmp new file mode 100644 index 0000000..1c84b6f --- /dev/null +++ b/MFC2AF5DEDB.tmp @@ -0,0 +1,178 @@ +#ifndef ETH_DEMO_H +#define ETH_DEMO_H + +#include "app_config.h" + + + + +//volatile uint8_t RgCanToGPSCnt = 0;//导航仪CAN计数器 +//volatile uint8_t RgCanToGPSCntLast = 0;//导航仪CAN计数器过去值 +//volatile uint8_t RgCanGPSFault = 0;//导航仪CAN故障 + +//volatile uint8_t RgCanMoterFault = 0;//电机控制器1CAN故障 +// +//volatile uint8_t RgENTFaultContral = 0;//控制器遥控以太网故障 +//volatile uint8_t RgConEnetVaulelast = 0;//遥控以太网过去数据 +// +//volatile uint8_t RgENTFaultOwn = 0;//控制器自主以太网故障 +//volatile uint8_t RgOwnEnetVaulelast = 0;//自主以太网过去数据 +// +//volatile uint8_t RgENTFaultRemoteControlRoom = 0;//控制器遥控室故障 +//volatile uint8_t RgRemoteControlRoomENTVaulelast = 0;//控制器遥控室过去数据 +// +//volatile uint16_t RgCanRC6GSFault = 0;//汽车遥控CAN接收故障 +//volatile uint16_t RgCanRC6GSCnt = 0;//汽车遥控CAN接收计数器 +//volatile uint16_t RgCanRC6GSCntLast = 0;//汽车遥控接收计数器过去值 +// +// +//uint16_t RgCanToBatteryCnt = 0;//BMS CAN接收计数器 +//uint16_t RgETHToPortableCnt = 0;//以太网遥控器接受计数器 +//uint16_t RgETHToOwnComputerCnt = 0;//以太网接受自主计算器 +//uint16_t RgETHToRemoteControlCnt = 0;//以太网监控室接收计数器 +// +//uint16_t RgCanToMotorCnt1 = 0;//CAN接收计数器 +//uint16_t RgCanToMotorCntLast1 = 0;//CAN接收计数器过去值 +// +//uint16_t RgCanToMotorCnt2 = 0;//CAN接收计数器 +//uint16_t RgCanToMotorCntLast2 = 0;//CAN接收计数器过去值 +// +//uint8_t RgEthernetOwnCnt = 0;//自主接收故障定时器 +//uint8_t RgEthernetTelecontrolCnt = 0;//手柄遥控故障定时器 + + + +typedef struct +{ + unsigned char gps_state; // GPS状态 | 0故障 1正常 + unsigned char motor1_state; // 电机1状态 | 0故障 1正常 + unsigned char motor2_state; // 电机2状态 | 0故障 1正常 + unsigned char remote_state; // 遥控状态 | 0故障 1正常 + unsigned char bms_state; // BMS状态 | 0故障 1正常 + unsigned char auto_state; // 自动状态 | 0故障 1正常 + unsigned char manual_state; // 手动状态 | 0故障 1正常 + + unsigned char gps_change; // GPS变化 | 0未发生变化 1变化 + unsigned char motor1_change; // 电机1变化 | 0未发生变化 1变化 + unsigned char motor2_change; // 电机2变化 | 0未发生变化 1变化 + unsigned char remote_change; // 遥控变化 | 0未发生变化 1变化 + unsigned char bms_change; // BMS变化 | 0未发生变化 1变化 + unsigned char auto_change; // 自动变化 | 0未发生变化 1变化 + unsigned char manual_change; // 手动变化 | 0未发生变化 1变化 + +} FaultInfo; + + +typedef struct +{ + uint8_t auto_count; //自动数据计数器 + uint8_t manual_count; //手动数据计数器 + uint8_t auto_state; // 自动状态 | 0故障 1正常 + uint8_t manual_state; // 手动状态 | 0故障 1正常 + + + uint8_t auto_count_old; //自动数据计数器 + uint8_t manual_count_old; //手动数据计数器 + uint8_t auto_state_old; // 自动状态 | 0故障 1正常 + uint8_t manual_state_old; // 手动状态 | 0故障 1正常 + uint8_t auto_state; // 自动状态 | 0故障 1正常 + uint8_t manual_state; // 手动状态 | 0故障 1正常 + +} StrFaultInformation; + + + + +typedef struct +{ + uint16_t navigator_counter; //导航仪计数器 + uint16_t motor1_counter; //电机控制器1计数器 + uint16_t motor2_counter; //电机控制器2计数器 + uint16_t remote_counter; //遥控器计数器 + uint16_t bms_cnt; //BMS计数器 + uint16_t auto_cnt; //自动数据计数器 + uint16_t manual_cnt; //手动数据计数器 + + uint16_t can_gps_cnt_old ; //导航仪计数器过去值 + uint16_t can_motor1_cnt_last; //电机控制器1计数器过去值 + uint16_t can_motor2_cnt_last; //电机控制器2计数器过去值 + uint16_t can_remote_control_cnt_last; //遥控器计数器过去值 + uint16_t can_bms_cnt_last; //bms计数器过去值 + uint16_t ethernet_auto_computer_cnt_last; //自动数据计数器过去值 + uint16_t ethernet_manual_computer_cnt_last;//手动数据计数器过去值 + + bool can_gps_state_last; //导航仪故障状态过去值 0故障 1正常 + bool can_motor1_state_last; //电机控制器1状态故障过去值 0故障 1正常 + bool can_motor2_state_last; //电机控制器2状态故障过去值 + bool can_bms_state_last; //bms故障状态过去值 + bool can_remote_control_state_last; //遥控器故障状态过去值 + bool ethernet_auto_computer_state_last; //自动数据故障状态过去值 + bool ethernet_manual_computer_state_last; //手动数据故障状态过去值 + +} StrFaultTemp; + + + + + + + + +typedef struct +{ + uint8_t local_ip[4]; + uint8_t mask[4]; + uint16_t Local_upper_port; + uint16_t Local_download_port; + uint16_t local_communication_port; + uint8_t computer_ip[4]; + uint8_t upper_ip[4]; + uint8_t download_ip[4]; + uint16_t target_upper_port; + uint16_t target_download_port; + uint16_t target_communication_port; + +} StrEthernetParameter; + + + + + + + + + + + + + + + + + + + + +#define UDPCB_1 1//通讯端口 +#define UDPCB_2 2//上位机端口 +#define UDPCB_3 3//下载端口 + + +#define COMMUNICATION_PORT 8011 +#define UPPER_PORT 8000 +#define DOWNLOAR_PORT 7811 + + +//外部函数 +void UDP_Echo_Init(uint8_t udpcbID, udp_recv_fn recv, uint16_t port); +void UdpSendToData(uint8_t udpcbID, uint8_t *buf, uint16_t len, uint8_t *sip, uint16_t port); + +void udp_Callback_1(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +void udp_Callback_2(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +//外部变量 +extern struct udp_pcb *udpcb_1; + +extern StrEthernetParameter ethernet_parameter; +extern StrFaultInformation str_faultInformation; + +#endif /*ETH_DEMO_H */ \ No newline at end of file diff --git a/app/20250324植树车app.rar b/app/20250324植树车app.rar new file mode 100644 index 0000000000000000000000000000000000000000..004dfa6c2a953ca7c01b616816f0973f47d88741 GIT binary patch literal 37063 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

!sVFs=02(& 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 literal 0 HcmV?d00001 diff --git a/app/app_brake.c b/app/app_brake.c new file mode 100644 index 0000000..f9379fc --- /dev/null +++ b/app/app_brake.c @@ -0,0 +1,224 @@ +#include "app_config.h" +#include "interface.h" +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" +#include "app_param_manage.h" + +#include "app_power.h" + +#include "app_brake.h" +#include "app_differential_drive.h" + +// 使用内联函数 +static inline uint8_t setBrakeOn(void) { return 1; } +static inline uint8_t setBrakeOff(void) { return 0; } + +BrakeSystem brake_data; + +// 判断是否需要刹车 +static uint8_t shouldApplyBrake() +{ + return (brake_data.emergency_stop_switch || + brake_data.remote_emergency_stop || + (brake_data.mode_signal == 0 && brake_data.remote_fault) || + (brake_data.mode_signal == 1 && brake_data.can_bus_fault));//20241021 修改不计算以太网故障 +// (brake_data.mode_signal == 1 && (brake_data.can_bus_fault || brake_data.ethernet_fault))); +} + +// 判断是否需要释放刹车 +static uint8_t shouldReleaseBrake() +{ + return (!brake_data.emergency_stop_switch && + !brake_data.remote_emergency_stop && + ((brake_data.mode_signal == 0 && !brake_data.remote_fault) || + (brake_data.mode_signal == 1 && !brake_data.can_bus_fault)));//20241021 修改不计算以太网故障 +// (brake_data.mode_signal == 1 && (!brake_data.can_bus_fault && !brake_data.ethernet_fault)))); +} + + + +// 输出处理函数 +static void brakeOutput(void *signal_id) +{ + (void)signal_id; + // 根据电机状态,填充发送数据结构,发送信号 + switch (brake_data.brake_motor_state) + { + case 1: // 电机前进状态 + un_h_bridge_output.bit_data.channel_01 = setBrakeOn(); + un_h_bridge_output.bit_data.channel_04 = setBrakeOn(); + un_h_bridge_output.bit_data.channel_02 = setBrakeOff(); + un_h_bridge_output.bit_data.channel_03 = setBrakeOff(); + un_h_bridge_output.bit_data.sleep_01 = setBrakeOn(); + un_h_bridge_output.bit_data.sleep_02 = setBrakeOn(); // 正转 + un_inf_can_kgf_output1.bit_data.KGF13 = setBrakeOff(); // 抱闸继电器 + un_inf_can_kgf_output1.bit_data.KGF14 = setBrakeOff(); // 抱闸继电器 + printf("Brake: Motor forward\n"); + break; + + case 2: // 电机后退状态 + un_h_bridge_output.bit_data.channel_01 = setBrakeOff(); + un_h_bridge_output.bit_data.channel_04 = setBrakeOff(); + un_h_bridge_output.bit_data.channel_02 = setBrakeOn(); + un_h_bridge_output.bit_data.channel_03 = setBrakeOn(); + un_h_bridge_output.bit_data.sleep_01 = setBrakeOn(); + un_h_bridge_output.bit_data.sleep_02 = setBrakeOn(); // 反转 + un_inf_can_kgf_output1.bit_data.KGF13 = setBrakeOn(); // 抱闸继电器 + un_inf_can_kgf_output1.bit_data.KGF14 = setBrakeOn(); // 抱闸继电器 + + printf("Brake: Motor reverse\n"); + break; + + default: + un_h_bridge_output.bit_data.channel_01 = setBrakeOff(); + un_h_bridge_output.bit_data.channel_04 = setBrakeOff(); + un_h_bridge_output.bit_data.channel_02 = setBrakeOff(); + un_h_bridge_output.bit_data.channel_03 = setBrakeOff(); + un_h_bridge_output.bit_data.sleep_01 = setBrakeOff(); + un_h_bridge_output.bit_data.sleep_02 = setBrakeOff(); // 关闭 + printf("Brake: Motor off\n"); + break; + } + + publishMessage(&un_h_bridge_output, 1); + publishMessage(&un_inf_can_kgf_output1, 1); +} + + + +// 修改刹车定时器处理函数 +static void brakeTimerProcess(void *signal_id) +{ + (void)signal_id; + +//#ifdef OIL_BRAKE + switch (brake_data.state) + { + case BRAKE_STATE_IDLE: + if (shouldApplyBrake()) + { + brake_data.state = BRAKE_STATE_APPLYING_BRAKE; + brake_data.brake_motor_state = 1; + brakeOutput(NULL); + timerStart(&brake_data.brake_apply_timer, (uint32_t)(getParam("brk_on")), 0); + } + break; + + case BRAKE_STATE_BRAKE_ON: + if (shouldReleaseBrake() && power_data.current_state == POWER_WORKING) + { + brake_data.state = BRAKE_STATE_RELEASING_BRAKE; + brake_data.brake_motor_state = 2; + brakeOutput(NULL); + timerStart(&brake_data.brake_release_timer, (uint32_t)(getParam("brk_off")), 0); + } + break; + + case BRAKE_STATE_APPLYING_BRAKE: + if (!brake_data.brake_apply_timer.active) + { + brake_data.state = BRAKE_STATE_BRAKE_ON; + brake_data.brake_motor_state = 0; + brakeOutput(NULL); + brake_data.brake_position = 1; // 刹车位置:1表示刹车 + } + break; + + case BRAKE_STATE_RELEASING_BRAKE: + if (!brake_data.brake_release_timer.active) + { + brake_data.state = BRAKE_STATE_IDLE; + brake_data.brake_motor_state = 0; + brakeOutput(NULL); + brake_data.brake_position = 0; // 刹车位置:0表示未刹车 + } + break; + + default: + printf("ERROR: Unknown state\n"); + brake_data.state = BRAKE_STATE_IDLE; + break; + } + // 如果刹车位置有变化,存入EEPROM + if (brake_data.brake_position != brake_data.old_brake_position) + { + setParam("brk_pos", (float)brake_data.brake_position); + brake_data.old_brake_position = brake_data.brake_position; + + + + printf("writeE2 brake_position = %d\n",brake_data.brake_position); + + } + timerStart(&brake_data.brake_timer, 100, 1); // 周期调用 +} + + +// 处理所有输入信号的函数 +static void brakeInput(void *signal_id) +{ +// BrakeSystem old_data = brake_data; // 定义并初始化old_data + + // 填充数据 + if (signal_id == &un_sw_sample) + { + brake_data.emergency_stop_switch = (uint8_t)un_sw_sample.bit_data.emergency_stop_switch; + } + else if ( (signal_id == &un_remote_control_input) && (1 == un_remote_control_input.bit_data.enable) )// 遥控器断线,不更新数据 + { + brake_data.remote_emergency_stop = ((uint8_t)un_remote_control_input.bit_data.switch_b == 1) ? 0 : 1; + brake_data.mode_signal = ((uint8_t)un_remote_control_input.bit_data.switch_c == 1) ? 1 : 0; + } + else if (signal_id == &can_fault_info) + { + brake_data.remote_fault = !can_fault_info.bit_data.remote_state; + brake_data.can_bus_fault = !can_fault_info.bit_data.motor1_state || !can_fault_info.bit_data.motor2_state || !can_fault_info.bit_data.navigator_state; + } + else if (signal_id == ðernet_fault_Info) + { + brake_data.ethernet_fault = !ethernet_fault_Info.bit_data.auto_state && !ethernet_fault_Info.bit_data.manual_state; + } + +} + +// 修改APP模块的初始化函数 +void brakeAppInit(void) +{ + // 初始化 + memset(&brake_data, 0, sizeof(BrakeSystem)); + brake_data.state = BRAKE_STATE_IDLE; + // 初始化时恢复刹车位置 + brake_data.brake_position = (uint8_t)getParam("brk_pos"); + brake_data.old_brake_position = brake_data.brake_position; + // 根据刹车位置恢复刹车状态 + if (brake_data.brake_position == 1) + { + brake_data.state = BRAKE_STATE_BRAKE_ON; + } + else + { + brake_data.state = BRAKE_STATE_IDLE; + } + + // 初始化定时器 + timerInit(&brake_data.brake_timer); + timerInit(&brake_data.brake_apply_timer); + timerInit(&brake_data.brake_release_timer); + + // 订阅输入信号,处理刹车逻辑 + subscribe(&un_sw_sample, brakeInput); + subscribe(&un_remote_control_input, brakeInput); + subscribe(&can_fault_info, brakeInput); + subscribe(ðernet_fault_Info, brakeInput); + + // 订阅定时器信号,用于状态机的定时处理 + subscribe(&brake_data.brake_timer, brakeTimerProcess); + subscribe(&brake_data.brake_apply_timer, brakeTimerProcess); + subscribe(&brake_data.brake_release_timer, brakeTimerProcess); + + // 启动定时器,定期调用 brakeTimerProcess + timerStart(&brake_data.brake_timer, 500, 1); + + printf("app_brake: initial OK \n"); +} diff --git a/app/app_brake.h b/app/app_brake.h new file mode 100644 index 0000000..2146c11 --- /dev/null +++ b/app/app_brake.h @@ -0,0 +1,58 @@ +#ifndef APP_BRAKE_H +#define APP_BRAKE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "app_config.h" +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" + +#define OIL_BRAKE 0 +#define ELECTROMAGNETIC_BRAKE 1 + + +// 定义刹车状态机状态 +typedef enum { + BRAKE_STATE_IDLE, + BRAKE_STATE_APPLYING_BRAKE, + BRAKE_STATE_RELEASING_BRAKE, + BRAKE_STATE_BRAKE_ON, +} BrakeState; + +typedef struct BrakeSystem +{ + uint32_t start_time; + Timer brake_timer; // 定时器结构体 + uint8_t brake_command; // 刹车命令变量:1表示刹车,2表示释放 + uint8_t brake_motor_state; // 刹车电机状态变量:0停止,1前进,2后退 + uint8_t brake_command_in_progress; // 刹车命令执行状态:0表示空闲,1表示正在执行 + + uint8_t emergency_stop_switch; // 急停开关 + uint8_t remote_emergency_stop; // 遥控器急停开关 + uint8_t remote_fault; // 遥控器故障 + uint8_t can_bus_fault; // CAN总线故障 + uint8_t ethernet_fault; // 以太网通信故障 + uint8_t mode_signal; // 模式信号:0表示手动模式,1表示自动模式 + BrakeState state; // 刹车状态机 + uint8_t brake_position; // 刹车位置:0表示未刹车,1表示刹车 + uint8_t old_brake_position; // 旧的刹车位置 + Timer brake_apply_timer; // 刹车定时器 + Timer brake_release_timer; // 释放刹车定时器 + +} BrakeSystem; + + +// 声明外部变量 +extern BrakeSystem brake_data; + + +void brakeAppInit(void); + +#ifdef __cplusplus +} +#endif + +#endif // APP_BRAKE_H diff --git a/app/app_config.h b/app/app_config.h new file mode 100644 index 0000000..edc68d5 --- /dev/null +++ b/app/app_config.h @@ -0,0 +1,39 @@ +#ifndef APP_CONFIG_H +#define APP_CONFIG_H + + +#ifdef __cplusplus +extern "C" { +#endif + +// 标准库,每个模块中也会包含 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//外部依赖放在这里,方便分层管理,实际代码中也有这个文件,但是没有依赖 +//移植的时候,存放依赖的文件不用移植 +#include "app_dependence.h" +// 接口,全局变量都放在这里 +#include "interface.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +static inline uint8_t app_close(void) { return 1; } +static inline uint8_t app_open(void) { return 0; } + + +#ifdef __cplusplus +} +#endif + + +#endif // APP_CONFIG_H diff --git a/app/app_dependence.h b/app/app_dependence.h new file mode 100644 index 0000000..4885068 --- /dev/null +++ b/app/app_dependence.h @@ -0,0 +1,90 @@ +#ifndef TEST_H +#define TEST_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "irq.h" +#include "udelay\udelay.h" + +#define PERIOD_TICK 1000000.0f // 1000000us = 1s + + + + +#ifdef __cplusplus +extern "C" { +#endif + +//unsigned int wrbyte_24c02(unsigned int addr, unsigned char data); +//unsigned char rdbyte_24c02(unsigned int addr); +//void feedWatchdog(void); +//uint32_t getCurrentTime(void); +//void udelay(uint32_t t ); +// +//typedef unsigned int irq_state_t; + +//static inline irq_state_t arch_irq_save(void) +//{ +// unsigned int cpsr = 0; +// return cpsr; +//} +// +//static inline void arch_irq_restore(irq_state_t flags) +//{ +// flags += 1; +//} + +//// 故障信息 +//typedef struct _StrCanFault +//{ +// uint8_t navigator_count; // 导航仪计数器 +// uint8_t motor1_count; // 左电机计数器 +// uint8_t motor2_count; // 右电机计数器 +// uint8_t bms_count; // bms计数器 +// uint8_t temperature_count; // 温度计数器 +// uint8_t remote_count; // 遥控计数器 +// +// uint8_t navigator_state; // 导航仪故障状态 +// uint8_t motor1_state; // 电机1故障状态 +// uint8_t motor2_state; // 电机2故障状态 +// uint8_t bms_state; // bms状态 +// uint8_t temperature_state; // 温度计数器 +// uint8_t remote_state; // 遥控状态 +//} StrCanFault; + +//typedef union _UnCanFault +//{ +// StrCanFault bit_data; // 使用定义的结构体类型 +// uint8_t arr[sizeof(StrCanFault)]; // 通过结构体确定数组大小 +//} UnCanFault; + +//extern UnCanFault can_fault_info; + +//typedef struct _StrEthernetFault +//{ +// uint8_t auto_count; // 自动数据计数器 +// uint8_t manual_count; // 手动数据计数器 +// uint8_t auto_state; // 自动状态 | 0正常 1故障 +// uint8_t manual_state; // 手动状态 | 0正常 1故障 +//} StrEthernetFault; +// +//typedef union _UnEthernetFault +//{ +// StrEthernetFault bit_data; // 使用定义的结构体类型 +// uint8_t arr[sizeof(StrEthernetFault)]; // 通过结构体大小确定数组大小 +//} UnEthernetFault; + +//extern UnEthernetFault ethernet_fault_Info; + +#ifdef __cplusplus +} +#endif + +#endif // TEST_H diff --git a/app/app_differential_drive.c b/app/app_differential_drive.c new file mode 100644 index 0000000..3bb5b03 --- /dev/null +++ b/app/app_differential_drive.c @@ -0,0 +1,932 @@ +#include "app_config.h" +#include "interface.h" + +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" +#include "app_param_manage.h" +#include "app_pid.h" + +#include "app_differential_drive.h" +#include "app_brake.h" +#include "app_power.h" + +Timer diff_app_timer; + +// 定义全局变量 +DiffData diff_data; + +PID_t speed_pid; +PID_t yaw_rate_pid; + +// 设置电机输出 +void setMotorOutput(float *out_torq, float max_torque, uint16_t feed_power, uint16_t discharge_power) +{ + + float abs_left_front_speed = 0; + float abs_right_front_speed = 0; + float abs_left_rear_speed = 0; + float abs_right_rear_speed = 0; + + // 档位 + un_motor_output1.bit_data.gear = diff_data.state; // 1 表示前进,2 表示后退,0空挡 + un_motor_output2.bit_data.gear = diff_data.state; + un_motor_output3.bit_data.gear = diff_data.state; + un_motor_output4.bit_data.gear = diff_data.state; + + + //增加系数以及偏移量 + if(diff_data.state == STATE_FORWARD)//根据挡位来判断,扭矩的正负 + { + abs_left_front_speed = (out_torq[0] + 300.0f) *100.0f; + abs_right_front_speed = (out_torq[1] + 300.0f) *100.0f; + abs_left_rear_speed = (out_torq[2] + 300.0f) *100.0f; + abs_right_rear_speed = (out_torq[3] + 300.0f) *100.0f; + } + else if(diff_data.state == STATE_BACKWARD)//倒挡直接修改为负扭矩发送出去 + { + abs_left_front_speed = (-out_torq[0] + 300.0f) *100.0f; + abs_right_front_speed = (-out_torq[1] + 300.0f) *100.0f; + abs_left_rear_speed = (-out_torq[2] + 300.0f) *100.0f; + abs_right_rear_speed = (-out_torq[3] + 300.0f) *100.0f; + } + else//空挡直接发0 + { + abs_left_front_speed = 0; + abs_right_front_speed = 0; + abs_left_rear_speed = 0; + abs_right_rear_speed = 0; + } + + + // 设置左右电机期望转速 +// un_motor_output1.bit_data.set_rotation_speed = ((uint16_t)roundf(abs_left_speed) + 30000); // 20240921 增加偏移量 30000 +// un_motor_output2.bit_data.set_rotation_speed = ((uint16_t)roundf(abs_right_speed) + 30000); // 20240921 增加偏移量 30000 + + // 设置模式为扭矩模式 + un_motor_output1.bit_data.mode = MOTOR_MODE; + un_motor_output2.bit_data.mode = MOTOR_MODE; + un_motor_output3.bit_data.mode = MOTOR_MODE; + un_motor_output4.bit_data.mode = MOTOR_MODE; + + // 设置最大扭矩 + un_motor_output1.bit_data.set_torque = (uint16_t)( (int16_t)abs_left_front_speed ); + un_motor_output2.bit_data.set_torque = (uint16_t)( (int16_t)abs_right_front_speed ); + un_motor_output3.bit_data.set_torque = (uint16_t)( (int16_t)abs_left_rear_speed ); + un_motor_output4.bit_data.set_torque = (uint16_t)( (int16_t)abs_right_rear_speed ); + + + // 设置馈电功率 + un_motor_output1.bit_data.feed_power = feed_power; + un_motor_output2.bit_data.feed_power = feed_power; + un_motor_output3.bit_data.feed_power = feed_power; + un_motor_output4.bit_data.feed_power = feed_power; + + + // 设置放电功率 + un_motor_output1.bit_data.discharge_power = discharge_power; + un_motor_output2.bit_data.discharge_power = discharge_power; + un_motor_output3.bit_data.discharge_power = discharge_power; + un_motor_output4.bit_data.discharge_power = discharge_power; + + +} + + +// 限制值在最小值和最大值之间 +float constrain(float value, float min_val, float max_val) +{ + if (value < min_val) + { + return min_val; + } + else if (value > max_val) + { + return max_val; + } + else + { + return value; + } +} + +// 计算当前速度、角速度 +uint8_t calculateCurrentSpeedYawRate(void) +{ + // 获取轮子周长 + float wheel_circumference = (float)getParam("whl_dia") * M_PI; + // 获取减速比 + float gear_ratio = (float)getParam("gRatio"); + if (fabsf(gear_ratio) < EPSILON) + { + return 0; // 避免除以0的情况 + } + // 将电机转速 (RPM) 转换为线速度 (m/s),考虑减速比 + + + float left_speed_mps = (diff_data.left_motor_speed * wheel_circumference) / (60.0f * gear_ratio); + float right_speed_mps = (diff_data.right_motor_speed * wheel_circumference) / (60.0f * gear_ratio); + +// float left_speed_mps = 0; +// float right_speed_mps = 0; + +// float left_speed_mps = 0; +// float right_speed_mps = 0; + + // 计算当前速度 + diff_data.speed = (left_speed_mps + right_speed_mps) / 2.0f; + // 计算速度差 + float speed_diff = left_speed_mps - right_speed_mps; + // 计算角速度 + float wheel_base = (float)getParam("whl_bas"); + if (fabsf(wheel_base) < EPSILON) + { + return 0; // 避免除以0的情况 + } + diff_data.yaw_rate = speed_diff / wheel_base; + + return 0; +} + + +// 计算加速度 +float calculateAcceleration(float speed, float previous_speed, float dt) +{ + if (fabs(dt) < EPSILON) + { + return 0; // 避免除以0的情况 + } + float acceleration = (speed - previous_speed) / dt; + return acceleration; +} + +// 计算减速度 +float calculateDeceleration(float speed, float previous_speed, float dt) +{ + if (fabs(dt) < EPSILON) + { + return 0; // 避免除以0的情况 + } + float deceleration = calculateAcceleration(previous_speed, speed, dt); // 减速度就是负的加速度 + return deceleration; +} + +// 计算最大速度 +float calculateMaxSpeed() +{ + // 获取最大电机转速 (RPM) + float max_rpm = (float)getParam("max_rpm"); + // 获取轮子周长 + float wheel_circumference = (float)getParam("whl_dia") * M_PI; + // 获取减速比 + float gear_ratio = (float)getParam("gRatio"); + if (fabsf(gear_ratio) < EPSILON) + { + return 0; // 避免除以0的情况 + } + // 将最大电机转速 (RPM) 转换为线速度 (m/s),考虑减速比 + float max_speed = (max_rpm * wheel_circumference) / (60.0f * gear_ratio); + return max_speed; +} + +// 计算最大加速度 +float calculateMaxAcceleration(void) +{ + // 获取车辆参数 + float max_motor_torque = (float)getParam("maxTorq"); // 最大电机扭矩 + float vehicle_mass = (float)getParam("VehMass"); // 车辆质量 + float wheel_radius = (float)getParam("whl_dia") / 2.0f; // 轮子半径 + float gear_ratio = (float)getParam("gRatio"); // 减速比 + if (fabsf(wheel_radius) < EPSILON || fabsf(vehicle_mass) < EPSILON ) + { + return 0; // 避免除以0的情况 + } + // 减速比计算扭矩 + float effective_torque = max_motor_torque * gear_ratio; + // 计算最大加速度 + float max_acceleration = (effective_torque / wheel_radius) / vehicle_mass; + return max_acceleration; +} + +// 计算当前状态,包括当前速度、角速度、加速度、减速度、最大速度 +void calculateCurrentState(float dt) +{ + static float previous_speed = 0.0f; + // 更新当前速度和当前角速度 + calculateCurrentSpeedYawRate(); + // 更新加速度、减速度等,根据需要计算 + diff_data.acceleration = calculateAcceleration(diff_data.speed, previous_speed, dt); + diff_data.deceleration = calculateDeceleration(diff_data.speed, previous_speed, dt); + diff_data.max_speed = calculateMaxSpeed(); + previous_speed = diff_data.speed; +} + + +/** + * @brief 基于转速反比的双电机扭矩分配函数 + * @param rpm1 电机1当前转速(单位:rpm) + * @param rpm2 电机2当前转速(单位:rpm) + * @param total_torque 系统总需求扭矩(单位:Nm) + * @param torque1 [out] 电机1分配到的扭矩(单位:Nm) + * @param torque2 [out] 电机2分配到的扭矩(单位:Nm) + * @note 分配原则:转速越高的电机分配扭矩越小,确保负载均衡 + */ +void distributeTorque(float rpm1, float rpm2, float total_torque, float* torque1, float* torque2, float max_torque, float min_torque) +{ + + // 总扭矩为0时快速返回 + if (fabs(total_torque) < 0.001f) { + *torque1 = 0.0f; + *torque2 = 0.0f; + return; + } + +// // 保护条件:当两电机均静止时采用平均分配策略 +// if (fabs(rpm1) < 0.001f && fabs(rpm2) < 0.001f) { +// *torque1 = total_torque / 2.0f; +// *torque2 = total_torque / 2.0f; +// return; +// } + + // 计算权重因子(与转速成反比关系) + // 注:添加0.001f防止零转速时除零错误,fabs确保负转速正确处理 + float weight1 = 1.0f / (fabs(rpm1) + 0.001f); + float weight2 = 1.0f / (fabs(rpm2) + 0.001f); + + // 归一化计算分配比例 + float total_weight = weight1 + weight2; + *torque1 = total_torque * (weight1 / total_weight); + *torque2 = total_torque * (weight2 / total_weight); + + // 独立限制单侧扭矩(修改核心逻辑) + if (fabs(*torque1) > max_torque) { + *torque1 = copysignf(max_torque, *torque1); + } + if (fabs(*torque2) > max_torque) { + *torque2 = copysignf(max_torque, *torque2); + } + + // 仅对非零扭矩应用下限限制 + if (fabs(*torque1) < min_torque) { + *torque1 = copysignf(min_torque, *torque1); + } + if ( fabs(*torque2) < min_torque) { + *torque2 = copysignf(min_torque, *torque2); + } + +} + + + +/** + * @brief 根据轮速差动态调整电机扭矩(带非负限制) + * @param speed_left 左轮速度(单位:rpm或自定义) + * @param speed_right 右轮速度(单位:rpm或自定义) + * @param torque_left 左轮扭矩指针(单位:Nm或自定义) + * @param torque_right 右轮扭矩指针(单位:Nm或自定义) + * @param threshold 触发调整的速差阈值(单位同轮速) + * @param k 扭矩调整系数(无量纲,建议0 threshold) { + // 计算需要减少的扭矩量(速差超出阈值部分×系数) + float torque_reduction = (speed_diff - threshold) * k; + + if (speed_left > speed_right) { + // 左轮过快时减少左扭矩,并限制最小值为0 + *torque_left = fmaxf(*torque_left - torque_reduction, 0.0f); + } else { + // 右轮过快时减少右扭矩,并限制最小值为0 + *torque_right = fmaxf(*torque_right - torque_reduction, 0.0f); + } + } +} +// 计算左右电机速度 +void computeInverseKinematics(float linear_velocity_x, float yaw_rate, float max_speed, float *motor_speed) +{ + // 防止速度过低导致不必要的计算 + if (fabs(max_speed) < EPSILON) + { + motor_speed[0] = 0.0f; + motor_speed[1] = 0.0f; + motor_speed[2] = 0.0f; + motor_speed[3] = 0.0f; + return; + } + +#if THROTTLE_PID_MODE + float max_torque = (float)getParam("maxTorq"); + + linear_velocity_x = constrain(linear_velocity_x, -max_torque, max_torque); + yaw_rate = constrain(yaw_rate, -2*max_torque, 2*max_torque); + + + float left_speed_mps = linear_velocity_x + yaw_rate; + float right_speed_mps = linear_velocity_x - yaw_rate; + +//扭矩分配 + if(max_torque < left_speed_mps) + { + right_speed_mps = right_speed_mps - (left_speed_mps - max_torque);//多减去超出限值得部分,保证转矩差 + left_speed_mps = max_torque; + } + else if(-max_torque > left_speed_mps) + { + right_speed_mps = right_speed_mps - (left_speed_mps + max_torque);//多减去超出限值得部分,保证转矩差 + left_speed_mps = -max_torque; + } + else if(max_torque < right_speed_mps) + { + left_speed_mps = left_speed_mps - (right_speed_mps - max_torque);//多减去超出限值得部分,保证转矩差 + right_speed_mps = max_torque; + } + else if(-max_torque > right_speed_mps) + { + left_speed_mps = left_speed_mps - (right_speed_mps + max_torque);//多减去超出限值得部分,保证转矩差 + right_speed_mps = -max_torque; + } + else{} + + printf("input_torq: left=%.1f right=%.1f yaw_rate=%.1f\n", left_speed_mps, right_speed_mps, yaw_rate); + + motor_speed[0] = left_speed_mps; + motor_speed[2] = left_speed_mps; + + motor_speed[1] = right_speed_mps; + motor_speed[3] = right_speed_mps; + + adjust_torque_by_speed_diff( diff_data.left_front_motor_speed,diff_data.left_rear_motor_speed, &motor_speed[0], &motor_speed[2],100, 5); + adjust_torque_by_speed_diff( diff_data.right_front_motor_speed,diff_data.right_rear_motor_speed, &motor_speed[1], &motor_speed[3],100, 5); + + +// printf("speed: FL=%.1f FR=%.1f RL=%.1f RR=%.1f\n", diff_data.left_front_motor_speed, diff_data.right_front_motor_speed, diff_data.left_rear_motor_speed, diff_data.right_rear_motor_speed); + + + + + + + + + +// distributeTorque(diff_data.left_front_motor_speed,diff_data.left_rear_motor_speed,2*left_speed_mps,&motor_speed[0],&motor_speed[2],diff_data.max_Torq,diff_data.min_Torq); +// distributeTorque(diff_data.right_front_motor_speed,diff_data.right_rear_motor_speed,2*right_speed_mps,&motor_speed[1],&motor_speed[3],diff_data.max_Torq,diff_data.min_Torq); + +// printf("torq: FL=%.1fNm FR=%.1fNm RL=%.1fNm RR=%.1fNm\n", motor_speed[0], motor_speed[1], motor_speed[2], motor_speed[3]); + +// // 返回计算结果 +// *left_motor_speed = left_speed_mps; +// *right_motor_speed = right_speed_mps; +#else + + // 限制线速度和偏航率 + linear_velocity_x = constrain(linear_velocity_x, -max_speed, max_speed); + float max_yaw_rate = max_speed / ((float)getParam("whl_bas") / 2.0f); + yaw_rate = constrain(yaw_rate, -max_yaw_rate, max_yaw_rate); + + // 计算旋转速度 + float rotational_velocity = ((float)getParam("whl_bas") / 2.0f) * yaw_rate; + + // 计算车辆左右线速度 (m/s) + float left_speed_mps = linear_velocity_x - rotational_velocity; //20250316 为解决原地转向和直行转向相同,所以把左右输出的速度交换 + float right_speed_mps = linear_velocity_x + rotational_velocity; + + // 计算轮子周长 + float wheel_circumference = (float)getParam("whl_dia") * M_PI; + + // 将车辆左右线速度转换为轮子转速 (RPM) + float left_wheel_rpm = (left_speed_mps * 60.0f) / wheel_circumference; + float right_wheel_rpm = (right_speed_mps * 60.0f) / wheel_circumference; + + // 获取减速比 + float gear_ratio = (float)getParam("gRatio"); + + // 将轮子转速转换为电机转速,考虑减速比 + float left_motor_rpm = left_wheel_rpm * gear_ratio; + float right_motor_rpm = right_wheel_rpm * gear_ratio; + + // 限制电机的最大和最小转速 + float max_motor_rpm = (float)getParam("max_rpm"); + left_motor_rpm = constrain(left_motor_rpm, -max_motor_rpm, max_motor_rpm); + right_motor_rpm = constrain(right_motor_rpm, -max_motor_rpm, max_motor_rpm); + // 当电机转速小于50转时,设置为0 + if (fabsf(left_motor_rpm) < 50)//速度慢所以设置位10转 + { + left_motor_rpm = 0; + } + if (fabsf(right_motor_rpm) < 50)//速度慢所以设置位10转 + { + right_motor_rpm = 0; + } + // 左边电机方向反一下,因为电机安装反了,返回来的数据也要反一下 + // left_motor_rpm = -left_motor_rpm; + // 返回计算结果 + *left_motor_speed = left_motor_rpm; + *right_motor_speed = right_motor_rpm; + +#endif +} + +// 映射遥控器速度,分为死区、低速区和高速区。 +float mapRemoteControlSpeed( + float input_speed, + float deadzone_limit, + float input_max, + float output_max, + float input_slow, + float output_slow +) +{ + float output_speed = 0.0f; + // 获取输入速度的绝对值 + float abs_input = fabsf(input_speed); +//diff_data.desired_speed, 0.1, 2, 10, 1, 5 + +// diff_data.desired_speed = mapRemoteControlSpeed(diff_data.desired_speed, 0.1, 20, 5, 5, 0.5); + + if (abs_input < deadzone_limit + EPSILON) + { + output_speed = 0.0f;// 死区 + } + else if (abs_input < input_slow + EPSILON)// 低速区 + { + output_speed = (abs_input - deadzone_limit) * output_slow / (input_slow - deadzone_limit);// + } + else if (abs_input <= input_max + EPSILON)// 高速区 + { + output_speed = output_slow + (abs_input - input_slow) * (output_max - output_slow) / (input_max - input_slow);// 0.2 + (3 - 0.5)* (15-0.2) / (17 - 0.5) + } + else // 超出范围 + { + output_speed = output_max; + } + + // 根据原始输入速度的符号恢复方向 + if (input_speed < 0) + { + output_speed = -output_speed; + } + return output_speed; +} + +/** + * @brief 状态机处理函数(修改后版本) + */ +void handleVehicleState(DiffData *ctx) +{ + switch (ctx->state) + { + //------------------------------------------- + // 初始状态:根据期望速度方向跳转 + //------------------------------------------- + case STATE_INIT: + { + if (ctx->desired_speed < 0.0f) + { + ctx->state = STATE_BACKWARD; + } + else + { + ctx->state = STATE_FORWARD; + } + break; + } + + //------------------------------------------- + // 前进状态:处理反向指令(新增else分支) + //------------------------------------------- + case STATE_FORWARD: + { + if ((ctx->desired_speed < 0.0f) && (ctx->speed == 0.0f)) + { + ctx->state = STATE_BACKWARD; // 零速时允许切换方向 + } + else if ((ctx->desired_speed < 0.0f) && (ctx->speed != 0.0f)) + { + ctx->desired_speed = 0.0f; // 非零速时清空期望速度 + ctx->state = STATE_FORWARD; // 显式保持当前状态 + } + else + { + ctx->state = STATE_FORWARD; // 新增:其他情况保持前进状态 + } + break; + } + + //------------------------------------------- + // 倒车状态:处理正向指令(新增else分支) + //------------------------------------------- + case STATE_BACKWARD: + { + if ((ctx->desired_speed > 0.0f) && (ctx->speed == 0.0f)) + { + ctx->state = STATE_FORWARD; // 零速时允许切换方向 + } + else if ((ctx->desired_speed > 0.0f) && (ctx->speed != 0.0f)) + { + ctx->desired_speed = 0.0f; // 非零速时清空期望速度 + ctx->state = STATE_BACKWARD; // 显式保持当前状态 + } + else + { + ctx->state = STATE_BACKWARD; // 新增:其他情况保持倒车状态 + } + break; + } + } +} + + + + +// 差速处理函数 +static void diffProcess(void *signal_id) +{ + (void)signal_id; + static float previous_time1 = 0.0f; + + float time1 = (float)getCurrentTime(); + float dt = (time1 - previous_time1) / PERIOD_TICK; + previous_time1 = time1; + + // 计算当前状态,包括当前速度、角速度、加速度、减速度、最大速度 + calculateCurrentState(dt); + + // 当速度小于1时,设定为原地转向 20250321 修改为考虑负号 + if( (diff_data.desired_speed >= 0) && (diff_data.desired_speed <= 1.0f) ) + { + diff_data.desired_yaw_rate = diff_data.desired_curvature * 1.0f; + } + else if( (diff_data.desired_speed < 0) && (diff_data.desired_speed >= -1.0f) ) + { + diff_data.desired_yaw_rate = diff_data.desired_curvature * -1.0f; + } + else + { + diff_data.desired_yaw_rate = diff_data.desired_curvature * diff_data.desired_speed; + } + + handleVehicleState(&diff_data); //20250704 换挡函数 速度为0才能换挡 + + +// printf("desired_speed: %f, desired_yaw: %f\n", diff_data.desired_speed, diff_data.desired_yaw_rate); + // 使用 PID 控制器计算输出速度和曲率 + float output_speed = calculatePidOutput(&speed_pid, diff_data.desired_speed, diff_data.speed, 0.0f, dt); + float output_yaw_rate = calculatePidOutput(&yaw_rate_pid, diff_data.desired_yaw_rate, diff_data.yaw_rate, 0.0f, dt); + + // 计算最大加速度,用函数计算 + float max_acceleration = calculateMaxAcceleration(); + // 限制输出速度在当前速度和最大加速度计算出来的速度之间 + // output_speed = constrain(output_speed, diff_data.speed - max_acceleration * dt, diff_data.speed + max_acceleration * dt); + + + if( (0 == diff_data.desired_yaw_rate) && (0 == diff_data.desired_speed) )//手柄回中,速度小的时候清0 + { + resetPidIntegral(&speed_pid); + resetPidIntegral(&yaw_rate_pid); + output_speed = 0; + output_yaw_rate = 0; + } + +// printf("output_speed: %f, output_yaw: %f, integral: %f\n", output_speed, output_yaw_rate,speed_pid.integral); + + +// if(diff_data.desired_yaw_rate != 0)//有转向的情况下下 +// { +// if( (output_yaw_rate > -500) && (output_yaw_rate < 500) )//如果是转向输出在-500~500之间,那么开始原地转向扭矩太小,所以设定最小扭矩。 +// { +// output_yaw_rate = 500; +// } +// } + + + // 使用差速车辆动力学模型计算左右电机的期望速度 + computeInverseKinematics(output_speed, output_yaw_rate, diff_data.max_speed, &diff_data.out_torq[0]); + + + + + + + +// if( (left_speed < 200) && (left_speed > -200) ) +// { +// left_speed = 0; +// } +// +// if( (right_speed < 200) && (right_speed > -200) ) +// { +// right_speed = 0; +// } + + + // 设置电机输出 + setMotorOutput(&diff_data.out_torq[0], + diff_data.max_Torq,// + (uint16_t)getParam("feedPwr"), + (uint16_t)getParam("dispPwr")); + // 发布左右电机期望转速,电源在工作状态才能发送 + if (power_data.current_state == POWER_WORKING) + { + publishMessage(&un_motor_output1, 1); + publishMessage(&un_motor_output2, 1); + publishMessage(&un_motor_output3, 1); + publishMessage(&un_motor_output4, 1); + + } + + + un_can_debug_output.bit_data.speed = (uint8_t)(int8_t)(diff_data.speed*10); + un_can_debug_output.bit_data.desired_speed = (uint8_t)(int8_t)(diff_data.desired_speed*10); + + un_can_debug_output.bit_data.curvature = (uint8_t)(int8_t)(diff_data.yaw_rate*10); + un_can_debug_output.bit_data.desired_curvature = (uint8_t)(int8_t)(diff_data.desired_yaw_rate*10); + + un_can_debug_output.bit_data.set_left_out = (uint16_t)(int16_t)(diff_data.left_motor_speed); + un_can_debug_output.bit_data.set_right_out = (uint16_t)(int16_t)(diff_data.right_motor_speed); + + publishMessage(&diff_data, 1); + +} + +/****************************************************************************** + Filter(); N个数中取两个 +******************************************************************************/ +int16_t Filter(int16_t *s,uint8_t Len) +{ + uint8_t i,j; + int16_t temp; +//降序排序 + for(i=0;i*(s+j)) + { + *(s+i)=*(s+i)^*(s+j); + *(s+j)=*(s+j)^*(s+i); + *(s+i)=*(s+i)^*(s+j); + } + } + temp=(*(s+Len/2)+*(s+(Len/2-1)))/2;//20210225修改为除以2,负数不能够右移 + return(temp); +} + + + + + + +// 差速输入处理函数 +static void diffInput(void *signal_id) +{ + float motor_speed_temp = 0.0f; + + if (signal_id == &un_sw_sample) + { + diff_data.emergency_stop_switch = (uint8_t)un_sw_sample.bit_data.emergency_stop_switch; + } + else if ( (signal_id == &un_remote_control_input) && (1 == un_remote_control_input.bit_data.enable) )// 遥控器断线,不更新数据 + { + diff_data.remote_emergency_stop = !(uint8_t)un_remote_control_input.bit_data.switch_b; + diff_data.mode = un_remote_control_input.bit_data.switch_c == 1 ? MODE_AUTO : MODE_MANUAL; + + if (diff_data.mode == MODE_MANUAL) + { + diff_data.desired_speed = (float)((int16_t)(un_remote_control_input.bit_data.speed)); + diff_data.desired_curvature = (float)((int16_t)(un_remote_control_input.bit_data.curvature)); + // 单位转换 + diff_data.desired_speed = diff_data.desired_speed * 0.01f; + diff_data.desired_curvature = diff_data.desired_curvature * 0.0001f; + // 遥控器速度映射,参数含义为:输入速度,死区,最大输入,最大输出,低速输入,低速输出 + diff_data.desired_speed = mapRemoteControlSpeed(diff_data.desired_speed, 0.1, 20, 5, 5, 0.5); + diff_data.desired_curvature = mapRemoteControlSpeed(diff_data.desired_curvature, 0.1, 2, 2, 1, 0.5); + + if(diff_data.desired_speed >= 0)//20250320 增加根据速度大小来决定方向,解决后退时转弯反向的问题 + { + diff_data.desired_curvature = diff_data.desired_curvature; + } + else + { + diff_data.desired_curvature = -diff_data.desired_curvature; + } + } + } + else if ( (signal_id == &un_manual_computer_input) && (diff_data.mode == MODE_AUTO) ) + { + diff_data.desired_speed = (float)((int16_t)(un_manual_computer_input.bit_data.set_speed)); + diff_data.desired_curvature = (float)((int16_t)(un_manual_computer_input.bit_data.set_curvature)); + // 单位转换 + diff_data.desired_speed = diff_data.desired_speed * 0.01f; + diff_data.desired_curvature = diff_data.desired_curvature * 0.0001f; + // 遥控器速度映射,参数含义为:输入速度,死区,最大输入,最大输出,低速输入,低速输出 + diff_data.desired_speed = mapRemoteControlSpeed(diff_data.desired_speed, 0.2, 2, 10, 1, 5);//20250320 修改死区为0.2解决停不住的问题 + diff_data.desired_curvature = mapRemoteControlSpeed(diff_data.desired_curvature, 0, 2, 2, 1, 1); + } + else if ( (signal_id == &un_auto_computer_input) && (diff_data.mode == MODE_AUTO) ) + { + diff_data.desired_speed = (float)((int16_t)(un_auto_computer_input.bit_data.set_speed)); + diff_data.desired_curvature = (float)((int16_t)(un_auto_computer_input.bit_data.set_curvature)); + // 单位转换 + diff_data.desired_speed = diff_data.desired_speed * 0.01f; + diff_data.desired_curvature = - diff_data.desired_curvature * 0.0001f;// 20241016 增加转弯反相 + // 遥控器速度映射,参数含义为:输入速度,死区,最大输入,最大输出,低速输入,低速输出 + diff_data.desired_speed = mapRemoteControlSpeed(diff_data.desired_speed, 0, 5, 10, 2.5, 5); + diff_data.desired_curvature = mapRemoteControlSpeed(diff_data.desired_curvature, 0, 2, 2, 1, 1); + } + else if ( (signal_id == &un_motor_input1) || (signal_id == &un_motor_input3) )// 处理第一个电机速度信号(左电机) + { + diff_data.left_front_motor_speed = (float)((int16_t)(un_motor_input1.bit_data.speed - 30000));//20240921 增加偏移量 + diff_data.left_rear_motor_speed = (float)((int16_t)(un_motor_input3.bit_data.speed - 30000));//20240921 增加偏移量 + + if(fabs(diff_data.left_rear_motor_speed) > fabs(diff_data.left_front_motor_speed))//取速度较小的轮速 + { + motor_speed_temp = diff_data.left_front_motor_speed; + } + else + { + motor_speed_temp = diff_data.left_rear_motor_speed; + } + diff_data.left_motor_speed = motor_speed_temp; + } + else if( (signal_id == &un_motor_input2) || (signal_id == &un_motor_input4) )// 处理第二个电机速度信号(右电机) + { + diff_data.right_front_motor_speed = (float)((int16_t)(un_motor_input2.bit_data.speed - 30000)); // 20250502 1号控制器增加反相 + diff_data.right_rear_motor_speed = (float)((int16_t)(un_motor_input4.bit_data.speed - 30000)); + + if(fabs(diff_data.right_front_motor_speed) > fabs(diff_data.right_rear_motor_speed))//取速度较小的轮速 + { + motor_speed_temp = diff_data.right_rear_motor_speed; + } + else + { + motor_speed_temp = diff_data.right_front_motor_speed; + } + + diff_data.right_motor_speed = motor_speed_temp; + } + + // 急停开关 + diff_data.emergency_stop_state = (uint8_t)(diff_data.emergency_stop_switch == app_close() || diff_data.remote_emergency_stop == app_close()); + + // 如果急停被激活,强制设定速度为0,急停包括车上急停开关和遥控器急停开关 + if (diff_data.emergency_stop_state == 1) + { + diff_data.desired_speed = 0.0; + diff_data.desired_curvature = 0.0; + } + // 遥控器断线,而且是在手动模式,期望值清0 + if ( (diff_data.mode == MODE_MANUAL) && (0 == un_remote_control_input.bit_data.enable) ) + { + diff_data.desired_speed = 0.0; + diff_data.desired_curvature = 0.0; + } + + if (diff_data.emergency_stop_state == 1)//刹车 20241017 增加的扭矩限制 + { + diff_data.max_Torq = 5;//20240403修改。刹车就是5N + } + else if ((0 == diff_data.desired_speed) && (0 == diff_data.desired_curvature) && (diff_data.left_motor_speed > -100) && (diff_data.left_motor_speed < 100)&& (((diff_data.right_motor_speed > -100) && (diff_data.right_motor_speed < 100))))//20240330只有当手柄回中,然后当前已经停止的状态才设置为最小停车扭矩 + { + diff_data.max_Torq = 5;//停车 就为0 20250425 修改为5,解决手柄回中,震荡问题 + } + else + { + diff_data.max_Torq = (uint16_t)getParam("maxTorq");//参数读取设定最大扭矩 + } + + diffProcess(&diff_data);//计算左右电机期望转速 +} + + + +// 预充完成处理函数 +void preChargeFinish(void *signal_id) +{ + (void)signal_id; + + float out_torq[4] = {0.0f,0.0f,0.0f,0.0f}; + + setMotorOutput(out_torq, (uint16_t)getParam("maxTorq"), (uint16_t)getParam("feedPwr"), (uint16_t)getParam("dispPwr")); + // 档位 +// un_motor_output1.bit_data.gear = 0; // 0表示空挡 +// un_motor_output2.bit_data.gear = 0; + publishMessage(&un_motor_output1, 1); + publishMessage(&un_motor_output2, 1); +} + + +void diffParametersInit(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 + + if(diff_data.mode == MODE_AUTO)//20250504 自动模式PID + { + setPidParameters(&speed_pid, + getParam("Ospd_kp"), + getParam("Ospd_ki"), + getParam("Ospd_kd"), + getParam("Ospd_il"), + getParam("Ospd_ol") + ); + + setPidParameters(&yaw_rate_pid, + getParam("Ocrv_kp"), + getParam("Ocrv_ki"), + getParam("Ocrv_kd"), + getParam("Ocrv_il"), + getParam("Ocrv_ol") + ); + } + else//手动模式 + { + setPidParameters(&speed_pid, + getParam("spd_kp"), + getParam("spd_ki"), + getParam("spd_kd"), + getParam("spd_il"), + getParam("spd_ol") + ); + + setPidParameters(&yaw_rate_pid, + getParam("crv_kp"), + getParam("crv_ki"), + getParam("crv_kd"), + getParam("crv_il"), + getParam("crv_ol") + ); + } + diff_data.min_Torq = (uint16_t)getParam("minTorq");//参数读取设定最大扭矩 + + + printf("desired_speed: %f, desired_yaw_rate: %f\n", diff_data.desired_speed, diff_data.desired_yaw_rate); + printf("speed: %f, yaw_rate: %f\n", diff_data.speed, diff_data.yaw_rate); +// printf("speed: %f, yaw_rate: %f\n", diff_data.speed, diff_data.yaw_rate); + + printf("left_motor_speed = %f\n",diff_data.left_motor_speed); + printf("right_motor_speed = %f\n",diff_data.right_motor_speed); + +// printf("speed: FL=%.1f FR=%.1f RL=%.1f RR=%.1f\n", diff_data.left_front_motor_speed, diff_data.right_front_motor_speed, diff_data.left_rear_motor_speed, diff_data.right_rear_motor_speed); +// printf("torq: FL=%.1fNm FR=%.1fNm RL=%.1fNm RR=%.1fNm\n", diff_data.out_torq[0], diff_data.out_torq[1], diff_data.out_torq[2], diff_data.out_torq[3]); + + float deffspeed = (float)((int16_t)(un_remote_control_input.bit_data.speed)); + float deffcurvature = (float)((int16_t)(un_remote_control_input.bit_data.curvature)); + // 单位转换 + deffspeed = deffspeed * 0.01f; + deffcurvature = deffcurvature * 0.0001f; + + printf("remote speed = %f, remote curvature = %f\n", deffspeed, deffcurvature); + + timerStart(&diff_app_timer,1000,1);//1s调用一次 +} + + +// 差速初始化函数 +void diffAppInit(void) +{ + // 初始化 diff_data + memset(&diff_data, 0, sizeof(DiffData)); + + // 订阅相关信号 + subscribe(&un_sw_sample, diffInput); // 急停开关、高压开关 + subscribe(&un_motor_input1, diffInput); + subscribe(&un_motor_input2, diffInput); + + + subscribe(&un_auto_computer_input, diffInput); + subscribe(&un_manual_computer_input, diffInput); + subscribe(&un_remote_control_input, diffInput); + subscribe(&power_data.pre_charge_finish, preChargeFinish); + + // 初始化速度 PID 控制器 + initializePid(&speed_pid, PID_MODE_DERIVATIVE_CALC, 0.0001f); + // 设置速度 PID 控制器的参数 + setPidParameters(&speed_pid, + getParam("spd_kp"), + getParam("spd_ki"), + getParam("spd_kd"), + getParam("spd_il"), + getParam("spd_ol") + ); + + // 初始化曲率 PID 控制器 + initializePid(&yaw_rate_pid, PID_MODE_DERIVATIVE_CALC, 0.0001f); + // 设置曲率 PID 控制器的参数 + setPidParameters(&yaw_rate_pid, + getParam("crv_kp"), + getParam("crv_ki"), + getParam("crv_kd"), + getParam("crv_il"), + getParam("crv_ol") + ); + + subscribe(&diff_app_timer, diffParametersInit); + timerStart(&diff_app_timer,1000,1);//1s调用一次 + + printf("diffControl: diffAppInit OK \n"); +} diff --git a/app/app_differential_drive.h b/app/app_differential_drive.h new file mode 100644 index 0000000..73041d5 --- /dev/null +++ b/app/app_differential_drive.h @@ -0,0 +1,84 @@ +#ifndef APP_DIFFERENTIAL_DRIVE_H +#define APP_DIFFERENTIAL_DRIVE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "app_config.h" + +#define SPEED_FITER_NUM 6 + + +#define SPEED_PID_MODE 0 +#define THROTTLE_PID_MODE 1 + + + +#define SPEED_MODE 0x01 +#define TORQUE_MODE 0x02 + +#define MOTOR_MODE TORQUE_MODE + + + +#define ALPHA 0.1f // 滤波系数α∈[0.01,0.3],0.2对应截止频率约10Hz(假设采样周期10ms) +#define LOWPASS_FILTER(speed, prev) (ALPHA * (speed) + (1 - ALPHA) * (prev)) + +// 状态机内部状态 +typedef enum +{ + STATE_INIT, ///< 初始状态(转速为0且等待扭矩方向判定) + STATE_FORWARD, ///< 正向旋转状态(扭矩为正) + STATE_BACKWARD, ///< 反向旋转状态(扭矩为负) +} MotorState; + +typedef enum +{ + MODE_MANUAL, // 手动模式 + MODE_AUTO // 自动模式 +} ControlMode; + +typedef struct DiffData +{ + ControlMode mode ; // 控制模式 + MotorState state; //当前状态机状态 + float desired_speed; // 期望速度 + float desired_curvature; // 期望曲率 + float left_motor_speed; // 当前左电机速度 + float right_motor_speed; // 当前右电机速度 + float left_front_motor_speed; // 当前左前电机速度 + float right_front_motor_speed; // 当前右前电机速度 + float left_rear_motor_speed; // 当前左后电机速度 + float right_rear_motor_speed; // 当前右后电机速度 + float speed; // 当前车速 + float curvature; // 当前曲率 + float yaw_rate; // 当前角速度 + float desired_yaw_rate; // 期望角速度 + float acceleration; // 当前加速度 + float deceleration; // 当前减速度 + float max_speed; // 最大速度 + float desired_acceleration; // 期望加速度 + float desired_deceleration; // 期望减速度 + uint8_t emergency_stop_switch; // 急停开关 + uint8_t remote_emergency_stop; // 遥控器急停开关 + uint8_t emergency_stop_state; // 急停状态 + float out_left_motor_speed; // 输出左电机速度 + float out_right_motor_speed; // 输出右电机速度 + float out_torq[4]; //4个电机扭矩 + float max_Torq; // 最大扭矩限制 + float min_Torq; // 最小扭矩限制 +} DiffData; + + +// 声明外部变量 +extern DiffData diff_data; + +void diffAppInit(void); + +#ifdef __cplusplus +} +#endif + +#endif // APP_DIFFERENTIAL_DRIVE_H diff --git a/app/app_frm_monitor.c b/app/app_frm_monitor.c new file mode 100644 index 0000000..06bdbbc --- /dev/null +++ b/app/app_frm_monitor.c @@ -0,0 +1,175 @@ +#include "app_config.h" +#include "interface.h" + +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" + +#include +#include +#include +#include + + + +// 全局日志缓冲区实例 +LogBuffer log_buffer; + +// 打印当前信号队列状态 +void printSignalQueueStatus(void) +{ + for (uint32_t i = 0; i < PRIORITY_LEVELS; i++) + { + printf("Priority %u Signal Count: %d\n", i, + getSignalCount(i)); + } +} + +// 打印订阅者信息 +void printSubscriberInfo(void) +{ + printf("Total Subscribers: %u\n", getSubscriberCount()); +} + +// 打印定时器状态 +void printTimerStatus(void) +{ + printf("Current Timer Count: %u / %u\n", + getCurrentTimerCount(), MAX_TIMERS); +} + +// 监控函数 +void monitorSignalSystem(void) +{ + static uint32_t last_print_time = 0; + uint32_t current_print_time = getCurrentTime(); + uint32_t time_interval = current_print_time - last_print_time; + + printf("---------------------------------------------------\n"); + printf("Time since last print: %u us\n", time_interval); + printSignalQueueStatus(); + printSubscriberInfo(); + printTimerStatus(); + printf("---------------------------------------------------\n"); + + last_print_time = current_print_time; +} + +int logBufferWrite(LogBuffer *lb, const char *format, ...) +{ + if (format == NULL || lb == NULL) + { + return -1; + } + + char temp_buffer[256]; // 临时缓冲区,假设单条日志不超过256字节 + va_list args; + va_start(args, format); + int length = vsnprintf(temp_buffer, sizeof(temp_buffer), format, args); + va_end(args); + + if (length <= 0) + { + return -1; + } + + // 进入关键区,保护缓冲区的写操作 + irq_state_t saved_state = enter_critical_section(); + + // 检查缓冲区是否有足够的空间 + if (lb->count + length > LOG_BUFFER_SIZE) + { + // 缓冲区满,无法写入 + exit_critical_section(saved_state); + return -1; + } + + // 写入数据到缓冲区 + for (int i = 0; i < length; i++) + { + lb->buffer[lb->tail] = temp_buffer[i]; + lb->tail = (lb->tail + 1) % LOG_BUFFER_SIZE; + } + lb->count += length; + + exit_critical_section(saved_state); + return 0; +} + +int logBufferRead(LogBuffer *lb, char *data, uint32_t max_length) +{ + if (max_length == 0 || data == NULL || lb == NULL) + { + return -1; + } + + // 进入关键区,保护缓冲区的读操作 + irq_state_t saved_state = enter_critical_section(); + + uint32_t length = lb->count < max_length ? lb->count : max_length; + + // 从缓冲区读取数据 + for (uint32_t i = 0; i < length; i++) + { + data[i] = lb->buffer[lb->head]; + lb->head = (lb->head + 1) % LOG_BUFFER_SIZE; + } + lb->count -= length; + + exit_critical_section(saved_state); + return length; +} + +// 初始化日志缓冲区 +void initLogBuffer(LogBuffer *lb) +{ + lb->head = 0; + lb->tail = 0; + lb->count = 0; + memset(lb->buffer, 0, LOG_BUFFER_SIZE); +} + +// 日志信号处理函数 +void logSignalHandler(void *signal_id) +{ + (void)signal_id; + char log_data[256]; // 假设单次读取不超过256字节 + int read_length; + + // 从缓冲区读取日志信息 + read_length = logBufferRead(&log_buffer, log_data, sizeof(log_data) - 1); + + if (read_length > 0) + { + log_data[read_length] = '\0'; // 确保字符串以NULL结尾 + + // 调用printf进行打印 + printf("%s", log_data); + } +} + +Timer log_timer; + +void logTimerHandler(void *timer_id) +{ + (void)timer_id; + // monitorSignalSystem(); + timerStart(&log_timer, 1000, 1); +} + +void appMonitorInit(void) +{ + // 初始化日志缓冲区 + initLogBuffer(&log_buffer); + // 订阅日志信号 + subscribe(&log_buffer, logSignalHandler); + timerInit(&log_timer); + timerStart(&log_timer, 1000, 1); + subscribe(&log_timer, logTimerHandler); +} + +// // 使用格式化字符串记录日志 +// if (logBufferWrite(&log_buffer, "ISR triggered: IRQ %d\n", irq_number) == 0) { +// // 发送信号,通知主线程有新日志 +// publishMessage(&log_buffer, LOG_SIGNAL_PRIORITY); +// } diff --git a/app/app_frm_monitor.h b/app/app_frm_monitor.h new file mode 100644 index 0000000..62cf5e2 --- /dev/null +++ b/app/app_frm_monitor.h @@ -0,0 +1,41 @@ +#ifndef APP_FRM_MONITOR_H +#define APP_FRM_MONITOR_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#define LOG_BUFFER_SIZE 1024 // 日志缓冲区的大小 +#define LOG_SIGNAL_PRIORITY 1 // 日志信号的优先级 + +typedef struct +{ + char buffer[LOG_BUFFER_SIZE]; + uint32_t head; // 读指针 + uint32_t tail; // 写指针 + uint32_t count; // 缓冲区中的数据量 +} LogBuffer; + +// 全局日志缓冲区实例 +extern LogBuffer log_buffer; + +// 函数声明 +void printSignalQueueStatus(void); +void printSubscriberInfo(void); +void printTimerStatus(void); +void monitorSignalSystem(void); + +// 新增函数接口 +int32_t logBufferWrite(LogBuffer *lb, const char *format, ...); +int32_t logBufferRead(LogBuffer *lb, char *data, uint32_t max_length); +void initLogBuffer(LogBuffer *lb); +void logSignalHandler(void *signal_id); +void appMonitorInit(void); + +#ifdef __cplusplus +} +#endif + +#endif // APP_FRM_MONITOR_H \ No newline at end of file diff --git a/app/app_frm_signal.c b/app/app_frm_signal.c new file mode 100644 index 0000000..55e0d03 --- /dev/null +++ b/app/app_frm_signal.c @@ -0,0 +1,324 @@ +#include "app_config.h" +#include "interface.h" + +#include "app_frm_signal.h" + +typedef struct +{ + void *signals[MAX_SIGNALS]; + uint32_t head; + uint32_t tail; + uint32_t count; +} SignalQueue; + +typedef struct +{ + void *signal_id; + CallbackFunc callbacks[MAX_CALLBACKS]; + uint32_t callback_count; +} Subscriber; + +// 优先级队列 +static SignalQueue priority_queues[PRIORITY_LEVELS]; + +// 订阅者表 +static Subscriber subscriber_table[MAX_SUBSCRIBERS] = {{NULL, {NULL}, 0}}; + +// 初始化队列 +static void initQueue(SignalQueue *q) +{ + q->head = 0; + q->tail = 0; + q->count = 0; +} + +// 将信号请求添加到队列中(按优先级) +static int32_t enqueue(SignalQueue *q, void *signal_id) +{ + if (q == NULL) + { + printf("Error: enqueue received NULL queue pointer\n"); + return -1; + } + if (signal_id == NULL) + { + printf("Error: Cannot enqueue NULL signal_id\n"); + return -1; + } + + irq_state_t saved_state = enter_critical_section(); + + if (q->count >= MAX_SIGNALS) + { + // 队列已满,移除最前面的信号 + q->signals[q->head] = NULL; + q->head = (q->head + 1) % MAX_SIGNALS; + q->count--; + printf("Error: Signal queue is full, remove the first signal\n"); + } + + // 添加新的信号到队列尾部 + q->signals[q->tail] = signal_id; + q->tail = (q->tail + 1) % MAX_SIGNALS; + q->count++; + + exit_critical_section(saved_state); + return 0; +} + + +// 从队列中取出信号请求(按优先级) +static int32_t dequeue(SignalQueue *q, void **signal_id) +{ + if (q == NULL) + { + printf("Error: dequeue received NULL queue pointer\n"); + return -1; + } + if (signal_id == NULL) + { + printf("Error: dequeue received NULL signal pointer\n"); + return -1; + } + + // 仅在修改共享资源时进入临界区 + if (q->count > 0) + { + irq_state_t saved_state = enter_critical_section(); + + *signal_id = q->signals[q->head]; + q->signals[q->head] = NULL; // 清除已取出的信号 + q->head = (q->head + 1) % MAX_SIGNALS; + q->count--; + + exit_critical_section(saved_state); + return 0; + } + // printf("Warning: dequeue attempted to remove signal from an empty queue\n"); + return -1; +} + +// 哈希函数 +static uint32_t hash(void *ptr) +{ + uintptr_t value = (uintptr_t)ptr; + uint32_t hash = 0; + while (value != 0) + { + hash += value & 0xFF; + hash += (hash << 10); + hash ^= (hash >> 6); + value >>= 8; + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; +} + +// 订阅信号, 给每个信号指定回调函数 +int32_t subscribe(void *signal_id, CallbackFunc callback) +{ + if (signal_id == NULL || callback == NULL) + { + printf("Error: Invalid signal_id or callback\n"); + return -1; + } + + irq_state_t saved_state = enter_critical_section(); + + uint32_t index = hash(signal_id) % MAX_SUBSCRIBERS; + uint32_t original_index = index; + + do + { + if (subscriber_table[index].signal_id == NULL || + subscriber_table[index].signal_id == signal_id) + { + if (subscriber_table[index].signal_id == NULL) + { + subscriber_table[index].signal_id = signal_id; + subscriber_table[index].callback_count = 0; + } + + if (subscriber_table[index].callback_count < MAX_CALLBACKS) + { + subscriber_table[index].callbacks[subscriber_table[index].callback_count++] = callback; + + exit_critical_section(saved_state); + return 0; + } + else + { + printf("Error: Maximum callbacks reached for this signal\n"); + exit_critical_section(saved_state); + return -1; + } + } + + index = (index + 1) % MAX_SUBSCRIBERS; + } while (index != original_index); + + printf("Error: Subscriber table is full\n"); + exit_critical_section(saved_state); + return -1; +} + +// 检查信号是否有订阅者 +static unsigned char hasSubscribers(void *signal_id) +{ + irq_state_t saved_state = enter_critical_section(); + + uint32_t index = hash(signal_id) % MAX_SUBSCRIBERS; + uint32_t original_index = index; + + do + { + if (subscriber_table[index].signal_id == signal_id) + { + unsigned char result = subscriber_table[index].callback_count > 0; + exit_critical_section(saved_state); + return result; + } + if (subscriber_table[index].signal_id == NULL) + { + exit_critical_section(saved_state); + return 0; // 没有订阅者 + } + index = (index + 1) % MAX_SUBSCRIBERS; + } while (index != original_index); + + exit_critical_section(saved_state); + return 0; // 没有订阅者 +} + +// 内部一致性检查 +static void internalConsistencyCheck(void) +{ + for (uint32_t i = 0; i < MAX_SUBSCRIBERS; i++) + { + assert(subscriber_table[i].callback_count <= MAX_CALLBACKS); + } +} + +// 处理队列中的信号, 调用所有匹配的回调函数 +static void processSignals(void) +{ + void *signal_id; + + for (uint32_t priority = 0; priority < PRIORITY_LEVELS; priority++) + { + SignalQueue *q = &priority_queues[priority]; + + while (dequeue(q, &signal_id) == 0) + { + // 进入临界区保护 subscriber_table 的读取 + irq_state_t saved_state = enter_critical_section(); + + uint32_t index = hash(signal_id) % MAX_SUBSCRIBERS; + uint32_t original_index = index; + unsigned char found = 0; + + do + { + if (subscriber_table[index].signal_id == signal_id) + { + CallbackFunc *callbacks = subscriber_table[index].callbacks; + uint32_t callback_count = subscriber_table[index].callback_count; + + // 复制回调函数指针, 避免在临界区外访问共享数据 + CallbackFunc local_callbacks[MAX_CALLBACKS]; + memcpy(local_callbacks, callbacks, sizeof(CallbackFunc) * callback_count); + + exit_critical_section(saved_state); + + // 在临界区外调用回调函数 + for (uint32_t i = 0; i < callback_count; i++) + { + local_callbacks[i](signal_id); + } + found = 1; + break; + } + if (subscriber_table[index].signal_id == NULL) + { + exit_critical_section(saved_state); + break; // 没有订阅者 + } + index = (index + 1) % MAX_SUBSCRIBERS; + } while (index != original_index); + + if (!found) + { + printf("Warning: No subscribers found for signal %p\n", signal_id); + } + } + } + internalConsistencyCheck(); // 处理完所有信号后进行一致性检查 +} + +// 初始化框架 +void initFramework(void) +{ + irq_state_t saved_state = enter_critical_section(); + + for (uint32_t i = 0; i < PRIORITY_LEVELS; i++) + { + initQueue(&priority_queues[i]); + } + memset(subscriber_table, 0, sizeof(subscriber_table)); + + exit_critical_section(saved_state); +} + +// 将信号请求添加到指定优先级的队列中 +int32_t publishMessage(void *signal_id, uint8_t priority) +{ + if ((uint32_t)priority >= PRIORITY_LEVELS) + { + printf("Error: Invalid priority\n"); + return -1; + } + + if (hasSubscribers(signal_id)) + { + return enqueue(&priority_queues[priority], signal_id); + } + else return 1; +} + +// 处理所有优先级的信号 +void processMessages(void) +{ + processSignals(); +} + +// 获取当前队列中的信号数量 +int32_t getSignalCount(uint32_t priority) +{ + if (priority >= PRIORITY_LEVELS) + { + printf("Error: Invalid priority\n"); + return -1; + } + return priority_queues[priority].count; +} + +// 获取订阅者数量 +uint32_t getSubscriberCount(void) +{ + uint32_t count = 0; + + irq_state_t saved_state = enter_critical_section(); + + for (uint32_t i = 0; i < MAX_SUBSCRIBERS; i++) + { + if (subscriber_table[i].signal_id != NULL) + { + count++; + } + } + + exit_critical_section(saved_state); + return count; +} diff --git a/app/app_frm_signal.h b/app/app_frm_signal.h new file mode 100644 index 0000000..94702a3 --- /dev/null +++ b/app/app_frm_signal.h @@ -0,0 +1,47 @@ +#ifndef APP_FRM_SIGNAL_H +#define APP_FRM_SIGNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include "app_dependence.h" + +#define MAX_SIGNALS 500u // 每个优先级的最大信号数量 +#define MAX_SUBSCRIBERS 50u // 不同信号的订阅者数量 +#define MAX_CALLBACKS 25u // 每个信号最多支持多少订阅者 +#define PRIORITY_LEVELS 2u // 优先级层次 + + +// 回调函数类型定义 +typedef void (*CallbackFunc)(void *signal_id); + +// 函数声明 +void initFramework(void); +int32_t subscribe(void *signal_id, CallbackFunc callback); +int32_t publishMessage(void *signal_id, uint8_t priority); +void processMessages(void); +int32_t getSignalCount(uint32_t priority); +uint32_t getSubscriberCount(void); + +// 进入临界区,禁用中断,并返回之前的中断状态 +static inline irq_state_t enter_critical_section(void) +{ + return arch_irq_save(); +} + +// 退出临界区,恢复之前的中断状态 +static inline void exit_critical_section(irq_state_t saved_state) +{ + arch_irq_restore(saved_state); +} + + + +#ifdef __cplusplus +} +#endif + +#endif // APP_FRM_SIGNAL_H diff --git a/app/app_frm_timer.c b/app/app_frm_timer.c new file mode 100644 index 0000000..f9a599c --- /dev/null +++ b/app/app_frm_timer.c @@ -0,0 +1,165 @@ +#include "app_config.h" +#include "interface.h" + +#include "app_frm_timer.h" +#include "app_frm_signal.h" + +// 全局计时器列表头指针 +static Timer *timer_list = NULL; + +// 添加一个静态变量来跟踪当前定时器数量 +static uint32_t current_timer_count = 0; + +// 初始化定时器 +void timerInit(Timer *timer) +{ + if (timer == NULL) + { + return; + } + timer->target_time = 0; + timer->elapsed_time = 0; + timer->start_time = 0; + timer->active = 0; + timer->priority = 1; // 默认优先级为1 + timer->next = NULL; +} + +// 修改 timerStart 函数 +void timerStart(Timer *timer, uint32_t target_time, unsigned char priority) +{ + if (timer == NULL || target_time == 0) + { + printf("Error: Null timer pointer or invalid target time\n"); + return; + } + + // 检查定时器是否已经在列表中 + Timer *current = timer_list; + while (current != NULL) + { + if (current == timer) + { + // 定时器已在列表中, 只需更新其参数 + irq_state_t saved_state = enter_critical_section(); + + timer->target_time = target_time; + timer->start_time = getCurrentTime(); + timer->elapsed_time = 0; + timer->active = 1; + timer->priority = priority; + + exit_critical_section(saved_state); + return; + } + current = current->next; + } + + // 检查是否达到最大定时器数量 + if (current_timer_count >= MAX_TIMERS) + { + printf("Error: Maximum number of timers reached\n"); + return; + } + + // 初始化新定时器 + irq_state_t saved_state = enter_critical_section(); + + timer->target_time = target_time; + timer->start_time = getCurrentTime(); + timer->elapsed_time = 0; + timer->active = 1; + timer->priority = priority; + + // 将定时器插入到定时器列表 + timer->next = timer_list; + timer_list = timer; + current_timer_count++; + + exit_critical_section(saved_state); +} + +// 停止定时器 +void timerStop(Timer *timer) +{ + if (timer == NULL) + { + return; + } + + irq_state_t saved_state = enter_critical_section(); + + Timer *current = timer_list; + Timer *prev = NULL; + while (current != NULL) + { + if (current == timer) + { + // 从链表中移除定时器 + if (prev == NULL) + { + timer_list = current->next; + } + else + { + prev->next = current->next; + } + current_timer_count--; + timer->active = 0; + timer->next = NULL; // 断开链接 + break; + } + prev = current; + current = current->next; + } + + exit_critical_section(saved_state); +} + +// 更新所有定时器, 在定时器中断中调用 +void timerUpdateAll(void) +{ + irq_state_t saved_state = enter_critical_section(); + + Timer *prev = NULL; + Timer *current = timer_list; + + while (current != NULL) + { + if (current->active) + { + current->elapsed_time++; + if (current->elapsed_time >= current->target_time) + { + current->active = 0; + // 发送定时器过期消息 + publishMessage((void *)(uintptr_t)current, current->priority); + + // 从链表中移除已过期的定时器 + if (prev == NULL) + { + timer_list = current->next; + } + else + { + prev->next = current->next; + } + current_timer_count--; + Timer *expired_timer = current; + current = current->next; + expired_timer->next = NULL; // 断开链接 + continue; // 跳过前进 prev 指针 + } + } + prev = current; + current = current->next; + } + + exit_critical_section(saved_state); +} + +// 获取当前定时器数量 +uint32_t getCurrentTimerCount(void) +{ + return current_timer_count; +} \ No newline at end of file diff --git a/app/app_frm_timer.h b/app/app_frm_timer.h new file mode 100644 index 0000000..5d96d9c --- /dev/null +++ b/app/app_frm_timer.h @@ -0,0 +1,35 @@ +#ifndef APP_FRM_TIMER_H +#define APP_FRM_TIMER_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MAX_TIMERS 100 // 定义最大定时器数量 + +// 定时器结构体定义 +typedef struct Timer { + uint32_t target_time; + uint32_t elapsed_time; + uint32_t start_time; + unsigned char active; + unsigned char priority; + struct Timer *next; +} Timer; + +// 函数声明 +void timerInit(Timer *timer); +void timerStart(Timer *timer, uint32_t target_time, unsigned char priority); +void timerStop(Timer *timer); +void timerUpdateAll(void); +uint32_t getCurrentTimerCount(void); + + + +#ifdef __cplusplus +} +#endif + +#endif // APP_FRM_TIMER_H \ No newline at end of file diff --git a/app/app_light.c b/app/app_light.c new file mode 100644 index 0000000..d2f008e --- /dev/null +++ b/app/app_light.c @@ -0,0 +1,240 @@ +#include "app_config.h" +#include "interface.h" +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" +#include "app_param_manage.h" + +#include "app_light.h" +#include "app_power.h" + +// 声明 light_data 变量 +LightSystem light_data; + +// ... existing code ... + +// 定义灯光按钮状态枚举 +typedef enum { + BUTTON_STATE_INITIAL, + BUTTON_STATE_SHORT_PRESS, + BUTTON_STATE_DOUBLE_PRESS_DETECTED, + BUTTON_STATE_SECOND_PRESS_DETECTED +} LightButtonState; + +// 定义灯光按钮结构体 +typedef struct { + LightButtonState state; + uint32_t press_start_time; + uint32_t release_start_time; + uint8_t is_light_on; + Timer timer; +} LightButton; + +// 全局变量 +static LightButton light_button = {BUTTON_STATE_INITIAL, 0, 0, 0, {0}}; + +static uint8_t power_state = 0; + +// 灯光按钮处理函数 +static void handleLightButton(void) +{ + switch (light_button.state) + { + case BUTTON_STATE_INITIAL: + if (light_data.light_switch == app_close()) + { + light_button.state = BUTTON_STATE_SHORT_PRESS; + timerStart(&light_button.timer, 300, 0); // 启动短按定时器,300ms + } + break; + + case BUTTON_STATE_SHORT_PRESS: + if (light_data.light_switch == app_open()) + { + if (light_button.timer.active) // 定时器未到期,短按完成,等待双击 + { + light_button.state = BUTTON_STATE_DOUBLE_PRESS_DETECTED; + timerStart(&light_button.timer, 300, 0); // 启动双击等待定时器,300ms + } + } + else if (!light_button.timer.active) // 短按定时器到期,重置为初始状态 + { + light_button.state = BUTTON_STATE_INITIAL; + } + break; + + case BUTTON_STATE_DOUBLE_PRESS_DETECTED: + if (light_data.light_switch == app_close()) + { + light_button.state = BUTTON_STATE_SECOND_PRESS_DETECTED; + timerStart(&light_button.timer, 300, 0); // 启动第二次按下定时器,300ms + } + else if (!light_button.timer.active) // 双击等待定时器到期,重置为初始状态 + { + light_button.state = BUTTON_STATE_INITIAL; + } + break; + + case BUTTON_STATE_SECOND_PRESS_DETECTED: + if (light_data.light_switch == app_open()) + { + if (!light_button.timer.active) // 第二次按下完成,切换灯光状态 + { + light_button.is_light_on = !light_button.is_light_on; + printf("LightButton: is_light_on = %d\n", light_button.is_light_on); + light_button.state = BUTTON_STATE_INITIAL; + } + } + else if (!light_button.timer.active) // 第二次按下定时器到期,重置为初始状态 + { + light_button.state = BUTTON_STATE_INITIAL; + } + break; + + default: + light_button.state = BUTTON_STATE_INITIAL; + break; + } +} + +// 灯光输出处理函数 +static void lightOutput(void *signal_id) +{ + (void)signal_id; + + // 根据当前状态,控制各个灯光 + for (int32_t i = 0; i < LIGHT_COUNT; i++) + { + uint8_t state_value = (light_data.states[i] == LIGHT_ON) ? setLightOn() : setLightOff(); + // 先判断灯光类型并设置状态 + switch (i) + {//正常所有灯光熄灭 + case LIGHT_HEAD://头灯,前面4个灯 + un_inf_can_kgf_output1.bit_data.KGF05 = state_value; + un_inf_can_kgf_output1.bit_data.KGF06 = state_value; + un_inf_can_kgf_output1.bit_data.KGF10 = state_value; + un_inf_can_kgf_output1.bit_data.KGF11 = state_value; + + break; + case LIGHT_TAIL://尾灯,后面4个灯 + un_inf_can_kgf_output2.bit_data.KGF12 = state_value; + un_inf_can_kgf_output2.bit_data.KGF13 = state_value; + un_inf_can_kgf_output2.bit_data.KGF14 = state_value; + un_inf_can_kgf_output2.bit_data.KGF15 = state_value; + break; + case LIGHT_LEFT_TURN://左转向,左边4个灯 + un_inf_can_kgf_output1.bit_data.KGF06 = state_value; + un_inf_can_kgf_output1.bit_data.KGF11 = state_value; + un_inf_can_kgf_output2.bit_data.KGF12 = state_value; + un_inf_can_kgf_output2.bit_data.KGF13 = state_value; + break; + case LIGHT_RIGHT_TURN://右转向灯,右边4个灯 + un_inf_can_kgf_output1.bit_data.KGF05 = state_value; + un_inf_can_kgf_output1.bit_data.KGF10 = state_value; + un_inf_can_kgf_output2.bit_data.KGF14 = state_value; + un_inf_can_kgf_output2.bit_data.KGF15 = state_value; + break; + case LIGHT_BRAKE://刹车灯,四个黄灯 + un_inf_can_kgf_output1.bit_data.KGF10 = state_value; + un_inf_can_kgf_output1.bit_data.KGF11 = state_value; + un_inf_can_kgf_output2.bit_data.KGF13 = state_value; + un_inf_can_kgf_output2.bit_data.KGF15 = state_value; + break; + case LIGHT_ALARM://报警灯,四个红灯 + un_inf_can_kgf_output1.bit_data.KGF05 = state_value; + un_inf_can_kgf_output1.bit_data.KGF06 = state_value; + un_inf_can_kgf_output2.bit_data.KGF12 = state_value; + un_inf_can_kgf_output2.bit_data.KGF14 = state_value; + break; + } + } + + // 灯的状态有变化,就存入参数,一个灯对应一位,共6位 + for (int32_t i = 0; i < LIGHT_COUNT; i++) + { + light_data.light_state |= (light_data.states[i] << i); + } + if (light_data.light_state != light_data.old_light_state) + { + setParam("lightSt", (float)light_data.light_state); + light_data.old_light_state = light_data.light_state; + } + + publishMessage(&un_inf_can_kgf_output1, 1); +} + +// 灯光状态处理函数 +static void lightProcess(void *signal_id) +{ + (void)signal_id; + + if(0 != power_state)//处于非掉电模式才能打开 + { + // 调用按钮处理函数 + handleLightButton(); + } + else + { + light_button.state = BUTTON_STATE_INITIAL;//一直保持初始化模式 + light_button.is_light_on = LIGHT_OFF;//一直关闭 + } + + // 根据双击标志控制灯光输出,相当于灯光总开关 + for (int32_t i = 0; i < LIGHT_COUNT; i++) + { + light_data.states[i] = (LightState)(light_button.is_light_on); + } + lightOutput(NULL); + + timerStart(&light_data.timer_function, 100, 1); +} + +// 处理输入信号的函数 +static void lightInput(void *signal_id) +{ +// LightSystem old_data = light_data; + + // 填充数据 + if ( (signal_id == &un_remote_control_input) && (1 == un_remote_control_input.bit_data.enable) )// 遥控器断线,不更新数据 + { + // 保存遥控器输入开关状态 + light_data.light_switch = un_remote_control_input.bit_data.switch_d ? LIGHT_ON : LIGHT_OFF; + } + else if(signal_id == &power_data) + { + power_state = power_data.current_state; + } +} + + +// APP模块的初始化 +void lightAppInit(void) +{ + // 初始化时恢复灯光状态 + light_data.light_state = (uint8_t)getParam("lightSt"); + light_data.old_light_state = light_data.light_state; + // 根据灯光状态恢复灯光 + for (int32_t i = 0; i < LIGHT_COUNT; i++) + { + light_data.states[i] = (LightState)( (light_data.light_state >> i) & 1 ); + } + // 初始化 + memset(&light_data, 0, sizeof(LightSystem)); + for (int32_t i = 0; i < LIGHT_COUNT; i++) + { + light_data.states[i] = LIGHT_OFF; + light_data.brightness[i] = 255; // 默认最大亮度 + light_data.blink_state[i] = 0; // 初始化闪烁状态 + light_data.blink_interval[i] = 500; // 默认闪烁间隔500ms + } + + // 订阅输入信号,处理灯光逻辑 + subscribe(&un_remote_control_input, lightInput); + subscribe(&power_data, lightInput); + + // 订阅定时器 + subscribe(&light_data.timer_function, lightProcess); + timerStart(&light_data.timer_function, 500, 1); + + printf("app_light: initial OK \n"); +} diff --git a/app/app_light.h b/app/app_light.h new file mode 100644 index 0000000..8ee6b00 --- /dev/null +++ b/app/app_light.h @@ -0,0 +1,62 @@ +#ifndef APP_LIGHT_H +#define APP_LIGHT_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + + + +// 定义灯光状态枚举 +typedef enum +{ + LIGHT_OFF, + LIGHT_ON, + LIGHT_BLINK +} LightState; + +// 定义灯光类型枚举 +typedef enum +{ + LIGHT_HEAD, + LIGHT_TAIL, + LIGHT_LEFT_TURN, + LIGHT_RIGHT_TURN, + LIGHT_BRAKE, + LIGHT_ALARM, + LIGHT_COUNT +} LightType; + +typedef struct +{ + LightState states[LIGHT_COUNT]; + uint8_t brightness[LIGHT_COUNT]; + uint16_t blink_interval[LIGHT_COUNT]; // 闪烁间隔(毫秒) + uint8_t blink_state[LIGHT_COUNT]; // 闪烁状态 + Timer timer;// 设置定时器,定时调用灯光处理函数 + uint8_t old_light_state; // 旧的灯光状态 + uint8_t light_state; // 当前的灯光状态 + Timer timer_function; // 函数定时器 + uint8_t light_switch; // 当前的灯光开关状态 + uint8_t double_click_flag;//双击标志 +} LightSystem; + +// 在头文件中声明外部变量 +extern LightSystem light_data; + +// 使用内联函数 +static inline uint8_t setLightOn(void) { return 1; } +static inline uint8_t setLightOff(void) { return 0; } + +void lightAppInit(void); +void setLightState(LightType light, LightState state); +void setLightBrightness(LightType light, uint8_t brightness); +void setBlinkInterval(uint16_t interval); + +#ifdef __cplusplus +} +#endif + +#endif // APP_LIGHT_H \ No newline at end of file diff --git a/app/app_param_manage.c b/app/app_param_manage.c new file mode 100644 index 0000000..cf7f312 --- /dev/null +++ b/app/app_param_manage.c @@ -0,0 +1,464 @@ +#include "app_config.h" +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" +#include "app_param_manage.h" + + +#define E2_RESERVE_COUNT 0x20 //增加IP地址 修改为0x20 20250110 + +// 待发送的参数请求信号 +UnParamRequest un_param_request1 ; +UnParamRequest un_param_request2; + +RequestContext request_send ; +RequestContext request_context ; + +uint8_t read_write_e2_finished = 0; + +// 定义全局信号实例,读写信号现在包括 offset 和 size +ParamSignal param_signal = { + .param_ptr = NULL, // 参数指针初始化为 NULL + .type = READ_OPERATION, // 操作类型设置为读操作 + .offset = 0, // 整个数据块的偏移 + .size = sizeof(param_manager.arr) // 整个数据块的大小 +}; + + +// 全局变量:初始化参数名称结构体 +ParamNames param_names = { +#define X(name) .name = #name, + PARAM_LIST +#undef X +}; + + +UnParamManager param_manager ; + +static uint8_t is_param_initialized = 0; + +// 打印所有参数的名称和值, 每行 4 个参数 +void printParams() +{ + unsigned int param_count = 0; + + #define X(name) \ + printf("%-8s: %-8.2f", param_names.name, param_manager.bit_data.name); \ + param_count++; \ + if (param_count % 4 == 0) { \ + printf("\n"); \ + } else { \ + printf(" "); \ + } + PARAM_LIST + #undef X + + // 如果最后一行不足 4 个参数, 打印换行 + if (param_count % 4 != 0) + { + printf("\n"); + } +} + + + +void writeByte24c02(uint16_t addr, uint8_t data) +{ + if(0 != wrbyte_24c02(addr,data)) + { + printf("E2PROM write error!\n"); + } +} + +uint8_t readByte24c02(uint16_t addr) +{ + return rdbyte_24c02(addr); +} + +// 定义一个通用的 EEPROM 访问函数 +uint8_t accessEeprom(size_t offset, void *data, size_t size, OperationType type) +{ + if (data == NULL || size == 0) + { + return 1; // 返回错误状态,表示无效的参数 + } + + uint8_t *byte_data = (uint8_t *)data; // 将 void* 转换为 uint8_t*,方便逐字节操作 + size_t index; + + if (type == WRITE_OPERATION) + { + // 写入操作 + for (index = 0; index < size; index++) + { + writeByte24c02((uint16_t)(offset + index + E2_RESERVE_COUNT), byte_data[index]); + udelay(4000);//写入一个字节延时4ms + } + // 校验 + for (index = 0; index < size; index++) + { + if (readByte24c02((uint16_t)(offset + index + E2_RESERVE_COUNT)) != byte_data[index]) + { + return 2; // 返回错误状态,表示写入验证失败 + } + } + } + else + { + // 读取操作 + for (index = 0; index < size; index++) + { + byte_data[index] = readByte24c02((uint16_t)(offset + index + E2_RESERVE_COUNT)); + } + } + return 0; // 返回状态,表示成功 +} + +void handleParamOp(void *data) +{ + ParamSignal *signal = (ParamSignal *)data; + + if (signal->param_ptr == NULL) + { + // 操作整个参数管理器 + if (accessEeprom(0, param_manager.arr, sizeof(param_manager.arr), signal->type) == 0) + { + read_write_e2_finished = 1; + publishMessage(&read_write_e2_finished, 1); // 读写成功 + } + else + { + read_write_e2_finished = 2; + publishMessage(&read_write_e2_finished, 1); // 读写失败 + } + } + else + { + // 根据信号中的偏移和大小操作单个参数 + if (accessEeprom(signal->offset, signal->param_ptr, signal->size, signal->type) == 0) + { + read_write_e2_finished = 1; + publishMessage(&read_write_e2_finished, 1); // 读写成功 + } + else + { + read_write_e2_finished = 2; + publishMessage(&read_write_e2_finished, 1); // 读写失败 + } + } +} + + +uint8_t calculateCRC(const uint8_t* data, uint32_t length) { + uint8_t crc = 0; + for (uint32_t i = 0; i < length; ++i) { + crc += data[i]; // 简单的校验和,按字节累加 + } + return crc; +} + + +float readParameter(const char *param_name) { + float float_value = 0; + unsigned int offset = 0; + + #define X(name) \ + if (strcmp(param_name, param_names.name) == 0) { \ + accessEeprom(offset, ¶m_manager.bit_data.name,sizeof(param_manager.bit_data.name), READ_OPERATION);\ + memcpy(&float_value, ¶m_manager.bit_data.name, sizeof(param_manager.bit_data.name)); \ + return float_value; \ + } \ + offset += 4; + + PARAM_LIST + #undef X + + printf("Parameter not found: %s\n", param_name); + return 0; +} + + + +void writeParameter(const char *param_name, const uint8_t *data) { + unsigned int offset = 0; + + #define X(name) \ + if (strcmp(param_name, param_names.name) == 0) { \ + memcpy(¶m_manager.bit_data.name, data, sizeof(param_manager.bit_data.name)); \ + accessEeprom(offset, ¶m_manager.bit_data.name,sizeof(param_manager.bit_data.name), WRITE_OPERATION);\ + return; \ + } \ + offset += 4; + + PARAM_LIST + #undef X + + printf("Parameter not found: %s\n", param_name); +} + + + +void sendParamRequestResponse(UnParamRequest *paramRequest, uint32_t sender_ip, uint16_t sender_port, uint8_t isWriteOperation) { + // 准备响应帧 + paramRequest->bit_data.frame_header = 0xFF80; + paramRequest->bit_data.frame_type = 0x002B; + paramRequest->bit_data.frame_length = sizeof(StrParamRequest); + paramRequest->bit_data.accumulated = 0; + paramRequest->bit_data.request_id = isWriteOperation ? 98 : 99; + + paramRequest->bit_data.crc = calculateCRC(paramRequest->arr, sizeof(paramRequest->arr) - 1); + + request_send.param_request = paramRequest; + request_send.sender_ip = sender_ip; + request_send.sender_port = sender_port; + // 发送信号,从UDP发送 + publishMessage(&request_send, 1); +} + + +void processReadAllParams(UnParamRequest *paramRequest, uint32_t sender_ip, uint16_t sender_port) { + uint8_t allParams[256][4]; // Size based on E2 size + unsigned int i = 0; + float param_value; + uint8_t exceeded_max = 0; // 新增标志变量 + + // 清零 paramRequest + memset(paramRequest, 0, sizeof(UnParamRequest)); + + accessEeprom(0, param_manager.arr, sizeof(param_manager.arr), READ_OPERATION); + + printf("Sending parameter data:\n"); + + #define X(name) \ + if (!exceeded_max) { \ + if (i < 256) { \ + strncpy((char *)paramRequest->bit_data.param_name[i], #name, sizeof(paramRequest->bit_data.param_name[i]) - 1); \ + paramRequest->bit_data.param_name[i][sizeof(paramRequest->bit_data.param_name[i]) - 1] = '\0'; \ + memcpy(allParams[i], ¶m_manager.bit_data.name, sizeof(param_manager.bit_data.name)); \ + memcpy(¶m_value, allParams[i], sizeof(float)); \ + printf("Parameter name: %-20s Value: %f\n", #name, param_value); \ + i++; \ + } else { \ + printf("Warning: Exceeded maximum number of parameters\n"); \ + exceeded_max = 1; \ + } \ + } + + PARAM_LIST + #undef X + + // Pack all parameter data into paramRequest + memcpy(paramRequest->bit_data.data, allParams, sizeof(allParams)); + + printf("Total parameters sent: %d\n", i); + + // Send response + sendParamRequestResponse(paramRequest, sender_ip, sender_port, 0); +} + + +void processWriteRequestFrame(UnParamRequest *paramRequest, uint32_t sender_ip, uint16_t sender_port) { + float value; + printf("Processing write request.\n"); + + // 先发送信号,然后从结构体读数 + for (int i = 0; i < 256; ++i) { + if (strlen((char *)paramRequest->bit_data.param_name[i]) > 0) { + writeParameter(paramRequest->bit_data.param_name[i], paramRequest->bit_data.data[i]); + printf("paramRequest->bit_data.param_name[i]:%s \n",paramRequest->bit_data.param_name[i]); + memcpy(&value, paramRequest->bit_data.data[i], sizeof(float)); + printf("paramRequest->bit_data.data[i]:%f \n", value); + } + } + + // 发送响应,发送所有参数 + processReadAllParams(paramRequest, sender_ip, sender_port); +} + + + +void processReadRequestFrame(UnParamRequest *paramRequest, uint32_t sender_ip, uint16_t sender_port) { + // 处理读请求的逻辑 + printf("Processing read request.\n"); + + // 清零 paramRequest + memset(paramRequest, 0, sizeof(UnParamRequest)); + + // 先发送信号,然后从结构体读数 + for (int i = 0; i < 256; ++i) { + if (strlen((char *)paramRequest->bit_data.param_name[i]) > 0) { + float readData = readParameter(paramRequest->bit_data.param_name[i]); + memcpy(paramRequest->bit_data.data[i], &readData, sizeof(paramRequest->bit_data.data[i])); + } + } + + // 发送响应 + sendParamRequestResponse(paramRequest, sender_ip, sender_port, 0); +} + + + + + +void OnParamSignal(void *data) +{ + RequestContext *signal = (RequestContext *)data; + + uint8_t *datagram = (uint8_t *)signal->param_request->arr; + uint16_t request_id = ((uint16_t)datagram[7] << 8) | (uint16_t)datagram[8];// 大端模式 + + // 调试输出 + printf("Received request ID: 0x%04X\n", request_id); + + // 计算CRC + uint8_t calculatedCrc = calculateCRC(datagram, sizeof(UnParamRequest) - 1); + uint8_t receivedCrc = datagram[sizeof(UnParamRequest) - 1]; + + // 比较CRC + if (calculatedCrc != receivedCrc) + { + printf("CRC check failed, discarding data\n"); + printf("Calculated CRC: 0x%02X, Received CRC: 0x%02X\n", calculatedCrc, receivedCrc); + return; + } + + printf("CRC check passed\n"); + + if (request_id == 100) + { // 读请求 + processReadRequestFrame(signal->param_request, signal->sender_ip, signal->sender_port); + } + else if (request_id == 101) + { // 写请求 + processWriteRequestFrame(signal->param_request, signal->sender_ip, signal->sender_port); + } + else if (request_id == 102) + { // 读取所有参数 + processReadAllParams(signal->param_request, signal->sender_ip, signal->sender_port); + } + else + { + printf("Unknown request ID.\n"); + return; + } +} + +float getParam(const char *param_name) +{ + // 检查是否已初始化 + if (!is_param_initialized) + { + printf("Parameters not initialized, reinitializing\n"); + accessEeprom(0, param_manager.arr, sizeof(param_manager.arr), READ_OPERATION);//Read all parameters from E2 + is_param_initialized = 1; // Mark as initialized + printParams(); + return 0.0f; + } + + // 检查参数名是否为空 + if (param_name == NULL) + { + printf("Error: Parameter name is empty\n"); + return 0.0f; + } + + // 遍历所有参数 + #define X(name) \ + if (strcmp(param_name, #name) == 0) \ + { \ + return param_manager.bit_data.name; \ + } + PARAM_LIST + #undef X + + // 如果没有找到匹配的参数名 + printf("Error: Parameter %s not found\n", param_name); + return 0.0f; +} + +// setParam 函数 +uint8_t setParam(const char *param_name, float value) +{ + // 检查参数名是否为空 + if (param_name == NULL) + { + printf("Error: Parameter name is empty\n"); + return 2; // 返回错误码 + } + + // 参数名和值写入EEPROM,先转成字节数组 + uint8_t data[sizeof(float)]; + memcpy(data, &value, sizeof(float)); + writeParameter(param_name, data); + + // 更新参数 + #define X(name) \ + if (strcmp(param_name, #name) == 0) \ + { \ + memcpy(¶m_manager.bit_data.name, data, sizeof(param_manager.bit_data.name)); \ + } + PARAM_LIST + #undef X + + return 0; +} + +void paramAppInit(void) +{ + // 初始化全局变量 + memset(&un_param_request1, 0, sizeof(UnParamRequest)); + memset(&un_param_request2, 0, sizeof(UnParamRequest)); + + // 正确初始化 RequestContext 结构体 + request_send.param_request = &un_param_request1; + request_send.sender_ip = 0; + request_send.sender_port = 0; + + request_context.param_request = &un_param_request2; + request_context.sender_ip = 0; + request_context.sender_port = 0; + + // 上电读取所有参数 + memset(param_manager.arr, 0, sizeof(param_manager.arr)); + accessEeprom(0, param_manager.arr, sizeof(param_manager.arr), READ_OPERATION); + + // 初始化每个参数 + // param_manager.bit_data.whl_bas = 1.5f; // 初始化轮距 + // param_manager.bit_data.max_rpm = 5500.0f; // 初始化最大转速 + // param_manager.bit_data.whl_dia = 0.6f; // 初始化轮直径 + // param_manager.bit_data.max_acc = 1.0f; // 初始化最大加速度 + // param_manager.bit_data.spd_kp = 5.0f; // 初始化速度控制 KP + // param_manager.bit_data.spd_ki = 1.0f; // 初始化速度控制 KI + // param_manager.bit_data.spd_kd = 0.0f; // 初始化速度控制 KD + // param_manager.bit_data.spd_il = 5.0f; // 初始化速度控制 IL + // param_manager.bit_data.spd_ol = 5.0f; // 初始化速度控制 OL + // param_manager.bit_data.crv_kp = 1.0f; // 初始化曲线控制 KP + // param_manager.bit_data.crv_ki = 0.0f; // 初始化曲线控制 KI + // param_manager.bit_data.crv_kd = 0.0f; // 初始化曲线控制 KD + // param_manager.bit_data.crv_il = 2.0f; // 初始化曲线控制 IL + // param_manager.bit_data.crv_ol = 2.0f; // 初始化曲线控制 OL + // param_manager.bit_data.brk_on = 1500.0f; // 初始化制动开启参数 + // param_manager.bit_data.brk_off = 800.0f; // 初始化制动关闭参数 + // param_manager.bit_data.maxTorq = 60.0f; // 初始化最大扭矩 + // param_manager.bit_data.feedPwr = 10000.0f; // 初始化馈电功率 + // param_manager.bit_data.dispPwr = 10000.0f; // 初始化显示功率 + // param_manager.bit_data.VehMass = 700.0f; // 初始化车辆质量 + // param_manager.bit_data.gRatio = 28.0f; // 初始化减速比 + // param_manager.bit_data.prCTime = 5.0f; // 初始化预充时间 + // param_manager.bit_data.brk_pos = 0.0f; // 初始化刹车位置, 0表示未刹车 + // param_manager.bit_data.pwr_sta = 0.0f; // 初始化电源状态 + // param_manager.bit_data.lightSt = 0.0f; // 初始化灯光状态 + // param_manager.bit_data.pwr_btn = 0.0f; // 初始化电源按钮状态 + // param_manager.bit_data.test = 0.0f; // 初始化测试参数 + + + // 订阅信号 + subscribe(¶m_signal, handleParamOp); + subscribe(&request_context, OnParamSignal);// 接收到上位机读写参数信号 + + printParams();//打印所有参数 + + is_param_initialized = 1; // 标记初始化完成 + + printf("paramAPP init OK! %d\n",getCurrentTime()); +} diff --git a/app/app_param_manage.h b/app/app_param_manage.h new file mode 100644 index 0000000..c397a39 --- /dev/null +++ b/app/app_param_manage.h @@ -0,0 +1,145 @@ +#ifndef APP_PARAM_MANAGE_H +#define APP_PARAM_MANAGE_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "app_config.h" + + +// 定义参数列表宏 +#define PARAM_LIST \ + X(whl_bas) \ + X(max_rpm) \ + X(whl_dia) \ + X(max_acc) \ + X(spd_kp) \ + X(spd_ki) \ + X(spd_kd) \ + X(spd_il) \ + X(spd_ol) \ + X(crv_kp) \ + X(crv_ki) \ + X(crv_kd) \ + X(crv_il) \ + X(crv_ol) \ + X(brk_on) \ + X(brk_off) \ + X(maxTorq) \ + X(feedPwr) \ + X(dispPwr) \ + X(VehMass) \ + X(gRatio) \ + X(prCTime) \ + X(brk_pos) \ + X(pwr_sta) \ + X(high_sw) \ + X(stop_sw) \ + X(lightSt) \ + X(pwr_btn) \ + X(sleepTm) \ + X(wakeTm) \ + X(Ospd_kp) \ + X(Ospd_ki) \ + X(Ospd_kd) \ + X(Ospd_il) \ + X(Ospd_ol) \ + X(Ocrv_kp) \ + X(Ocrv_ki) \ + X(Ocrv_kd) \ + X(Ocrv_il) \ + X(Ocrv_ol) \ + X(minTorq) \ + X(test) + +// 定义一个包含所有参数名称的结构体 +typedef struct { + #define X(name) const char* name; + PARAM_LIST + #undef X +} ParamNames; + +// 参数结构体,不能使用位域,不要超过E2的大小, 1K byte +typedef struct +{ + #define X(name) float name; + PARAM_LIST + #undef X +} ParamData; + +typedef union +{ + ParamData bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(ParamData)]; // 通过结构体类型确定大小 +} UnParamManager; + +// 定义信号操作类型 +typedef enum +{ + READ_OPERATION, + WRITE_OPERATION +} OperationType; + +// 定义信号数据结构 +typedef struct +{ + void *param_ptr; // 参数数据的指针 + OperationType type; // 操作类型 + size_t offset; // 参数在结构体中的偏移 + size_t size; // 参数大小 +} ParamSignal; + +#pragma pack(push, 1) + +typedef struct _StrParamRequest { + //-------------------------------------------------- + uint16_t frame_header; // 帧头 固定值0xFF80 (16位) + uint16_t frame_type; // 帧类型 固定值0x002A (16位) + uint16_t frame_length; // 帧长 根据参数数据的长度动态设置 (16位) + uint8_t accumulated; // 累加值 按帧累加 (8位) + uint16_t request_id; // 请求帧ID 请求ID 100表示读,101 表示写参数 (16位) + char param_name[256][8]; // 参数名称 标识要写入或读出的参数 + uint8_t data[256][4]; // 数据 用于写入或读出的参数值,一个参数最大4字节 (8位*4) + uint8_t crc; // CRC 按字节累加之和 取低8位 (8位) +} StrParamRequest; + +typedef union _UnParamRequest { + StrParamRequest bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrParamRequest)]; // 通过结构体类型确定大小 +} UnParamRequest; + +typedef struct { + UnParamRequest *param_request; // 指向 UnParamRequest 的指针 + uint32_t sender_ip; // 发送方的 IP 地址(使用标准的32位整数表示) + uint16_t sender_port; // 发送方的端口号(使用标准的16位整数表示) +} RequestContext; + +#pragma pack(pop) + +extern UnParamRequest un_param_request;// 声明用于参数响应的帧实例 +extern RequestContext request_context; + +// 声明全局信号实例 +extern ParamNames param_names; +extern UnParamManager param_manager; // 全局参数管理实例 +extern ParamSignal param_signal; +extern uint8_t read_write_e2_finished; +extern RequestContext request_send;// 待发送的参数请求信号 + +uint8_t access_eeprom(size_t offset, void *data, size_t size, OperationType type); +void paramAppInit(void); + +// 在适当的位置添加以下函数声明 +float getParam(const char *param_name); +uint8_t setParam(const char *param_name, float value); +void printParams(void); +void handleParamOp(void *data); +void OnParamSignal(void *data); + +#ifdef __cplusplus +} +#endif + +#endif // APP_PARAM_MANAGE_H diff --git a/app/app_pid.c b/app/app_pid.c new file mode 100644 index 0000000..1f541a6 --- /dev/null +++ b/app/app_pid.c @@ -0,0 +1,130 @@ +#include "app_config.h" + +#include "app_pid.h" + + + + +// PID控制器初始化 +void initializePid(PID_t *pid, pid_mode_t mode, float dtMin) +{ + pid->mode = mode; + pid->dt_min = dtMin > SIGMA ? dtMin : SIGMA; + pid->kp = 0.0f; + pid->ki = 0.0f; + pid->kd = 0.0f; + pid->integral = 0.0f; + pid->integral_limit = 0.0f; + pid->output_limit = 0.0f; + pid->error_previous = 0.0f; + pid->last_output = 0.0f; +} + +// 设置PID参数 +int32_t setPidParameters(PID_t *pid, float kp, float ki, float kd, float integralLimit, float outputLimit) +{ + int32_t ret = 0; + + if (isfinite(kp)) { + pid->kp = kp; + } else { + ret = -1; + } + + if (isfinite(ki)) { + pid->ki = ki; + } else { + ret = -2; + } + + if (isfinite(kd)) { + pid->kd = kd; + } else { + ret = -3; + } + + if (isfinite(integralLimit)) { + pid->integral_limit = integralLimit; + } else { + ret = -4; + } + + if (isfinite(outputLimit)) { + pid->output_limit = outputLimit; + } else { + ret = -5; + } + + return ret; +} + +/** + * @brief 计算PID控制器的输出 + * + * @param pid 指向PID_t结构体的指针,包含PID控制器的状态和参数 + * @param sp 设定值(Setpoint),期望系统达到的目标值 + * @param val 当前值(Current Value),系统的实际测量值 + * @param val_dot 当前值的导数(Derivative of Current Value),即测量值的变化率(用于微分项计算) + * @param dt 时间增量(Time Increment),两次调用之间的时间间隔,用于计算积分和微分 + * + * @return float 返回PID控制器计算出的输出值 + */ +float calculatePidOutput(PID_t *pid, float sp, float val, float val_dot, float dt) +{ + // 检查输入参数的有效性 + if (!isfinite(sp) || !isfinite(val) || !isfinite(val_dot) || !isfinite(dt) || dt < pid->dt_min) { + return pid->last_output; + } + + // 计算误差 + float error = sp - val; + + // 根据模式计算微分项 + float derivative = 0.0f; + switch (pid->mode) { + case PID_MODE_DERIVATIVE_CALC: + derivative = (error - pid->error_previous) / dt; + pid->error_previous = error; + break; + case PID_MODE_DERIVATIVE_CALC_NO_SP: + derivative = (-val - pid->error_previous) / dt; + pid->error_previous = -val; + break; + case PID_MODE_DERIVATIVE_SET: + derivative = -val_dot; + break; + default: + derivative = 0.0f; + break; + } + + // 计算比例和微分项的输出 + float output = (pid->kp * error) + (pid->kd * derivative); + + // 计算积分项,并检查积分饱和 + if (pid->ki > SIGMA) { + pid->integral += error * dt; + if (pid->integral > pid->integral_limit) { + pid->integral = pid->integral_limit; + } else if (pid->integral < -pid->integral_limit) { + pid->integral = -pid->integral_limit; + } + output += pid->ki * pid->integral; + } + + // 限制输出范围 + if (output > pid->output_limit) { + output = pid->output_limit; + } else if (output < -pid->output_limit) { + output = -pid->output_limit; + } + + pid->last_output = output; + return output; +} + +// 重置积分器 +void resetPidIntegral(PID_t *pid) +{ + pid->integral = 0.0f; +} diff --git a/app/app_pid.h b/app/app_pid.h new file mode 100644 index 0000000..e93cf49 --- /dev/null +++ b/app/app_pid.h @@ -0,0 +1,46 @@ +#ifndef PID_H +#define PID_H + +#ifdef __cplusplus +extern "C" { +#endif + +// 防止除零和其他误差的极小值 +#define EPSILON 1e-5f +#define SIGMA EPSILON + +#include "app_config.h" + +// PID 控制模式 +typedef enum { + PID_MODE_DERIVATIVE_NONE = 0, // PI 控制器模式,无微分项 + PID_MODE_DERIVATIVE_CALC, // 根据当前误差计算微分项 + PID_MODE_DERIVATIVE_CALC_NO_SP, // 根据当前值计算微分项,忽略设定值 + PID_MODE_DERIVATIVE_SET // 使用外部提供的微分项值 +} pid_mode_t; + +// PID 控制器结构体 +typedef struct { + pid_mode_t mode; // 控制模式 + float dt_min; // 最小时间间隔 + float kp; // 比例系数 + float ki; // 积分系数 + float kd; // 微分系数 + float integral; // 积分累积值 + float integral_limit; // 积分限幅 + float output_limit; // 输出限幅 + float error_previous; // 上一次的误差值 + float last_output; // 上一次的输出值 +} PID_t; + +// 函数声明 +void initializePid(PID_t *pid, pid_mode_t mode, float dtMin); +int32_t setPidParameters(PID_t *pid, float kp, float ki, float kd, float integralLimit, float outputLimit); +float calculatePidOutput(PID_t *pid, float sp, float val, float val_dot, float dt); +void resetPidIntegral(PID_t *pid); + +#ifdef __cplusplus +} +#endif + +#endif // PID_H diff --git a/app/app_power.c b/app/app_power.c new file mode 100644 index 0000000..1ff0227 --- /dev/null +++ b/app/app_power.c @@ -0,0 +1,429 @@ +#include "app_config.h" +#include "interface.h" +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" +#include "app_param_manage.h" + +#include "app_power.h" + + +// 定义按钮状态枚举 +typedef enum { + BUTTON_STATE_INITIAL, + BUTTON_STATE_SHORT_PRESS, + BUTTON_STATE_SHORT_PRESS_DETECTED, + BUTTON_STATE_WAIT_FOR_LONG_PRESS, + BUTTON_STATE_LONG_PRESS, + BUTTON_STATE_LONG_PRESS_WAIT +} ButtonState; + +// 定义按钮结构体 +typedef struct { + ButtonState state; + uint32_t press_start_time; + uint32_t release_start_time; + uint8_t is_power_on; + Timer timer; + uint8_t old_is_power_on; + Timer timer1; + +} PowerButton; + +// 全局变量 +PowerSystem power_data; +static PowerButton power_button = {BUTTON_STATE_INITIAL, 0, 0, 0, {0},0}; + +// 电源按钮处理函数 +static void handlePowerButton(void) +{ + switch (power_button.state) + { + case BUTTON_STATE_INITIAL: + if (power_data.remote_power_switch == app_close()) + { + power_button.state = BUTTON_STATE_SHORT_PRESS_DETECTED; + timerStart(&power_button.timer, 500, 0); // 启动短按定时器,500ms + } + break; + + case BUTTON_STATE_SHORT_PRESS_DETECTED: + if (power_data.remote_power_switch == app_open()) + { + if (power_button.timer.active) // 定时器未到期,短按完成,启动等待长按定时器 + { + power_button.state = BUTTON_STATE_WAIT_FOR_LONG_PRESS; + timerStart(&power_button.timer, 500, 0); // 启动等待长按定时器,500ms + } + } + else if (!power_button.timer.active)// 短按定时器到期,按键仍被按下,视为无效,重置为初始状态 + { + power_button.state = BUTTON_STATE_INITIAL; + } + break; + + case BUTTON_STATE_WAIT_FOR_LONG_PRESS: + if (power_data.remote_power_switch == app_close())// 检测是否在等待时间内进行长按 + { + power_button.state = BUTTON_STATE_LONG_PRESS; + timerStart(&power_button.timer, 1000, 0); // 启动长按定时器,1000ms + } + else if (!power_button.timer.active) // 等待长按超时,重置为初始状态 + { + power_button.state = BUTTON_STATE_INITIAL; + } + break; + + case BUTTON_STATE_LONG_PRESS: + + if (!power_button.timer.active)// 长按完成,切换电源状态 20250423 修改不需要判断松开按键就打开控制器 + { + power_button.is_power_on = !power_button.is_power_on; + printf("PowerButton: is_power_on = %d\n", power_button.is_power_on); + power_button.state = BUTTON_STATE_LONG_PRESS_WAIT; + } + else if(power_data.remote_power_switch == app_open()) + { + power_button.state = BUTTON_STATE_INITIAL; + printf("Long press for short duration"); + } + else + break; + + case BUTTON_STATE_LONG_PRESS_WAIT: + if (power_data.remote_power_switch == app_open())// 检测按键释放 + { + power_button.state = BUTTON_STATE_INITIAL; + printf("Release the button"); + } + default: + power_button.state = BUTTON_STATE_INITIAL; + break; + } +} + + +// 输出处理函数 +static void powerOutput(void *signal_id) +{ + (void)signal_id; + + // 根据当前状态,控制各个设备的电源 + switch (power_data.current_state) + { + case POWER_PRE_CHARGE: + publishMessage(&power_data.pre_charge_finish, 1);//发布预充完成信号,100ms发送一次,直到预充完成 + un_inf_can_kgf_output1.bit_data.KGF04 = setPowerOn(); // 预充继电器 + un_inf_can_kgf_output1.bit_data.KGF07 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output1.bit_data.KGF08 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output2.bit_data.KGF10 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF11 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF01 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF02 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF03 = setPowerOn(); // 遥控器 + un_inf_can_kgf_output2.bit_data.KGF05 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF06 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output1.bit_data.KGF09 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF04 = setPowerOn(); // E3 + break; + + case POWER_NEUTRAL: + publishMessage(&power_data.pre_charge_finish, 1);//20250316增加,发送空挡信号,保证电机控制器高压上电后,发送空挡信号 + un_inf_can_kgf_output1.bit_data.KGF04 = setPowerOff(); // 预充继电器 + un_inf_can_kgf_output1.bit_data.KGF07 = setPowerOn(); // 高压继电器 + un_inf_can_kgf_output1.bit_data.KGF08 = setPowerOn(); // 高压继电器 + un_inf_can_kgf_output2.bit_data.KGF10 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF11 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF01 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF02 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF03 = setPowerOn(); // 遥控器 + un_inf_can_kgf_output2.bit_data.KGF05 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF06 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output1.bit_data.KGF09 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF04 = setPowerOn(); // E3 + break; + + + case POWER_STANDBY: + // 初始状态,只开启基本设备 + un_inf_can_kgf_output1.bit_data.KGF04 = setPowerOff(); // 预充继电器 + un_inf_can_kgf_output1.bit_data.KGF07 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output1.bit_data.KGF08 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output2.bit_data.KGF10 = setPowerOff(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF11 = setPowerOff(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF01 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF02 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF03 = setPowerOn(); // 遥控器 + un_inf_can_kgf_output2.bit_data.KGF05 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF06 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output1.bit_data.KGF09 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF04 = setPowerOn(); // E3 + break; + + case POWER_WORKING: + // 工作状态,除预充继电器外所有设备开启 + un_inf_can_kgf_output1.bit_data.KGF04 = setPowerOff(); // 预充继电器 + un_inf_can_kgf_output1.bit_data.KGF07 = setPowerOn(); // 高压继电器 + un_inf_can_kgf_output1.bit_data.KGF08 = setPowerOn(); // 高压继电器 + un_inf_can_kgf_output2.bit_data.KGF10 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF11 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF01 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF02 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF03 = setPowerOn(); // 遥控器 + un_inf_can_kgf_output2.bit_data.KGF05 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF06 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output1.bit_data.KGF09 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF04 = setPowerOn(); // E3 + break; + + case POWER_EMERGENCY: + // 急停状态,断开高压 + un_inf_can_kgf_output1.bit_data.KGF04 = setPowerOff(); // 预充继电器 + un_inf_can_kgf_output1.bit_data.KGF07 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output1.bit_data.KGF08 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output2.bit_data.KGF10 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF11 = setPowerOn(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF01 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF02 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF03 = setPowerOn(); // 遥控器 + un_inf_can_kgf_output2.bit_data.KGF05 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF06 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output1.bit_data.KGF09 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF04 = setPowerOn(); // E3 + break; + + case POWER_SLEEP: + // 休眠状态,关闭所有设备 + un_inf_can_kgf_output1.bit_data.KGF04 = setPowerOff(); // 预充继电器 + un_inf_can_kgf_output1.bit_data.KGF07 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output1.bit_data.KGF08 = setPowerOff(); // 高压继电器 + un_inf_can_kgf_output2.bit_data.KGF10 = setPowerOff(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF11 = setPowerOff(); // 低压继电器 + un_inf_can_kgf_output2.bit_data.KGF01 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF02 = setPowerOn(); // 计算机 + un_inf_can_kgf_output2.bit_data.KGF03 = setPowerOn(); // 遥控器 + un_inf_can_kgf_output2.bit_data.KGF05 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF06 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output1.bit_data.KGF09 = setPowerOn(); // 网络交换机 + un_inf_can_kgf_output2.bit_data.KGF04 = setPowerOn(); // E3 + break; + + default: + break; + } + publishMessage(&power_data, 1); + publishMessage(&un_inf_can_kgf_output1, 1); + publishMessage(&un_inf_can_kgf_output2, 1); +} + +static void wakeupProcess(void *signal_id) +{ + (void)signal_id; + + un_gather_output.bit_data.sleep_duration = (uint16_t)getParam("sleepTm"); + un_gather_output.bit_data.wakeup_interval = (uint16_t)getParam("wakeTm"); + + if(un_gather_output.bit_data.sleep_duration < 5)//最小值限定 + { + un_gather_output.bit_data.sleep_duration = 5; + } + + if(un_gather_output.bit_data.wakeup_interval < 5)//最小值限定 + { + un_gather_output.bit_data.wakeup_interval = 5; + } + + un_gather_output.bit_data.vehicle_mode = power_data.current_state; + + publishMessage(&un_gather_output, 1); + timerStart(&power_data.timer1, 500, 1); //周期调用 +} + + +// 定时器处理函数 +static void powerTimerProcess(void *signal_id) +{ + (void)signal_id; + + // 调用电源按钮处理函数 + handlePowerButton(); + // 电源按钮状态有变化,保存到参数 + if (power_button.is_power_on != power_button.old_is_power_on) + { + setParam("pwr_btn", (float)power_button.is_power_on); + power_button.old_is_power_on = power_button.is_power_on; + } + + // 状态转换逻辑 + switch (power_data.current_state) + { + case POWER_PRE_CHARGE: + if (!power_data.timer_pre_charge.active) // 预充时间到 + { + power_data.current_state = POWER_NEUTRAL; // 工作 + power_data.pre_charge_finish = 1; // 预充完成 + printf("Power: Transitioning from PRE_CHARGE to POWER_NEUTRAL state\n"); + } + break; + case POWER_NEUTRAL://20250316增加,发送空挡信号 + if (power_data.neutral_cnt >= 5) // 运行5次 + { + power_data.neutral_cnt = 0; + power_data.current_state = POWER_WORKING; // 工作 + power_data.pre_charge_finish = 1; // 预充完成 + printf("Power: Transitioning from POWER_NEUTRAL to WORKING state\n"); + } + else + { + power_data.neutral_cnt ++; + power_data.current_state = POWER_NEUTRAL; // 空挡 + power_data.pre_charge_finish = 1; // 预充完成 + } + break; + + case POWER_STANDBY: + if (power_data.high_voltage_switch == app_open()) // 高压开关断开 + { + power_data.current_state = POWER_SLEEP; // 休眠 + printf("Power: Transitioning from STANDBY to SLEEP state\n"); + } + else if (power_button.is_power_on == app_close() && power_data.emergency_stop == app_close()) // 遥控器电源开关闭合且急停开关闭合 + { + power_data.current_state = POWER_EMERGENCY; // 急停 + printf("Power: Transitioning from STANDBY to EMERGENCY state\n"); + } + break; + + case POWER_WORKING: + if (power_data.high_voltage_switch == app_open()) // 高压开关断开 + { + power_data.current_state = POWER_SLEEP; // 休眠 + printf("Power: Transitioning from STANDBY to SLEEP state\n"); + } + else if (power_data.emergency_stop == app_close()) // 急停开关闭合 + { + power_data.current_state = POWER_EMERGENCY; // 急停 + printf("Power: Transitioning from WORKING to EMERGENCY state\n"); + + printf("emergency_stop_switch: %d, remote_emergency_stop: %d\n", power_data.emergency_stop_switch, power_data.remote_emergency_stop); //打印状态 + printf("remote_stop: %d\n", un_remote_control_input.bit_data.switch_b); + } + break; + case POWER_EMERGENCY: + if (power_data.high_voltage_switch == app_open()) // 高压开关断开 + { + power_data.current_state = POWER_SLEEP; // 休眠 + printf("Power: Transitioning from EMERGENCY to SLEEP state\n"); + } + else if (power_button.is_power_on == app_open()) // 遥控器电源开关断开 + { + power_data.current_state = POWER_STANDBY; // 待机 + printf("Power: Transitioning from EMERGENCY to STANDBY state\n"); + } + else if (power_data.emergency_stop == app_open()) // 急停断开 + { + power_data.current_state = POWER_PRE_CHARGE; // 预充 + timerStart(&power_data.timer_pre_charge, (uint32_t)(getParam("prCTime") * 1000), 1); // 启动预充定时器 + printf("Power: Transitioning from EMERGENCY to PRE_CHARGE state\n"); + } + break; + case POWER_SLEEP: + if (power_data.high_voltage_switch == app_close()) // 高压开关闭合 + { + power_data.current_state = POWER_STANDBY; // 待机 + printf("Power: Transitioning from SLEEP to STANDBY state\n"); + } + break; + default: + power_data.current_state = POWER_STANDBY; // 待机 + break; + } + + powerOutput(NULL); // 输出 + + // 电源状态有变化,记录到参数 + if (power_data.old_state != power_data.current_state) + { + power_data.old_state = power_data.current_state; + setParam("pwr_sta", (float)power_data.current_state); + } + + timerStart(&power_data.timer, 100, 1); //周期调用 +} + + + + +// 处理所有输入信号的函数 +static void powerInput(void *signal_id) +{ + //不能直接赋值,用memcpy + PowerSystem old_data; + memcpy(&old_data, &power_data, sizeof(PowerSystem)); + + // 填充数据 + if (signal_id == &un_sw_sample) + { + power_data.emergency_stop_switch = (uint8_t)un_sw_sample.bit_data.emergency_stop_switch;//急停开关 + power_data.high_voltage_switch = (uint8_t)un_sw_sample.bit_data.High_voltage_switch;//高压开关 + } + else if ( (signal_id == &un_remote_control_input) && (1 == un_remote_control_input.bit_data.enable) )// 遥控器断线,不更新数据 + { + power_data.remote_power_switch = (uint8_t)un_remote_control_input.bit_data.switch_d; // 遥控器电源开关 + power_data.remote_emergency_stop = ((uint8_t)un_remote_control_input.bit_data.switch_b == 1) ? 0 : 1;// 遥控器急停开关 + } + // 急停开关 + power_data.emergency_stop = (uint8_t)( (power_data.emergency_stop_switch == app_close()) || (power_data.remote_emergency_stop == app_close()) ); + + // 急停开关有变化,记录到参数 + if (power_data.old_emergency_stop != power_data.emergency_stop) + { + power_data.old_emergency_stop = power_data.emergency_stop; + setParam("stop_sw", (float)power_data.emergency_stop); + } + + // 高压开关状态有变化,记录到参数 + if (power_data.old_high_voltage_switch != power_data.high_voltage_switch) + { + power_data.old_high_voltage_switch = power_data.high_voltage_switch; + setParam("high_sw", (float)power_data.high_voltage_switch); + } +} + + +// APP模块的初始化 +void powerAppInit(void) +{ + // 初始化变量 + memset(&power_data, 0, sizeof(PowerSystem)); + power_data.current_state = POWER_STANDBY; + // 初始化时恢复电源状态 + power_data.current_state = (PowerState)getParam("pwr_sta"); + power_data.old_state = power_data.current_state; + // 恢复电源按钮状态 + power_button.is_power_on = (uint8_t)getParam("pwr_btn"); + power_button.old_is_power_on = power_button.is_power_on; + //恢复高压开关状态 + power_data.high_voltage_switch = (uint8_t)getParam("high_sw"); + power_data.old_high_voltage_switch = power_data.high_voltage_switch; + //恢复急停开关状态 + power_data.emergency_stop = (uint8_t)getParam("stop_sw"); + power_data.old_emergency_stop = power_data.emergency_stop; + + // 订阅输入信号 + subscribe(&un_sw_sample, powerInput); // 急停开关、高压开关 + subscribe(&un_remote_control_input, powerInput); // 遥控器电源开关 + // 定时器 + timerInit(&power_data.timer); + subscribe(&power_data.timer, powerTimerProcess); + timerStart(&power_data.timer, 500, 1); // 周期调用 + //定时器唤醒 + timerInit(&power_data.timer1); + subscribe(&power_data.timer1, wakeupProcess); + timerStart(&power_data.timer1, 500, 1); // 周期调用 + //预充定时器 + timerInit(&power_data.timer_pre_charge); + subscribe(&power_data.timer_pre_charge, powerTimerProcess); + + printf("app_power: initial OK\n"); +} diff --git a/app/app_power.h b/app/app_power.h new file mode 100644 index 0000000..3784f77 --- /dev/null +++ b/app/app_power.h @@ -0,0 +1,57 @@ +#ifndef APP_POWER_H +#define APP_POWER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "app_config.h" +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" + +// 定义电源状态枚举 +typedef enum { + POWER_STANDBY, + POWER_WORKING, + POWER_EMERGENCY, + POWER_PRE_CHARGE, + POWER_NEUTRAL, + POWER_SLEEP +} PowerState; + +// 使用内联函数 +static inline uint8_t setPowerOn(void) { return 1; } +static inline uint8_t setPowerOff(void) { return 0; } + + +// 声明 power_data 变量结构体 +typedef struct { + PowerState current_state; // 当前电源状态 + uint32_t start_time; // 定时器起始时间 + Timer timer; // 定时器 + Timer timer1; + Timer timer_pre_charge; // 预充定时器 + PowerState last_state; // 上一次状态 + uint8_t emergency_stop_switch; // 急停开关 + uint8_t high_voltage_switch; // 高压开关 + uint8_t old_high_voltage_switch; // 上一次高压开关 + uint8_t remote_power_switch; // 遥控器电源开关 + uint8_t remote_emergency_stop; // 遥控器急停开关 + uint8_t emergency_stop; // 急停状态 + uint8_t old_emergency_stop; // 上一次急停开关 + uint8_t pre_charge_finish; // 预充完成标志位 + uint8_t old_state; // 上一次状态 + uint8_t neutral_cnt; +} PowerSystem; + +// 声明外部变量 +extern PowerSystem power_data; + +void powerAppInit(void); + +#ifdef __cplusplus +} +#endif + +#endif // APP_POWER_H diff --git a/app/app_request.c b/app/app_request.c new file mode 100644 index 0000000..ebf5b05 --- /dev/null +++ b/app/app_request.c @@ -0,0 +1,396 @@ +#include "app_config.h" +#include "interface.h" +#include "app_request.h" +#include "app_param_manage.h" + +uint16_t request_id = 0; + + +static void processRequestframe(uint16_t id) +{ + uint32_t TempAcc = 0; + uint8_t i = 0; + static uint8_t VehicleStaACC0 = 0; + static uint8_t VehicleStaACC1 = 0; + static uint8_t VehicleStaACC2 = 0; + static uint8_t VehicleStaACC3 = 0; + + uint16_t RgExchangeTemp = 0; + uint32_t Rg32ExchangeTemp = 0; +//----------------------------------------------------------- +// printf("request_read_id:%d\n",id); + switch (id)//注意是高位在前,低位在后 + { + case 0x2000://状态帧 + un_vehicle_Info_output.bit_data.frame_header = 0xCCAA;//帧头 + un_vehicle_Info_output.bit_data.frame_type = 0x2000;//帧类型 + un_vehicle_Info_output.bit_data.frame_length = 0x2900;//帧长 + un_vehicle_Info_output.bit_data.accumulated = VehicleStaACC0++;//累加值 + + TempAcc = 0; + for (i = 0; i < 40; i++)//累加前40个字节 + { + TempAcc = TempAcc + (uint32_t)(un_vehicle_Info_output.arr[i]); + } + un_vehicle_Info_output.bit_data.crc = (uint8_t)TempAcc;//累加值 + + publishMessage(&un_vehicle_Info_output, 1); + + break; + + case 0x2100://电机帧 + un_motor_status_output.bit_data.frame_header = 0xCCAA;//帧头 + un_motor_status_output.bit_data.frame_type = 0x2100;//帧类型 + un_motor_status_output.bit_data.frame_length = 0x1E00;//帧长 + un_motor_status_output.bit_data.accumulated = VehicleStaACC1++;//累加值 + RgExchangeTemp = ( (uint16_t)getParam("maxTorq") + 300 ) *100 ; + un_motor_status_output.bit_data.left_torque_limit = ((RgExchangeTemp << 8) | (RgExchangeTemp >> 8));//左侧扭矩限制 + un_motor_status_output.bit_data.right_torque_limit = ((RgExchangeTemp << 8) | (RgExchangeTemp >> 8));//右侧扭矩限制 + un_motor_status_output.bit_data.left_power_in = (((uint16_t)getParam("feedPwr") << 8) | ((uint16_t)getParam("feedPwr") >> 8));//左侧馈电功率 + un_motor_status_output.bit_data.right_power_in = (((uint16_t)getParam("feedPwr") << 8) | ((uint16_t)getParam("feedPwr") >> 8));//右侧馈电功率 + un_motor_status_output.bit_data.left_power_out = (((uint16_t)getParam("dispPwr") << 8) | ((uint16_t)getParam("dispPwr") >> 8));//左侧放电功率 + un_motor_status_output.bit_data.right_power_out = (((uint16_t)getParam("dispPwr") << 8) | ((uint16_t)getParam("dispPwr") >> 8));//右侧放电功率 + + TempAcc = 0; + for (i = 0; i < 31; i++)//累加前31个字节 + { + TempAcc = TempAcc + (uint32_t)(un_motor_status_output.arr[i]); + un_motor_status_output.bit_data.checksum = (uint8_t)TempAcc;//累加值 + } + + publishMessage(&un_motor_status_output, 1); + break; + + case 0x2200: + un_pid_output.bit_data.frame_header = 0xCCAA;//帧头 + un_pid_output.bit_data.frame_type = 0x2200;//帧类型 + un_pid_output.bit_data.frame_length = 0x3800;//帧长 + un_pid_output.bit_data.accumulated = VehicleStaACC2++;//累加值 + + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("spd_kp")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.rc_straight_p = Rg32ExchangeTemp;//遥控直行P参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("spd_ki")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.rc_straight_i = Rg32ExchangeTemp;//遥控直行I参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("spd_kd")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.rc_straight_d = Rg32ExchangeTemp;//遥控直行D参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("spd_il")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.auto_straight_p = Rg32ExchangeTemp;//自主直行P参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("spd_ol")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.auto_straight_i = Rg32ExchangeTemp;//自主直行I参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("spd_kd")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.auto_straight_d = Rg32ExchangeTemp;//自主直行D参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("crv_kp")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.rc_turn_p = Rg32ExchangeTemp;//遥控转弯P参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("crv_ki")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.rc_turn_i = Rg32ExchangeTemp;//遥控转弯I参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("crv_kd")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.rc_turn_d = Rg32ExchangeTemp;//遥控转弯D参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("crv_il")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.auto_turn_p = Rg32ExchangeTemp;//自主转弯P参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("crv_ol")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.auto_turn_i = Rg32ExchangeTemp;//自主转弯I参数 + + Rg32ExchangeTemp = (uint32_t)(int32_t)(getParam("spd_kd")*1000); + Rg32ExchangeTemp = ( ((Rg32ExchangeTemp >> 24) &0xff ) | ((Rg32ExchangeTemp >> 8) & 0xFF00) | ((Rg32ExchangeTemp << 8) & 0xFF0000) | ((Rg32ExchangeTemp << 24)) ); + un_pid_output.bit_data.auto_turn_d = Rg32ExchangeTemp;//自主转弯I参数 + + TempAcc = 0; + for (i = 0; i < 55; i++)//累加前40个字节 + { + TempAcc = TempAcc + (uint32_t)(un_pid_output.arr[i]); + } + un_pid_output.bit_data.checksum = (uint8_t)TempAcc;//累加值 + + publishMessage(&un_pid_output, 1); + + break; + + case 0x2300: +// ETHTxtempArr[0] = 0xAA; +// ETHTxtempArr[1] = 0xCC; +// ETHTxtempArr[2] = 0x00; +// ETHTxtempArr[3] = 0x23; +// ETHTxtempArr[4] = 0; +// ETHTxtempArr[5] = 27; +// ETHTxtempArr[6] = VehicleStaACC3++; +// //AIAO +// memcpy(ÐTxtempArr[7],(uint8_t *)&(UnAIAOSignal_1.ArrData.ArrRx[0]),17);//电池数据拷贝 +// ETHTxtempArr[24] = (u8)(RgCanToAiAOCnt>>8); +// ETHTxtempArr[25] = (u8)RgCanToAiAOCnt;//累加值 +// +// TempAcc = 0; +// for (i = 0; i < 26; i++)//累加前40个字节 +// { +// TempAcc = TempAcc + (u32)(ETHTxtempArr[i]); +// } +// ETHTxtempArr[26] = (uint8_t)TempAcc;//累加值 +// +// TxLen = 27; +// UdpSendToData(UDPCB_2,(uint8_t *)(&un_analog_signal_output), 27, (uint8_t *)ðernet_parameter.upper_ip[0], ethernet_parameter.target_upper_port); + break; + + case 0x2400: + un_remote_control_output.bit_data.frame_header = 0xCCAA;//帧头 + un_remote_control_output.bit_data.frame_type = 0x2400;//帧类型 + un_remote_control_output.bit_data.frame_length = 0x1400;//帧长 + un_remote_control_output.bit_data.accumulated = VehicleStaACC3++;//累加值 + //RCH_3 + + TempAcc = 0; + for (i = 0; i < 17; i++)//累加前40个字节 + { + TempAcc = TempAcc + (uint32_t)(un_remote_control_output.arr[i]); + } + un_remote_control_output.bit_data.crc = (uint8_t)TempAcc;//累加值 + + publishMessage(&un_remote_control_output, 1); + break; + + case 0x2500: + un_manual_control_output.bit_data.frame_type = 0x2500; + + TempAcc = 0; + for (i = 0; i < 14; i++)//累加前40个字节 + { + TempAcc = TempAcc + (uint32_t)(un_manual_control_output.arr[i]); + } + un_manual_control_output.bit_data.crc_2 = (uint8_t)TempAcc;//累加值 + + publishMessage(&un_manual_control_output, 1); + break; + + case 0x2600: + un_auto_control_output.bit_data.frame_type = 0x2600; + + TempAcc = 0; + for (i = 0; i < 27; i++)//累加前40个字节 + { + TempAcc = TempAcc + (uint32_t)(un_auto_control_output.arr[i]); + } + un_auto_control_output.bit_data.crc = (uint8_t)TempAcc;//累加值 + + publishMessage(&un_auto_control_output, 1); + break; + +// case 0x2700: +// memcpy(ÐTxtempArr[0],(uint8_t *)&RemoteControlRoomToVcuBuf,11);//手柄拷贝 +// ETHTxtempArr[2] = 0;//修改帧类型为0x0025 +// ETHTxtempArr[3] = 0x27; +// ETHTxtempArr[11] = (u8)(RgETHToRemoteControlCnt>>8); +// ETHTxtempArr[12] = (u8)RgETHToRemoteControlCnt;//累加值 +// TempAcc = 0; +// for (i = 0; i < 13; i++)//累加前40个字节 +// { +// TempAcc = TempAcc + (u32)(ETHTxtempArr[i]); +// } +// ETHTxtempArr[13] = (uint8_t)TempAcc;//累加值 +// +// TxLen = 14; +// UdpSendToData(SocketId2,ETHTxtempArr,&TxLen,ip_addr,port);//测试 +// break; + +// case 0xFFFF: +// memcpy(ÐTxtempArr[0],(uint8_t *)&RemoteControlRoomToVcuBuf,11);//手柄拷贝 +// ETHTxtempArr[2] = 0x27;//修改帧类型为0x0025 +// ETHTxtempArr[3] = 0; +// ETHTxtempArr[11] = (u8)RgETHToRemoteControlCnt; +// ETHTxtempArr[12] = (u8)(RgETHToRemoteControlCnt>>8);//累加值 +// TempAcc = 0; +// for (i = 0; i < 13; i++)//累加前40个字节 +// { +// TempAcc = TempAcc + (u32)(ETHTxtempArr[i]); +// } +// ETHTxtempArr[13] = (uint8_t)TempAcc;//累加值 +// +// TxLen = 14; +// UdpSendToData(SocketId2,ETHTxtempArr,&TxLen,ip_addr,port);//测试 +// break; + default: break; + } +} + + + +// 处理所有输入信号的函数 +static void requestInput(void *signal_id) +{ + uint16_t request16_temp = 0; + +//-------------------------------------------------------- + if (signal_id == &diff_data) + { + request16_temp = (uint16_t)(int16_t)(diff_data.desired_speed * 100.0); + un_vehicle_Info_output.bit_data.desired_speed = ((request16_temp << 8) | (request16_temp >> 8));//当前速度 + + request16_temp = (uint16_t)(int16_t)(diff_data.desired_curvature * 10000.0); + un_vehicle_Info_output.bit_data.desired_curvature = ((request16_temp << 8) | (request16_temp >> 8));//当前曲率 + + request16_temp = (uint16_t)(int16_t)(diff_data.speed * 100.0); + un_vehicle_Info_output.bit_data.speed = ((request16_temp << 8) | (request16_temp >> 8));//当前速度 + + request16_temp = (uint16_t)(int16_t)(diff_data.curvature * 10000.0); + un_vehicle_Info_output.bit_data.curvature = ((request16_temp << 8) | (request16_temp >> 8));//当前曲率 + + request16_temp = (uint16_t)(int16_t)(diff_data.left_motor_speed *6); + un_vehicle_Info_output.bit_data.set_left_speed = ((request16_temp << 8) | (request16_temp >> 8));//当前速度 + + request16_temp = (uint16_t)(int16_t)(diff_data.right_motor_speed *6); + un_vehicle_Info_output.bit_data.set_right_speed = ((request16_temp << 8) | (request16_temp >> 8));//当前曲率 + + } + else if(signal_id == &un_auto_computer_input) + { + un_vehicle_Info_output.bit_data.longitude = un_auto_computer_input.bit_data.longitude;//经度 + + un_vehicle_Info_output.bit_data.latitude = un_auto_computer_input.bit_data.latitude; + + un_vehicle_Info_output.bit_data.altitude = un_auto_computer_input.bit_data.altitude; + + un_vehicle_Info_output.bit_data.heading_angle = un_auto_computer_input.bit_data.heading;//航向 + + memcpy(&un_auto_control_output.arr[0],&(un_auto_computer_input.arr[0]),25);//手柄拷贝 + } + else if(signal_id == &un_bms_input) + { + un_vehicle_Info_output.bit_data.battery_voltage = un_bms_input.bit_data.bus_voltage/10;//电池电压读取得的10mV,所以输出的是100mV单位,所以缩小10倍 + un_vehicle_Info_output.bit_data.battery_soc = un_bms_input.bit_data.soc;//SOC + un_vehicle_Info_output.bit_data.battery_current = un_bms_input.bit_data.bus_current;//电池电流 + } + else if(signal_id == &un_motor_input1) + { +// un_motor_status_output.bit_data.left_wheel_speed = SWAP_ENDIAN_16( (uint16_t)((int16_t)(un_motor_input1.bit_data.MotCon_1Signal4) + 30000) ); + +// un_motor_status_output.bit_data.left_torque = ((un_motor_input1.bit_data.torque << 8) | (un_motor_input1.bit_data.torque >> 8));//左侧扭矩 +// un_motor_status_output.bit_data.left_voltage = ((un_motor_input1.bit_data.bus_voltage << 8) | (un_motor_input1.bit_data.bus_voltage >> 8));//左侧电压 +// un_motor_status_output.bit_data.left_fault_code = un_motor_input1.bit_data.fault_code;//左侧故障码 + + } + else if(signal_id == &un_motor_input2) + { +// un_motor_status_output.bit_data.right_wheel_speed = SWAP_ENDIAN_16 ( (uint16_t)((int16_t)(un_motor_input1.bit_data.MotCon_1Signal3) + 30000) );//左侧轮速 +// un_motor_status_output.bit_data.right_torque = ((un_motor_input2.bit_data.torque << 8) | (un_motor_input2.bit_data.torque >> 8));//右侧扭矩 +// un_motor_status_output.bit_data.right_fault_code = un_motor_input2.bit_data.fault_code;//右侧故障码 +// un_motor_status_output.bit_data.right_voltage = ((un_motor_input2.bit_data.bus_voltage << 8) | (un_motor_input2.bit_data.bus_voltage >> 8));//右侧电压 + + } + else if(signal_id == &un_remote_control_input) + { + //RCH_3 + un_remote_control_output.bit_data.speed = ((un_remote_control_input.bit_data.speed << 8) | (un_remote_control_input.bit_data.speed >> 8));//遥控器期望速度 + un_remote_control_output.bit_data.curvature = ((un_remote_control_input.bit_data.curvature << 8) | (un_remote_control_input.bit_data.curvature >> 8));//遥控器期望曲率 + memcpy(&un_remote_control_output.arr[11],&un_remote_control_input.arr[4],4);//遥控数据拷贝 + } + else if(signal_id == &un_manual_computer_input) + { + memcpy(&un_manual_control_output.arr[0],&(un_manual_computer_input.arr[0]),12);//手柄拷贝 + } + else if(signal_id == ðernet_fault_Info) + { + un_auto_control_output.arr[25] = (uint8_t)(ethernet_fault_Info.bit_data.auto_count>>8); + un_auto_control_output.arr[26] = (uint8_t)(ethernet_fault_Info.bit_data.auto_count);//累加值 + un_manual_control_output.arr[12] = (uint8_t)(ethernet_fault_Info.bit_data.manual_count>>8); + un_manual_control_output.arr[13] = (uint8_t)(ethernet_fault_Info.bit_data.manual_count);//累加值 + } + + else if(signal_id == &can_fault_info) + { + un_remote_control_output.arr[15] = (uint8_t)(can_fault_info.bit_data.remote_count>>8); + un_remote_control_output.arr[16] = (uint8_t)(can_fault_info.bit_data.remote_count);//累加值 + } + else if(signal_id == &un_request_frame) + { + request_id = REQUEST_READ_ID; + processRequestframe(request_id); + } + else{} +} + +// 修改APP模块的初始化函数 +void requestAppInit(void) +{ + // 订阅消息,使用静态成员函数作为回调 参数回馈 + subscribe(&diff_data, requestInput); + subscribe(&un_auto_computer_input, requestInput); + subscribe(&un_bms_input, requestInput); + subscribe(&un_motor_input1, requestInput); + subscribe(&un_motor_input2, requestInput); + subscribe(&un_remote_control_input, requestInput); + subscribe(&can_fault_info, requestInput); + subscribe(ðernet_fault_Info, requestInput); + +// // 订阅消息,使用静态成员函数作为回调 参数回馈 + subscribe(&un_request_frame, requestInput); + + printf("app_request: initial OK \n"); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/app_request.h b/app/app_request.h new file mode 100644 index 0000000..8f76eaf --- /dev/null +++ b/app/app_request.h @@ -0,0 +1,89 @@ +#ifndef APP_REQUEST_H +#define APP_REQUEST_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "app_config.h" +#include "app_differential_drive.h" + + + +#define SWAP_ENDIAN_16(x) ((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF)) +#define SWAP_ENDIAN_32(x) (((x) << 24) | (((x) & 0xFF00) << 8) | (((x) >> 8) & 0xFF00) | ((x) >> 24)) + + + + +//typedef enum +//{ +// MODE_MANUAL, // 手动模式 +// MODE_AUTO // 自动模式 +//} ControlMode; +// +typedef struct RequestData +{ + float desired_speed; // 期望速度 + float desired_curvature; // 期望曲率 + float left_motor_speed; // 当前左电机速度 + float right_motor_speed; // 当前右电机速度 + float speed; // 当前车速 + float curvature; // 当前曲率 + float yaw_rate; // 当前角速度 + float desired_yaw_rate; // 期望角速度 + float acceleration; // 当前加速度 + float deceleration; // 当前减速度 + float max_speed; // 最大速度 + float desired_acceleration; // 期望加速度 + float desired_deceleration; // 期望减速度 + float out_left_motor_speed; // 输出左电机速度 + float out_right_motor_speed; // 输出右电机速度 +} RequestData; + + + + +// 声明外部变量 +extern DiffData diff_data; + + +void requestAppInit(void); + + +#ifdef __cplusplus +} +#endif + +#endif // APP_DIFFERENTIAL_DRIVE_H + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/app_temp.c b/app/app_temp.c new file mode 100644 index 0000000..b901351 --- /dev/null +++ b/app/app_temp.c @@ -0,0 +1,285 @@ +#include "app_config.h" +#include "interface.h" +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" +#include "app_param_manage.h" + +#include "app_temp.h" + + +// 声明 temp_data 变量 +TempSystem temp_data; + + +static void handleTemperatureAlarm(int16_t current_temp, float alarm_temp, + float critical_temp, float threshold_temp, + TempState *state) +{ + switch (*state) + { + case TEMP_NORMAL: + // 从正常状态进入警告状态的条件 + if (current_temp > (alarm_temp + threshold_temp)) + { + *state = TEMP_WARNING; + printf("Temperature Warning: Activated! Current temp: %d°C\n", current_temp); + } + // 从正常状态直接进入严重状态的条件 + else if (current_temp > (critical_temp + threshold_temp)) + { + *state = TEMP_CRITICAL; + printf("Temperature Critical: Activated! Current temp: %d°C\n", current_temp); + } + else + { + *state = TEMP_NORMAL; + } + break; + + case TEMP_WARNING: + // 从警告状态返回正常状态的条件 + if (current_temp < (alarm_temp - threshold_temp)) + { + *state = TEMP_NORMAL; + printf("Temperature Warning: Deactivated! Current temp: %d°C\n", current_temp); + } + // 从警告状态进入严重状态的条件 + else if (current_temp > (critical_temp + threshold_temp)) + { + *state = TEMP_CRITICAL; + printf("Temperature Critical: Activated! Current temp: %d°C\n", current_temp); + } + else + { + *state = TEMP_WARNING; + } + break; + + case TEMP_CRITICAL: + // 从严重状态返回警告状态的条件 + if (current_temp < (critical_temp - threshold_temp)) + { + *state = TEMP_WARNING; + printf("Temperature Critical: Deactivated! Current temp: %d°C\n", current_temp); + } + // 从严重状态直接返回正常状态的条件 + else if (current_temp < (alarm_temp - threshold_temp)) + { + *state = TEMP_NORMAL; + printf("Temperature Warning: Deactivated! Current temp: %d°C\n", current_temp); + } + else + { + *state = TEMP_CRITICAL; + } + break; + + default: + *state = TEMP_NORMAL; + break; + } +} + + +// 温度输出处理函数 +static void tempOutput(void *signal_id) +{ + (void)signal_id; + + // 电机1风扇 左前 + switch (temp_data.state[0]) + { + case TEMP_NORMAL: + un_inf_can_kgf_output1.bit_data.KGF01 = setFanOff();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_01 = 0; + break; + case TEMP_WARNING: + un_inf_can_kgf_output1.bit_data.KGF01 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_01 = 5; + break; + case TEMP_CRITICAL: + un_inf_can_kgf_output1.bit_data.KGF01 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_01 = 0; + break; + } + + // 电机2风扇 右前 + switch (temp_data.state[1]) + { + case TEMP_NORMAL: + un_inf_can_kgf_output1.bit_data.KGF02 = setFanOff();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_02 = 0; + break; + case TEMP_WARNING: + un_inf_can_kgf_output1.bit_data.KGF02 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_02 = 5; + break; + case TEMP_CRITICAL: + un_inf_can_kgf_output1.bit_data.KGF02 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_02 = 0; + break; + } + + + // 电机3风扇 左后 + switch (temp_data.state[2]) + { + case TEMP_NORMAL: + un_inf_can_kgf_output1.bit_data.KGF07 = setFanOff();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_07 = 0; + break; + case TEMP_WARNING: + un_inf_can_kgf_output1.bit_data.KGF07 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_07 = 5; + break; + case TEMP_CRITICAL: + un_inf_can_kgf_output1.bit_data.KGF07 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_07 = 0; + break; + } + + // 电机4风扇 右后 + switch (temp_data.state[3]) + { + case TEMP_NORMAL: + un_inf_can_kgf_output1.bit_data.KGF08 = setFanOff();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_08 = 0; + break; + case TEMP_WARNING: + un_inf_can_kgf_output1.bit_data.KGF08 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_08 = 5; + break; + case TEMP_CRITICAL: + un_inf_can_kgf_output1.bit_data.KGF08 = setFanOn();//电机控制器风扇 + un_inf_can_kgf_output1.bit_data.pwm_08 = 0; + break; + } + +// // 电机3风扇 +// switch (temp_data.state[2]) +// { +// case TEMP_NORMAL: +// un_inf_can_kgf_output1.bit_data.KGF01 = setFanOff();//电机控制器风扇 +// un_inf_can_kgf_output1.bit_data.pwm_01 = 0; +// break; +// case TEMP_WARNING: +// un_inf_can_kgf_output1.bit_data.KGF01 = setFanOn();//电机控制器风扇 +// un_inf_can_kgf_output1.bit_data.pwm_01 = 5; +// break; +// case TEMP_CRITICAL: +// un_inf_can_kgf_output1.bit_data.KGF01 = setFanOn();//电机控制器风扇 +// un_inf_can_kgf_output1.bit_data.pwm_01 = 0; +// break; +// } + + publishMessage(&un_inf_can_kgf_output1, 1); +} + +// 温度状态处理函数 +static void tempProcess(void *signal_id) +{ + (void)signal_id; + int16_t max_temp[4] = {0,0}; + + max_temp[0] = temp_data.current_temp[0]; + max_temp[1] = temp_data.current_temp[1]; + +// printf("motor1 temp: %d, motor2 temp: %d\n", max_temp[0], max_temp[1]); + handleTemperatureAlarm(max_temp[0], MOTOR_WARNING_TEMP, MOTOR_CRITICAL_TEMP, MOTOR_THRESHOLD_TEMP, &temp_data.state[0]); + + handleTemperatureAlarm(max_temp[1], MOTOR_WARNING_TEMP, MOTOR_CRITICAL_TEMP, MOTOR_THRESHOLD_TEMP, &temp_data.state[1]); + + handleTemperatureAlarm(max_temp[2], MOTOR_WARNING_TEMP, MOTOR_CRITICAL_TEMP, MOTOR_THRESHOLD_TEMP, &temp_data.state[2]); + + handleTemperatureAlarm(max_temp[3], MOTOR_WARNING_TEMP, MOTOR_CRITICAL_TEMP, MOTOR_THRESHOLD_TEMP, &temp_data.state[3]); + + + +// if (max_temp[0] >= 60) // 假设60度为危险温度 +// { +// temp_data.state[0] = TEMP_CRITICAL; +// } +// else if (max_temp[0] >= 40) // 假设40度为警告温度 +// { +// temp_data.state[0] = TEMP_WARNING; +// } +// else +// { +// temp_data.state[0] = TEMP_NORMAL; +// } +// +// +// max_temp[1] = temp_data.current_temp[1]; +// if (max_temp[1] >= 60) // 假设60度为危险温度 +// { +// temp_data.state[1] = TEMP_CRITICAL; +// } +// else if (max_temp[1] >= 40) // 假设40度为警告温度 +// { +// temp_data.state[1] = TEMP_WARNING; +// } +// else +// { +// temp_data.state[1] = TEMP_NORMAL; +// } +// +//// printf("motor1 temp: %d, motor2 temp: %d\n", max_temp[0], max_temp[1]); +//// printf("motor1 state: %d, motor2 state: %d\n", temp_data.state[0], temp_data.state[1]); + + tempOutput(NULL); + + timerStart(&temp_data.timer, 1000, 1); //1s +} + +// 处理输入信号的函数 +static void tempInput(void *signal_id) +{ + (void)signal_id; + // 填充数据 + if (signal_id == &un_motor_temp1) + { + temp_data.current_temp[0] = ( (int16_t)(un_motor_temp1.bit_data.controller_temp) - 40);//40偏移量 + } + else if(signal_id == &un_motor_temp2) + { + temp_data.current_temp[1] = ( (int16_t)(un_motor_temp2.bit_data.controller_temp) - 40); + } + else if(signal_id == &un_motor_temp3) + { + temp_data.current_temp[2] = ( (int16_t)(un_motor_temp3.bit_data.controller_temp) - 40); + } + else if(signal_id == &un_motor_temp4) + { + temp_data.current_temp[3] = ( (int16_t)(un_motor_temp4.bit_data.controller_temp) - 40); + } + else{} +} + + +// APP模块的初始化 +void tempAppInit(void) +{ + // 初始化 + timerInit(&temp_data.timer); + + memset(&temp_data, 0, sizeof(TempSystem)); + temp_data.state[0] = TEMP_NORMAL; + temp_data.state[1] = TEMP_NORMAL; + temp_data.mode = TEMP_MODE_AUTO; + temp_data.target_temp = 25; // 默认目标温度25度 + + // 订阅输入信号,处理温度逻辑 + subscribe(&un_motor_temp1, tempInput); + subscribe(&un_motor_temp2, tempInput); + subscribe(&un_motor_temp3, tempInput); + subscribe(&un_motor_temp4, tempInput); + + // 启动定时器,每秒检查一次温度 + subscribe(&temp_data.timer, tempProcess); + timerStart(&temp_data.timer, 1000, 1); //1s + + printf("app_temp: initial OK \n"); + + +} diff --git a/app/app_temp.h b/app/app_temp.h new file mode 100644 index 0000000..0450619 --- /dev/null +++ b/app/app_temp.h @@ -0,0 +1,58 @@ +#ifndef APP_TEMP_H +#define APP_TEMP_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MOTOR_WARNING_TEMP 40 +#define MOTOR_CRITICAL_TEMP 60 +#define MOTOR_THRESHOLD_TEMP 5//回滞值 + + + + + +// 定义温度状态枚举 +typedef enum +{ + TEMP_NORMAL, + TEMP_WARNING, + TEMP_CRITICAL +} TempState; + +// 定义温度控制模式枚举 +typedef enum +{ + TEMP_MODE_AUTO, + TEMP_MODE_MANUAL +} TempMode; + +typedef struct +{ + TempState state[8]; + TempMode mode; + int16_t current_temp[8]; // 当前温度,8个不同的温度 + int16_t target_temp; // 目标温度 + uint8_t fan_speed[8]; // 风扇速度 8个通道 + Timer timer; // 定时器 +} TempSystem; + +// 在头文件中声明外部变量 +extern TempSystem temp_data; + +// 使用内联函数 +static inline uint8_t setFanOn(void) { return 1; } +static inline uint8_t setFanOff(void) { return 0; } + +void tempAppInit(void); +void setTempMode(TempMode mode); +void setTargetTemp(int16_t temp); +void setFanSpeed(uint8_t speed); + +#ifdef __cplusplus +} +#endif + +#endif // APP_TEMP_H \ No newline at end of file diff --git a/app/app_test.c b/app/app_test.c new file mode 100644 index 0000000..7dd16e2 --- /dev/null +++ b/app/app_test.c @@ -0,0 +1,62 @@ +#include "app_config.h" +#include "app_dependence.h" +#include "interface.h" + +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" + +#include "sdrv_vic.h" +#include "app_test.h" +#include "app_differential_drive.h" + + +// 定时器结构体 +Timer test_timer; + +// 定时器信号处理函数 +void testTimerProcess(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 +// static uint32_t start_time = 0; +// uint32_t test_irq[6] = {0}; + // 再次启动定时器,实现周期定时 + + timerStart(&test_timer, 5000,1); + + + + + +// printf("speed = %f ",diff_data.desired_speed); +// printf("curvature = %f ",diff_data.desired_curvature); +// printf("mode = %d\n",diff_data.mode); + + +// +// sdrv_vic_lld_read_all(test_irq);//打印所有中断使能位 +// printf("irq state = %#X ",test_irq[0]); +// printf("irq state = %#X ",test_irq[1]); +// printf("irq state = %#X ",test_irq[2]); +// printf("irq state = %#X ",test_irq[3]); +// printf("irq state = %#X ",test_irq[4]); +// printf("irq state = %#X\n",test_irq[5]); + +// printf("testAPP: %d us \n",getCurrentTime() - start_time); +// start_time = getCurrentTime(); + +} + + +// APP模块的初始化 +void testAppInit(void) +{ + // 初始化定时器 + timerInit(&test_timer); + // 订阅定时器信号,用于停止电机 + subscribe(&test_timer, testTimerProcess); + + printf("testAPP: initial OK %d\n",getCurrentTime()); + + timerStart(&test_timer, 5000,1); +} diff --git a/app/app_test.h b/app/app_test.h new file mode 100644 index 0000000..c20f1be --- /dev/null +++ b/app/app_test.h @@ -0,0 +1,18 @@ +#ifndef TEST_H +#define TEST_H + +#ifdef __cplusplus +extern "C" { +#endif + + + +extern void testAppInit(void); + + + +#ifdef __cplusplus +} +#endif + +#endif // TEST_H diff --git a/app/app_ultrasonic.c b/app/app_ultrasonic.c new file mode 100644 index 0000000..bbc96a6 --- /dev/null +++ b/app/app_ultrasonic.c @@ -0,0 +1,83 @@ +#include "app_config.h" +#include "app_dependence.h" +#include "interface.h" + +#include "app_frm_monitor.h" +#include "app_frm_signal.h" +#include "app_frm_timer.h" + +#include "sdrv_vic.h" +#include "app_ultrasonic.h" + + +// 定时器结构体 +Timer ultrasonic_timer; +Timer ultrasonic_timer1; + +uint16_t fornt_distance = 0;//mm + +// 定时器信号处理函数 +void ultrasonicTimer1Process(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 + + printf("fornt distance = %d\n",fornt_distance); + + + timerStart(&ultrasonic_timer1, 1000,1); +} + + + + + +// 定时器信号处理函数 +void ultrasonicTimerProcess(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 + + un_ultrasonic_output1.bit_data.node = ULTRASONIC_FRONT_NODE; + un_ultrasonic_output1.bit_data.function_code = ULTRASONIC_READ; + un_ultrasonic_output1.bit_data.register_address = REALTIME_DISTANCE_REG; + un_ultrasonic_output1.bit_data.data = 0x100; + publishMessage(&un_ultrasonic_output1, 1); + + timerStart(&ultrasonic_timer, 200,1); +} + +void ultrasonicInput(void *signal_id) +{ + if(signal_id == &un_ultrasonic_input1) + { + fornt_distance = SWAP_ENDIAN_16(un_ultrasonic_input1.bit_data.data);//高低字节交换 + } +} + + + + +// APP模块的初始化 +void ultrasonicAppInit(void) +{ + // 初始化定时器 + timerInit(&ultrasonic_timer); + timerInit(&ultrasonic_timer1); + // 订阅定时器信号 + subscribe(&ultrasonic_timer, ultrasonicTimerProcess); + subscribe(&ultrasonic_timer1, ultrasonicTimer1Process); + + subscribe(&un_ultrasonic_input1, ultrasonicInput); + printf("ultrasonicAPP: initial OK %d\n",getCurrentTime()); + timerStart(&ultrasonic_timer, 200,1); + timerStart(&ultrasonic_timer1, 1000,1); +} + + + + + + + + + + diff --git a/app/app_ultrasonic.h b/app/app_ultrasonic.h new file mode 100644 index 0000000..00691f7 --- /dev/null +++ b/app/app_ultrasonic.h @@ -0,0 +1,75 @@ +#ifndef ULTRASONIC_H +#define ULTRASONIC_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ULTRASONIC_FRONT_NODE 0x1 +#define ULTRASONIC_BACK_NODE 0x2 + +#define ULTRASONIC_ID_1 0x520 + ULTRASONIC_FRONT_NODE +#define ULTRASONIC_ID_2 0x520 + ULTRASONIC_BACK_NODE + +#define ULTRASONIC_READ 0x03 +#define ULTRASONIC_WRITE 0x06 + + + + +#define SOFTWARE_VERSION_REG 0x0000 // ģ汾(ʮֵ), : uint16_t + + +#define PROCESSED_DISTANCE_REG 0x0100 /* + * ľֵ(mm), : uint16_t + * ָ࣬㷨 + * Ӧʱ䣺190-750ms(̶) + */ + +#define REALTIME_DISTANCE_REG 0x0101 /* + * ʵʱβֵ(mm), : uint16_t + * ָ󴥷β + * Ӧʱ䣺15-140ms(̶) + */ + +#define TEMPERATURE_REG 0x0102 /* + * ¶ȴֵ, : int16_t + * λ0.1 (ԭʼֵ/10), ֱʣ0.5 + * Ӧʱ䣺15-140ms(̶) + */ + +#define ECHO_TIME_REG 0x010A /* + * زʱԭʼֵ(s), : uint16_t + * 뻻㣺ֵ/5.75 = ׾ + * Ӧʱ䣺15-140ms(̶) + */ + + + +#define SWAP_ENDIAN_16(x) ((((x) & 0xFF) << 8) | (((x) >> 8) & 0xFF)) +#define SWAP_ENDIAN_32(x) (((x) << 24) | (((x) & 0xFF00) << 8) | (((x) >> 8) & 0xFF00) | ((x) >> 24)) + + + + + + + + + + + + void ultrasonicAppInit(void); + + + + + + + +#ifdef __cplusplus +} +#endif + +#endif // ULTRASONIC_H diff --git a/app_brake.c b/app_brake.c new file mode 100644 index 0000000..b33c48a --- /dev/null +++ b/app_brake.c @@ -0,0 +1,127 @@ +#include "app_config.h" + +//定义并初始化 +BrakeSystem brake_system = { + .brake_timer = {0, 0, 0, 0, 0}, // 初始化 Timer 结构体 + .brake_command = 0, + .brake_motor_state = 0, + .brake_command_in_progress = 0, + .emergency_stop_switch = 0, + .remote_emergency_stop = 0, + .remote_fault = 0, + .can_bus_fault = 0, + .ethernet_fault = 0, + .mode_signal = 0 +}; + + +// 处理所有输入信号的函数 +static void processInputSignals(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 + + // 如果当前有刹车命令在执行,忽略新的输入信号 + if (brake_system.brake_command_in_progress) + { + return; + } + + if (brake_system.emergency_stop_switch || brake_system.remote_emergency_stop || + (brake_system.mode_signal == 0 && brake_system.remote_fault) || // 手动模式下的遥控器故障 + (brake_system.mode_signal == 1 && (brake_system.can_bus_fault || brake_system.ethernet_fault))) // 自动模式下的CAN总线或以太网通信故障 + { + brake_system.brake_command = 1; // 发送刹车指令 + publishMessage(&brake_system.brake_command, 1); + brake_system.brake_command_in_progress = 1; // 标记刹车命令正在执行 + } + else + { + brake_system.brake_command = 2; // 发送释放刹车指令 + publishMessage(&brake_system.brake_command, 1); + brake_system.brake_command_in_progress = 1; // 标记释放命令正在执行 + } +} + +// 刹车信号处理函数 +static void brakeProcess(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 + int signal = *(int *)signal_id; + + if (signal == 1) // 刹车 + { + brake_system.brake_motor_state = 1; + publishMessage(&brake_system.brake_motor_state, 1); // 状态改变时发送刹车电机状态信号 + timerInit(&brake_system.brake_timer, 1500); // 控制刹车电机前进,保持1.5秒 + } + else if (signal == 2) // 释放刹车 + { + brake_system.brake_motor_state = 2; + publishMessage(&brake_system.brake_motor_state, 1); // 状态改变时发送刹车电机状态信号 + timerInit(&brake_system.brake_timer, 800); // 控制刹车电机后退,保持0.8秒 + } + + timerStart(&brake_system.brake_timer); +} + +// 定时器信号处理函数 +static void brakeTimerProcess(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 + + brake_system.brake_motor_state = 0; + brake_system.brake_command_in_progress = 0; // 刹车命令执行完成,重置状态 + publishMessage(&brake_system.brake_motor_state, 1); // 状态改变时发送刹车电机状态信号 +} + +// 输出处理函数 +static void outputProcess(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 + //根据电机状态,填充发送数据结构,发送信号 + switch (brake_system.brake_motor_state) { + case 1: // 电机前进状态 + UnHBridgeOutput.brake_motor1 = 0; + UnHBridgeOutput.brake_motor2 = 1; + UnHBridgeOutput.sleep_01 = 0; + break; + + case 2: // 电机后退状态 + UnHBridgeOutput.brake_motor1 = 1; + UnHBridgeOutput.brake_motor2 = 0; + UnHBridgeOutput.sleep_01 = 0; + break; + default: + UnHBridgeOutput.brake_motor1 = 0; + UnHBridgeOutput.brake_motor2 = 0; + UnHBridgeOutput.sleep_01 = 0; + break; + } + publishMessage(&UnHBridgeOutput, 1); +} + +// APP模块的初始化 +void brakeAppInit(void) +{ + // 初始化定时器,使用 brake_timer 的地址作为信号ID + timerInit(&brake_system.brake_timer, 0); + + // 订阅刹车命令 + subscribe(&brake_system.brake_command, brakeProcess); + + // 订阅定时器信号,用于停止电机 + subscribe(&brake_system.brake_timer, brakeTimerProcess); + + // 订阅电机状态 + subscribe(&brake_system.brake_motor_state, outputProcess); + + // 订阅输入信号,处理刹车逻辑 + subscribe(&UnSwSample, processInputSignals); + subscribe(&UnRemoteControlInput, processInputSignals); + subscribe(&brake_system.remote_fault, processInputSignals); + subscribe(&brake_system.can_bus_fault, processInputSignals); + subscribe(&brake_system.ethernet_fault, processInputSignals); + subscribe(&brake_system.mode_signal, processInputSignals); + + +} diff --git a/app_brake.h b/app_brake.h new file mode 100644 index 0000000..e359c4e --- /dev/null +++ b/app_brake.h @@ -0,0 +1,34 @@ +#ifndef APP_BRAKE_H +#define APP_BRAKE_H + +#ifdef __cplusplus +extern "C" { +#endif + + +#include "app_config.h" + + +typedef struct { + Timer brake_timer; // 定时器结构体 + int brake_command; // 刹车命令变量:1表示刹车,2表示释放 + int brake_motor_state; // 刹车电机状态变量:0停止,1前进,2后退 + int brake_command_in_progress; // 刹车命令执行状态:0表示空闲,1表示正在执行 + //输入 + int emergency_stop_switch; // 急停开关 + int remote_emergency_stop; // 遥控器急停开关 + int remote_fault; // 遥控器故障 + int can_bus_fault; // CAN总线故障 + int ethernet_fault; // 以太网通信故障 + int mode_signal; // 模式信号:0表示手动模式,1表示自动模式 +} BrakeSystem; + +// 在头文件中声明外部变量 +extern BrakeSystem brake_system; + + +#ifdef __cplusplus +} +#endif + +#endif // APP_BRAKE_H diff --git a/crc16.h b/crc16.h new file mode 100644 index 0000000..47d37c5 --- /dev/null +++ b/crc16.h @@ -0,0 +1,51 @@ +#ifndef _CRC16_H_ +#define _CRC16_H_ + +static const unsigned short crc16tab[256]= { + 0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7, + 0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef, + 0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6, + 0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de, + 0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485, + 0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d, + 0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4, + 0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc, + 0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823, + 0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b, + 0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12, + 0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a, + 0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41, + 0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49, + 0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70, + 0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78, + 0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f, + 0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067, + 0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e, + 0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256, + 0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d, + 0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405, + 0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c, + 0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634, + 0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab, + 0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3, + 0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a, + 0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92, + 0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9, + 0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1, + 0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8, + 0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0 +}; + +__inline unsigned short crc16_ccitt(const unsigned char *buf, unsigned int len) +{ + register unsigned int counter; + register unsigned short crc = 0; + for( counter = 0; counter < len; counter++) + crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *(unsigned char *)buf++)&0x00FF]; + return crc; +} +extern __inline unsigned short crc16_ccitt(const unsigned char *buf, unsigned int len); + +#endif /* _CRC16_H_ */ + + diff --git a/interface.c b/interface.c new file mode 100644 index 0000000..f27e8b5 --- /dev/null +++ b/interface.c @@ -0,0 +1,70 @@ + + +#include "interface_config.h" + +UnMotorInput un_motor_input1 ;//电机控制器1 左前侧 +UnMotorInput un_motor_input2 ;//电机控制器2 右前侧 +UnMotorInput un_motor_input3 ;//电机控制器1 左后侧 +UnMotorInput un_motor_input4 ;//电机控制器2 右后侧 + + +UnMotorTempInput un_motor_temp1 ;//电机控制器1 左前侧 +UnMotorTempInput un_motor_temp2 ;//电机控制器2 右前侧 +UnMotorTempInput un_motor_temp3 ;//电机控制器3 左后侧 +UnMotorTempInput un_motor_temp4 ;//电机控制器4 右后侧 + + + +UnBmsInput un_bms_input ;//BMS接收数据 +UnTempModuleInput un_temp_module_input ;//温度采集模块 + +UnMotorOutput un_motor_output1 ;//电机输出 +UnMotorOutput un_motor_output2 ;//电机输出 +UnMotorOutput un_motor_output3 ;//电机输出 +UnMotorOutput un_motor_output4 ;//电机输出 + +UnInfCanKGFOutput un_inf_can_kgf_output1 ;//kgf输出 +UnInfCanKGFOutput un_inf_can_kgf_output2 ; +UnHBridgeOutput un_h_bridge_output ;//H桥输出 +UnWheelSpeedOutput un_wheel_wpeed_output ;//轮速输出 + +UnRemoteControlInput un_remote_control_input ;//遥控器输入 + +UnHBridgeOutput un_h_bridge_output ;//H桥输出 + +UnGatherOutput un_gather_output ;//采集模块输出 + +UnUltrasonicInput un_ultrasonic_input1 ;//超声波传感器输入1 + +UnUltrasonicOutput un_ultrasonic_output1 ;//超声波传感器输出 + + +//IO口 +UnSwSample un_sw_sample ;//采集 + + +//以太网 +UnAutoComputerInput un_auto_computer_input ;//自主计算机自动数据 +UnManualComputerInput un_manual_computer_input ;//自主计算机手动数据 +UnRequestFrame un_request_frame ;//请求帧 + +UnComputerOutput un_computer_output ;//输出给自主计算机 + +//输出给上位机 +UnVehicleInfoOutput un_vehicle_Info_output ;// 车辆信息,输出给上位机 +UnMotorStatusOutput un_motor_status_output ;// 电机状态信息,输出给上位机 +UnPIDOutput un_pid_output ;// PID参数输出,输出给上位机 +UnAnalogSignalOutput un_analog_signal_output ;// 模拟信号输出,输出给上位机 +UnRemoteControlOutput un_remote_control_output ;// 遥控器数据输出,给上位机 +UnManualControlOutput un_manual_control_output ;// 手动控制数据,返回给请求者 +UnAutoControlOutput un_auto_control_output ;// 自动控制数据输出,返回给请求者 + + + + +UnCanDebugOutput un_can_debug_output;//调试输出 + + + + + diff --git a/interface.h b/interface.h new file mode 100644 index 0000000..15efdb0 --- /dev/null +++ b/interface.h @@ -0,0 +1,984 @@ +#ifndef _INTERFACE_H_ +#define _INTERFACE_H_ + +#include "stdint.h" + +#include "app/app_config.h" // 假设包含基础配置和宏定义 +#include "irq.h" +#include "interface_config.h" +#include + + + +#pragma pack(1)//数据结构一个字节对齐 + + +#define REQUEST_READ_ID un_request_frame.bit_data.request_id//读取ID +#define REQUEST_HEADER_ID un_request_frame.bit_data.frame_header//帧头 + + +#define FAULT 0 +#define NORMAL 1 + + +//-----CAN---------------------------------------------------------------- +// 接收电机控制器输入 +typedef struct _StrMotorInput +{ + //-----接收数据0x101或者0x201---------------------------------------------- + unsigned int speed : 16; // 转速 偏移量 -30000 + unsigned int bus_voltage : 16; // 母线电压 系数 0.1 偏移量 -3000 + unsigned int torque : 16; // 扭矩 系数 0.01 偏移量 -300 实际物理量=数据×系数+偏移量 + unsigned int fault_code : 8; // 故障码 + unsigned int heartbeat : 8; // 心跳 + +} StrMotorInput; +typedef union _UnMotorInput +{ + StrMotorInput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrMotorInput)]; // 通过结构体类型确定大小 +} UnMotorInput; + + + +// 接收电机控制器输入 +typedef struct _StrCanDebugOutput +{ + uint8_t speed; + uint8_t desired_speed; + uint8_t curvature; + uint8_t desired_curvature; + uint16_t set_left_out; + uint16_t set_right_out; +} StrCanDebugOutput; + +typedef union _UnCanDebugOutput +{ + StrCanDebugOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrCanDebugOutput)]; // 通过结构体类型确定大小 +} UnCanDebugOutput; + + + + + + + + + + +typedef struct _StrMotorTempInput +{ + //-----接收数据0x103或者0x104---------------------------------------------- + unsigned int controller_temp : 8; // 控制器温度 偏移量 -40 + unsigned int motor_temp : 8; // 电机温度 偏移量 -40 + unsigned int motor_max_torque: 16; // 电机最大扭矩 系数 0.01 偏移量 -300 实际物理量=数据×系数+偏移量 + unsigned int reserved_1 : 8; // 保留1 + unsigned int reserved_2 : 8; // 保留2 + unsigned int reserved_3 : 8; // 保留3 + unsigned int heartbeat2 : 8; // 心跳 + +} StrMotorTempInput; + +typedef union _UnMotorTempInput +{ + StrMotorTempInput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrMotorInput)]; // 通过结构体类型确定大小 +} UnMotorTempInput; + + + + + + + + + + + +// 接收BMS输入 +typedef struct _StrBmsInput +{ +//----接收0x100---------------------------------- + // 多字节数据,高位在前,低位在后 + unsigned int bus_voltage : 16; // 母线电压 单位为10mV + unsigned int bus_current : 16; // 母线电流 单位为10mA + unsigned int remainder_capacity : 16; // 剩余容量 单位为10mAh 充电为正,放电为负 + unsigned int crc1 : 16; //crc +//----接收0x101---------------------------------- + // 多字节数据,高位在前,低位在后 + unsigned int full_capacity : 16; // 充满容量 单位为10mAh + unsigned int Discharge_times : 16; // 放电循环次数 单位为1次 + unsigned int soc : 16; // soc 1% + unsigned int crc2 : 16; //crc +} StrBmsInput; + +typedef union _UnBmsInput +{ + StrBmsInput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrBmsInput)]; // 通过结构体类型确定大小 +} UnBmsInput; + + +// 接收温度模块输入 +typedef struct _StrTempModuleInput +{ + //-----接收数据0x301,302---------------------------------------------- + // 多字节数据,高位在前,低位在后 + unsigned int channel_1 : 16; // 通道1 温度传感器 系数为0.1 有符号 正数表示正温度,负数表示负温度 + unsigned int channel_2 : 16; // 通道2 + unsigned int channel_3 : 16; // 通道3 + unsigned int channel_4 : 16; // 通道4 + unsigned int channel_5 : 16; // 通道5 + unsigned int channel_6 : 16; // 通道6 + unsigned int channel_7 : 16; // 通道7 + unsigned int channel_8 : 16; // 通道8 +} StrTempModuleInput; + +typedef union _UnTempModuleInput +{ + StrTempModuleInput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrTempModuleInput)]; // 通过结构体类型确定大小 +} UnTempModuleInput; + + + + +//-----以太网------------------------------------------------------------- +// 接收自主计算机自动输入 +typedef struct _StrAutoComputerInput +{ + // 多字节数据,高位在前,低位在后 + unsigned int frame_header : 16; // 帧头 固定值0xFFCC + unsigned int frame_type : 16; // 帧类型 固定值0x0001 + unsigned int frame_length : 8; // 帧长 固定值0x19 + unsigned int heartbeat : 8; // 心跳 按帧累加 + unsigned int set_speed : 16; // 设定速度 系数0.01,正为前进,负为后退 单位m/s + unsigned int set_curvature : 16; // 设定曲率 系数0.0001,正为左转,负为右转 + unsigned int latitude : 32; // 纬度 系数10^-7,431234567表示43.1234567度 + unsigned int longitude : 32; // 经度 系数10^-7,431234567表示43.1234567度 + unsigned int altitude : 32; // 高度 单位mm + unsigned int heading : 16; // 航向 车辆航向,35999表示359.99度 + unsigned int crc : 8; // CRC 按字节累加之和,溢出取低8位 +} StrAutoComputerInput; + +typedef union _UnAutoComputerInput +{ + StrAutoComputerInput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrAutoComputerInput)]; // 通过结构体类型确定大小 +} UnAutoComputerInput; + + + + + +// 接收自主计算机手动输入 + +typedef struct _StrManualComputerInput +{ + // 手动控制数据 高位在前,低位在后 + unsigned int frame_header : 16; // 帧头 固定值0xFFBB + unsigned int frame_type : 16; // 帧类型 固定值0x0011 + unsigned int frame_length : 8; // 帧长 固定值0x0B + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int set_speed : 16; // 期望速度 系数0.01,正为前进,负为后退 单位m/s + unsigned int set_curvature : 16; // 期望曲率 系数0.0001,正为左转,负为右转 + unsigned int reserved : 8; // 保留 同时按下LB+Y时发0xFF,松开发0,同时按下LT+Y时发0x10,松开发0 + unsigned int crc : 8; // CRC 按字节累加之和,溢出取低8位 +} StrManualComputerInput; + +typedef union _UnManualComputerInput +{ + StrManualComputerInput bit_data; // 使用定义的结构体变量名 + unsigned int arr[sizeof(StrManualComputerInput) / sizeof(unsigned int)]; // 通过结构体类型确定大小 +} UnManualComputerInput; + + + + + + + + + +// 接收请求帧 +typedef struct _StrRequestFrame +{ + //-------------------------------------------------- + unsigned int frame_header : 16; // 帧头 固定值0x0080 + unsigned int frame_type : 16; // 帧类型 固定值0x0029 + unsigned int frame_length : 16; // 帧长 固定值10 + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int request_id : 16; // 请求帧ID 请求ID 0-FFFF,FFFF表示全部帧 + unsigned int crc : 8; // CRC 按字节累加之和 取低8位 +} StrRequestFrame; + +typedef union _UnRequestFrame +{ + StrRequestFrame bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrRequestFrame)]; // 通过结构体类型确定大小 +} UnRequestFrame; + + +// 接收遥控器输入 +typedef struct _StrRemoteControlInput +{ + //-----接收数据0x12000013---------------------------------------------- + unsigned int speed : 16; // 速度 + unsigned int curvature : 16; // 曲率 + unsigned int reserve1 : 16; // 遥控轴 + + unsigned int switch_a : 1; // SwA + unsigned int switch_b : 2; // SwB 急停开关 1释放 0/2是急停 + unsigned int switch_c : 2; // SwC 模式开关 1自动 0/2是手动 + unsigned int switch_d : 1; // SwD 上电开关 先短按再长按 + unsigned int reserve2 : 1; // 保留 + unsigned int reserve3 : 1; // 保留 + + unsigned int enable : 8; // 使能 +} StrRemoteControlInput; + +typedef union _UnRemoteControlInput +{ + StrRemoteControlInput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrRemoteControlInput)]; // 通过结构体类型确定大小 +} UnRemoteControlInput; + + +//-----IO口--------------------------------------------------------------- +// 从IO口输入 + +//20250116 增加温度采集字节 +typedef struct _StrSwSample +{ + unsigned int emergency_stop_switch : 1; // 通道1,急停开关 + unsigned int High_voltage_switch : 1; // 通道2,高压开关 + unsigned int flg_wake_ecu : 1; // 通道3 + unsigned int CH04 : 1; // 通道4 + unsigned int CH05 : 1; // 通道5 + unsigned int CH06 : 1; // 通道6 + unsigned int CH07 : 1; // 通道7 + unsigned int CH08 : 1; // 通道8 + unsigned int CH09 : 1; // 通道9 + unsigned int CH10 : 1; // 通道10 + unsigned int CH11 : 1; // 通道11 + unsigned int CH12 : 1; // 通道12 + unsigned int CH13 : 1; // 通道13 + unsigned int CH14 : 1; // 通道14 + unsigned int CH15 : 1; // 通道15 + unsigned int CH16 : 1; // 通道16 + unsigned int CH17 : 1; // 通道17 + unsigned int CH18 : 1; // 通道18 + unsigned int CH19 : 1; // 通道19 + unsigned int CH20 : 1; // 通道20 + unsigned int CH21 : 1; // 通道21 + unsigned int CH22 : 1; // 通道22 + unsigned int CH23 : 1; // 通道23 + unsigned int CH24 : 1; // 通道24 + unsigned int CH25 : 1; // 通道25 + unsigned int CH26 : 1; // 通道26 + unsigned int CH27 : 1; // 通道27 + unsigned int CH28 : 1; // 通道28 + unsigned int CH29 : 1; // 通道29 + unsigned int CH30 : 1; // 通道30 + unsigned int CH31 : 1; // 通道31 + unsigned int CH32 : 1; // 通道32 + +// unsigned int CH33 : 1; // 通道33 +// unsigned int CH34 : 1; // 通道34 +// unsigned int CH35 : 1; // 通道35 +// unsigned int CH36 : 1; // 通道36 +// unsigned int CH37 : 1; // 通道37 +// unsigned int CH38 : 1; // 通道38 +// unsigned int CH39 : 1; // 通道39 +// unsigned int CH40 : 1; // 通道40 +// unsigned int CH41 : 1; // 通道41 +// unsigned int CH42 : 1; // 通道42 +// unsigned int CH43 : 1; // 通道43 +// unsigned int CH44 : 1; // 通道44 +// unsigned int reserve : 4; + unsigned int temperature[2]; // 温度 + +} StrSwSample; + +typedef union _UnSwSample +{ + StrSwSample bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrSwSample)]; // 通过结构体类型确定大小 +} UnSwSample; + + +//-----输出数据结构--------------------------------------------------------------- +//-----CAN---------------------------------------------------------------- +// 输出到电机控制器 +typedef struct _StrMotorOutput +{ +//-----发送数据0x201或者0x202---------------------------------------------- + unsigned int mode : 8; // 模式 0x1恒速模式,0x2恒扭模式,其他无效 + unsigned int gear : 8; // 档位 0x0空挡模式,0x1前进挡,0x2倒退档,其他无效 + unsigned int set_torque : 16; // 给定扭矩 系数 0.01 偏移量 -300 实际物理量=数据×系数+偏移量 + unsigned int set_rotation_speed : 16; // 给定转速 偏移量 -30000 + unsigned int fault_code : 8; // 故障码 + unsigned int heartbeat : 8; // 心跳 +//-----发送数据0x401或者0x402---------------------------------------------- + unsigned int feed_power : 16; // 馈电功率 单位为 W 最大为10KW + unsigned int discharge_power : 16; // 放电功率 单位为 W 最大为15kW + unsigned int reserve1 : 16; // 保留 + unsigned int reserve2 : 16; // 保留 +} StrMotorOutput; + +typedef union _UnMotorOutput +{ + StrMotorOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrMotorOutput)]; // 通过结构体类型确定大小 +} UnMotorOutput; + + +// 输出到采集模块 +typedef struct _StrGatherOutput +{ +//----- Send Data 0x15000002 ---------------------------------------------- + unsigned int sleep_duration : 16; // 休眠时间 + unsigned int wakeup_interval : 16; // 唤醒时间 + unsigned int vehicle_mode : 8; // 整车模式 + unsigned int reserved1 : 8; // 保留1 + unsigned int reserved2 : 8; // 保留2 + unsigned int reserved3 : 8; // 保留3 +} StrGatherOutput; + +typedef union _UnGatherOutput +{ + StrGatherOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrGatherOutput)]; // 通过结构体类型确定大小 +} UnGatherOutput; + + + + + + + + + +// canoe协议输出 +typedef struct _StrSdoOutput +{ +//-----发送数据0x601---------------------------------------------- + unsigned int cmd : 8; // 命令 + unsigned int object_index : 16; // 索引 + unsigned int sub_index : 8; // 从索引 + unsigned int data : 32; // 数据 +} StrSdoOutput; + +typedef union _UnSdoOutput +{ + StrSdoOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrSdoOutput)]; // 通过结构体类型确定大小 +} UnSdoOutput; + + + +// 超声波数据发送 +typedef struct _StrUltrasonicOutput +{ +//-----发送数据0x521---------------------------------------------- + uint8_t node; // 节点 + uint8_t function_code; // 功能码 + uint16_t register_address; // 寄存器地址 + uint16_t data; // 数据 + uint16_t reserve;// 保留 +} StrUltrasonicOutput; + +typedef union _UnUltrasonicOutput +{ + StrUltrasonicOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrUltrasonicOutput)]; // 通过结构体类型确定大小 +} UnUltrasonicOutput; + + +// 超声波数据读取 +typedef struct _StrUltrasonicIntput +{ +//-----发送数据0x521---------------------------------------------- + uint8_t node; // 节点 + uint8_t function_code; // 功能码 + uint8_t len; // 长度 + uint16_t data; // 数据 + uint8_t reserve1;// 保留 + uint16_t reserve2;// 保留 +} StrUltrasonicInput; + +typedef union _UnUltrasonicInput +{ + StrUltrasonicInput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrUltrasonicInput)]; // 通过结构体类型确定大小 +} UnUltrasonicInput; + + + + + + + + + + + + + + + + +//typedef struct _StrMotorOutput +//{ +////-----发送数据0x10F80807---------------------------------------------- +// unsigned int gear : 2; // 0 表示空挡,1 表示前进,2 表示后退 +// unsigned int can_gear : 1; // 0-无效 1-有效。无效时 BIT10 的挡位无效,以线路控制挡位为准 +// unsigned int can_break : 1; // 0:不刹车,1-刹车(刹车时才能启动电子刹车) +// unsigned int reserve1 : 1; // 0-只有高速档 1-可以通过接线切换 123 档。 +// unsigned int reserve2 : 1; // 0-无效 1-有效:线控防盗使能 +// unsigned int reserve3 : 1; // 0-无效 1-有效:线控巡航使能 +// unsigned int reserve4 : 1; // 0-无效 1-有效:线控座桶使能 +// +// unsigned int reserve5 : 1; // 0-无效 1-有效:线控边撑使能 +// unsigned int reserve6 : 1; // 0-无效 1-有效:线控防盗使能 +// unsigned int reserve7 : 1; // 0-无效 1-有效:线控巡航使能 +// unsigned int reserve8 : 1; // 0-无效 1-有效:线控座桶使能 +// unsigned int reserve9 : 1; // 0-无效 1-有效:线控巡航使能 +// unsigned int reserve10 : 1; // 0-无效 1-有效:线控座桶使能 +// unsigned int reserve11 : 1; // 0-无效 1-有效:线控巡航使能 +// unsigned int reserve12 : 1; // 0-无效 1-有效:线控座桶使能 +// +// unsigned int reserve13 : 1; // 0-无效 1-有效:线控边撑使能 +// unsigned int reserve14 : 1; // 0-无效 1-有效:线控防盗使能 +// unsigned int reserve15 : 1; // 0-无效 1-有效:线控巡航使能 +// unsigned int reserve16 : 1; // 0-无效 1-有效:线控座桶使能 +// unsigned int reserve17 : 1; // 0-无效 1-有效:线控巡航使能 +// unsigned int reserve18 : 1; // 0-无效 1-有效:线控座桶使能 +// unsigned int motor_direction : 1; // 0 和 1 (静止空闲状态设置有效,在油门、 转矩、转速模式下允许设置,否则使用控制器 内部保存的参数控制电机方向) +// unsigned int Contactor : 1; // 0-断开 1-闭合,(部分控制器支持) +// +// unsigned int reserve19 : 1; // 0-无效 1-有效:线控边撑使能 +// unsigned int reserve20 : 1; // 0-无效 1-有效:线控防盗使能 +// unsigned int reserve21 : 1; // 0-无效 1-有效:线控巡航使能 +// unsigned int reserve22 : 1; // 0-无效 1-有效:线控座桶使能 +// unsigned int mode : 4; //0x0:转把控制,0x5:油门模式,0xA:转矩模式, 0xC:转速模式,其它无效停机。在这三种模式下,电机方向设置有效。只允许在停机状态下设置控制模式。 +// +// unsigned int control_data1 : 16; // 油门-256~+256:(0~+256 表示最大油门,-256 表 示最大电子刹车力度。转矩 -256~10000,(正数 驱 动 扭 矩 0~1000.0Nm,负数表示刹车,-256 表示最大电子刹车力度)转速-256~12000,(正数表示转速 0~12000rpm, 负数表示刹车,-256 最大刹车力度) +// unsigned int control_data2 : 16; // 控制数据和上一个一样 +//} StrMotorOutput; +// +//typedef union _UnMotorOutput +//{ +// StrMotorOutput bit_data; // 使用定义的结构体变量名 +// uint8_t arr[sizeof(StrMotorOutput)]; // 通过结构体类型确定大小 +//} UnMotorOutput; + + + + + + + + + + + +//电机控制器风扇左 +//kgf1 +//电机控制器风扇右 +//kgf3 +//预充 +//kgf4 +//高压压继电器 +//kgf7,8 +//低压继电器 +//kgf11-12 +//左前红灯 +//kgf6 +//左前黄灯 +//kgf9 +//左风扇 +//kgf14 +//右风扇 +//kgf19 +//电脑 +//kgf 17-18 +//交换机 +//kgf 21-22 +//右前红灯 +//kgf24 +//右前黄灯 +//kgf25 +//左后红灯 +//kgf26 +//左后黄灯 +//kgf27 +//右后红灯 +//kgf29 +//右后黄灯 +//kgf30 + + +// 输出到开关阀模块 +typedef struct _StrInfCanKGFOutput +{ + //----------主机发送命令字0x11000002 -------------------------------------------- + unsigned int KGF01 : 1; // 通道1 + unsigned int KGF02 : 1; // 通道2 + unsigned int KGF03 : 1; // 通道3 + unsigned int KGF04 : 1; // 通道4 + unsigned int KGF05 : 1; // 通道5 + unsigned int KGF06 : 1; // 通道6 + unsigned int KGF07 : 1; // 通道7 + unsigned int KGF08 : 1; // 通道8 + unsigned int KGF09 : 1; // 通道9 + unsigned int KGF10 : 1; // 通道10 + unsigned int KGF11 : 1; // 通道11 + unsigned int KGF12 : 1; // 通道12 + unsigned int KGF13 : 1; // 通道13 + unsigned int KGF14 : 1; // 通道14 + unsigned int KGF15 : 1; // 通道15 + unsigned int KGF16 : 1; // 通道16 + + unsigned int can_rx2 : 8; // 保留 + unsigned int can_rx3 : 8; // 保留 + unsigned int can_rx4 : 8; // 保留 + unsigned int can_rx5 : 8; // 保留 + unsigned int can_period_h : 8; // 发送周期高位 + unsigned int can_period_l : 8; // 发送周期低位 + + //----------发送0x11000003 --------------------------------------------------- + unsigned int pwm_01 : 4; // PWM通道1 + unsigned int pwm_02 : 4; // PWM通道2 + unsigned int pwm_03 : 4; // PWM通道3 + unsigned int pwm_04 : 4; // PWM通道4 + unsigned int pwm_05 : 4; // PWM通道5 + unsigned int pwm_06 : 4; // PWM通道6 + unsigned int pwm_07 : 4; // PWM通道7 + unsigned int pwm_08 : 4; // PWM通道8 + unsigned int pwm_09 : 4; // PWM通道9 + unsigned int pwm_10 : 4; // PWM通道10 + unsigned int pwm_11 : 4; // PWM通道11 + unsigned int pwm_12 : 4; // PWM通道12 + unsigned int pwm_13 : 4; // PWM通道13 + unsigned int pwm_14 : 4; // PWM通道14 + unsigned int pwm_15 : 4; // PWM通道15 + unsigned int pwm_16 : 4; // PWM通道16 +} StrInfCanKGFOutput; + +typedef union _UnInfCanKGFOutput +{ + StrInfCanKGFOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrInfCanKGFOutput)]; // 通过结构体类型确定大小 +} UnInfCanKGFOutput; + + + +// 输出到H桥模块 +typedef struct _StrHBridgeOutput +{ + //----------主机发送命令字0x7F2 -------------------------------------------- + unsigned int channel_01 : 1; // 通道1 + unsigned int channel_02 : 1; // 通道2 + unsigned int channel_03 : 1; // 通道3 + unsigned int channel_04 : 1; // 通道4 + unsigned int channel_05 : 1; // 通道5 + unsigned int channel_06 : 1; // 通道6 + unsigned int channel_07 : 1; // 通道7 + unsigned int channel_08 : 1; // 通道8 + unsigned int sleep_01 : 1; // 休眠1 + unsigned int sleep_02 : 1; // 休眠2 + unsigned int sleep_03 : 1; // 休眠3 + unsigned int sleep_04 : 1; // 休眠4 + unsigned int reserve_01 : 1; // 保留1 + unsigned int reserve_02 : 1; // 保留2 + unsigned int reserve_03 : 1; // 保留3 + unsigned int reserve_04 : 1; // 保留4 + + unsigned int reserve_05 : 8; // 保留5 + unsigned int reserve_06 : 8; // 保留6 + unsigned int reserve_07 : 8; // 保留7 + unsigned int reserve_08 : 8; // 保留8 + unsigned int can_period_h : 8; // 发送周期高位 + unsigned int can_period_l : 8; // 发送周期低位 + + //----------发送0x7F3 --------------------------------------------------- + unsigned int pwm_channel_01 : 4; // PWM通道1 + unsigned int pwm_channel_02 : 4; // PWM通道2 + unsigned int pwm_channel_03 : 4; // PWM通道3 + unsigned int pwm_channel_04 : 4; // PWM通道4 + unsigned int pwm_channel_05 : 4; // PWM通道5 + unsigned int pwm_channel_06 : 4; // PWM通道6 + unsigned int pwm_channel_07 : 4; // PWM通道7 + unsigned int pwm_channel_08 : 4; // PWM通道8 + unsigned int pwm_reserve_01 : 4; // 保留pwm1 + unsigned int pwm_reserve_02 : 4; // 保留pwm2 + unsigned int pwm_reserve_03 : 4; // 保留pwm3 + unsigned int pwm_reserve_04 : 4; // 保留pwm4 + unsigned int pwm_reserve_05 : 4; // 保留pwm5 + unsigned int pwm_reserve_06 : 4; // 保留pwm6 + unsigned int pwm_reserve_07 : 4; // 保留pwm7 + unsigned int pwm_reserve_08 : 4; // 保留pwm8 +} StrHBridgeOutput; + +typedef union _UnHBridgeOutput +{ + StrHBridgeOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrHBridgeOutput)]; // 通过结构体类型确定大小 +} UnHBridgeOutput; + + +// 输出给导航仪 +typedef struct _StrWheelSpeedOutput +{ + //-----发送数据0x98---------------------------------------------- + unsigned int left_front : 16; // 左前轮速 + unsigned int right_front : 16; // 右前轮速 + unsigned int left_rear : 16; // 左后轮速 + unsigned int right_rear : 16; // 右后轮速 +} StrWheelSpeedOutput; + +typedef union _UnWheelSpeedOutput +{ + StrWheelSpeedOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrWheelSpeedOutput)]; // 通过结构体类型确定大小 +} UnWheelSpeedOutput; + + +// 输出给基站升降杆 +typedef struct _StrLifterOutput +{ + //-----发送数据0x6F2---------------------------------------------- + unsigned int cmd : 8 ; // 上升命令 + unsigned int reserve1 : 8 ; // 保留 + unsigned int reserve2 : 16; // 保留 + unsigned int reserve3 : 16; // 保留 + unsigned int reserve4 : 16; // 保留 +} StrLifterOutput; + +typedef union _UnrLifterOutput +{ + StrLifterOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrLifterOutput)]; // 通过结构体类型确定大小 +} UnLifterOutput; + + +//-----以太网------------------------------------------------------------- +// 输出给自主计算机 +typedef struct _StrComputerOutput +{ + //-------------------------------------------------- + unsigned int frame_header : 16; // 帧头 0xFFCC + unsigned int frame_type : 16; // 帧类型 0x0011 + unsigned int frame_length : 8; // 帧长 0x000b,11 + unsigned int accumulated : 8; // 累加值 + unsigned int speed : 16; // 左侧轮速 + unsigned int curvature : 16; // 右侧轮速 + unsigned int crc : 8; // CRC +} StrComputerOutput; + +typedef union _UnComputerOutput +{ + StrComputerOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrComputerOutput)]; // 通过结构体类型确定大小 +} UnComputerOutput; + + + + +// 车辆信息,输出给上位机 +typedef struct _StrVehicleInfoOutput +{ + //-------------------------------------------------- + unsigned int frame_header : 16; // 帧头 固定值0xAACC + unsigned int frame_type : 16; // 帧类型 固定值0x0020 + unsigned int frame_length : 16; // 帧长 固定值41 + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int desired_speed : 16; // 期望速度 系数0.01, 正为前进,负为后退 单位m/s + unsigned int desired_curvature : 16; // 期望曲率 系数0.0001,正为左转,负为右转 + unsigned int set_left_speed : 16; // 设定左转速度 电机1设定转速 正为正传,负为反转 + unsigned int set_right_speed : 16; // 设定右转速度 电机2设定转速 正为正传,负为反转 + unsigned int longitude : 32; // 纬度 系数 1e-7 值域(-180°,180°) + unsigned int latitude : 32; // 经度 系数 1e-7 值域(-90°,90°) + unsigned int altitude : 32; // 高度 + unsigned int heading_angle : 16; // 航向角 系数 0.01 值域(0-360°) + unsigned int speed : 16; // 当前车速 系数 0.01 正为前进,负为后退 单位m/s + unsigned int curvature : 16; // 当前曲率 系数 0.0001正为左转,负为右转 + unsigned int battery_voltage : 16; // 电池电压 系数 0.1 单位V + unsigned int battery_soc : 16; // 电池SOC 系数 0.1 单位:% + unsigned int battery_current : 16; // 电池电流 系数 0.1 偏移量 -30000 单位A + unsigned int vehicle_fault_state : 8; // 整车故障状态 0 故障 1正常 + unsigned int crc : 8; // CRC 按字节累加之和 取低8位 +} StrVehicleInfoOutput; + +typedef union _UnVehicleInfoOutput +{ + StrVehicleInfoOutput bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrVehicleInfoOutput)]; // 通过结构体类型确定大小 +} UnVehicleInfoOutput; + + +// 电机状态信息,输出给上位机 +typedef struct _StrMotorStatusOutput +{ + //-------------------------------------------------- + unsigned int frame_header : 16; // 帧头 固定值0xAACC + unsigned int frame_type : 16; // 帧类型 固定值0x0021 + unsigned int frame_length : 16; // 帧长 固定值30 + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int left_wheel_speed : 16; // 当前左侧轮速 系数 1 偏移量 -30000 单位rad/min + unsigned int right_wheel_speed : 16; // 当前右侧轮速 系数 1 偏移量 -30000 单位rad/min + unsigned int left_torque : 16; // 左侧电机扭矩 系数 0.01 偏移量 -300 单位N/s + unsigned int right_torque : 16; // 右侧电机扭矩 系数 0.01 偏移量 -300 单位N/s + unsigned int left_fault_code : 8; // 左侧电机故障码 + unsigned int right_fault_code : 8; // 右侧电机故障码 + unsigned int left_torque_limit : 16; // 左侧电机扭矩限制 系数 0.01 偏移量 -300 单位N/s + unsigned int right_torque_limit : 16; // 右侧电机扭矩限制 系数 0.01 偏移量 -300 单位N/s + unsigned int left_power_in : 16; // 左侧电机馈电功率 系数 1 偏移量 0 单位W + unsigned int right_power_in : 16; // 右侧电机馈电功率 系数 1 偏移量 0 单位W + unsigned int left_power_out : 16; // 左侧电机放电功率 系数 1 偏移量 0 单位W + unsigned int right_power_out : 16; // 右侧电机放电功率 系数 1 偏移量 0 单位W + unsigned int left_voltage : 16; // 左侧电机电压 系数0.1 偏移量-3000 单位V + unsigned int right_voltage : 16; // 右侧电机电压 系数0.1 偏移量-3000 单位V + unsigned int checksum : 8; // 校验和 按字节累加之和 取低8位 +} StrMotorStatusOutput; + +typedef union _UnMotorStatusOutput +{ + StrMotorStatusOutput bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrMotorStatusOutput)]; // 通过结构体类型确定大小 +} UnMotorStatusOutput; + + + + +// PID参数输出,输出给上位机 +typedef struct _StrPIDOutput +{ + //-------------------------------------------------- + unsigned int frame_header : 16; // 帧头 固定值0xAACC + unsigned int frame_type : 16; // 帧类型 固定值0x0022 + unsigned int frame_length : 16; // 帧长 固定值56 + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int rc_straight_p : 32; // 遥控直行P参数 系数 0.001 + unsigned int rc_straight_i : 32; // 遥控直行I参数 系数 0.001 + unsigned int rc_straight_d : 32; // 遥控直行D参数 系数 0.001 + unsigned int auto_straight_p : 32; // 自主直行P参数 系数 0.001 + unsigned int auto_straight_i : 32; // 自主直行I参数 系数 0.001 + unsigned int auto_straight_d : 32; // 自主直行D参数 系数 0.001 + unsigned int rc_turn_p : 32; // 遥控转弯P参数 系数 0.001 + unsigned int rc_turn_i : 32; // 遥控转弯I参数 系数 0.001 + unsigned int rc_turn_d : 32; // 遥控转弯D参数 系数 0.001 + unsigned int auto_turn_p : 32; // 自主转弯P参数 系数 0.001 + unsigned int auto_turn_i : 32; // 自主转弯I参数 系数 0.001 + unsigned int auto_turn_d : 32; // 自主转弯D参数 系数 0.001 + unsigned int checksum : 8; // 校验和 按字节累加之和 取低8位 +} StrPIDOutput; + +typedef union _UnPIDOutput +{ + StrPIDOutput bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrPIDOutput)]; // 通过结构体类型确定大小 +} UnPIDOutput; + +// 模拟信号输出,输出给上位机 +typedef struct _StrAnalogSignalOutput +{ + //-------------------------------------------------- + unsigned int frame_header : 16; // 帧头 固定值0xAACC + unsigned int frame_type : 16; // 帧类型 固定值0x0023 + unsigned int frame_length : 16; // 帧长 固定值24 + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int channel_1 : 16; // 通道1 温度传感器 系数为0.1 有符号 正数表示正温度,负数标表示负温度 + unsigned int channel_2 : 16; // 通道2 + unsigned int channel_3 : 16; // 通道3 + unsigned int channel_4 : 16; // 通道4 + unsigned int channel_5 : 16; // 通道5 温度传感器 系数为0.1 有符号 正数表示正温度,负数标表示负温度 + unsigned int channel_6 : 16; // 通道6 + unsigned int channel_7 : 16; // 通道7 + unsigned int channel_8 : 16; // 通道8 + unsigned int crc : 8 ; // 校验和 按字节累加之和 取低8位 + +} StrAnalogSignalOutput; + +typedef union _UnAnalogSignalOutput +{ + StrAnalogSignalOutput bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrAnalogSignalOutput)]; // 通过结构体类型确定大小 +} UnAnalogSignalOutput; + + + +// 遥控器数据输出,给上位机 +typedef struct _StrRemoteControlOutput +{ + //-------------------------------------------------- + unsigned int frame_header : 16; // 帧头 固定值0xAACC + unsigned int frame_type : 16; // 帧类型 固定值0x0024 + unsigned int frame_length : 16; // 帧长 固定值20 + unsigned int accumulated : 8; // 累加值 按帧累加 + + // RC6GS遥控原始数据 + unsigned int speed : 16; // 速度 系数0.01,正为前进,负为后退 单位m/s + unsigned int curvature : 16; // 曲率 系数0.0001,正为左转,负为右转 + unsigned int reserve_1 : 16; // 备用1 + + unsigned int switch_a : 1; // SwA + unsigned int switch_b : 2; // SwB 0和2刹车状态 1正常状态 + unsigned int switch_c : 2; // SwC 0和2自主状态 1手动状态 + unsigned int switch_d : 1; // SwD + unsigned int hv_relay_state : 1; // 高压继电机状态 0 断开, 1开启 + unsigned int reserve_2 : 1; // 备用 + unsigned int enable : 8; // 使能 1遥控数据有效,0无效 + unsigned int accumulated_value : 16; // 接收累加值 + unsigned int crc : 8; // 校验和 按字节累加之和 取低8位 +} StrRemoteControlOutput; + +typedef union _UnRemoteControlOutput +{ + StrRemoteControlOutput bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrRemoteControlOutput)]; // 通过结构体类型确定大小 +} UnRemoteControlOutput; + + + +// 手动控制数据,返回给请求者 +typedef struct _StrManualControlOutput +{ + //-------------------------------------------------- + // 手动控制数据 高位在前,低位在后 + unsigned int frame_header : 16; // 帧头 固定值0xFFBB + unsigned int frame_type : 16; // 帧类型 固定值0x0025 + unsigned int frame_length : 8; // 帧长 固定值0x0C + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int set_speed : 16; // 设定速度 系数0.01,正为前进,负为后退 单位m/s + unsigned int set_curvature : 16; // 设定曲率 系数0.0001,正为左转,负为右转 + unsigned int reserved : 8; // 保留 + unsigned int crc_1 : 8 ; // CRC 按字节累加之和,溢出取低8位 + unsigned int accumulated_value : 16; // 接收累加值 + unsigned int crc_2 : 8 ; // CRC 按字节累加之和,溢出取低8位 +} StrManualControlOutput; + +typedef union _UnManualControlOutput +{ + StrManualControlOutput bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrManualControlOutput)]; // 通过结构体类型确定大小 +} UnManualControlOutput; + + + + +// 自动控制数据输出,返回给请求者 +typedef struct _StrAutoControlOutput +{ + //-------------------------------------------------- + // 自主计算机自动数据 高位在前,低位在后 + unsigned int frame_header : 16; // 帧头 固定值0xFFCC + unsigned int frame_type : 16; // 帧类型 固定值0x0026 + unsigned int frame_length : 8; // 帧长 固定值0x19 + unsigned int accumulated : 8; // 累加值 按帧累加 + unsigned int set_speed : 16; // 设定速度 系数0.01,正为前进,负为后退 单位m/s + unsigned int set_curvature : 16; // 设定曲率 系数0.0001,正为左转,负为右转 + unsigned int latitude : 32; // 纬度 系数10^-7,431234567表示43.1234567度 + unsigned int longitude : 32; // 经度 系数10^-7,431234567表示43.1234567度 + unsigned int altitude : 32; // 高度 单位mm + unsigned int heading : 16; // 航向 车辆航向,35999表示359.99度。 + unsigned int accumulated_value : 16; // 累加值 按帧累加 + unsigned int crc : 8 ; // CRC 总体累加CRC +} StrAutoControlOutput; + +typedef union _UnAutoControlOutput +{ + StrAutoControlOutput bit_data; // 使用定义的结构体变量名 + unsigned char arr[sizeof(StrAutoControlOutput)]; // 通过结构体类型确定大小 +} UnAutoControlOutput; + + + + + +//-----IO口--------------------------------------------------------------- +// 电压信号输出,到遥控器 +typedef struct _StrVoltageSignalOutput +{ + unsigned int pwm_value : 16; // PWM值 +} StrVoltageSignalOutput; + +typedef union _UnVoltageSignalOutput +{ + StrVoltageSignalOutput bit_data; // 使用定义的结构体变量名 + uint8_t arr[sizeof(StrVoltageSignalOutput)]; // 通过结构体类型确定大小 +} UnVoltageSignalOutput; + + + +//外部数据结构声明 +extern UnMotorInput un_motor_input1 ;//电机控制器1 左侧 +extern UnMotorInput un_motor_input2 ;//电机控制器2 右侧 +extern UnMotorInput un_motor_input3 ;//电机控制器1 左后侧 +extern UnMotorInput un_motor_input4 ;//电机控制器2 右后侧 +extern UnBmsInput un_bms_input ;//BMS接收数据 +extern UnTempModuleInput un_temp_module_input;//温度采集模块 +extern UnAutoComputerInput un_auto_computer_input;//自主计算机自动数据 +extern UnManualComputerInput un_manual_computer_input;//自主计算机手动数据 + +extern UnUltrasonicInput un_ultrasonic_input1;//超声波传感器输入1 + +extern UnUltrasonicOutput un_ultrasonic_output1;//超声波传感器输出 + + + +extern UnMotorOutput un_motor_output1; //电机输出 +extern UnMotorOutput un_motor_output2; //电机输出 +extern UnMotorOutput un_motor_output3; //电机输出 +extern UnMotorOutput un_motor_output4; //电机输出 +extern UnMotorTempInput un_motor_temp1; //电机控制器1 温度 +extern UnMotorTempInput un_motor_temp2; //电机控制器2 温度 +extern UnMotorTempInput un_motor_temp3; //电机控制器3 左后侧 +extern UnMotorTempInput un_motor_temp4; //电机控制器4 右后侧 + + +extern UnInfCanKGFOutput un_inf_can_kgf_output1; +extern UnInfCanKGFOutput un_inf_can_kgf_output2; +extern UnHBridgeOutput un_h_bridge_output; + +extern UnWheelSpeedOutput un_wheel_wpeed_output; +extern UnGatherOutput un_gather_output;//采集模块输出 + + +//串口 +extern UnRemoteControlInput un_remote_control_input; //遥控器输入 + +//IO口 +extern UnSwSample un_sw_sample; + +//以太网 +extern UnRequestFrame un_request_frame; //请求帧 + +extern UnComputerOutput un_computer_output; //输出给自主计算机 + +//输出给上位机 +extern UnVehicleInfoOutput un_vehicle_Info_output; // 车辆信息,输出给上位机 +extern UnMotorStatusOutput un_motor_status_output; // 电机状态信息,输出给上位机 +extern UnPIDOutput un_pid_output; // PID参数输出,输出给上位机 +extern UnAnalogSignalOutput un_analog_signal_output; // 模拟信号输出,输出给上位机 +extern UnRemoteControlOutput un_remote_control_output;// 遥控器数据输出,给上位机 +extern UnManualControlOutput un_manual_control_output;// 手动控制数据,返回给请求者 +extern UnAutoControlOutput un_auto_control_output; // 自动控制数据输出,返回给请求者 +extern UnSdoOutput un_sdo_output ;//转向电机输出 + + +//变量 +extern uint8_t test_app[26]; + +extern UnCanDebugOutput un_can_debug_output;//调试输出 + + +//函数 +void canSendAll(void *signal_id); +void ethernetSendAll(void *signal_id); + +#pragma pack() + +#endif /* _INTERFACE_H_ */ diff --git a/interface_24c02.c b/interface_24c02.c new file mode 100644 index 0000000..77fbccd --- /dev/null +++ b/interface_24c02.c @@ -0,0 +1,428 @@ + + +#include +#include +#include +#include "sdrv_spi.h" +#include "irq_num.h" +#include "clock_ip.h" + + + +#include "interface_config.h" + + +#define _nop_() udelay(1); +#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();} +#define bit bool + +#define MASTER_TEST_LEN 100//෢100ֽڵ + +static uint8_t m_rx_buf_u8[MASTER_TEST_LEN] __attribute__((__aligned__(32))); +static uint8_t m_tx_buf_u8[MASTER_TEST_LEN] __attribute__((__aligned__(32))); + +static struct sdrv_spi g_master; + +void iic_start(void); +void iic_stop(void); +void iic_ack(bit ackbit); +void iic_sendbyte(unsigned char byt); +//void wrbyte_24c02(unsigned int add,unsigned char dat); +void delay(unsigned char t); + +bit iic_waitack(void); +unsigned char i2c_recbyte(void); +unsigned char rdbyte_24c02(unsigned int add); +unsigned char wrEE_CRC_Bak(unsigned char add,unsigned char *eeData,unsigned char len,unsigned char addbak); +unsigned char rdEE_CRC_Bak(unsigned char add,unsigned char *eeData,unsigned char len,unsigned char addbak); + + +////FM25CL64ָ +#define FM25CL64_WREN 0x06 //ʹ +#define FM25CL64_WRDI 0x04 //ʧ +#define FM25CL64_RDSR 0x05 //״̬ +#define FM25CL64_WRSR 0x01 //д״̬ +#define FM25CL64_READ 0x03 // +#define FM25CL64_WRITE 0x02 //д + + + +#define MAX_FM25CL64_LEN 8192//8kֽ + +static const struct spi_device_config device_mode0_8bits_ss0 = { + .sclk_freq = 1000000, + .cpol = SCK_IDLE_LOW, + .cpha = DATA_CPT_ON_FIRST_SCK_EDGE, + .cs_pol = CS_ACTIVE_LOW, + .cs_sel = CS_SEL_SS0, + .width = SPI_DATA_WIDTH_BYTE, + .fream_delay = 0, + .clk2cs_delay = 0, + .clk2cs_end_delay = 0, + .is_lsb_mode = false, + +}; + +static struct spi_common_config spi_master = { + .is_spi_mode = true, + .is_half_mode = false, + .is_master = true, + .base = APB_SPI6_BASE, + .irq = SPI6_SPI_INTR_NUM, +#if CONFIG_E3 + .clk = &g_ckgen_ip_spi_sf_1_to_4, +#else + .clk = &g_ckgen_ip_spi_sf_1_to_3, +#endif +}; + + + + + +void initSpi() +{ + /* Init Spi Instance */ + sdrv_spi_init(&g_master, &spi_master); + sdrv_spi_config_device(&g_master, &device_mode0_8bits_ss0); +} + + + + + + + +void SDAOut(bit c) +{ +// sdrv_pinctrl_set_input_select(GPIO_Y3, PIN_IS_CMOS); +// sdrv_gpio_set_pin_direction(GPIO_Y3, GPIO_DIR_OUT); + sdrv_gpio_set_pin_output_level(GPIO_Y3, c); +} + +void SCLOut(bit c) +{ + sdrv_gpio_set_pin_output_level(GPIO_Y2, c); +} + +void iic_start(void) +{ + SDAOut(1); + _nop_(); + SCLOut(1); + somenop; + SDAOut(0); + somenop; + SCLOut(0); +} + +void iic_stop(void) +{ + SDAOut(0); + _nop_(); + SCLOut(1); + somenop; + SDAOut(1); +} + +void iic_ack(bit ackbit) +{ + if(ackbit) + SDAOut(0); + else + SDAOut(1); + somenop; + SCLOut(1); + somenop; + SCLOut(0); + SDAOut(1); + somenop; +} + +bit iic_waitack(void) +{ + SDAOut(1); + somenop; + SCLOut(1); +// sdrv_pinctrl_set_input_select(GPIO_Y3, PIN_IS_CMOS_SCHMITT); +// sdrv_gpio_set_pin_direction(GPIO_Y3, GPIO_DIR_IN); + somenop; + if(sdrv_gpio_read_pin_input_level(GPIO_Y3)) + { + SCLOut(0); + iic_stop(); + return 0; + } + else + { + SCLOut(0); + return 1; + } +} + +void iic_sendbyte(unsigned char byt) +{ + unsigned char i; + for(i=0;i<8;i++) + { + if(byt&0x80) + SDAOut(1); + else + SDAOut(0); + somenop; + SCLOut(1); + byt <<= 1; + somenop; + SCLOut(0); + } +} + +unsigned char iic_recbyte(void) +{ + unsigned char da; + unsigned char i; + for(i=0;i<8;i++) + { + SCLOut(1); +// sdrv_pinctrl_set_input_select(GPIO_Y3, PIN_IS_CMOS_SCHMITT); +// sdrv_gpio_set_pin_direction(GPIO_Y3, GPIO_DIR_IN); + somenop; + da <<= 1; + +// P1_IOCR01 = 0x0020; // load port control register 1 + if(sdrv_gpio_read_pin_input_level(GPIO_Y3)) + da |= 0x01; + SCLOut(0); + somenop; + } + return da; +} + +unsigned char wrbyte_24c02(unsigned int add,unsigned char dat) +{ +#if EN_24C02 + unsigned char eeprom_page = 0; + unsigned char eeprom_add = 0; + unsigned char device_add = 0; +//------------------------------------------------- + + eeprom_page = add/256;//ҳ + eeprom_add = add%256; + if(eeprom_page >= 3)//ĿǰE2һ4ҳ1k + { + eeprom_page = 3; + } + // Device Address 1100 0 p1 p0 R/W + device_add = (0xa0 | (eeprom_page << 1));// + +// ssdk_printf(SSDK_CRIT, "eeprom_page:0x%x\r\n", eeprom_page); +// ssdk_printf(SSDK_CRIT, "eeprom_add:0x%x\r\n", eeprom_add); +// ssdk_printf(SSDK_CRIT, "device_add:0x%x\r\n", device_add); + + iic_start(); + iic_sendbyte(device_add); + iic_waitack(); + iic_sendbyte(eeprom_add); + iic_waitack(); + iic_sendbyte(dat); + iic_waitack(); + iic_stop(); +#else + if(add >= MAX_FM25CL64_LEN)//ַ + { + printf("E2 len error!\r\n"); + } + else + { + m_tx_buf_u8[0] = FM25CL64_WREN;//дʹ + if (sdrv_spi_sync_transmit(&g_master, m_tx_buf_u8, m_rx_buf_u8,1,1)) + { + printf("E2 write Failed!\r\n"); + } + + m_tx_buf_u8[0] = FM25CL64_WRITE;//д + m_tx_buf_u8[1] = (uint8_t)( add >> 8);// 8λַ + m_tx_buf_u8[2] = (uint8_t)( add );// + m_tx_buf_u8[3] = dat;// + + if (sdrv_spi_sync_transmit(&g_master, m_tx_buf_u8, m_rx_buf_u8,4,4)) + { + printf("E2 write Failed!\r\n"); + } + } +#endif + return 0; +} + +unsigned char rdbyte_24c02(unsigned int add) +{ +#if EN_24C02 + unsigned char eeprom_page = 0; + unsigned char eeprom_add = 0; + unsigned char device_add = 0; + unsigned char da; +//------------------------------------------------- + + eeprom_page = add/256;//ҳ + eeprom_add = add%256; + if(eeprom_page >= 3)//ĿǰE2һ4ҳ1k + { + eeprom_page = 3; + } + + // Device Address 1100 000 R/W + iic_start(); + device_add = (0xa0 | (eeprom_page << 1));// αд + iic_sendbyte(device_add); + iic_waitack(); + iic_sendbyte(eeprom_add); + iic_waitack(); + iic_start(); + + device_add = (0xa1 | (eeprom_page << 1));// + + ssdk_printf(SSDK_CRIT, "device_add:0x%x\r\n", device_add); + + iic_sendbyte(device_add); + iic_waitack(); + da = iic_recbyte(); + iic_ack(0); + iic_stop(); +//CAN_sendAck(add, da); + return da; +#else + if(add >= MAX_FM25CL64_LEN)//ַ + { + printf("E2 len error!\r\n"); + } + else + { + m_tx_buf_u8[0] = FM25CL64_READ;// + m_tx_buf_u8[1] = (uint8_t)( add >> 8);// 8λַ + m_tx_buf_u8[2] = (uint8_t)( add );// + m_tx_buf_u8[3] = 0xFF;// + + if (sdrv_spi_sync_transmit(&g_master, m_tx_buf_u8, m_rx_buf_u8,4,4)) + { + printf("E2 write Failed!\r\n"); + } + + return m_rx_buf_u8[3]; + } +#endif + return 0xFF; +} + + +#ifdef _EEROM_CRC_ +#define POLY 0x1021 +/** +* Calculating CRC-16 in 'C' +* @para addr, start of data +* @para num, length of data +* @para crc, incoming CRC +*/ +unsigned int crc16(unsigned char *addr, int num, unsigned int crc) +{ + int i; + for (; num > 0; num--) /* Step through bytes in memory */ + { + crc = crc ^ ((*addr) << 8); /* Fetch byte from memory, XOR into CRC top byte*/ + addr++; + for (i = 0; i < 8; i++) /* Prepare to rotate 8 bits */ + { + if (crc & 0x8000) /* b15 is set... */ + crc = (crc << 1) ^ POLY; /* rotate and XOR with polynomic */ + else /* b15 is clear... */ + crc <<= 1; /* just rotate */ + } /* Loop for 8 bits */ + crc &= 0xFFFF; /* Ensure CRC remains 16-bit value */ + } /* Loop until num=0 */ + return(crc); /* Return updated CRC */ +} + +//дȷԶдһݣдͲд +unsigned char wrEE_CRC_Bak(unsigned char add,unsigned char *eeData,unsigned char len,unsigned char addbak) +{ + uword crc_Res; + unsigned char index; + unsigned char flagEEwrOK; + + crc_Res = crc16(eeData, len-2, 0xffff); //ݵУ + eeData[len-2] = (ubyte)(crc_Res ); + eeData[len-1] = (ubyte)(crc_Res >> 8); + + for(index=0;index +#include +#include +#include +#include +#include "sdrv_rstgen.h" +#include "interface_config.h" + + + +uint16_t FrameHeader = 0;//֡ͷ +bool boot_can_flag = false;//֡ͷ +bool boot_eth_flag = false;//֡ͷ + + +SystemDataRecord g_systemDataRecord = {0,0,0,0}; + +bool WDTReFresh_flag = false;// + +Timer boot_timer_interface; + + + +void bootmian(void *signal_id) +{ + static uint16_t bootmianSTT = 0; +// uint32_t time_boot = getCurrentTime();//¼ǰʱ +//------------------------------------------------------------------------------ + (void)signal_id; // DZΪʹã + + if( (true == boot_can_flag) || (true == boot_eth_flag) )//־жнպ1 + { + boot_can_flag = false; + boot_eth_flag = false; + if(EXCUTE_APP == FrameHeader)//д־0APP + { + printf("go to app!\r\n"); + wrbyte_24c02(Update_Flg_E2adr,NORMAL_ON); //д־λΪ0һγֱӽapp +// udelay(3000);//ʱ3ms + g_systemDataRecord.canBootloaderUpgrade = rdbyte_24c02(Update_Flg_E2adr); //ݷι + +// sdrv_rstgen_global_reset(&rstctl_glb); + for(;;) + { + printf("Restart!\r\n"); + } + } + else if(ENTER_UPDATE_MODE == FrameHeader)//д־1boot + { + ssdk_printf(SSDK_INFO, "go to boot!\r\n"); + wrbyte_24c02(Update_Flg_E2adr,CAN_BOOTLOADER_UPGRADE); //д־ +// udelay(3000);//ʱ3ms + +// sdrv_rstgen_global_reset(&rstctl_glb); + for(;;) + { + printf("Restart!\r\n"); + } + } + } + + //жϴe2ȡboot־󣬾ǷAPPʱι + if( CAN_BOOTLOADER_UPGRADE == (g_systemDataRecord.canBootloaderUpgrade) )//boot־ + { + //boot־Ϊ1ϵbootλι + if(true == WDTReFresh_flag)//յIDŸWDT յ־ι + { + feedWatchdog();//ι + WDTReFresh_flag = false; + } + } + else//APPԼι + { + bootmianSTT ++; + if(bootmianSTT >= 5)//5*1000*100us = 500ms + { + bootmianSTT = 0; + feedWatchdog();//ι + } + } + + timerStart(&boot_timer_interface, 100,0); + +// printf("bootAPP spend time:%d\n",getCurrentTime() - time_boot);//app˶೤ʱ +} + + + +static uint32_t time_wdt = 0; +// ι +void feedWatchdog(void) +{ + sdrv_gpio_toggle_pin_output_level(WDTGPIO); //ⲿwdtι + printf("WDT:%d \n",getCurrentTime() - time_wdt); + time_wdt = getCurrentTime(); +} + + + + + + + +// APPģijʼ +void bootInterfaceInit(void) +{ + // ʼʱ + timerInit(&boot_timer_interface); + // Ķʱźţڶʱɼ + subscribe(&boot_timer_interface, bootmian); + + timerStart(&boot_timer_interface, 100,0); //100ms + + feedWatchdog();//ι,ʼιһ + + printf("bootInterface: initial OK %d\n",getCurrentTime()); +} + + + + + + + + + + + + diff --git a/interface_boot.h b/interface_boot.h new file mode 100644 index 0000000..66bbfc4 --- /dev/null +++ b/interface_boot.h @@ -0,0 +1,69 @@ + +#ifndef __INTERFACE_BOOT_H_ +#define __INTERFACE_BOOT_H_ + +#include +#include +#include "stdint.h" +#include + + + + +//#define WDTGPIO GPIO_H13 +#define WDTGPIO GPIO_F5 + + + +typedef struct { + volatile uint8_t canBootloaderUpgrade; //CAN־λ + uint8_t test1; + uint8_t test2; + uint8_t test3; +} SystemDataRecord;//ṹAPPͬ + +typedef enum{ + NORMAL_ON = 0, + CAN_BOOTLOADER_UPGRADE, +}UpgradeFlag; + + +#define Update_Flg_E2adr 0x0 //ռ1ֽ +#define BOOT0_VERSION_E2adr 0x1 //ռ5ֽ +ʱ+汾 20 24 08 08 01 +#define BOOT1_VERSION_E2adr 0x6 //ռ5ֽ +ʱ+汾 20 24 08 08 01 +#define APP_VERSION_E2adr 0xB //ռ5ֽ +ʱ+汾 20 24 08 08 01 +#define BOOT_DES_IP 0x10 //ռ4ֽ IP 192.168.17.3 + + + + +#define ENTER_UPDATE_MODE 0x1 +#define READ_VERSION 0x100 +#define CRC_UPDATE 0x101 +#define Write_VERSION 0x103 +#define ENTER_APP 0x102 +#define EXCUTE_APP 0x02 +#define FEEDDOG_HEADER 0x200 //յιcan֡֡ͷ + +//ⲿ +void bootmian(void *signal_id); +void reboot_global(sdrv_rom_ctrl_boot_mode_e boot_mode); +void bootInterfaceInit(void); + + +//ⲿ +extern uint32_t OTA_CANTxID;//ĬϷIDΪ0x02 +extern uint32_t OTA_CANRxID;//ĬϽIDΪ0x01 +extern uint32_t WDT_CANRxID;//ĬϽIDΪ0x03 + +extern SystemDataRecord g_systemDataRecord ; +extern uint16_t FrameHeader;//֡ͷ +extern bool boot_can_flag;//֡ͷ +extern bool boot_eth_flag;//֡ͷ +//ι +extern void feedWatchdog(void); + + +#endif /*__INTERFACE_BOOT_H_*/ + + diff --git a/interface_btm.c b/interface_btm.c new file mode 100644 index 0000000..ef8a7fe --- /dev/null +++ b/interface_btm.c @@ -0,0 +1,99 @@ +#include "regs_base.h" +#include "irq_num.h" +#include "sdrv_btm.h" + +#include "interface_config.h" + +//app +#include "app/app_config.h" + +static sdrv_btm_t gstsdrv_btm_timer0; +static sdrv_btm_t gstsdrv_btm_timer1; + +volatile uint8_t Btm10ms = 0; + + +#define DEVICE_BASE(dev) _DEVICE_BASE(dev) +#define _DEVICE_BASE(dev) APB_##dev##_BASE + +#define DEVICE_INTR(dev) _DEVICE_INTR(dev) +#define _DEVICE_INTR(dev) dev##_INTR_NUM + + +/*SDRV_BTM_G0ʱԴAPB clock, APB clock150MHz*/ +/*SDRV_BTM_G0Ƶ֮clock1M*/ +static sdrv_btm_cfg_t timer0_config = { + .base = DEVICE_BASE(BTM2), + .irq = DEVICE_INTR(BTM2_O_BTM), + .tmr_id = SDRV_BTM_G0, + .tmr_cfg = { + .si_val = 74, /*ʱÿ(si_val + 1)cycle, G0inc_val*/ + .inc_val = 1, + .frc_rld_rst_cnt_en = true, /*ĬtrueʾʼʱǷcounter㡣*/ + .term_use_mode = SDRV_BTM_DIRECT, /*overflowֵЧǵȵһЧ*/ + .cmp_use_mode = SDRV_BTM_DIRECT, /*compareֵЧǵȵһЧ*/ + .cnt_dir = SDRV_BTM_CNT_UP, /*üֵ*/ + .cnt_mode = SDRV_BTM_CONTINOUS_MODE, /*üģʽ*/ + } +}; + + +/*SDRV_BTM_G1ʱԴⲿ񣬵24MHz*/ +/*SDRV_BTM_G1Ƶ֮clock1M*/ +static sdrv_btm_cfg_t timer1_config = { + .base = DEVICE_BASE(BTM2), + .irq = DEVICE_INTR(BTM2_O_BTM), + .tmr_id = SDRV_BTM_G1, + .tmr_cfg = { + .si_val = 23, + .inc_val = 1, + .frc_rld_rst_cnt_en = true, + .term_use_mode = SDRV_BTM_DIRECT, + .cmp_use_mode = SDRV_BTM_DIRECT, + .cnt_dir = SDRV_BTM_CNT_UP, + .cnt_mode = SDRV_BTM_CONTINOUS_MODE, + } +}; + +//ص10msʱ־ +static void timer1_handle(void *arg) +{ + static int timer1_count = 0; + timer1_count++; + + if(timer1_count >= 100) + { + timer1_count = 0; + Btm10ms = 1; + } + + //app + timerUpdateAll(); // öʱº + +} + + +/*g1*/ +int btm_init(void) +{ + sdrv_btm_init(&gstsdrv_btm_timer1, &timer0_config);//ʱ1ʼ + sdrv_btm_set_callback(&gstsdrv_btm_timer1, timer1_handle, &gstsdrv_btm_timer1);//趨ص + sdrv_btm_start(&gstsdrv_btm_timer1, BTM_TYPE_PERIOD, BTM_TIME_US, 1000);//趨1000usʱ + + sdrv_btm_init(&gstsdrv_btm_timer0, &timer1_config);//ʱ0ʼ + sdrv_btm_start(&gstsdrv_btm_timer0, BTM_TYPE_PERIOD, BTM_TIME_MS, ~0);//趨1msʱ + return 0; +} + +//ȡǰʱ,lwip +uint32_t current_time(void) +{ + return sdrv_btm_get_current_time(&gstsdrv_btm_timer0) / 1000; +} + +//ȡǰʱus +uint32_t getCurrentTime(void) +{ + return sdrv_btm_get_current_time(&gstsdrv_btm_timer0); +} + diff --git a/interface_btm.h b/interface_btm.h new file mode 100644 index 0000000..9647e92 --- /dev/null +++ b/interface_btm.h @@ -0,0 +1,19 @@ +#ifndef __INTERFACE_BTM_H__ +#define __INTERFACE_BTM_H__ + +#include +#include +#include +#include "sdrv_btm.h" + +// +extern volatile uint8_t Btm10ms; + + +// +int btm_init(void); +extern uint32_t current_time(void); +extern uint32_t getCurrentTime(void); + + +#endif /* __BTM_INIT_H__ */ \ No newline at end of file diff --git a/interface_can.c b/interface_can.c new file mode 100644 index 0000000..bb0fff1 --- /dev/null +++ b/interface_can.c @@ -0,0 +1,1422 @@ + +#include +#include "debug.h" +#include "interface_config.h" +#include "app/app_config.h" +#define TX_PADDING_VAL (0xA5) +#include "sdrv_vic.h" +#include "intrinsics.h" +#include "app/app_differential_drive.h" +#include "app/app_param_manage.h" +#include "app/app_ultrasonic.h" + + + +uint32_t OTA_CANTxID = 0x02;//ĬϷIDΪ0x02 +uint32_t OTA_CANRxID = 0x01;//ĬϽIDΪ0x01 +uint32_t WDT_CANRxID = 0x03;//ĬϽIDΪ0x03 + + +Timer can_timer_interface1; +Timer can_timer_interface2; + +bool ecu_online = 0;//0ߣ1 + + +UnCanFault can_fault_info = { + .bit_data.navigator_count = 0, //Ǽ + .bit_data.motor1_count = 0, //ֶݼ + .bit_data.motor2_count = 0, //ֶݼ + .bit_data.bms_count = 0, //ֶݼ + .bit_data.temperature_count = 0, //¶ȼ + .bit_data.remote_count = 0, //ңؼ + + .bit_data.navigator_state = 0, //Զݼ + .bit_data.motor1_state = 0, //ֶݼ + .bit_data.motor2_state = 0, //ֶݼ + .bit_data.bms_state = 0, //ֶݼ + .bit_data.temperature_state = 0, //¶״̬ + .bit_data.remote_state = 0, //ң״̬ +}; + + + +// +//StrCanFifoQueue can0_Queue;//8֡can棬Ͷ +//StrCanFifoQueue can1_Queue; +//StrCanFifoQueue can2_Queue; +//StrCanFifoQueue can3_Queue; +//StrCanFifoQueue can4_Queue; +//StrCanFifoQueue can5_Queue; +//StrCanFifoQueue can6_Queue; +//StrCanFifoQueue can7_Queue; + + +//bool busoff_occur_flag = false;//busoff־ + +bool can_0_busoff_flag = false;//busoff־ +bool can_1_busoff_flag = false;//busoff־ +bool can_2_busoff_flag = false;//busoff־ +bool can_3_busoff_flag = false;//busoff־ +bool can_4_busoff_flag = false;//busoff־ +bool can_5_busoff_flag = false;//busoff־ +bool can_6_busoff_flag = false;//busoff־ +bool can_7_busoff_flag = false;//busoff־ + + +flexcan_handle_t can_handle_0;//canʼṹ +flexcan_handle_t can_handle_1; +flexcan_handle_t can_handle_2; +flexcan_handle_t can_handle_3; +flexcan_handle_t can_handle_4; +flexcan_handle_t can_handle_5; +flexcan_handle_t can_handle_6; +flexcan_handle_t can_handle_7; + + + +static uint8_t fifo_Data_0[8]; +static flexcan_frame_t fifo_Buf_0; + +static uint8_t fifo_Data_1[8]; +static flexcan_frame_t fifo_Buf_1; + +static uint8_t fifo_Data_2[8]; +static flexcan_frame_t fifo_Buf_2; + +static uint8_t fifo_Data_3[8]; +static flexcan_frame_t fifo_Buf_3; + +static uint8_t fifo_Data_4[8]; +static flexcan_frame_t fifo_Buf_4; + +static uint8_t fifo_Data_5[8]; +static flexcan_frame_t fifo_Buf_5; + +static uint8_t fifo_Data_6[8]; +static flexcan_frame_t fifo_Buf_6; + +static uint8_t fifo_Data_7[8]; +static flexcan_frame_t fifo_Buf_7; + + +uint8_t flexcan_config_rx_fifo(flexcan_handle_t *handle, + flexcan_rx_fifo_config_t *config) +{ + flexcan_frame_t *rx_fifo_frame; +//------------------------------------------------------------------------------ + if(CAN_INDEX_0 == (handle->controller_id))//ѡͬжϺԼַ + { + rx_fifo_frame = &fifo_Buf_0; + rx_fifo_frame->dataBuffer = &fifo_Data_0[0]; + } + else if(CAN_INDEX_1 == (handle->controller_id)) + { + rx_fifo_frame = &fifo_Buf_1; + rx_fifo_frame->dataBuffer = &fifo_Data_1[0]; + } + else if(CAN_INDEX_2 == (handle->controller_id)) + { + rx_fifo_frame = &fifo_Buf_2; + rx_fifo_frame->dataBuffer = &fifo_Data_2[0]; + } + else if(CAN_INDEX_3 == (handle->controller_id)) + { + rx_fifo_frame = &fifo_Buf_3; + rx_fifo_frame->dataBuffer = &fifo_Data_3[0]; + } + else if(CAN_INDEX_4 == (handle->controller_id)) + { + rx_fifo_frame = &fifo_Buf_4; + rx_fifo_frame->dataBuffer = &fifo_Data_4[0]; + } + else if(CAN_INDEX_5 == (handle->controller_id)) + { + rx_fifo_frame = &fifo_Buf_5; + rx_fifo_frame->dataBuffer = &fifo_Data_5[0]; + } + else if(CAN_INDEX_6 == (handle->controller_id)) + { + rx_fifo_frame = &fifo_Buf_6; + rx_fifo_frame->dataBuffer = &fifo_Data_6[0]; + } + else if(CAN_INDEX_7 == (handle->controller_id)) + { + rx_fifo_frame = &fifo_Buf_7; + rx_fifo_frame->dataBuffer = &fifo_Data_7[0]; + } + else + { + return 0; + } + + flexcan_set_rx_fifo_config(handle, config);//fifo + + for (uint8_t i = 0; i < USED_MB_FOR_FIFO; + i++) { + flexcan_set_rx_individual_mask(handle, i, config->filter_tab[i].filter_mask); + } + + /* rx by interrupt */ + flexcan_fifo_transfer_t Xfer = {rx_fifo_frame}; + flexcan_receive_fifo_nonblocking(handle, &Xfer); + + return 1; +} + + +/********************************************************************* + * @fn CAN_Send_Msg + * + * @brief CAN Transmit function. + * + * @param CANx- CAN1 or CAN2 + * ID - Message ID + * IDE - CAN_Id_Standard or CAN_Id_Extended + * RTR - CAN_RTR_Data or CAN_RTR_Remote + * msg - Transmit data buffer. + * len - Data length. + * + * @return 0 - Send successful. + * 1 - Send failed. + */ +uint8_t CAN_Send_Msg( flexcan_handle_t *handle, uint32_t ID, flexcan_frame_format_e ide, flexcan_frame_type_e rtr, uint8_t *msg, uint8_t len, uint8_t tx_index) +{ + uint16_t i = 0; +//------------------------------------------------------------------------------ + + flexcan_frame_t frame = {.id = ID, + .length = len, + .type = rtr, + .format = ide, + .dataBuffer = msg}; + flexcan_mb_transfer_t xfer = {&frame, tx_index}; + + while( ( flexcan_get_mb_state(handle, tx_index) != FLEXCAN_StateIdle ) && (i < 0xFFF) ) + { + i++; + } + + if( i == 0xFFF ) + { + return 1; + + } + else + { + flexcan_send_nonblocking(handle, &xfer, TX_PADDING_VAL); + return 0; + } +} + + + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ +void flexcan_Receive_callback_0(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ + flexcan_frame_t *buf = (flexcan_frame_t *)userData; + uint8_t i = 0; +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + + if(TEMP_MODULE_INPUT_ID_1 == (buf->id))//¶ + { + for(i = 0; i < (buf->length); i++) + { + un_sw_sample.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_sw_sample, 1);//ź + } + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_0_busoff_flag = true; + break; + + default: + break; + } +} + + + + + + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ + +//uint32_t time_elapsed = 0; +//uint32_t time_elapsed1 = 0; +void flexcan_Receive_callback_1(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ + flexcan_frame_t *buf = (flexcan_frame_t *)userData; + + uint8_t i = 0; +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + if(LEFT_FRONT_MOTOR_INPUT1 == (buf->id)) + { + can_fault_info.bit_data.motor1_count ++; + for(i = 0; i < (buf->length); i++) + { + un_motor_input1.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_input1, 1); + } + else if( LEFT_FRONT_MOTOR_INPUT2 == (buf->id) ) + { + for(i = 0; i < (buf->length); i++) + { + un_motor_temp1.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_temp1, 1);//ź + } + else if( LEFT_REAR_MOTOR2_INPUT1 == (buf->id) )// + { + can_fault_info.bit_data.motor3_count ++; + for(i = 0; i < (buf->length); i++) + { + un_motor_input3.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_input3, 1); + } + else if( LEFT_REAR_MOTOR2_INPUT2 == (buf->id) ) + { + for(i = 0; i < (buf->length); i++) + { + un_motor_temp3.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_temp3, 1);//ź + } + else{} + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_1_busoff_flag = true; + break; + + default: + break; + } +} + + + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ +void flexcan_Receive_callback_2(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ + flexcan_frame_t *buf = (flexcan_frame_t *)userData; + uint8_t i = 0; +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + if(RIGHT_FRONT_MOTOR_INPUT1 == (buf->id)) + { + can_fault_info.bit_data.motor2_count ++; + for(i = 0; i < (buf->length); i++) + { + un_motor_input2.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_input2, 1); + } + else if( RIGHT_FRONT_MOTOR_INPUT2 == (buf->id) ) + { + for(i = 0; i < (buf->length); i++) + { + un_motor_temp2.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_temp2, 1);//ź + } + else if( RIGHT_REAR_MOTOR_INPUT1 == (buf->id) )// + { + can_fault_info.bit_data.motor4_count ++; + for(i = 0; i < (buf->length); i++) + { + un_motor_input4.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_input4, 1); + } + else if( RIGHT_REAR_MOTOR_INPUT2 == (buf->id) ) + { + for(i = 0; i < (buf->length); i++) + { + un_motor_temp4.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_motor_temp4, 1);//ź + } + else{} + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_2_busoff_flag = true; + break; + + default: + break; + } +} + + + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ +void flexcan_Receive_callback_3(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ + flexcan_frame_t *buf = (flexcan_frame_t *)userData; + uint8_t i = 0; +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + + if(BMS_INPUT_ID1 == (buf->id))//BMS + { + can_fault_info.bit_data.bms_count ++; + for(i = 0; i < (buf->length); i++) + { + un_bms_input.arr[i] = buf->dataBuffer[i]; + } + publishMessage(&un_bms_input, 1); + } + else if(BMS_INPUT_ID2 == (buf->id))//BMS + { + for(i = 0; i < (buf->length); i++) + { + un_bms_input.arr[i+8] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_bms_input, 1); + } + else{} + + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_3_busoff_flag = true; + break; + + default: + break; + } +} + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ +void flexcan_Receive_callback_4(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_4_busoff_flag = true; + break; + + default: + break; + } +} + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ +void flexcan_Receive_callback_5(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_5_busoff_flag = true; + break; + + default: + break; + } +} + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ +void flexcan_Receive_callback_6(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ + flexcan_frame_t *buf = (flexcan_frame_t *)userData; + uint8_t i = 0; +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + if(OTA_CANRxID == (buf->id))//IDΪ1 boot + { + boot_can_flag = true; + FrameHeader = ( (buf->dataBuffer[0] << 8) | (buf->dataBuffer[1]) ); + } + else if(WDT_CANRxID == (buf->id))//յιID + { + if(FEEDDOG_HEADER == ( (buf->dataBuffer[0] << 8) | (buf->dataBuffer[1]) )) + { + WDTReFresh_flag = true;//ι־ + printf("Feed dog flag received %d\n",getCurrentTime()); + } + } + else if(ULTRASONIC_ID_1 == (buf->id)) + { + for(i = 0; i < (buf->length); i++) + { + un_ultrasonic_input1.arr[i] = buf->dataBuffer[i]; + } + publishMessage(&un_ultrasonic_input1, 1); + } + else{} + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_6_busoff_flag = true; + break; + + default: + break; + } +} + + + +/********************************************************************* + * @fn flexcan_Receive_callback + * + * @brief erase Data-Flash block, minimal block is 256B + * + * @param Page_Address - the address of the page being erased. + * Length - Erased data length + * + * @return none + */ +void flexcan_Receive_callback_7(flexcan_handle_t *handle, + flexcan_status_e status, uint32_t result, + void *userData) +{ + flexcan_frame_t *buf = (flexcan_frame_t *)userData; + uint8_t i = 0; + //uintptr_t +//-------------------------------------------------------------- + switch (status) + { + case FLEXCAN_RX_IDLE: + break; + + case FLEXCAN_RX_FIFO_IDLE: + if(REMOTE_ID == (buf->id))//ңCAN + { + can_fault_info.bit_data.remote_count ++; + for(i = 0; i < (buf->length); i++) + { + un_remote_control_input.arr[i] = buf->dataBuffer[i]; + } + //ź + publishMessage(&un_remote_control_input, 1); + +// printf("ori_remote_stop: %d\n", un_remote_control_input.bit_data.switch_b); + } + else + { + } + break; + + case FLEXCAN_TX_IDLE: + break; + + case FLEXCAN_WAKEUP_TIMEOUT: + break; + + case FLEXCAN_WAKEUP_MATCH: + break; + + case FLEXCAN_ERROR_STATUS: + can_7_busoff_flag = true; + break; + + default: + break; + } +} + + +//fifo_config ˲ +//can_config Լ +//call_back жϻص +uint8_t initialization_Flexcan(uint8_t can_index, const flexcan_config_t *can_config, flexcan_rx_fifo_config_t *fifo_config, flexcan_transfer_callback_t call_back) +{ + flexcan_handle_t *handle; + uint8_t can_irq_num = 0; + uint32_t can_reg_base = 0; +//------------------------------------------------------------------ + if(FLEXCAN7 == can_index)//ѡͬжϺԼַ + { + handle = &can_handle_0; + can_irq_num = CANFD7_CANFD_INTR_NUM; + can_reg_base = APB_CANFD7_BASE; + } + else if(FLEXCAN21 == can_index) + { + handle = &can_handle_1; + can_irq_num = CANFD21_CANFD_INTR_NUM; + can_reg_base = APB_CANFD21_BASE; + } + else if(FLEXCAN16 == can_index) + { + handle = &can_handle_2; + can_irq_num = CANFD16_CANFD_INTR_NUM; + can_reg_base = APB_CANFD16_BASE; + } + else if(FLEXCAN3 == can_index) + { + handle = &can_handle_3; + can_irq_num = CANFD3_CANFD_INTR_NUM; + can_reg_base = APB_CANFD3_BASE; + } + else if(FLEXCAN23 == can_index) + { + handle = &can_handle_4; + can_irq_num = CANFD23_CANFD_INTR_NUM; + can_reg_base = APB_CANFD23_BASE; + } + else if(FLEXCAN5 == can_index) + { + handle = &can_handle_5; + can_irq_num = CANFD5_CANFD_INTR_NUM; + can_reg_base = APB_CANFD5_BASE; + } + else if(FLEXCAN6 == can_index) + { + handle = &can_handle_6; + can_irq_num = CANFD6_CANFD_INTR_NUM; + can_reg_base = APB_CANFD6_BASE; + } + else if(FLEXCAN4 == can_index) + { + handle = &can_handle_7; + can_irq_num = CANFD4_CANFD_INTR_NUM; + can_reg_base = APB_CANFD4_BASE; + } + else + { + return 0; + } + + //initialize the FlexCAN handle + flexcan_create_handle(handle, can_index, (void *)can_reg_base, can_irq_num, call_back, NULL); + + /* initialize flexCAN. */ + flexcan_init(handle, can_config); + + /* unfreeze the flexCAN by demo. */ + flexcan_freeze(handle, false); + + /* enable busoff interrupt. */ + flexcan_enable_interrupts(handle, FLEXCAN_BusOffInterruptEnable);// + + /* enable irq. */ + irq_attach(handle->irq_num, flexcan_irq_handler, handle); + irq_enable(handle->irq_num); + + /* assign fifo only for rx. */ + flexcan_config_rx_fifo(handle, fifo_config); + + /* assign mailbox14-20 for tx. */ + for (uint8_t i = TX_MB_INDEX; i < (TX_MB_INDEX + TX_MAILBOX_NUM); i++) + { + flexcan_set_tx_mb_config(handle, i, true); + } + + return 1; +} + +/* reinitialize the controller. */ +void flexcan_Busoff_Recovery(void) +{ +//---------------------------------------------------------- + if (can_0_busoff_flag == true) //busoff + { + printf("can0 busoff !\n"); + flexcan_deinit(&can_handle_0); + + initialization_Flexcan(CAN_INDEX_0, &can_0_config, &can_0_fifo_config, flexcan_Receive_callback_0); + + can_0_busoff_flag = false; + } + + if (can_1_busoff_flag == true) //busoff + { + printf("can1 busoff !\n"); + flexcan_deinit(&can_handle_1); + + initialization_Flexcan(CAN_INDEX_1, &can_1_config, &can_1_fifo_config, flexcan_Receive_callback_1); + + can_1_busoff_flag = false; + } + + if (can_2_busoff_flag == true) //busoff + { + printf("can2 busoff !\n"); + flexcan_deinit(&can_handle_2); + + initialization_Flexcan(CAN_INDEX_2, &can_2_config, &can_2_fifo_config, flexcan_Receive_callback_2); + + can_2_busoff_flag = false; + } + + if (can_3_busoff_flag == true) //busoff + { + printf("can3 busoff !\n"); + flexcan_deinit(&can_handle_3); + + initialization_Flexcan(CAN_INDEX_3, &can_3_config, &can_3_fifo_config, flexcan_Receive_callback_3); + + can_3_busoff_flag = false; + } + + if (can_4_busoff_flag == true) //busoff + { + printf("can4 busoff !\n"); + flexcan_deinit(&can_handle_4); + + initialization_Flexcan(CAN_INDEX_4, &can_4_config, &can_4_fifo_config, flexcan_Receive_callback_4); + + can_4_busoff_flag = false; + } + + if (can_5_busoff_flag == true) //busoff + { + printf("can5 busoff !\n"); + flexcan_deinit(&can_handle_5); + + initialization_Flexcan(CAN_INDEX_5, &can_5_config, &can_5_fifo_config, flexcan_Receive_callback_5); + + can_5_busoff_flag = false; + } + + if (can_6_busoff_flag == true) //busoff + { + printf("can6 busoff !\n"); + flexcan_deinit(&can_handle_6); + + initialization_Flexcan(CAN_INDEX_6, &can_6_config, &can_6_fifo_config, flexcan_Receive_callback_6); + + can_6_busoff_flag = false; + } + + if (can_7_busoff_flag == true) //busoff + { + printf("can7 busoff !\n"); + flexcan_deinit(&can_handle_7); + + initialization_Flexcan(CAN_INDEX_7, &can_7_config, &can_7_fifo_config, flexcan_Receive_callback_7); + + can_7_busoff_flag = false; + } +} + + + +/* initialization_all_flexcan. */ +void initialization_All_Flexcan(void) +{ + sdrv_gpio_set_pin_output_level(GPIO_H12, 0); //CANʹ + + initialization_Flexcan(CAN_INDEX_0, &can_0_config, &can_0_fifo_config, flexcan_Receive_callback_0);//250k + + initialization_Flexcan(CAN_INDEX_1, &can_1_config, &can_1_fifo_config, flexcan_Receive_callback_1);//250k + + initialization_Flexcan(CAN_INDEX_2, &can_2_config, &can_2_fifo_config, flexcan_Receive_callback_2);//250k + + initialization_Flexcan(CAN_INDEX_3, &can_3_config, &can_3_fifo_config, flexcan_Receive_callback_3);//1M + + initialization_Flexcan(CAN_INDEX_4, &can_4_config, &can_4_fifo_config, flexcan_Receive_callback_4);//250k + + initialization_Flexcan(CAN_INDEX_5, &can_5_config, &can_5_fifo_config, flexcan_Receive_callback_5);//250k + + initialization_Flexcan(CAN_INDEX_6, &can_6_config, &can_6_fifo_config, flexcan_Receive_callback_6);//1M + + initialization_Flexcan(CAN_INDEX_7, &can_7_config, &can_7_fifo_config, flexcan_Receive_callback_7);//250k +} + + + + + + +//100ms һ +void canTimerProcess(void *signal_id) +{ + static uint8_t can_timer[5] = {0,0,0,0,0}; + static uint8_t can_temp[10] = {0,0,0,0,0,0,0,0,0,0};//мжֵ + uint8_t temp = 0; + + can_timer[0] ++; + if(can_timer[0] >= 1)//100msжһ + { + can_timer[0] = 0; + + if(can_fault_info.bit_data.motor1_count == can_temp[0])//һʾ + { + can_fault_info.bit_data.motor1_state = FAULT; + } + else + { + can_fault_info.bit_data.motor1_state = NORMAL; + can_temp[0] = can_fault_info.bit_data.motor1_count;//ݸ + } + + if(can_fault_info.bit_data.motor1_state != can_temp[1]) + { + can_temp[1] = can_fault_info.bit_data.motor1_state; + temp ++; + } + + + if(can_fault_info.bit_data.motor2_count == can_temp[2])//һʾ + { + can_fault_info.bit_data.motor2_state = FAULT; + } + else + { + can_fault_info.bit_data.motor2_state = NORMAL; + can_temp[2] = can_fault_info.bit_data.motor2_count;//ݸ + } + + if(can_fault_info.bit_data.motor2_state != can_temp[3]) + { + can_temp[3] = can_fault_info.bit_data.motor2_state; + temp ++; + } + } + + can_timer[1] ++;//BMSж + if(can_timer[1] >= 20)//2sжһ + { + can_timer[1] = 0; + //BMS + if(can_fault_info.bit_data.bms_count == can_temp[4])//һʾ + { + can_fault_info.bit_data.bms_state = FAULT; + } + else + { + can_fault_info.bit_data.bms_state = NORMAL; + can_temp[4] = can_fault_info.bit_data.bms_count;//ݸ + } + if(can_fault_info.bit_data.bms_state != can_temp[5]) + { + can_temp[5] = can_fault_info.bit_data.bms_state; + temp ++; + } + + //¶ģ + if(can_fault_info.bit_data.temperature_count == can_temp[6])//һʾ + { + can_fault_info.bit_data.temperature_state = FAULT; + } + else + { + can_fault_info.bit_data.temperature_state = NORMAL; + can_temp[6] = can_fault_info.bit_data.temperature_count;//ݸ + } + if(can_fault_info.bit_data.temperature_state != can_temp[7]) + { + can_temp[7] = can_fault_info.bit_data.temperature_state; + temp ++; + } + } + + can_timer[2] ++;//ңж + if(can_timer[2] >= 5)//500msжһ + { + can_timer[2] = 0; + //ң + if(can_fault_info.bit_data.remote_count == can_temp[8])//һʾ + { + can_fault_info.bit_data.remote_state = FAULT; + } + else + { + can_fault_info.bit_data.remote_state = NORMAL; + can_temp[8] = can_fault_info.bit_data.remote_count;//ݸ + } + if(can_fault_info.bit_data.remote_state != can_temp[9]) + { + can_temp[9] = can_fault_info.bit_data.remote_state; + temp ++; + } + } + + can_timer[4] ++;//ڷź + if( (0 != temp) || (can_timer[4] >= 5) )//500źţ仯 + { + can_timer[4] = 0; + publishMessage(&can_fault_info, 1);// + } + + //busoffж + can_timer[3] ++; + if(can_timer[3] >= 10)//100*100*10 = 1sһ + { + can_timer[3] = 0; + + flexcan_Busoff_Recovery();//BUSS OFF + } +} + + +//static void processSdoOutput1(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_3, 0x601, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_sdo_output1, 8, 15);// +//} +// +//static void processSdoOutput2(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_3, 0x601, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_sdo_output2, 8, 16); +//} +// +//static void processSdoOutput3(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_3, 0x601, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_sdo_output3, 8, 17); +//} +// +//static void processSdoOutput4(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_3, 0x601, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_sdo_output4, 8, 18); +//} +// +//static void processSdoOutput5(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_3, 0x601, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_sdo_output5, 8, 19); +//} +// +// +//static void processSdoOutput7(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_3, 0x601, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_sdo_output7, 8, 20); +//} + + + +static void processMotorOutput1(void *signal_id) +{ + (void)signal_id; // DZΪʹã + CAN_Send_Msg(&can_handle_1, LEFT_FRONT_MOTOR_OUTPUT1, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output1, 8, 15);//1Ťغת + CAN_Send_Msg(&can_handle_1, LEFT_REAR_MOTOR_OUTPUT1, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output3, 8, 16);//1Ťغת +} + +static void processMotorOutput2(void *signal_id) +{ + (void)signal_id; // DZΪʹã + CAN_Send_Msg(&can_handle_2, RIGHT_FRONT_MOTOR_OUTPUT1, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output2, 8, 15);//2Ťغת + CAN_Send_Msg(&can_handle_2, RIGHT_REAR_MOTOR_OUTPUT1, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output4, 8, 16);//2Ťغת +} + +static void processMotorOutput3(void *signal_id) +{ + (void)signal_id; // DZΪʹã + + CAN_Send_Msg(&can_handle_1, LEFT_FRONT_MOTOR_OUTPUT2, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output1.arr[8], 8, 17);//1 + CAN_Send_Msg(&can_handle_1, LEFT_REAR_MOTOR_OUTPUT2, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output3.arr[8], 8, 17);//1 + +} + +static void processMotorOutput4(void *signal_id) +{ + (void)signal_id; // DZΪʹã + CAN_Send_Msg(&can_handle_2, RIGHT_FRONT_MOTOR_OUTPUT2, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output2.arr[8], 8, 17);//2 + CAN_Send_Msg(&can_handle_2, RIGHT_FRONT_MOTOR_OUTPUT2, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_motor_output4.arr[8], 8, 17);//2 +} + +static void processKgfOutput1(void *signal_id) +{ + (void)signal_id; // DZΪʹã + CAN_Send_Msg(&can_handle_0, 0x11000002, FLEXCAN_EXTEND_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_inf_can_kgf_output1, 8, 15);//KGF1 +} + +static void processKgfOutput2(void *signal_id) +{ + (void)signal_id; // DZΪʹã + if(1 == ecu_online)//20250318 ޸Ϊ߲ܷͣɼģE3ͬʱ + { + un_inf_can_kgf_output2.bit_data.can_rx5 = 0xE3; + CAN_Send_Msg(&can_handle_0, 0x14000002, FLEXCAN_EXTEND_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_inf_can_kgf_output2, 8, 16);//KGF2 + } + +} + +//static void processKgfOutput2(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// if(1 == ecu_online)//20250318 ޸Ϊ߲ܷͣɼģE3ͬʱ +// { +// un_inf_can_kgf_output2.bit_data.can_rx5 = 0xE3; +// CAN_Send_Msg(&can_handle_0, 0x14000002, FLEXCAN_EXTEND_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_inf_can_kgf_output2, 8, 16);//KGF2 +// } +// +//} + + + +static void processWheelSpeedOutput(void *signal_id) +{ + float CANPressSpeedTemp = 0.0;//ٶȼмֵ + (void)signal_id; // DZΪʹã + + CANPressSpeedTemp = (diff_data.left_motor_speed*(float)getParam("whl_dia") * M_PI*60)/1000.0/(float)getParam("gRatio");// ת/ӡkm/h һȦ1.8 20241016 Լٱ + CANPressSpeedTemp = CANPressSpeedTemp*100;//,Ҫ100 ,ϵ0.01 + un_wheel_wpeed_output.bit_data.left_front = (uint16_t)((int16_t)(CANPressSpeedTemp));//ת*1.8*60*100/1000/ ת/ӡkm/h һȦ1.8,Ҫ100ϵΪ0.01תΪ޷ͣ 20240629 ٱȲҪѾ + un_wheel_wpeed_output.bit_data.left_rear = (uint16_t)((int16_t)(CANPressSpeedTemp));//תΪintתΪ޷ + + CANPressSpeedTemp = (diff_data.right_motor_speed*(float)getParam("whl_dia") * M_PI*60)/1000.0/(float)getParam("gRatio");// ת/ӡkm/h һȦ1.8 + CANPressSpeedTemp = CANPressSpeedTemp*100;//,Ҫ100 ,ϵ0.01 + un_wheel_wpeed_output.bit_data.right_front = (uint16_t)((int16_t)(CANPressSpeedTemp));//ת*1.8*60*100/1000/ ת/ӡkm/h һȦ1.8,Ҫ100ϵΪ0.01תΪ޷ͣ 20240629 ٱȲҪѾ + un_wheel_wpeed_output.bit_data.right_rear = (uint16_t)((int16_t)(CANPressSpeedTemp));//תΪintתΪ޷ + + CAN_Send_Msg(&can_handle_4, 0x98, FLEXCAN_EXTEND_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_wheel_wpeed_output, 8, 15);// +} + +static void processHBridgeOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + CAN_Send_Msg(&can_handle_0, 0x7F2, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_h_bridge_output, 8, 17);//H +} + +static void processUnGatherOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + CAN_Send_Msg(&can_handle_0, 0x15000002, FLEXCAN_EXTEND_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_gather_output, 8, 18);//ɼ +} + + + +static void processUltrasonicOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + CAN_Send_Msg(&can_handle_6, ULTRASONIC_ID_1, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_ultrasonic_output1, 8, 15);// +} + +//static void processHBridgeOutput2(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_5, 0x722, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_h_bridge_output2, 8, 16);//H +//} + + +//static void processLifterOutput(void *signal_id) +//{ +// (void)signal_id; // DZΪʹã +// CAN_Send_Msg(&can_handle_5, 0x6F2, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, (uint8_t *)&un_lifter_output, 8, 17);//Ƹ +//} + + + + +//can 100msһ +void canSendAll(void *signal_id) +{ + static uint16_t wheel_speed_cnt = 0; +// static uint8_t kgf_cnt = 0; + static uint16_t bms_cnt1 = 0; + static uint16_t bms_cnt2 = 0; +// static uint16_t motor_speed_cnt = 0; + static uint16_t motor_power_cnt = 0; +// static uint8_t h_bridge_cnt = 0; + uint8_t CanData[8] = {0,0,0,0,0,0,0,0}; +//------------------------------------------------------------------------- + (void)signal_id; // DZΪʹã + + bms_cnt1 ++; + if(bms_cnt1 >= 1000)//1s + { + bms_cnt1 = 0; + + CanData[0] = 0x5A; + + CAN_Send_Msg(&can_handle_3, 0x100, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 1, 15);//BMS + } + + bms_cnt2 ++; + if(bms_cnt2 >= 1100)//1s + { + bms_cnt2 = 0; + + CanData[0] = 0x5A; + + CAN_Send_Msg(&can_handle_3, 0x101, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 1, 16);//BMS + } + + + motor_power_cnt ++; + if(motor_power_cnt >= 1000)//1sһ + { + motor_power_cnt = 0; + processMotorOutput3(CanData); + processMotorOutput4(CanData); + } + +// motor_power_cnt ++; +// if(motor_power_cnt >= 10)//ȡת 20ms +// { +// motor_power_cnt = 0; +// +// un_motor_output1.bit_data.MotCon_1Signal6 = 0x84; +// un_motor_output1.bit_data.MotCon_1Signal7 = 0x02; +// un_motor_output2.bit_data.MotCon_1Signal6 = 0x84; +// un_motor_output2.bit_data.MotCon_1Signal7 = 0x02; +// +// processMotorOutput3(CanData); +// processMotorOutput4(CanData); +// } + +// kgf_cnt ++; +// if(kgf_cnt >= 5)//20210312 CANͨѶģ 20210710޸Ϊ50ms +// { +// kgf_cnt = 0; +// +// processKgfOutput1(CanData); +// processKgfOutput2(CanData); +// } +// + //ٷ + wheel_speed_cnt ++; + if(wheel_speed_cnt >= 100) + { + wheel_speed_cnt = 0; + + processWheelSpeedOutput(CanData); + +// CAN_Send_Msg(&can_handle_0, 0x120, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 8, 16);//BMS +// CAN_Send_Msg(&can_handle_1, 0x121, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 8, 17);//BMS +// CAN_Send_Msg(&can_handle_2, 0x122, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 8, 17);//BMS +// CAN_Send_Msg(&can_handle_3, 0x123, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 8, 16);//BMS +// CAN_Send_Msg(&can_handle_4, 0x124, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 8, 16);//BMS +// CAN_Send_Msg(&can_handle_5, 0x125, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 8, 16);//BMS + CAN_Send_Msg(&can_handle_6, 0x126, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, &un_can_debug_output.arr[0], 8, 16);//BMS +// CAN_Send_Msg(&can_handle_7, 0x127, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, CanData, 8, 16);//BMS + } +// + + //Hݷ +// h_bridge_cnt ++; +// if(h_bridge_cnt >= 5) +// { +// h_bridge_cnt = 0; +// +// processHBridgeOutput(CanData); +// } + + timerStart(&can_timer_interface1,1,1);//1msһ +} + + + + +// canʱźŴ +static void canInterfaceTimerProcess(void *signal_id) +{ + (void)signal_id; // DZΪʹã +// uint32_t time_boot = getCurrentTime();//¼ǰʱ + + canTimerProcess(signal_id); + +// printf("motor1 interval:%d,motor2 interval:%d\n",time_elapsed,time_elapsed1);//ӡ12ռ + + timerStart(&can_timer_interface2,100,1);//100msһ + +// printf("canInterface spend time:%d\n",getCurrentTime() - time_boot);//app˶೤ʱ +} + +static void canInterfaceInput(void *signal_id) +{ + if (signal_id == &un_sw_sample) + { + ecu_online = un_sw_sample.bit_data.flg_wake_ecu; + } +} + + + +// APPģijʼ +void canInterfaceInit(void) +{ + memset(&un_motor_input1, 0, sizeof(UnMotorInput)); + memset(&un_motor_input2, 0, sizeof(UnMotorInput)); + memset(&un_bms_input , 0, sizeof(UnBmsInput)); + memset(&un_temp_module_input, 0, sizeof(UnTempModuleInput)); + + memset(&un_motor_output1, 0, sizeof(UnMotorOutput)); + memset(&un_motor_output2, 0, sizeof(UnMotorOutput)); + +// un_motor_output1.bit_data.mode = 0x05; +// un_motor_output1.bit_data.gear = 0x01; +// un_motor_output1.bit_data.can_gear = 0x01; +// un_motor_output1.bit_data.motor_direction = 0x01; +// un_motor_output1.bit_data.control_data1 = 0x0; +// un_motor_output1.bit_data.control_data2 = 0x0; +// +// un_motor_output2.bit_data.mode = 0x05; +// un_motor_output2.bit_data.gear = 0x01; +// un_motor_output2.bit_data.can_gear = 0x01; +// un_motor_output2.bit_data.motor_direction = 0x00; +// un_motor_output2.bit_data.control_data1 = 0x0; +// un_motor_output2.bit_data.control_data2 = 0x0; +// +// un_motor_output3.bit_data.mode = 0x05; +// un_motor_output3.bit_data.gear = 0x01; +// un_motor_output3.bit_data.can_gear = 0x01; +// un_motor_output3.bit_data.motor_direction = 0x01; +// un_motor_output3.bit_data.control_data1 = 0x0; +// un_motor_output3.bit_data.control_data2 = 0x0; +// +// un_motor_output4.bit_data.mode = 0x05; +// un_motor_output4.bit_data.gear = 0x01; +// un_motor_output4.bit_data.can_gear = 0x01; +// un_motor_output4.bit_data.motor_direction = 0x00; +// un_motor_output4.bit_data.control_data1 = 0x0; +// un_motor_output4.bit_data.control_data2 = 0x0; + + + +// un_motor_output1.bit_data.set_torque = 30000;//ƫʼ +// un_motor_output1.bit_data.set_rotation_speed = 30000; +// un_motor_output1.bit_data.mode = 0; +// un_motor_output2.bit_data.set_torque = 30000; +// un_motor_output2.bit_data.set_rotation_speed = 30000; +// un_motor_output2.bit_data.mode = 0; +// can_fault_info.bit_data.navigator_state = 1; + + memset(&un_inf_can_kgf_output1, 0, sizeof(UnInfCanKGFOutput)); + memset(&un_inf_can_kgf_output2, 0, sizeof(UnInfCanKGFOutput)); + memset(&un_h_bridge_output, 0, sizeof(UnHBridgeOutput)); + memset(&un_wheel_wpeed_output, 0, sizeof(UnWheelSpeedOutput)); + memset(&un_remote_control_input, 0, sizeof(UnRemoteControlInput)); + + un_inf_can_kgf_output2.bit_data.KGF04 = 1;//ɱǿԼϵͨ + + + // ʼʱʹ brake_timer ĵַΪźID + timerInit(&can_timer_interface1); + timerInit(&can_timer_interface2); + + subscribe(&can_timer_interface1, canSendAll); + subscribe(&can_timer_interface2, canInterfaceTimerProcess); + subscribe(&un_motor_output1, processMotorOutput1); + subscribe(&un_motor_output2, processMotorOutput2); + subscribe(&un_inf_can_kgf_output1, processKgfOutput1); + subscribe(&un_inf_can_kgf_output2, processKgfOutput2); + subscribe(&un_wheel_wpeed_output, processWheelSpeedOutput); + subscribe(&un_h_bridge_output, processHBridgeOutput); + subscribe(&un_gather_output, processUnGatherOutput); + subscribe(&un_sw_sample, canInterfaceInput); // ͣءѹ ѱ־ + subscribe(&un_ultrasonic_output1, processUltrasonicOutput); // + + + + + + + + +// subscribe(&un_h_bridge_output2, processHBridgeOutput2); +// subscribe(&un_lifter_output, processLifterOutput); + +// subscribe(&un_sdo_output1, processSdoOutput1); +// subscribe(&un_sdo_output2, processSdoOutput2); +// subscribe(&un_sdo_output3, processSdoOutput3); +// subscribe(&un_sdo_output4, processSdoOutput4); +// subscribe(&un_sdo_output5, processSdoOutput5); +// subscribe(&un_sdo_output7, processSdoOutput7); + + timerStart(&can_timer_interface1,1,1);//1msһ + + timerStart(&can_timer_interface2,100,1);//100msһ + + printf( "canInterface: initial OK %d\n",getCurrentTime()); +} + + + diff --git a/interface_can.h b/interface_can.h new file mode 100644 index 0000000..7d388d9 --- /dev/null +++ b/interface_can.h @@ -0,0 +1,204 @@ + +#ifndef _INTERFACE_CAN_H_ +#define _INTERFACE_CAN_H_ + +#include "regs_base.h" +#include "irq_num.h" +#include + + +#define CAN_INDEX_0 FLEXCAN7 +#define CAN_INDEX_1 FLEXCAN21 +#define CAN_INDEX_2 FLEXCAN16 +#define CAN_INDEX_3 FLEXCAN3 +#define CAN_INDEX_4 FLEXCAN23 +#define CAN_INDEX_5 FLEXCAN5 +#define CAN_INDEX_6 FLEXCAN6 +#define CAN_INDEX_7 FLEXCAN4 + + + +#define TX_MB_INDEX (USED_MB_FOR_FIFO) + + +#define LEFT_FRONT_MOTOR_INPUT1 0x101 +#define LEFT_FRONT_MOTOR_INPUT2 0x103//¶ + + +#define LEFT_REAR_MOTOR2_INPUT1 0x102 +#define LEFT_REAR_MOTOR2_INPUT2 0x104//¶ + + +#define RIGHT_FRONT_MOTOR_INPUT1 0x101 +#define RIGHT_FRONT_MOTOR_INPUT2 0x103//¶ + + +#define RIGHT_REAR_MOTOR_INPUT1 0x102 +#define RIGHT_REAR_MOTOR_INPUT2 0x104//¶ + + +#define LEFT_FRONT_MOTOR_OUTPUT1 0x201 +#define LEFT_FRONT_MOTOR_OUTPUT2 0x103 + +#define LEFT_REAR_MOTOR_OUTPUT1 0x202 +#define LEFT_REAR_MOTOR_OUTPUT2 0x104 + +#define RIGHT_FRONT_MOTOR_OUTPUT1 0x201 +#define RIGHT_FRONT_MOTOR_OUTPUT2 0x103 + +#define RIGHT_REAR_MOTOR_OUTPUT1 0x202 +#define RIGHT_REAR_MOTOR_OUTPUT2 0x104 + + + + +//#define MOTOR_INPUT_ID_1 0x15000003//ɼģ +//#define MOTOR_INPUT_ID_2 0x10F92708//ǰ +//#define MOTOR_INPUT_ID_3 0x15000003//ɼģ +//#define MOTOR_INPUT_ID_4 0x10F94708//Һ +// +// +#define MOTOR_INPUT_ID_5 0x10F81708//ǰ λ +#define MOTOR_INPUT_ID_6 0x10F82708//ǰ +#define MOTOR_INPUT_ID_7 0x10F83708// +#define MOTOR_INPUT_ID_8 0x10F84708//Һ + + + + +#define BMS_INPUT_ID1 0x100 +#define BMS_INPUT_ID2 0x101 +#define REMOTE_ID 0x12000023 +#define TEMP_MODULE_INPUT_ID_1 0x15000003 + + + +#define CAN_FIFO_SIZE 8 + +//#define TEMP_MODULE_INPUT_ID_2 0x302 + + +// Ϣ +typedef struct _StrCanFault +{ + uint8_t navigator_count; //Ǽ + uint8_t motor1_count; //ֶݼ + uint8_t motor2_count; //ֶݼ + uint8_t motor3_count; //ֶݼ + uint8_t motor4_count; //ֶݼ + + uint8_t bms_count; //bms + uint8_t temperature_count; //¶ȼ + uint8_t remote_count; //ңؼ + + uint8_t navigator_state; //״̬ + uint8_t motor1_state; //1״̬ + uint8_t motor2_state; //2״̬ + uint8_t motor3_state; //1״̬ + uint8_t motor4_state; //2״̬ + uint8_t bms_state; //bms״̬ + uint8_t temperature_state; //¶ȼ + uint8_t remote_state; //ң״̬ +} StrCanFault; + +typedef union _UnCanFault +{ + StrCanFault bit_data; // ʹöĽṹ + uint8_t arr[sizeof(StrCanFault)]; // ͨṹȷС +} UnCanFault; + + + + + +// canڵ +typedef struct _StrCanBuffer +{ + uint32_t id; //**< CAN Frame Identifier. */ + uint8_t dataBuffer[8]; //ݻ + unsigned int length : 7; //**< CAN frame payload length in bytes(Range: 0~8). */ + unsigned int type : 1; //**< CAN Frame Type(DATA or REMOTE). */ + unsigned int format : 1; //**< CAN Frame Identifier(STD or EXT format). */ + +}StrCanBuffer; + + + +typedef struct Fifo_Queue_Tag +{ + StrCanBuffer Data[CAN_FIFO_SIZE];// + uint8_t front;//ͷָ + uint8_t rear;//βָ +}StrCanFifoQueue; + + + + + + + + + + + + + + + +#define ON 1 +#define OFF 0 + +#define left_motor_fan(Value) un_inf_can_kgf_output1.bit_data.KGF01 = Value;// +#define right_motor_fan(Value) un_inf_can_kgf_output1.bit_data.KGF03 = Value;// +#define pre_charge_relay(Value) un_inf_can_kgf_output1.bit_data.KGF04 = Value;//Ԥ +#define high_voltage_relay(Value) un_inf_can_kgf_output1.bit_data.KGF07 = Value;un_inf_can_kgf_output1.bit_data.KGF08 = Value//ѹ̵ +#define low_voltage_relay(Value) un_inf_can_kgf_output1.bit_data.KGF11 = Value;un_inf_can_kgf_output1.bit_data.KGF12 = Value//ѹ̵ +#define yellow_light(Value) un_inf_can_kgf_output1.bit_data.KGF06 = Value;//Ƶ +#define red_light(Value) un_inf_can_kgf_output1.bit_data.KGF09 = Value;// +#define left_vehicle_fan(Value) un_inf_can_kgf_output1.bit_data.KGF14 = Value;// +#define right_vehicle_fan(Value) un_inf_can_kgf_output2.bit_data.KGF03 = Value;//ҷ +#define computer(Value) un_inf_can_kgf_output2.bit_data.KGF01 = Value;un_inf_can_kgf_output2.bit_data.KGF02 = Value// +#define network_switch(Value) un_inf_can_kgf_output2.bit_data.KGF05 = Value;un_inf_can_kgf_output2.bit_data.KGF06 = Value//罻· + +//H +#define brake_motor_forward un_h_bridge_output.bit_data.channel_01 = ON ;un_h_bridge_output.bit_data.channel_04 = ON ;un_h_bridge_output.bit_data.channel_02 = OFF;un_h_bridge_output.bit_data.channel_03 = OFF;un_h_bridge_output.bit_data.sleep_01 = ON ;un_h_bridge_output.bit_data.sleep_02 = ON//ת +#define brake_motor_reversal un_h_bridge_output.bit_data.channel_01 = OFF;un_h_bridge_output.bit_data.channel_04 = OFF;un_h_bridge_output.bit_data.channel_02 = ON ;un_h_bridge_output.bit_data.channel_03 = ON ;un_h_bridge_output.bit_data.sleep_01 = ON ;un_h_bridge_output.bit_data.sleep_02 = ON//ת +#define brake_motor_off un_h_bridge_output.bit_data.channel_01 = OFF;un_h_bridge_output.bit_data.channel_04 = OFF;un_h_bridge_output.bit_data.channel_02 = OFF;un_h_bridge_output.bit_data.channel_03 = OFF;un_h_bridge_output.bit_data.sleep_01 = OFF;un_h_bridge_output.bit_data.sleep_02 = OFF//ر + + + + +//ⲿ +void flexcan_transfer_callback(flexcan_handle_t *handle,flexcan_status_e status, uint32_t result,void *userData); +uint8_t flexcan_config_rx_fifo(flexcan_handle_t *handle,flexcan_rx_fifo_config_t *config); +uint8_t CAN_Send_Msg( flexcan_handle_t *handle, uint32_t ID, flexcan_frame_format_e ide, flexcan_frame_type_e rtr, uint8_t *msg, uint8_t len, uint8_t tx_index); +void flexcan_Busoff_Recovery(void); +void initialization_All_Flexcan(void); + + + + +//ⲿ +extern flexcan_handle_t g_flexcan_handle; +extern bool busoff_occur_flag;//־ +extern bool WDTReFresh_flag;//±־ +extern flexcan_handle_t g_flexcan_handle; +extern uint16_t FrameHeader;//֡ͷ +extern flexcan_handle_t can_handle_0;//canʼṹ +extern flexcan_handle_t can_handle_1; +extern flexcan_handle_t can_handle_2; +extern flexcan_handle_t can_handle_3; +extern flexcan_handle_t can_handle_4; +extern flexcan_handle_t can_handle_5; +extern flexcan_handle_t can_handle_6; +extern flexcan_handle_t can_handle_7; +extern UnCanFault can_fault_info; + +extern uint32_t time_elapsed; +extern uint32_t time_elapsed1; + +//ⲿ +void canInterfaceInit(void); + + +#endif /* INTERFACE_CAN_H */ \ No newline at end of file diff --git a/interface_config.h b/interface_config.h new file mode 100644 index 0000000..cb6ba5b --- /dev/null +++ b/interface_config.h @@ -0,0 +1,70 @@ +#ifndef _INTERFACE_CONFIG_H_ +#define _INTERFACE_CONFIG_H_ + +//ͷļ +#include "interface.h" +#include "interface_can.h" +#include "interface_gpio.h" +#include "interface_ethernet.h" +#include "interface_btm.h" +#include "interface_boot.h" +#include "interface_wdt.h" +#include "interface_24c02.h" + +#include "app/app_frm_monitor.h" +#include "app/app_frm_signal.h" +#include "app/app_frm_timer.h" + + + +#include "irq.h" +#include +#include +#include "lwip/udp.h" +#include +#include +#include "debug.h" +#include +#include "board.h" + + + + + + + + + + + + +#endif /* _INTERFACE_CONFIG_H_ */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface_ethernet.c b/interface_ethernet.c new file mode 100644 index 0000000..76df6e1 --- /dev/null +++ b/interface_ethernet.c @@ -0,0 +1,660 @@ +#include +#include +#include "debug.h" +#include +#include +#include "interface_ethernet.h" +#include "eth_cfg.h" +#include "lwip/timeouts.h" +#include "sdrv_eth.h" +#include "app/app_param_manage.h" +#include "app/app_differential_drive.h" + + +// +#define MAX_BUFFER_SIZE (sizeof(((RequestContext *)0)->param_request->arr)) +#define MAX_PACKET_SIZE 1024 // СΪ1K + +Timer ethernet_timer_interface; +Timer ethernet_timer_interface1; + +struct udp_pcb *udpcb_1; +struct udp_pcb *udpcb_2; +struct udp_pcb *udpcb_3; +struct udp_pcb *udpcb_4; +struct udp_pcb *udpcb_5; + +bool eth_pool_rx = false; + + +UnEthernetFault ethernet_fault_Info = { + .bit_data.auto_count = 0, + .bit_data.manual_count = 0, + .bit_data.auto_state = 0, + .bit_data.manual_state = 0, +}; + + + +StrEthernetParameter ethernet_parameter = { + .local_ip = {192,168,17,20}, + .mask = {255,255,255,0}, + .computer_ip = {192,168,17,3}, + .local_communication_port = 8011, + .Local_upper_port = 8000, + .Local_download_port = 7811, + .upper_ip = {192,168,17,3}, + .download_ip = {192,168,17,183}, + .target_upper_port = 8000, + .target_download_port = 7811, + .target_communication_port = 8011, +}; + + + +static bool g_eth1_rx_pkt; + + + +static void eth_dma_rx_int_cb(struct net_driver_s *dev) +{ + if (dev == &g_eth1_dev) + g_eth1_rx_pkt = true; + +// printf("eth_dma_rx_int_cb\n"); +} + + + + +static void lwip_Ethernet(void *signal_id) +{ +// uint32_t time_boot = getCurrentTime();//¼ǰʱ + (void)signal_id; // DZΪʹã + // ETH֡ݸLWIPЭջ + // ʹܽжϣΪISRdisableжϣˣ + // жϽձ־(g_eth1_rx_pkt)Ĵв + // µĽжϱӦԣﲻԭ⡣ + if ((!eth_pool_rx && g_eth1_rx_pkt) || eth_pool_rx) + { + g_eth1_rx_pkt = false; + dwc_eth_rx(&g_eth1_dev, eth_pool_rx); + } + + // LWIPЭջӿڣLWIPʱ + sys_check_timeouts(); + + timerStart(ðernet_timer_interface1, 10,1); //10msһ + + // printf("lwipInterface spend time:%d\n",getCurrentTime() - time_boot);//app˶೤ʱ +} + + +//err_t +//udp_bind(struct udp_pcb *pcb, const ip_addr_t *ipaddr, u16_t port) + +int8_t UdpSendToData(uint8_t udpcbID, uint8_t *buf, uint16_t len, uint8_t *sip, uint16_t port) +{ + struct pbuf *DesPuff = NULL; + ip4_addr_t Desaddr; + int8_t SendState = 0; +//---------------------------------------------------------------------------------------------------- + IP4_ADDR(&Desaddr,sip[0],sip[1],sip[2],sip[3]);//ֵַת + + DesPuff = pbuf_alloc(PBUF_TRANSPORT, len, PBUF_POOL); /* ڴ */ + + pbuf_take(DesPuff, buf, len); /* g_lwip_demo_sendbufеݴpbufṹ */ + + if(UDPCB_1 == udpcbID) + { + SendState = udp_sendto(udpcb_1, DesPuff, &Desaddr, port); + } + else if(UDPCB_2 == udpcbID) + { + SendState = udp_sendto(udpcb_2, DesPuff, &Desaddr, port); + } + else if(UDPCB_3 == udpcbID) + { + SendState = udp_sendto(udpcb_3, DesPuff, &Desaddr, port); + } + else if(UDPCB_3 == udpcbID) + { + SendState = udp_sendto(udpcb_3, DesPuff, &Desaddr, port); + } + else if(UDPCB_4 == udpcbID) + { + SendState = udp_sendto(udpcb_4, DesPuff, &Desaddr, port); + } + else if(UDPCB_5 == udpcbID) + { + SendState = udp_sendto(udpcb_5, DesPuff, &Desaddr, port); + } + else + { + } + pbuf_free(DesPuff); /* ͷڴ */ + + return SendState; +} + +// udpcbID UDP +//recv ص +//port 󶨶˿ +void UDP_Echo_Init(uint8_t udpcbID, udp_recv_fn recv, uint16_t port) +{ +//------------------------------------------ + if(UDPCB_1 == udpcbID) + { + /* ½һƿ*/ + udpcb_1 = udp_new(); + ASSERT(udpcb_1); + /* 󶨶˿ں */ + udp_bind(udpcb_1, IP_ADDR_ANY, port); + /* עݻص */ + udp_recv(udpcb_1, recv, (void *)udpcbID); + } + else if(UDPCB_2 == udpcbID) + { + /* ½һƿ*/ + udpcb_2 = udp_new(); + ASSERT(udpcb_2); + /* 󶨶˿ں */ + udp_bind(udpcb_2, IP_ADDR_ANY, port); + /* עݻص */ + udp_recv(udpcb_2, recv, (void *)udpcbID); + } + else if(UDPCB_3 == udpcbID) + { + /* ½һƿ*/ + udpcb_3 = udp_new(); + ASSERT(udpcb_3); + /* 󶨶˿ں */ + udp_bind(udpcb_3, IP_ADDR_ANY, port); + /* עݻص */ + udp_recv(udpcb_3, recv, (void *)udpcbID); + } + else if(UDPCB_4 == udpcbID) + { + /* ½һƿ*/ + udpcb_4 = udp_new(); + ASSERT(udpcb_4); + /* 󶨶˿ں */ + udp_bind(udpcb_4, IP_ADDR_ANY, port); + /* עݻص */ + udp_recv(udpcb_4, recv, (void *)udpcbID); + } + else if(UDPCB_5 == udpcbID) + { + /* ½һƿ*/ + udpcb_5 = udp_new(); + ASSERT(udpcb_5); + /* 󶨶˿ں */ + udp_bind(udpcb_5, IP_ADDR_ANY, port); + /* עݻص */ + udp_recv(udpcb_5, recv, (void *)udpcbID); + } + else + { + } + +} + + + +void udp_Callback_1(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + uint8_t *buf = (uint8_t *)(p->payload); + uint16_t i = 0; + uint16_t len = 0; + uint16_t udp_temp = 0; +//------------------------------------------------------------------------------ + + if( (0xFF == buf[0] ) && ( 0xBB == buf[1] ) )//ֶңԶң + { + ethernet_fault_Info.bit_data.manual_count ++; + + if( (p->len) >= sizeof(UnManualComputerInput) )//ȡȳȡС + { + len = sizeof(UnManualComputerInput); + } + else + { + len = p->len; + } + + for(i = 0; i < len; i++) + { + un_manual_computer_input.arr[i] = buf[i]; + } + publishMessage(&un_manual_computer_input, 1); + +// p->len = len; +// printf("Manualrecive len:%d\n",len); +// udp_sendto(upcb, p, addr, port); + } + else if( (0xFF == buf[0] ) && (0xCC == buf[1] ) )// Զ + { + ethernet_fault_Info.bit_data.auto_count ++; + + if( (p->len) >= sizeof(UnAutoComputerInput) )//ȡȳȡС + { + len = sizeof(UnAutoComputerInput); + } + else + { + len = p->len; + } + + +// unsigned int frame_header : 16; // ֡ͷ ̶ֵ0xFFCC +// unsigned int frame_type : 16; // ֡ ̶ֵ0x0001 +// unsigned int frame_length : 8; // ֡ ̶ֵ0x19 +// unsigned int heartbeat : 8; // ֡ۼ +// unsigned int set_speed : 16; // 趨ٶ ϵ0.01ΪǰΪ λm/s +// unsigned int set_curvature : 16; // 趨 ϵ0.0001ΪתΪת +// unsigned int latitude : 32; // γ ϵ10^-7431234567ʾ43.1234567 +// unsigned int longitude : 32; // ϵ10^-7431234567ʾ43.1234567 +// unsigned int altitude : 32; // ߶ λmm +// unsigned int heading : 16; // 35999ʾ359.99 +// unsigned int crc : 8; // CRC ֽۼ֮ͣȡ8λ + for(i = 0; i < len; i++) + { + un_auto_computer_input.arr[i] = buf[i]; + } + + udp_temp = ((un_auto_computer_input.bit_data.set_speed << 8) | (un_auto_computer_input.bit_data.set_speed >> 8));//趨ٶ 20240928 ޸ĸߵλ + un_auto_computer_input.bit_data.set_speed = udp_temp; + + udp_temp = ((un_auto_computer_input.bit_data.set_curvature << 8) | (un_auto_computer_input.bit_data.set_curvature >> 8));//趨 + un_auto_computer_input.bit_data.set_curvature = udp_temp; + publishMessage(&un_auto_computer_input, 1); + +// p->len = len; +// printf("Autorecive len:%d\n",len); +// udp_sendto(upcb, p, addr, port); + } + else + { + } + + pbuf_free(p); +} + + + +void udp_Callback_2(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + uint8_t *buf = (uint8_t *)(p->payload); + uint8_t ip_addr[4] = {0,0,0,0}; + +//------------------------------------------------------------------------------------------------ + + ip_addr[0] = addr->addr & 0xff; /* IADDR4 */ + ip_addr[1] = (addr->addr >> 8) & 0xff; /* IADDR3 */ + ip_addr[2] = (addr->addr >> 16) & 0xff; /* IADDR2 */ + ip_addr[3] = (addr->addr >> 24) & 0xff; /* IADDR1 */ + + ethernet_parameter.target_upper_port = port;//յĶ˿ںIP´ηͶӦIPͶ˿ + + ethernet_parameter.upper_ip[0] = ip_addr[0]; + ethernet_parameter.upper_ip[1] = ip_addr[1]; + ethernet_parameter.upper_ip[2] = ip_addr[2]; + ethernet_parameter.upper_ip[3] = ip_addr[3]; + + if( (0x80 == buf[0]) && (0x00 == buf[1]) ) + { + memcpy((uint8_t *)&(un_request_frame.arr[0]),buf, sizeof(UnRequestFrame)); + publishMessage(&un_request_frame, 1); + } + + pbuf_free(p); +} + + +void udp_Callback_4(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + uint8_t *buf = (uint8_t *)(p->payload); +//------------------------------------------------------------------------------------------------ + + boot_eth_flag = true; + FrameHeader = ( (buf[0] << 8) | (buf[1]) ); + printf("FrameHeader %d\n",FrameHeader); + + pbuf_free(p); +} + + +void udp_Callback_5(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + uint8_t *buf = (uint8_t *)(p->payload); +//------------------------------------------------------------------------------------------------ + + if(FEEDDOG_HEADER == ( (buf[0] << 8) | (buf[1]) )) + { + WDTReFresh_flag = true;//ι־ + printf("Feed dog flag received %d\n",getCurrentTime()); + } + + + pbuf_free(p); +} + + +//100ms һ +void ethernetTimerProcess(void) +{ + static uint8_t ethernet_timer = 0; + static uint8_t ethernet_temp[4] = {0,0,0,0};//мжֵ + uint8_t temp = 0; + + ethernet_timer ++; + if(ethernet_timer >= 5)//500msжһ + { + ethernet_timer = 0; + +//ж------------------------------------------------------------ + if(ethernet_fault_Info.bit_data.auto_count == ethernet_temp[0])//һʾ + { + ethernet_fault_Info.bit_data.auto_state = FAULT; + } + else + { + ethernet_fault_Info.bit_data.auto_state = NORMAL; + ethernet_temp[0] = ethernet_fault_Info.bit_data.auto_count;//ݸ + } + + if(ethernet_fault_Info.bit_data.auto_state != ethernet_temp[1]) + { + ethernet_temp[1] = ethernet_fault_Info.bit_data.auto_state; + temp ++; + } + + +//ֶж------------------------------------------------------------ + if(ethernet_fault_Info.bit_data.manual_count == ethernet_temp[2])//һʾ + { + ethernet_fault_Info.bit_data.manual_state = FAULT; + } + else + { + ethernet_fault_Info.bit_data.manual_state = NORMAL; + ethernet_temp[2] = ethernet_fault_Info.bit_data.manual_count;//ݸ + } + + if(ethernet_fault_Info.bit_data.manual_state != ethernet_temp[3]) + { + ethernet_temp[3] = ethernet_fault_Info.bit_data.manual_state; + temp ++; + } + } + + publishMessage(ðernet_fault_Info, 1);// ״̬仯 ź +} + + +static void vehicleInfOoutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + + UdpSendToData(UDPCB_2,(uint8_t *)(&un_vehicle_Info_output), sizeof(un_vehicle_Info_output), (uint8_t *)ðernet_parameter.upper_ip[0], ethernet_parameter.target_upper_port); +} + +static void motorStatusOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + + UdpSendToData(UDPCB_2,(uint8_t *)(&un_motor_status_output), sizeof(un_motor_status_output), (uint8_t *)ðernet_parameter.upper_ip[0], ethernet_parameter.target_upper_port); +} + +static void pidOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + + UdpSendToData(UDPCB_2,(uint8_t *)(&un_pid_output), sizeof(un_pid_output), (uint8_t *)ðernet_parameter.upper_ip[0], ethernet_parameter.target_upper_port); +} + +static void remoteControlOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + + UdpSendToData(UDPCB_2,(uint8_t *)(&un_remote_control_output), sizeof(un_remote_control_output), (uint8_t *)ðernet_parameter.upper_ip[0], ethernet_parameter.target_upper_port); +} + +static void manualControlOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + + UdpSendToData(UDPCB_2,(uint8_t *)(&un_manual_control_output),sizeof(un_manual_control_output), (uint8_t *)ðernet_parameter.upper_ip[0], ethernet_parameter.target_upper_port); + +} + +static void autoControlOutput(void *signal_id) +{ + (void)signal_id; // DZΪʹã + + UdpSendToData(UDPCB_2,(uint8_t *)(&un_auto_control_output), sizeof(un_auto_control_output), (uint8_t *)ðernet_parameter.upper_ip[0], ethernet_parameter.target_upper_port); +} + + + + + + +//̫ +void ethernetSendAll(void *signal_id) +{ + static uint8_t computer_output_cnt = 0; + uint32_t crc_temp = 0; + uint8_t i = 0; + uint16_t Rg_Tmp = 0; + float Rg_FloatTmp = 0; + static uint8_t eth_cnt = 0; + static uint8_t app_output_cnt = 0; + uint8_t BOOT_Arr[2] = {0x01,0x02};//ϵ緢app֡λ +//------------------------------------------------------------------------- + //̫50ms 20210811޸Ϊ100ms + //20210827޸Ϊλǰλٺһ + computer_output_cnt ++; + if(computer_output_cnt >= 1) + { + computer_output_cnt = 0; + //ֽۼӺͣעⲻź 20210826޸İֽۼ + +// printf("left_motor_speed = %f\n",diff_data.left_motor_speed); +// printf("right_motor_speed = %f\n",diff_data.right_motor_speed); + + un_computer_output.bit_data.frame_header = 0xCCFF; + un_computer_output.bit_data.frame_type = 0x1100; + un_computer_output.bit_data.frame_length = 0x0B; + un_computer_output.bit_data.accumulated = eth_cnt ++; + + Rg_FloatTmp = (diff_data.left_motor_speed*(float)getParam("whl_dia") * M_PI*60)/1000.0/(float)getParam("gRatio");// ת/ӡkm/h һȦ1.8 + Rg_FloatTmp = Rg_FloatTmp*100;//,Ҫ100 ,ϵ0.01 + Rg_Tmp = (uint16_t)((int16_t)(Rg_FloatTmp));//תΪ޷); //20231012޸ٷ 20231226-3ų޸ķ + un_computer_output.bit_data.speed = ((Rg_Tmp << 8) | (Rg_Tmp >> 8));//λǰλֺ + + Rg_FloatTmp = (diff_data.right_motor_speed*(float)getParam("whl_dia") * M_PI*60)/1000.0/(float)getParam("gRatio");// ת/ӡkm/h һȦ1.8 + Rg_FloatTmp = Rg_FloatTmp*100;//,Ҫ100 ,ϵ0.01 + Rg_Tmp = (uint16_t)((int16_t)(Rg_FloatTmp));//תΪ޷); //20231012޸ٷ 20231226-3ų޸ķ + un_computer_output.bit_data.curvature = ((Rg_Tmp << 8) | (Rg_Tmp >> 8));//λǰλֺ + + crc_temp = 0; + for(i = 0; i<10 ;i++)//ȹ̶ + { + crc_temp = crc_temp + (un_computer_output.arr[i]); + } + un_computer_output.bit_data.crc = (uint8_t)crc_temp; + + UdpSendToData(UDPCB_1,(uint8_t *)(&un_computer_output.arr[0]), 11, (uint8_t *)ðernet_parameter.computer_ip[0], COMMUNICATION_PORT); + UdpSendToData(UDPCB_4,(uint8_t *)(&un_computer_output.arr[0]), 11, (uint8_t *)ðernet_parameter.computer_ip[0], COMMUNICATION_PORT); + } + + + if(app_output_cnt < 10)//20250109 100ms 10֡app̫֡ûгʼɾͷ͵Ķ֡ + { + app_output_cnt ++; + UdpSendToData(UDPCB_4, BOOT_Arr, 2, (uint8_t *)ðernet_parameter.download_ip[0], BOOT_TX_PORT); + } +} + +// ̫ʱźŴ +static void ethernetInterfaceTimerProcess(void *signal_id) +{ + uint32_t time_boot = getCurrentTime();//¼ǰʱ + (void)signal_id; // DZΪʹã + + ethernetSendAll(signal_id); + + ethernetTimerProcess();//ж + + timerStart(ðernet_timer_interface, 100,1); //100msһ + +// printf("ethernetInterface spend time:%d\n",getCurrentTime() - time_boot);//app˶೤ʱ +} + + + + + + + + +static unsigned char receive_buffer[MAX_BUFFER_SIZE]; +//ص +void udp_Callback_3(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port) +{ + static unsigned int received_size = 0; + uint8_t *buf = (uint8_t *)(p->payload); + + // Ƿµ֡ͷ + if ((0x80 == buf[1]) && (0xFF == buf[0])) + { + // ýչ + received_size = 0; + printf("⵽µ֡ͷ,ýչ\n"); + } + + // Ƿ㹻Ŀռ洢 + if (received_size + p->len <= MAX_BUFFER_SIZE) + { + printf("p->len %d :\n" , p->len); + + memcpy(receive_buffer + received_size, buf, p->len); + received_size += p->len; + + // Ƿյ + if (received_size >= sizeof(request_context.param_request->arr)) + { + printf("received_size : %d :\n" , received_size); + + for(u16_t i = 0; i< sizeof(request_context.param_request->arr); i++) + { + request_context.param_request->arr[i] = receive_buffer[i]; + } + + memcpy(request_context.param_request->arr, receive_buffer, sizeof(request_context.param_request->arr)); + request_context.sender_ip = (unsigned int)addr->addr; + request_context.sender_port = port; + + // ӡ request_context.param_request->arr +// printf("յ param_request->arr :\n"); +// for (size_t i = 0; i < sizeof(request_context.param_request->arr); ++i) +// { +// printf("%02X ", request_context.param_request->arr[i]); +// if ((i + 1) % 1024 == 0 || i == sizeof(request_context.param_request->arr) - 1) +// { +// printf("\n"); +// feedWatchdog(); +// } +// } + + publishMessage(&request_context, 1); + + printf("received_size%d \n" , received_size); + // ýջ + received_size = 0; + printf("յ,\n"); + } + } + else + { + // ,ý + received_size = 0; + printf("ջ,ݶ\n"); + } + + unsigned int tmp_count = pbuf_free(p); + printf("pbuf_freeѾͷţtmp_count :%d \n" , tmp_count); + p = NULL; +} + +void OnParamSend(void *data) +{ + uint8_t ip_addr[4] = {0,0,0,0}; + RequestContext *signal = (RequestContext *)(data); + + ip_addr[0] = signal->sender_ip & 0xff; /* IADDR4 */ + ip_addr[1] = (signal->sender_ip >> 8) & 0xff; /* IADDR3 */ + ip_addr[2] = (signal->sender_ip >> 16) & 0xff; /* IADDR2 */ + ip_addr[3] = (signal->sender_ip >> 24) & 0xff; /* IADDR1 */ + + uint32_t total_size = sizeof(signal->param_request->arr); + uint32_t sent_size = 0; + + + while (sent_size < total_size) + { + uint32_t remaining = total_size - sent_size; + uint32_t packet_size = (remaining > MAX_PACKET_SIZE) ? MAX_PACKET_SIZE : remaining; + + UdpSendToData(UDPCB_3, + (uint8_t *)(signal->param_request->arr) + sent_size, + packet_size, + ip_addr, + signal->sender_port); + + sent_size += packet_size; + // Сӳ,ʧ + udelay(1000); + } + printf("ݷɣ%d \n", sent_size); +} + + + +// APPģijʼ +void ethernetInterfaceInit(void) +{ +//----------------------------------- + if (!eth_pool_rx) { + // ʹDMA RxжϡTxδʹжϣΪETHʺܸߣ + // Txжϴʱٶȡ + dwc_eth_enable_dma_rx_int(&g_eth1_dev, eth_dma_rx_int_cb); + } + + timerInit(ðernet_timer_interface1); + timerInit(ðernet_timer_interface); + + // Ķʱźţڶʱɼ + subscribe(ðernet_timer_interface, ethernetInterfaceTimerProcess); + subscribe(ðernet_timer_interface1, lwip_Ethernet); + + + subscribe(&un_vehicle_Info_output, vehicleInfOoutput); + subscribe(&un_motor_status_output, motorStatusOutput); + subscribe(&un_pid_output, pidOutput); + subscribe(&un_remote_control_output, remoteControlOutput); + subscribe(&un_manual_control_output, manualControlOutput); + subscribe(&un_auto_control_output, autoControlOutput); + + // Ϣʹþ̬ԱΪص + subscribe(&request_send, OnParamSend); + + + timerStart(ðernet_timer_interface, 100,1); //100msһ + timerStart(ðernet_timer_interface1, 10,1); //10msһ + + printf( "ethernetInterface: initial OK %d\n",getCurrentTime()); +} + + \ No newline at end of file diff --git a/interface_ethernet.h b/interface_ethernet.h new file mode 100644 index 0000000..3798543 --- /dev/null +++ b/interface_ethernet.h @@ -0,0 +1,121 @@ +#ifndef _INTERFACE_ETHERNET_H_ +#define _INTERFACE_ETHERNET_H_ + +#include "interface_config.h" +#include "lwip/err.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/udp.h" + +#include "lwip/netif.h" +#include "lwip/ip.h" +#include "lwip/init.h" +#include "netif/etharp.h" +#include "lwip/pbuf.h" + + + + + +//̫Ϣ +typedef struct _StrEthernetFault +{ + uint8_t auto_count; //Զݼ + uint8_t manual_count; //ֶݼ + uint8_t auto_state; // Զ״̬ | 0 1 + uint8_t manual_state; // ֶ״̬ | 0 1 +} StrEthernetFault; + +typedef union _UnEthernetFault +{ + StrEthernetFault bit_data; // ʹöĽṹ + uint8_t arr[sizeof(StrEthernetFault)]; // ͨṹȷС +} UnEthernetFault; + + +extern UnEthernetFault ethernet_fault_Info; + + + + + + + + + + + +typedef struct +{ + uint8_t local_ip[4]; + uint8_t mask[4]; + uint16_t Local_upper_port; + uint16_t Local_download_port; + uint16_t local_communication_port; + uint8_t computer_ip[4]; + uint8_t upper_ip[4]; + uint8_t download_ip[4]; + uint16_t target_upper_port; + uint16_t target_download_port; + uint16_t target_communication_port; + +} StrEthernetParameter; + + + + + + + + + + +#define UDPCB_1 1//ͨѶ˿ +#define UDPCB_2 2//λ˿ +#define UDPCB_3 3//λ˿ +#define UDPCB_4 4//λ˿ +#define UDPCB_5 5//λ˿ + + + +#define COMMUNICATION_PORT 8011 +#define UPPER_PORT 8000 +#define PARAM_PORT 8080 + +#define DOWNLOAR_PORT 7812 +#define BOOT_TX_PORT 7811 //ʱдĶ˿ڣĿ˿ڣ˭ +#define WDT_PORT 7813 //ʼʱĶ˿ڣն˿ + + + + +//ⲿ +void UDP_Echo_Init(uint8_t udpcbID, udp_recv_fn recv, uint16_t port); +int8_t UdpSendToData(uint8_t udpcbID, uint8_t *buf, uint16_t len, uint8_t *sip, uint16_t port); + +void udp_Callback_1(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +void udp_Callback_2(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +void udp_Callback_3(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +void udp_Callback_4(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); +void udp_Callback_5(void *arg, struct udp_pcb *upcb, struct pbuf *p, const ip_addr_t *addr, u16_t port); + +void ethernetTimerProcess(void); +void ethernetInterfaceInit(void); + + + +//ⲿ +extern struct udp_pcb *udpcb_1; +extern StrEthernetParameter ethernet_parameter; + +extern struct udp_pcb *udpcb_1; +extern struct udp_pcb *udpcb_2; +extern struct udp_pcb *udpcb_3; +extern struct udp_pcb *udpcb_4; +extern struct udp_pcb *udpcb_5; + +extern bool eth_pool_rx; + + + +#endif /*ETH_DEMO_H */ \ No newline at end of file diff --git a/interface_gpio.c b/interface_gpio.c new file mode 100644 index 0000000..1a6ec7a --- /dev/null +++ b/interface_gpio.c @@ -0,0 +1,145 @@ +#include "interface_gpio.h" + + +Timer gpio_timer_interface; + +void gpioTimerProcess(void *signal_id) +{ + (void)signal_id; // 标记变量为已使用,避免编译器警告 +// uint32_t time_boot = getCurrentTime();//记录当前时间 +//-------------------------------------------- +// un_sw_sample.bit_data.emergency_stop_switch = sdrv_gpio_read_pin_input_level(GPIO_A4); +// un_sw_sample.bit_data.High_voltage_switch = sdrv_gpio_read_pin_input_level(GPIO_C7); +// +// publishMessage(&un_sw_sample, 1);//发射信号 + + timerStart(&gpio_timer_interface, 100,1); + printf("sw state %d\n",un_sw_sample.arr[0]); + } + + +// APP模块的初始化 +void gpioInterfaceInit(void) +{ + // 初始化定时器 + timerInit(&gpio_timer_interface); + // 订阅定时器信号,用于定时采集 + subscribe(&gpio_timer_interface, gpioTimerProcess); + + timerStart(&gpio_timer_interface, 100,1); + + printf("gpioInterface: initial OK %d\n",getCurrentTime()); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface_gpio.h b/interface_gpio.h new file mode 100644 index 0000000..3ea2cf1 --- /dev/null +++ b/interface_gpio.h @@ -0,0 +1,25 @@ +#ifndef _INTERFACE_GPIO_H_ +#define _INTERFACE_GPIO_H_ + + +#include "interface_config.h" + + + + + + +//#deifne emergency_stop_switch sdrv_gpio_read_pin_input_level(GPIO_A6) +// +//#deifne high_voltage_switch sdrv_gpio_read_pin_input_level(GPIO_A7) + + +void gpioTimerProcess(void *signal_id); + +void gpioInterfaceInit(void); + + + + + +#endif /* _INTERFACE_GPIO_H_ */ \ No newline at end of file diff --git a/interface_power.c b/interface_power.c new file mode 100644 index 0000000..a7a0419 --- /dev/null +++ b/interface_power.c @@ -0,0 +1,139 @@ + + +#include "interface_power.h" +#include "app/app_config.h" + +Timer ppwer_timer; + + +// 100ms +void powerOn(void) +{ + static uint8_t power_state = 0; + static uint8_t power_count = 0; +//--------------------------------------- + switch(power_state) + { + case 0: + left_motor_fan(ON); + right_motor_fan(ON); + pre_charge_relay(ON); + high_voltage_relay(OFF); + low_voltage_relay(ON); + yellow_light(ON); + red_light(ON); + left_vehicle_fan(ON); + right_vehicle_fan(ON); + computer(ON); + network_switch(ON); + power_state = 10; + power_count = 0; + break; + case 10: + if (power_count >= 100)//10s + { + left_motor_fan(ON); + right_motor_fan(ON); + pre_charge_relay(OFF); + high_voltage_relay(ON); + low_voltage_relay(ON); + yellow_light(ON); + red_light(ON); + left_vehicle_fan(ON); + right_vehicle_fan(ON); + computer(ON); + network_switch(ON); + power_state = 11; + power_count = 0; + } + else + { + left_motor_fan(ON); + right_motor_fan(ON); + pre_charge_relay(ON); + high_voltage_relay(OFF); + low_voltage_relay(ON); + yellow_light(ON); + red_light(ON); + left_vehicle_fan(ON); + right_vehicle_fan(ON); + computer(ON); + network_switch(ON); + power_state = 10; + power_count ++; + } + break; + case 11: + power_state = 11; +// left_motor_fan(ON); +// left_motor_fan(ON); +// right_motor_fan(ON); +// pre_charge_relay(OFF); +// high_voltage_relay(ON); +// low_voltage_relay(ON); +// yellow_light(ON); +// red_light(ON); +// left_vehicle_fan(ON); +// right_vehicle_fan(ON); +// computer(ON); +// network_switch(ON); + break; + default:break; + } + + canSendAll(); +// ethernetSendAll(&power_state); +} + +//ϵ紦 +//void powerOnSignal(void *data) +//{ +// +// +// +// +// +// +// +// +// +// +//} + + +// APPģijʼ +void powerAppInit(void) +{ + + // յλдź +// subscribe(&un_remote_control_input, powerOnSignal); +// timerStart(&test_timer, 5000); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface_power.h b/interface_power.h new file mode 100644 index 0000000..202193d --- /dev/null +++ b/interface_power.h @@ -0,0 +1,115 @@ + +#ifndef _INTERFACE_POWER_H_ +#define _INTERFACE_POWER_H_ + + +#include "interface_config.h" + +#define ON 1 +#define OFF 0 + +// +//kgf1 + +// +//kgf3 + +//Ԥ +//kgf4 + +//ѹѹ̵ +//kgf78 + +//ѹ̵ +//kgf11-12 + +//1 +//kgf6 + +//2 +//kgf9 + +// +//kgf14 + +//ҷ +//kgf19 + +// +//kgf 17-18 + +#define left_motor_fan(Value) un_inf_can_kgf_output1.bit_data.KGF01 = Value;// +#define right_motor_fan(Value) un_inf_can_kgf_output1.bit_data.KGF03 = Value;// +#define pre_charge_relay(Value) un_inf_can_kgf_output1.bit_data.KGF04 = Value;//Ԥ +#define high_voltage_relay(Value) un_inf_can_kgf_output1.bit_data.KGF07 = Value;un_inf_can_kgf_output1.bit_data.KGF08 = Value//ѹ̵ +#define low_voltage_relay(Value) un_inf_can_kgf_output1.bit_data.KGF11 = Value;un_inf_can_kgf_output1.bit_data.KGF12 = Value//ѹ̵ +#define yellow_light(Value) un_inf_can_kgf_output1.bit_data.KGF06 = Value;//Ƶ +#define red_light(Value) un_inf_can_kgf_output1.bit_data.KGF09 = Value;// +#define left_vehicle_fan(Value) un_inf_can_kgf_output1.bit_data.KGF14 = Value;// +#define right_vehicle_fan(Value) un_inf_can_kgf_output2.bit_data.KGF03 = Value;//ҷ +#define computer(Value) un_inf_can_kgf_output2.bit_data.KGF01 = Value;un_inf_can_kgf_output2.bit_data.KGF02 = Value//ѹ̵ +#define network_switch(Value) un_inf_can_kgf_output2.bit_data.KGF05 = Value;un_inf_can_kgf_output2.bit_data.KGF06 = Value//罻· + +//H +#define brake_motor_forward un_h_bridge_output.bit_data.channel_01 = ON ;un_h_bridge_output.bit_data.channel_04 = ON ;un_h_bridge_output.bit_data.channel_02 = OFF;un_h_bridge_output.bit_data.channel_03 = OFF;un_h_bridge_output.bit_data.sleep_01 = ON ;un_h_bridge_output.bit_data.sleep_02 = ON//ת +#define brake_motor_reversal un_h_bridge_output.bit_data.channel_01 = OFF;un_h_bridge_output.bit_data.channel_04 = OFF;un_h_bridge_output.bit_data.channel_02 = ON ;un_h_bridge_output.bit_data.channel_03 = ON ;un_h_bridge_output.bit_data.sleep_01 = ON ;un_h_bridge_output.bit_data.sleep_02 = ON//ת +#define brake_motor_off un_h_bridge_output.bit_data.channel_01 = OFF;un_h_bridge_output.bit_data.channel_04 = OFF;un_h_bridge_output.bit_data.channel_02 = OFF;un_h_bridge_output.bit_data.channel_03 = OFF;un_h_bridge_output.bit_data.sleep_01 = OFF;un_h_bridge_output.bit_data.sleep_02 = OFF//ر + + + +//#define OutputL01_13(Value) UnInfCanKGF_2.bit_data.KGF03 = Value;UnBCM_1Signal_1.bit_data.BCM_1SignalW9 = Value//ת 20200106ת޸ӳΪK19 ϵƲܹͬһͨϡ +//#define OutputL01_14(Value) UnInfCanKGF_1.bit_data.KGF13 = Value;UnBCM_1Signal_1.bit_data.BCM_1SignalW7 = Value//ת +//#define OutputL01_19(Value) UnInfCanKGF_1.bit_data.KGF05 = Value;UnInfCanKGF_1.bit_data.KGF06 = Value; UnBCM_1Signal_1.bit_data.BCM_1SignalW22 = Value //Զ +//#define OutputL01_18(Value) UnInfCanKGF_1.bit_data.KGF03 = Value;UnInfCanKGF_1.bit_data.KGF04 = Value; UnBCM_1Signal_1.bit_data.BCM_1SignalW23 = Value // +//#define OutputL01_22(Value) UnInfCanKGF_1.bit_data.KGF11 = Value;UnInfCanKGF_1.bit_data.KGF12 = Value // +//#define OutputL01_06(Value) UnInfCanKGF_1.bit_data.KGF01 = Value;UnInfCanKGF_1.bit_data.KGF02 = Value; UnBCM_1Signal_1.bit_data.BCM_1SignalW2 = Value//λ +//#define OutputL01_04(Value) UnInfCanKGF_2.bit_data.KGF05 = Value//յ 20200106յ޸ӳΪK21 +//#define OutputL01_02(Value) UnInfCanKGF_1.bit_data.KGF16 = Value//ǰյ +//#define OutputL01_20(Value) UnInfCanKGF_1.bit_data.KGF09 = Value;UnInfCanKGF_1.bit_data.KGF10 = Value //ƶ +//#define OutputL01_21(Value) UnInfCanKGF_1.bit_data.KGF07 = Value;UnInfCanKGF_1.bit_data.KGF08 = Value;UnBCM_1Signal_1.bit_data.BCM_1SignalW28 = Value// +// +//#define OutputL01_05(Value) UnInfCanKGF_2.bit_data.KGF01 = Value//ƶ ҲΪƶ +//#define OutputL01_11(Value) UnInfCanKGF_2.bit_data.KGF02 = Value//յ1LED +//#define OutputL01_12(Value) UnInfCanKGF_1.bit_data.KGF14 = Value//յ2LED +//#define OutputL01_10(Value) UnInfCanKGF_2.bit_data.KGF04 = Value;UnBCM_1Signal_1.bit_data.BCM_1SignalW21 = Value//ΣLed +//#define OutputL01_16(Value) UnInfCanKGF_1.bit_data.KGF15 = Value//ε1 202001061޸ӳΪK15 +//#define OutputL01_17(Value) UnInfCanKGF_2.bit_data.KGF06 = Value//ε2 +//#define OutputL01_07(Value) UnInfCanKGF_2.bit_data.KGF07 = Value;UnBCM_2Signal_1.bit_data.BCM_2SignalW12 = Value// +//#define OutputL01_08(Value) UnInfCanKGF_2.bit_data.KGF08 = Value;UnBCM_2Signal_1.bit_data.BCM_2SignalW10 = Value//սŵ +//#define OutputL01_09(Value) UnInfCanKGF_2.bit_data.KGF09 = Value//ǰ˪LED +//#define OutputL01_01(Value) UnInfCanKGF_2.bit_data.KGF11 = Value;UnInfCanKGF_2.bit_data.KGF12 = Value;UnBCM_2Signal_1.bit_data.BCM_2SignalW8 = Value//ǰϴ +//#define OutputL01_03(Value) UnInfCanKGF_2.bit_data.KGF10 = Value//ε1ٶȿ +//#define OutputL01_15(Value) UnInfCanKGF_2.bit_data.KGF13 = Value//20190202 +//#define OutputL01_23(Value) UnInfCanKGF_2.bit_data.KGF14 = Value//ε2ٶȿ +//#define OutputL01_24(Value) UnInfCanKGF_2.bit_data.KGF15 = Value//ǰ˪¿ +//#define OutputL01_25(Value) UnInfCanKGF_2.bit_data.KGF16 = Value//220VӴ + + + + + + + + +//wⲿ + +void powerOn(void); + + + + + + + + + + + + +#endif /* _APP_POWER_H_ */ + + + + + + diff --git a/interface_uart.c b/interface_uart.c new file mode 100644 index 0000000..543e670 --- /dev/null +++ b/interface_uart.c @@ -0,0 +1,471 @@ + + + +#include "interface_uart.h" + + +#define BUFFER_SIZE 256 + +#define SBUS_UART UART3 + + +UartFaultInfo uart_fault_info = { + .remote_count = 0, + .remote_state = 0, +}; + + + +// 岢ʼ SBus ṹ +typedef struct { + uint16_t channels[16]; // 洢16ͨĽ + uint8_t flags; // ־ֽ +} SBusData; + + +SBusData sbus_data = { + .channels = {0}, + .flags = 0 +}; + +///* Buffer used to receive data from the console */ +typedef struct user_data { + uint8_t user_buffer[BUFFER_SIZE]; + uint8_t *buff_ptr; + uint32_t buff_remain; +} user_data_t; +static user_data_t user_data; +///* Buffer used to transmit welcome message */ + + +sdrv_uart_t uart_ctrl_ptr; + +/* uart config structures */ +//sbus ĬΪ100k +static sdrv_uart_config_t g_uart_config = { + .base = DEVICE_BASE(SBUS_UART), + .irq = DEVICE_INTR(SBUS_UART), + .baud = 100000, + .data_bits = SDRV_UART_CHAR_8_BITS, + .stop_bits = SDRV_UART_STOP_2_BIT, + .parity = SDRV_UART_EVEN_PARITY, +}; + + +// SBus ݽ +SBusData* parseSBusData(const uint8_t *input_data) +{ + + for(uint8_t i = 0; i < 25; i++) + { + test_app[i] = input_data[i]; + } + test_app[25] = 0x44; + + float sbus_temp = 0.0; + // 16ͨݣÿͨΪ11λ 0xFΪ֡ͷ + sbus_data.channels[0] = (input_data[1] | input_data[2] << 8) & 0x07FF; + sbus_data.channels[1] = (input_data[2] >> 3 | input_data[3] << 5) & 0x07FF; + sbus_data.channels[2] = (input_data[3] >> 6 | input_data[4] << 2 | input_data[5] << 10) & 0x07FF; + sbus_data.channels[3] = (input_data[5] >> 1 | input_data[6] << 7) & 0x07FF; + sbus_data.channels[4] = (input_data[6] >> 4 | input_data[7] << 4) & 0x07FF; + sbus_data.channels[5] = (input_data[7] >> 7 | input_data[8] << 1 | input_data[9] << 9) & 0x07FF; + sbus_data.channels[6] = (input_data[9] >> 2 | input_data[10] << 6) & 0x07FF; + sbus_data.channels[7] = (input_data[10] >> 5 | input_data[11] << 3) & 0x07FF; + sbus_data.channels[8] = (input_data[12] | input_data[13] << 8) & 0x07FF; + sbus_data.channels[9] = (input_data[13] >> 3 | input_data[14] << 5) & 0x07FF; + sbus_data.channels[10] = (input_data[14] >> 6 | input_data[15] << 2 | input_data[16] << 10) & 0x07FF; + sbus_data.channels[11] = (input_data[16] >> 1 | input_data[17] << 7) & 0x07FF; + sbus_data.channels[12] = (input_data[17] >> 4 | input_data[18] << 4) & 0x07FF; + sbus_data.channels[13] = (input_data[18] >> 7 | input_data[19] << 1 | input_data[20] << 9) & 0x07FF; + sbus_data.channels[14] = (input_data[20] >> 2 | input_data[21] << 6) & 0x07FF; + sbus_data.channels[15] = (input_data[21] >> 5 | input_data[22] << 3) & 0x07FF; + + // ־ֽ + sbus_data.flags = input_data[23]; + + //ת + sbus_temp = (float)(sbus_data.channels[0]); + sbus_temp = (ZERO_VALUE - sbus_temp)*23;//Ҫ任һ·ţΪ + remote_curvature = (uint16_t)((int16_t)sbus_temp);// + + //ת + sbus_temp = (float)(sbus_data.channels[1]); + sbus_temp = (ZERO_VALUE - sbus_temp)*2.3;//Ҫ任һ·ţΪ + remote_speed = (uint16_t)((int16_t)sbus_temp);//ת + + remote_Reserve = sbus_data.channels[7]; + + //SwA + if(sbus_data.channels[3] >= 1700)// + { + emergency_stop = 1; + } + else + { + emergency_stop = 0; + } + + //SwB + if(sbus_data.channels[4] >= 1700)// + { + remote_switch_b = 2; + } + else if(sbus_data.channels[6] <= 250)//ڶ + { + remote_switch_b = 0; + } + else//һ + { + remote_switch_b = 1; + } + + //SwC + if(sbus_data.channels[5] >= 1700)// + { + remote_switch_c = 2; + } + else if(sbus_data.channels[4] <= 250)//ڶ + { + remote_switch_c = 0; + } + else//һ + { + remote_switch_c = 1; + } + + //SwD + if(sbus_data.channels[6] >= 1700)// + { + remote_switch_d = 1; + } + else + { + remote_switch_d = 0; + } + + if(0 == sbus_data.flags)//ֱ߹ж //ͨ־жϣ Ϊ0ʾֱӣ + { + remote_enable = 1;//ֱ + } + else + { + remote_enable = 0;//ֱ + } + + ssdk_printf(SSDK_NOTICE, "sta\r\n"); + for(int i=0;i<16;i++) + { + ssdk_printf(SSDK_EMERG, "%04x\r\n",sbus_data.channels[i]); + } + ssdk_printf(SSDK_NOTICE, "end\r\n"); + return &sbus_data; +} + + +void callback(sdrv_uart_t *ctrl, sdrv_uart_callback_status_e status, + void *userData) +{ + uint8_t char_data[25] = {0};//һֽڻ + static uint8_t cnt_sbus = 0; + static uint8_t state = 0; + static uint8_t receive = 0; + static uint8_t sbus_buff[25]; + SBusData *tmp_sbus_data; + +// user_data_t *user_data = (user_data_t *)userData; + +// ssdk_printf(SSDK_NOTICE, "123456789\r\n"); + + /* Uart receive data. */ + if (SDRV_UART_RxFWF == status) + { + uart_fault_info.remote_count ++; + + size_t size = sdrv_uart_get_rxfifodata(ctrl, char_data,1); + +// for(uint8_t i = 0; i < 25; i++) +// { +// test_app[i] = char_data[i]; +// +// } + +// sdrv_uart_sync_transmit(&g_console_uart, char_data, +// 25, NULL, +// 0Xffff); + +// for(uint8_t i=0;i<25;i++) +// { +// ssdk_printf(SSDK_INFO,"char_data: %x \r\n", char_data[i]); +// } +// + +// for(int i=0;i= 24) + { + for(uint8_t i = 0; i < 25; i++) + { + test_app[i] = sbus_buff[i]; + } + test_app[25] = 0x55; +// ssdk_printf(SSDK_INFO,"char_data24: %x \r\n", char_data[0]); + if(0x0 == char_data[0]) + { + cnt_sbus = 0; + receive = 0; + sbus_buff[cnt_sbus] = char_data[0]; + state = 0; + tmp_sbus_data = parseSBusData(sbus_buff); + +// sdrv_uart_sync_transmit(ctrl, "AA\r\n", strlen("AA\r\n"), NULL, 0xFFFF); + +// sdrv_uart_sync_transmit(ctrl, ( const uint8_t *)&tmp_sbus_data->channels[0], +// 32, NULL, +// 0Xffff); + // ssdk_printf(SSDK_EMERG, "AAAr\n"); + } + } + else if(0x0f == char_data[0]) + { + receive = 0; + cnt_sbus = 0; + sbus_buff[cnt_sbus] = char_data[0]; + cnt_sbus++; + state = 1; + } + else + { + sbus_buff[cnt_sbus] = char_data[0]; + cnt_sbus ++; + state = 1; + } + break; + + default: + break; + } +// } + } + else if (SDRV_UART_RxFifoOverFlow == status) + { +// if (0 != user_data->buff_remain) { +// size_t size = sdrv_uart_get_rxfifodata(ctrl, user_data->user_buffer, +// user_data->buff_remain); +// } +// sdrv_uart_sync_transmit(ctrl, "\r\n", strlen("\r\n"), NULL, TIMES_OUT); +// sdrv_uart_sync_transmit(ctrl, user_data->user_buffer, +// BUFFER_SIZE - user_data->buff_remain, NULL, +// TIMES_OUT); +// sdrv_uart_sync_transmit(ctrl, "\r\n", strlen("\r\n"), NULL, TIMES_OUT); +// +// memset(user_data->user_buffer, '\0', BUFFER_SIZE); +// user_data->buff_ptr = user_data->user_buffer; +// user_data->buff_remain = BUFFER_SIZE; +// +// sdrv_uart_sync_transmit( +// ctrl, "\r\ncallback: SDRV_UART_RxFifoOverFlow!\r\n", +// strlen("\r\ncallback: SDRV_UART_RxFifoOverFlow!\r\n"), NULL, +// TIMES_OUT); +// +// /* User can stop or reset realtime receive if you want, when transfer +// * occur errors */ +// sdrv_uart_stop_realtime_receive(ctrl); +// sdrv_uart_start_realtime_receive(ctrl); + + } + else if (SDRV_UART_ParityError == status) + { +// sdrv_uart_sync_transmit( +// ctrl, "\r\ncallback: SDRV_UART_ParityError!\r\n", +// strlen("\r\ncallback: SDRV_UART_ParityError!\r\n"), NULL, +// TIMES_OUT); + } + else if (SDRV_UART_BaudrateError == status) + { +// sdrv_uart_sync_transmit( +// ctrl, "\r\ncallback: SDRV_UART_BaudrateError!\r\n", +// strlen("\r\ncallback: SDRV_UART_BaudrateError!\r\n"), NULL, +// TIMES_OUT); + } + else if (SDRV_UART_NoiseError == status) + { +// sdrv_uart_sync_transmit( +// ctrl, "\r\ncallback: SDRV_UART_NoiseError!\r\n", +// strlen("\r\ncallback: SDRV_UART_NoiseError!\r\n"), NULL, TIMES_OUT); + } + else if (SDRV_UART_FramingError == status) + { +// sdrv_uart_sync_transmit( +// ctrl, "\r\ncallback: SDRV_UART_FramingError!\r\n", +// strlen("\r\ncallback: SDRV_UART_FramingError!\r\n"), NULL, +// TIMES_OUT); + } + else + { +// ssdk_printf(SSDK_NOTICE, "234567891\r\n"); + } +} + + + +//ʼ +void uart_Initialize(void) +{ + /* Get uart clk Config. */ +#if ((CONFIG_E3210) || (CONFIG_E3110)) + if (g_uart_config.irq <= UART8_INTR_NUM) { + g_uart_config.clk_freq = + sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_uart_sf_1_to_8)); + } else { + g_uart_config.clk_freq = + sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_uart_sf_9_to_16)); + } +#else + if (g_uart_config.irq <= UART6_INTR_NUM) { + g_uart_config.clk_freq = + sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_uart_sf_1_to_6)); + } else { + g_uart_config.clk_freq = + sdrv_ckgen_get_rate(CLK_NODE(g_ckgen_ip_uart_sf_7_to_12)); + } +#endif + + /* Initializes sdrv uart controller. */ + + user_data.buff_ptr = user_data.user_buffer; + user_data.buff_remain = BUFFER_SIZE; + + ssdk_printf(SSDK_NOTICE, "uart3 init\r\n"); + sdrv_uart_controller_init(&uart_ctrl_ptr, &g_uart_config, callback, + &user_data); + + sdrv_uart_start_realtime_receive(&uart_ctrl_ptr); + +} + + +void uartTimerProcess(void) +{ + static uint8_t uart_timer = 0; + static uint8_t uart_temp[1] = {2};//мжֵ +//---------------------------------------------------------------------------- + uart_timer ++; + if(uart_timer >= 1)//500msжһ + { + uart_timer = 0; + if(uart_fault_info.remote_count == uart_temp[0])//һʾ + { + uart_fault_info.remote_state = FAULT; + } + else + { + uart_fault_info.remote_state = NORMAL; + uart_temp[0] = uart_fault_info.remote_count;//ݸ + } + + if(uart_fault_info.remote_state != uart_temp[1]) + { +// publishMessage(&uart_fault_info.remote_state, 1);// ״̬仯 ź + uart_temp[1] = uart_fault_info.remote_state; + } + } +} + + + + + + + +//Timer uart_timer_interface; + +// APPģijʼ +void uartAppInit(void) +{ + // ʼʱʹ brake_timer ĵַΪźID +// timerInit(&uart_timer_interface, 100); +// subscribe(&uart_timer_interface, uartTimerProcess); + +// timerStart(&uart_timer_interface); +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface_uart.h b/interface_uart.h new file mode 100644 index 0000000..2695f36 --- /dev/null +++ b/interface_uart.h @@ -0,0 +1,157 @@ +#ifndef _INTERFACE_UART_H_ +#define _INTERFACE_UART_H_ + +#include "interface_config.h" +#include + + +#define ZERO_VALUE 1022//ң0ʱΪ1022 + +#define remote_speed un_remote_control_input.bit_data.speed//ٶ +#define remote_curvature un_remote_control_input.bit_data.curvature//ת +#define remote_Reserve un_remote_control_input.bit_data.reserve1// +#define emergency_stop un_remote_control_input.bit_data.switch_a//DF_SwA +#define remote_switch_b un_remote_control_input.bit_data.switch_b//DF_SwB +#define remote_switch_c un_remote_control_input.bit_data.switch_c//DF_SwC +#define remote_switch_d un_remote_control_input.bit_data.switch_d//DF_SwD +#define remote_enable un_remote_control_input.bit_data.enable//ֱʹ״̬ + + + + + + + + + + + + + + + + + + + + + + + +typedef struct +{ + uint16_t remote_count; //ңؼ + uint8_t remote_state; //ң״̬ +}UartFaultInfo; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +void uart_Initialize(void); + +void callback(sdrv_uart_t *ctrl, sdrv_uart_callback_status_e status, + void *userData); + +#endif /* _INTERFACE_H_ */ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/interface_wdt.c b/interface_wdt.c new file mode 100644 index 0000000..de7ed4a --- /dev/null +++ b/interface_wdt.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include +#include +#include "interface_config.h" + +sdrv_wdt_t *wdt_type = (sdrv_wdt_t *)(uintptr_t)APB_WDT1_BASE; + +static bool internal_reset_switch = true; +static bool external_reset_switch = false; + +//Źʼ +void wdt_init(uint32_t timeoutms) +{ + static sdrv_wdt_config_t wdt_cfg; + int ret = 0; +//-------------------------------------------------- + sdrv_wdt_get_default_config(&wdt_cfg); + + if (internal_reset_switch) { + wdt_cfg.int_rst.reset_en = true; + sdrv_rstgen_wdt_reset_enable(RESET_WDT1, true); + } + + if (external_reset_switch) { + /* config GPIO_H12 as WDT1_RST_N function */ + wdt_cfg.ext_rst.reset_en = true; + wdt_cfg.ext_rst.reset_mode = 0; /* low level active */ + } + + ret = sdrv_wdt_init(wdt_type, &wdt_cfg); + ASSERT(ret == 0); + +// irq_attach(wdt_irq, wdt_irq_handler, NULL); +// irq_enable(wdt_irq); + + sdrv_wdt_set_timeout(wdt_type, timeoutms); + + ret = sdrv_wdt_enable(wdt_type); +} + + + + + + + diff --git a/interface_wdt.h b/interface_wdt.h new file mode 100644 index 0000000..719a2c9 --- /dev/null +++ b/interface_wdt.h @@ -0,0 +1,64 @@ +#ifndef _INTERFACE_WDT_H_ +#define _INTERFACE_WDT_H_ + +#include + + + +#define WDT_OUTms 1600 + + + + +//ⲿ +void wdt_init(uint32_t timeoutms); + + + + +void External_wdt_refresh(void); + +//ⲿ +extern sdrv_wdt_t *wdt_type; + +// + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif /* _INTERFACE_WDT_H_*/ \ No newline at end of file diff --git a/main.c b/main.c new file mode 100644 index 0000000..931b915 --- /dev/null +++ b/main.c @@ -0,0 +1,142 @@ +#include +#include "board.h" +#include "debug.h" +#include "regs_base.h" +#include "irq_num.h" + +#include "clock_cfg.h" +#include "reset_cfg.h" +#include "pinmux_cfg.h" +#include "eth_cfg.h" +#include "lwip/err.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/timeouts.h" +#include + +#include "lwip/udp.h" +#include "flexcan_cfg.h" + +#include "interface_config.h" +#include "irq.h" + +//app包含 +#include "app/app_config.h" +#include "app/app_param_manage.h" +#include "app/app_power.h" +#include "app/app_brake.h" +#include "app/app_differential_drive.h" +#include +#include +#include +#include "app/app_request.h" +#include "app/app_ultrasonic.h" + +void testAppInit(void); + +#define IP_ADDR0 10 +#define IP_ADDR1 18 +#define IP_ADDR2 252 +#define IP_ADDR3 34 + + +extern int btm_init(void); +extern struct tcp_pcb *netdemo_connect_server(char *ip, int port); +extern bool netdemo_tcp_connected(void); +extern bool netdemo_tcp_send_done(void); +extern void netdemo_clear_tcp_send_done(void); + + + + + +uint8_t mainCnt = 0; +uint8_t mainCntarr[8] = {0x56,0x88,0x98,0x79,0x23}; + + +uint8_t test_app[26] = {0}; + +int main(void) +{ + initFramework(); + + uint8_t BOOT_Arr[2] = {0x01,0x02};//上电发送app帧给上位机用 + + // 释放MCU各模块reset信号 + board_reset_init(); + + // 配置时钟 + int ret = sdrv_ckgen_init(&g_clock_config); + ASSERT(ret == 0); + + // VIC初始化 + irq_initialize(VIC1_BASE, IRQ_MAX_INTR_NUM); + + // 配置pinmux + sdrv_pinctrl_init(NUM_OF_CONFIGURED_PINS, g_pin_init_config); + + // Timer初始化,用于提供LWIP sys_now接口获取当前时间 + btm_init(); + + // 使能打印 + board_debug_console_init(); + + printf("debug_console_init initial OK %d\n",getCurrentTime()); + //初始化所有can + initialization_All_Flexcan(); + + printf("initialization_All_Flexcan initial OK %d\n",getCurrentTime()); + // ETH初始化 + board_eth_init(); + + initSpi();//初始化SPI + + //以太网端口初始化 + UDP_Echo_Init(UDPCB_1, udp_Callback_1, COMMUNICATION_PORT); + UDP_Echo_Init(UDPCB_2, udp_Callback_2, UPPER_PORT); + UDP_Echo_Init(UDPCB_3, udp_Callback_3, PARAM_PORT); + UDP_Echo_Init(UDPCB_4, udp_Callback_4, DOWNLOAR_PORT); + UDP_Echo_Init(UDPCB_5, udp_Callback_5, WDT_PORT); + + printf("board_eth_init initial OK %d\n",getCurrentTime()); + //读取重启标志 + g_systemDataRecord.canBootloaderUpgrade = rdbyte_24c02(0x00); + printf("rdbyte_24c02 OK %d\n",getCurrentTime()); + + ethernet_parameter.download_ip[0] = rdbyte_24c02(BOOT_DES_IP);//读取下载的IP + ethernet_parameter.download_ip[1] = rdbyte_24c02(BOOT_DES_IP+1);//读取下载的IP + ethernet_parameter.download_ip[2] = rdbyte_24c02(BOOT_DES_IP+2);//读取下载的IP + ethernet_parameter.download_ip[3] = rdbyte_24c02(BOOT_DES_IP+3);//读取下载的IP + + //发送重启后的第一帧给上位机 + CAN_Send_Msg(&can_handle_6,OTA_CANTxID, FLEXCAN_STANDARD_FRAME, FLEXCAN_FrameTypeData, BOOT_Arr,2, TX_MB_INDEX);//app 帧 + + printf("CAN_Send_Msg can_handle_6 OK %d\n",getCurrentTime()); + + + //打印版本号 + printf("version: V1.72 \n"); + // 初始化框架 放在最前面,解决电机can发送信号累积不处理的问题。 + + testAppInit(); + paramAppInit(); + diffAppInit(); + brakeAppInit(); + powerAppInit(); //电源管理 + tempAppInit(); //温度 + lightAppInit(); //灯光 + ethernetInterfaceInit(); //以太网先初始化 + requestAppInit(); + canInterfaceInit(); + bootInterfaceInit(); +// ultrasonicAppInit(); + + printf("All init OK ------ %d\n",getCurrentTime()); + + sdrv_gpio_set_pin_output_level(GPIO_B9, 1); //测量时间 + for (;;) + { + // 处理信号 + processMessages(); + } +}