mirror of
https://github.com/goldenfishs/MRobot.git
synced 2026-02-04 18:00:19 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 843936525f | |||
| e47d170066 | |||
| 2d15be44d0 | |||
| 2de9f5c428 | |||
| c5acabdc49 | |||
| 8a031012fa | |||
| 5e8bab2014 | |||
| 21052cf0a7 | |||
| 4a3e0d8391 | |||
| 7d8ae97c25 | |||
| 296118b408 | |||
| 7300d03812 | |||
| 1ae3860612 | |||
| ae6afa9fbd |
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@
|
||||
*.lst
|
||||
*.ini
|
||||
*.iex
|
||||
*.pyc
|
||||
*.sct
|
||||
*.scvd
|
||||
*.uvguix
|
||||
|
||||
@ -8,7 +8,7 @@ OutputBaseFilename=MRobotInstaller
|
||||
|
||||
[Files]
|
||||
; 复制整个 dist\MRobot 文件夹(onedir 模式生成的所有文件)
|
||||
Source: "dist\MRobot\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
|
||||
Source: "dist\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
|
||||
; 复制 assets 资源文件到安装目录(支持后续更新)
|
||||
Source: "assets\logo\*"; DestDir: "{app}\assets\logo"; Flags: ignoreversion recursesubdirs
|
||||
|
||||
|
||||
@ -2,8 +2,11 @@ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QStackedWidget, QSizePolicy
|
||||
from PyQt5.QtCore import Qt
|
||||
from qfluentwidgets import PushSettingCard, FluentIcon, TabBar
|
||||
from qfluentwidgets import TitleLabel, BodyLabel, PushButton, FluentIcon
|
||||
from PyQt5.QtWidgets import QFileDialog
|
||||
from PyQt5.QtWidgets import QFileDialog, QDialog, QHBoxLayout
|
||||
from qfluentwidgets import ComboBox, PrimaryPushButton, SubtitleLabel
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from .function_fit_interface import FunctionFitInterface
|
||||
from .ai_interface import AIInterface
|
||||
from qfluentwidgets import InfoBar
|
||||
@ -56,6 +59,10 @@ class CodeConfigurationInterface(QWidget):
|
||||
self.update_template_btn.setFixedWidth(200)
|
||||
mainLayout.addWidget(self.update_template_btn, alignment=Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
self.preset_ioc_btn = PushButton(FluentIcon.LIBRARY, "获取预设IOC")
|
||||
self.preset_ioc_btn.setFixedWidth(200)
|
||||
mainLayout.addWidget(self.preset_ioc_btn, alignment=Qt.AlignmentFlag.AlignCenter)
|
||||
|
||||
mainLayout.addSpacing(10)
|
||||
mainLayout.addStretch()
|
||||
|
||||
@ -69,6 +76,7 @@ class CodeConfigurationInterface(QWidget):
|
||||
self.tabBar.tabCloseRequested.connect(self.onCloseTab)
|
||||
self.choose_btn.clicked.connect(self.choose_project_folder) # 启用选择项目路径按钮
|
||||
self.update_template_btn.clicked.connect(self.on_update_template)
|
||||
self.preset_ioc_btn.clicked.connect(self.use_preset_ioc) # 启用预设工程按钮
|
||||
|
||||
|
||||
def on_update_template(self):
|
||||
@ -88,6 +96,170 @@ class CodeConfigurationInterface(QWidget):
|
||||
)
|
||||
update_code(parent=self, info_callback=info, error_callback=error)
|
||||
|
||||
def get_preset_ioc_files(self):
|
||||
"""获取预设的ioc文件列表"""
|
||||
try:
|
||||
preset_ioc_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), "assets", "User_code", "ioc")
|
||||
if not os.path.exists(preset_ioc_dir):
|
||||
return []
|
||||
|
||||
ioc_files = []
|
||||
for filename in os.listdir(preset_ioc_dir):
|
||||
if filename.endswith('.ioc'):
|
||||
ioc_files.append({
|
||||
'name': os.path.splitext(filename)[0],
|
||||
'filename': filename,
|
||||
'path': os.path.join(preset_ioc_dir, filename)
|
||||
})
|
||||
return ioc_files
|
||||
except Exception as e:
|
||||
print(f"获取预设ioc文件失败: {e}")
|
||||
return []
|
||||
|
||||
def use_preset_ioc(self):
|
||||
"""使用预设ioc文件"""
|
||||
preset_files = self.get_preset_ioc_files()
|
||||
if not preset_files:
|
||||
InfoBar.warning(
|
||||
title="无预设工程",
|
||||
content="未找到可用的预设工程文件",
|
||||
parent=self,
|
||||
duration=2000
|
||||
)
|
||||
return
|
||||
|
||||
# 创建选择对话框
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("获取预设IOC")
|
||||
dialog.resize(400, 200)
|
||||
dialog.setModal(True)
|
||||
|
||||
layout = QVBoxLayout(dialog)
|
||||
layout.setContentsMargins(24, 24, 24, 24)
|
||||
layout.setSpacing(16)
|
||||
|
||||
# 标题
|
||||
title_label = SubtitleLabel("选择要使用的IOC模版")
|
||||
layout.addWidget(title_label)
|
||||
|
||||
# 选择下拉框
|
||||
select_layout = QHBoxLayout()
|
||||
select_label = BodyLabel("预设IOC:")
|
||||
preset_combo = ComboBox()
|
||||
|
||||
# 修复ComboBox数据问题
|
||||
for i, preset in enumerate(preset_files):
|
||||
preset_combo.addItem(preset['name'])
|
||||
|
||||
select_layout.addWidget(select_label)
|
||||
select_layout.addWidget(preset_combo)
|
||||
layout.addLayout(select_layout)
|
||||
|
||||
layout.addSpacing(16)
|
||||
|
||||
# 按钮区域
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_layout.addStretch()
|
||||
|
||||
cancel_btn = PushButton("取消")
|
||||
ok_btn = PrimaryPushButton("保存到")
|
||||
|
||||
cancel_btn.clicked.connect(dialog.reject)
|
||||
ok_btn.clicked.connect(dialog.accept)
|
||||
|
||||
btn_layout.addWidget(cancel_btn)
|
||||
btn_layout.addWidget(ok_btn)
|
||||
layout.addLayout(btn_layout)
|
||||
|
||||
# 显示对话框
|
||||
if dialog.exec() == QDialog.Accepted:
|
||||
selected_index = preset_combo.currentIndex()
|
||||
if selected_index >= 0 and selected_index < len(preset_files):
|
||||
selected_preset = preset_files[selected_index]
|
||||
self.save_preset_template(selected_preset)
|
||||
|
||||
def save_preset_template(self, preset_info):
|
||||
"""保存预设模板到用户指定位置"""
|
||||
try:
|
||||
# 让用户选择保存位置
|
||||
save_dir = QFileDialog.getExistingDirectory(
|
||||
self,
|
||||
f"选择保存 {preset_info['name']} 模板的位置",
|
||||
os.path.expanduser("~")
|
||||
)
|
||||
|
||||
if not save_dir:
|
||||
return
|
||||
|
||||
# 复制ioc文件到用户选择的目录
|
||||
target_path = os.path.join(save_dir, preset_info['filename'])
|
||||
|
||||
# 检查目标文件是否已存在
|
||||
if os.path.exists(target_path):
|
||||
from qfluentwidgets import Dialog
|
||||
dialog = Dialog("文件已存在", f"目标位置已存在 {preset_info['filename']},是否覆盖?", self)
|
||||
if dialog.exec() != Dialog.Accepted:
|
||||
return
|
||||
|
||||
# 复制文件
|
||||
shutil.copy2(preset_info['path'], target_path)
|
||||
|
||||
InfoBar.success(
|
||||
title="模板保存成功",
|
||||
content=f"预设模板 {preset_info['name']} 已保存到:\n{target_path}",
|
||||
parent=self,
|
||||
duration=3000
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
InfoBar.error(
|
||||
title="保存失败",
|
||||
content=f"保存预设模板失败: {str(e)}",
|
||||
parent=self,
|
||||
duration=3000
|
||||
)
|
||||
|
||||
def open_project_from_path(self, folder_path):
|
||||
"""从指定路径打开工程"""
|
||||
try:
|
||||
if not os.path.exists(folder_path):
|
||||
return
|
||||
|
||||
ioc_files = [f for f in os.listdir(folder_path) if f.endswith('.ioc')]
|
||||
if ioc_files:
|
||||
# 检查是否已存在 codeGenPage 标签页
|
||||
for i in range(self.stackedWidget.count()):
|
||||
widget = self.stackedWidget.widget(i)
|
||||
if widget is not None and widget.objectName() == "codeGenPage":
|
||||
# 如果已存在,则切换到该标签页,并更新路径显示
|
||||
if hasattr(widget, "project_path"):
|
||||
widget.project_path = folder_path
|
||||
if hasattr(widget, "refresh"):
|
||||
widget.refresh()
|
||||
self.stackedWidget.setCurrentWidget(widget)
|
||||
self.tabBar.setCurrentTab("codeGenPage")
|
||||
return
|
||||
|
||||
# 不存在则新建
|
||||
code_gen_page = CodeGenerateInterface(folder_path, self)
|
||||
self.addSubInterface(code_gen_page, "codeGenPage", "代码生成")
|
||||
self.stackedWidget.setCurrentWidget(code_gen_page)
|
||||
self.tabBar.setCurrentTab("codeGenPage")
|
||||
else:
|
||||
InfoBar.error(
|
||||
title="未找到.ioc文件",
|
||||
content="所选文件夹不是有效的CUBEMX工程目录",
|
||||
parent=self,
|
||||
duration=3000
|
||||
)
|
||||
except Exception as e:
|
||||
InfoBar.error(
|
||||
title="打开工程失败",
|
||||
content=f"打开工程失败: {str(e)}",
|
||||
parent=self,
|
||||
duration=3000
|
||||
)
|
||||
|
||||
def choose_project_folder(self):
|
||||
folder = QFileDialog.getExistingDirectory(self, "选择CUBEMX工程目录")
|
||||
if not folder:
|
||||
|
||||
@ -77,8 +77,29 @@ class BspSimplePeripheral(QWidget):
|
||||
return False
|
||||
output_path = os.path.join(self.project_path, f"User/bsp/{filename}")
|
||||
CodeGenerator.save_with_preserve(output_path, template_content) # 使用保留用户区域的写入
|
||||
|
||||
# 复制BSP文件夹下的其他额外文件(如 README.md, CHANGELOG.md)
|
||||
periph_template_dir = os.path.join(template_base_dir, periph_folder)
|
||||
if os.path.exists(periph_template_dir) and os.path.isdir(periph_template_dir):
|
||||
import shutil
|
||||
files_to_process = list(self.template_names.values())
|
||||
for item in os.listdir(periph_template_dir):
|
||||
# 跳过已处理的主要文件
|
||||
if item in files_to_process:
|
||||
continue
|
||||
|
||||
src_file = os.path.join(periph_template_dir, item)
|
||||
dst_file = os.path.join(self.project_path, f"User/bsp/{item}")
|
||||
|
||||
# 只复制文件,不复制子目录
|
||||
if os.path.isfile(src_file):
|
||||
os.makedirs(os.path.dirname(dst_file), exist_ok=True)
|
||||
shutil.copy2(src_file, dst_file)
|
||||
print(f"复制BSP额外文件: {item}")
|
||||
|
||||
self._save_config()
|
||||
return True
|
||||
return True
|
||||
|
||||
|
||||
def _save_config(self):
|
||||
@ -405,6 +426,19 @@ class bsp_can(BspPeripheralBase):
|
||||
get_available_can
|
||||
)
|
||||
|
||||
def _generate_bsp_code_internal(self):
|
||||
"""重写生成方法,直接复制can文件夹中的文件"""
|
||||
# 检查是否需要生成
|
||||
if not self.is_need_generate():
|
||||
for filename in self.template_names.values():
|
||||
output_path = os.path.join(self.project_path, f"User/bsp/{filename}")
|
||||
if os.path.exists(output_path):
|
||||
return "skipped"
|
||||
return "not_needed"
|
||||
|
||||
# 调用父类方法生成配置化的代码(头文件和源文件)
|
||||
return super()._generate_bsp_code_internal()
|
||||
|
||||
def _generate_source_file(self, configs, template_dir):
|
||||
# 从子文件夹加载模板(与_generate_header_file保持一致)
|
||||
periph_folder = self.peripheral_name.lower()
|
||||
@ -657,6 +691,37 @@ class bsp_fdcan(BspPeripheralBase):
|
||||
get_available_fdcan
|
||||
)
|
||||
|
||||
def _generate_bsp_code_internal(self):
|
||||
"""重写生成方法,调用父类生成FDCAN代码后复制CAN兼容层"""
|
||||
# 先调用父类方法生成FDCAN代码
|
||||
result = super()._generate_bsp_code_internal()
|
||||
if result and result not in ["skipped", "not_needed"]:
|
||||
# 成功后复制CAN兼容层文件
|
||||
self._copy_can_wrapper()
|
||||
return result
|
||||
|
||||
def _copy_can_wrapper(self):
|
||||
"""复制CAN兼容层文件(can.h)到项目"""
|
||||
try:
|
||||
template_base_dir = CodeGenerator.get_assets_dir("User_code/bsp")
|
||||
fdcan_folder = os.path.join(template_base_dir, "fdcan")
|
||||
bsp_output_dir = os.path.join(self.project_path, "User/bsp")
|
||||
|
||||
# 确保输出目录存在
|
||||
os.makedirs(bsp_output_dir, exist_ok=True)
|
||||
|
||||
# 复制can.h(CAN兼容层头文件)
|
||||
can_h_src = os.path.join(fdcan_folder, "can.h")
|
||||
can_h_dst = os.path.join(bsp_output_dir, "can.h")
|
||||
if os.path.exists(can_h_src):
|
||||
with open(can_h_src, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
CodeGenerator.save_with_preserve(can_h_dst, content)
|
||||
print(f"✓ 已复制CAN兼容层: can.h")
|
||||
|
||||
except Exception as e:
|
||||
print(f"复制CAN兼容层文件时出错: {e}")
|
||||
|
||||
def _generate_header_file(self, configs, template_dir):
|
||||
"""重写头文件生成,添加 FDCAN 使能和 FIFO 分配定义"""
|
||||
# 从子文件夹加载模板
|
||||
@ -852,10 +917,48 @@ class bsp_spi(BspPeripheralBase):
|
||||
|
||||
|
||||
def patch_uart_interrupts(project_path, uart_instances):
|
||||
"""自动修改 stm32f4xx_it.c,插入 UART BSP 相关代码"""
|
||||
it_path = os.path.join(project_path, "Core/Src/stm32f4xx_it.c")
|
||||
"""自动修改中断文件,插入 UART BSP 相关代码(支持 F1/F4/H7 等系列)"""
|
||||
# 检测MCU型号,确定正确的中断文件
|
||||
ioc_files = [f for f in os.listdir(project_path) if f.endswith('.ioc')]
|
||||
if not ioc_files:
|
||||
return
|
||||
|
||||
ioc_path = os.path.join(project_path, ioc_files[0])
|
||||
mcu_name = analyzing_ioc.get_mcu_name_from_ioc(ioc_path)
|
||||
|
||||
if not mcu_name:
|
||||
return
|
||||
|
||||
# 根据MCU型号确定中断文件名
|
||||
mcu_upper = mcu_name.upper()
|
||||
if 'STM32F1' in mcu_upper:
|
||||
it_file = "stm32f1xx_it.c"
|
||||
elif 'STM32F4' in mcu_upper:
|
||||
it_file = "stm32f4xx_it.c"
|
||||
elif 'STM32H7' in mcu_upper:
|
||||
it_file = "stm32h7xx_it.c"
|
||||
elif 'STM32F7' in mcu_upper:
|
||||
it_file = "stm32f7xx_it.c"
|
||||
elif 'STM32G4' in mcu_upper:
|
||||
it_file = "stm32g4xx_it.c"
|
||||
elif 'STM32L4' in mcu_upper:
|
||||
it_file = "stm32l4xx_it.c"
|
||||
else:
|
||||
# 通用处理:尝试从MCU名称提取系列信息
|
||||
# 格式通常为 STM32X0XXX,提取 X0 部分
|
||||
import re as regex
|
||||
match = regex.match(r'STM32([A-Z]\d)', mcu_upper)
|
||||
if match:
|
||||
series = match.group(1).lower()
|
||||
it_file = f"stm32{series}xx_it.c"
|
||||
else:
|
||||
# 默认尝试 F4
|
||||
it_file = "stm32f4xx_it.c"
|
||||
|
||||
it_path = os.path.join(project_path, f"Core/Src/{it_file}")
|
||||
if not os.path.exists(it_path):
|
||||
return
|
||||
|
||||
with open(it_path, "r", encoding="utf-8") as f:
|
||||
code = f.read()
|
||||
|
||||
@ -1113,18 +1216,25 @@ class bsp_gpio(QWidget):
|
||||
)
|
||||
|
||||
# 生成EXTI使能代码 - 使用用户自定义的BSP枚举名称
|
||||
# 根据引脚编号获取正确的IRQn(适配不同MCU)
|
||||
enable_lines = []
|
||||
disable_lines = []
|
||||
for config in configs:
|
||||
if config['has_exti']:
|
||||
ioc_label = config['ioc_label']
|
||||
custom_name = config['custom_name']
|
||||
# 尝试从IOC label中提取引脚编号,优先使用IOC定义的IRQn
|
||||
enable_lines.append(f" case BSP_GPIO_{custom_name}:")
|
||||
enable_lines.append(f"#if defined({ioc_label}_EXTI_IRQn)")
|
||||
enable_lines.append(f" HAL_NVIC_EnableIRQ({ioc_label}_EXTI_IRQn);")
|
||||
enable_lines.append(f" break;")
|
||||
enable_lines.append(f"#endif")
|
||||
enable_lines.append(f" return BSP_OK;")
|
||||
|
||||
disable_lines.append(f" case BSP_GPIO_{custom_name}:")
|
||||
disable_lines.append(f"#if defined({ioc_label}_EXTI_IRQn)")
|
||||
disable_lines.append(f" HAL_NVIC_DisableIRQ({ioc_label}_EXTI_IRQn);")
|
||||
disable_lines.append(f" break;")
|
||||
disable_lines.append(f"#endif")
|
||||
disable_lines.append(f" return BSP_OK;")
|
||||
|
||||
content = CodeGenerator.replace_auto_generated(
|
||||
content, "AUTO GENERATED BSP_GPIO_ENABLE_IRQ", "\n".join(enable_lines)
|
||||
|
||||
@ -124,6 +124,26 @@ class ComponentSimple(QWidget):
|
||||
continue
|
||||
output_path = os.path.join(self.project_path, f"User/component/{filename}")
|
||||
CodeGenerator.save_with_preserve(output_path, template_content)
|
||||
|
||||
# 复制组件文件夹下的其他额外文件
|
||||
comp_template_dir = os.path.join(template_base_dir, comp_folder)
|
||||
if os.path.exists(comp_template_dir) and os.path.isdir(comp_template_dir):
|
||||
import shutil
|
||||
files_to_process = list(self.template_names.values())
|
||||
for item in os.listdir(comp_template_dir):
|
||||
# 跳过已处理的主要文件
|
||||
if item in files_to_process:
|
||||
continue
|
||||
|
||||
src_file = os.path.join(comp_template_dir, item)
|
||||
dst_file = os.path.join(self.project_path, f"User/component/{item}")
|
||||
|
||||
# 只复制文件,不复制子目录
|
||||
if os.path.isfile(src_file):
|
||||
os.makedirs(os.path.dirname(dst_file), exist_ok=True)
|
||||
shutil.copy2(src_file, dst_file)
|
||||
print(f"复制组件额外文件: {item}")
|
||||
|
||||
self._save_config()
|
||||
return True
|
||||
|
||||
@ -271,75 +291,27 @@ class component(QWidget):
|
||||
if not dep_name.endswith(('.h', '.c', '.hpp', '.cpp')):
|
||||
components_to_generate.add(dep_name)
|
||||
|
||||
# 为没有对应页面但需要生成的依赖组件创建临时页面
|
||||
# 检查缺失的依赖组件
|
||||
user_code_dir = CodeGenerator.get_assets_dir("User_code")
|
||||
missing_dependencies = []
|
||||
for comp_name in components_to_generate:
|
||||
if comp_name not in component_pages:
|
||||
# 创建临时组件页面
|
||||
template_names = {'header': f'{comp_name}.h', 'source': f'{comp_name}.c'}
|
||||
temp_page = ComponentSimple(project_path, comp_name.upper(), template_names)
|
||||
# temp_page.set_forced_enabled(True) # 自动启用依赖组件
|
||||
component_pages[comp_name] = temp_page
|
||||
missing_dependencies.append(comp_name)
|
||||
|
||||
# 如果没有组件需要生成,返回提示信息
|
||||
if not components_to_generate:
|
||||
return "没有启用的组件需要生成代码。"
|
||||
|
||||
# 生成代码和依赖文件
|
||||
# 如果有缺失的依赖组件,提示用户
|
||||
if missing_dependencies:
|
||||
missing_msg = f"警告:以下依赖组件未启用,可能导致编译错误:{', '.join(missing_dependencies)}\n请在组件配置中启用这些依赖组件。\n\n"
|
||||
else:
|
||||
missing_msg = ""
|
||||
|
||||
# 生成代码
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
fail_list = []
|
||||
|
||||
# 处理依赖文件的复制
|
||||
all_deps = set()
|
||||
for page in pages:
|
||||
if hasattr(page, "component_name") and hasattr(page, "is_need_generate"):
|
||||
if page.is_need_generate():
|
||||
deps = page.get_enabled_dependencies()
|
||||
all_deps.update(deps)
|
||||
|
||||
# 复制依赖文件
|
||||
for dep_path in all_deps:
|
||||
try:
|
||||
# 检查是否是 bsp 层依赖
|
||||
if dep_path.startswith('bsp/'):
|
||||
# 对于 bsp 层依赖,跳过复制,因为这些由 BSP 代码生成负责
|
||||
print(f"跳过 BSP 层依赖: {dep_path} (由 BSP 代码生成负责)")
|
||||
continue
|
||||
|
||||
# dep_path 格式如 "component/filter" 或 "component/user_math.h"
|
||||
src_path = os.path.join(user_code_dir, dep_path)
|
||||
dst_path = os.path.join(project_path, "User", dep_path)
|
||||
|
||||
if os.path.isdir(src_path):
|
||||
# 如果是目录,复制整个目录
|
||||
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
|
||||
if os.path.exists(dst_path):
|
||||
shutil.rmtree(dst_path)
|
||||
shutil.copytree(src_path, dst_path)
|
||||
elif os.path.isfile(src_path):
|
||||
# 如果是文件,复制单个文件并保留用户区域
|
||||
os.makedirs(os.path.dirname(dst_path), exist_ok=True)
|
||||
with open(src_path, 'r', encoding='utf-8') as f:
|
||||
new_content = f.read()
|
||||
CodeGenerator.save_with_preserve(dst_path, new_content)
|
||||
else:
|
||||
# 如果既不是文件也不是目录,跳过
|
||||
print(f"跳过不存在的依赖: {dep_path}")
|
||||
continue
|
||||
|
||||
success_count += 1
|
||||
print(f"成功复制依赖: {dep_path}")
|
||||
except Exception as e:
|
||||
# 对于 bsp 层依赖的错误,只记录但不计入失败
|
||||
if dep_path.startswith('bsp/'):
|
||||
print(f"BSP 层依赖 {dep_path} 复制失败,但忽略此错误: {e}")
|
||||
else:
|
||||
fail_count += 1
|
||||
fail_list.append(f"{dep_path} (依赖复制异常: {e})")
|
||||
print(f"复制依赖失败: {dep_path}, 错误: {e}")
|
||||
|
||||
# 生成组件代码
|
||||
skipped_count = 0
|
||||
skipped_list = []
|
||||
|
||||
@ -370,8 +342,8 @@ class component(QWidget):
|
||||
fail_list.append(f"{comp_name} (生成异常: {e})")
|
||||
print(f"生成组件异常: {comp_name}, 错误: {e}")
|
||||
|
||||
total_items = len(all_deps) + len(components_to_generate)
|
||||
msg = f"组件代码生成完成:总共处理 {total_items} 项,成功生成 {success_count} 项,跳过 {skipped_count} 项,失败 {fail_count} 项。"
|
||||
total_items = len(components_to_generate)
|
||||
msg = missing_msg + f"组件代码生成完成:总共处理 {total_items} 项,成功生成 {success_count} 项,跳过 {skipped_count} 项,失败 {fail_count} 项。"
|
||||
if skipped_list:
|
||||
msg += f"\n跳过项(文件已存在且未勾选):\n" + "\n".join(skipped_list)
|
||||
if fail_list:
|
||||
|
||||
@ -278,11 +278,11 @@ class DeviceSimple(QWidget):
|
||||
with open(dst_path, 'w', encoding='utf-8') as f:
|
||||
f.write(content)
|
||||
|
||||
# 复制设备文件夹下的其他文件(如 lcd_lib.h)
|
||||
# 复制设备文件夹下的其他额外文件(如 lcd_lib.h)
|
||||
if os.path.exists(device_template_dir):
|
||||
import shutil
|
||||
for item in os.listdir(device_template_dir):
|
||||
# 跳过已处理的文件
|
||||
# 跳过已处理的主要文件
|
||||
if item in files_to_process:
|
||||
continue
|
||||
|
||||
@ -291,11 +291,9 @@ class DeviceSimple(QWidget):
|
||||
|
||||
# 只复制文件,不复制子目录
|
||||
if os.path.isfile(src_file):
|
||||
# 检查文件是否已存在,避免覆盖
|
||||
if not os.path.exists(dst_file):
|
||||
os.makedirs(os.path.dirname(dst_file), exist_ok=True)
|
||||
shutil.copy2(src_file, dst_file)
|
||||
print(f"复制额外文件: {dst_file}")
|
||||
os.makedirs(os.path.dirname(dst_file), exist_ok=True)
|
||||
shutil.copy2(src_file, dst_file)
|
||||
print(f"复制设备额外文件: {item}")
|
||||
|
||||
self._save_config()
|
||||
return True
|
||||
|
||||
@ -456,11 +456,19 @@ class DataInterface(QWidget):
|
||||
|
||||
def generate_freertos_task(self):
|
||||
import re
|
||||
freertos_path = os.path.join(self.project_path, "Core", "Src", "freertos.c")
|
||||
if not os.path.exists(freertos_path):
|
||||
# 尝试查找 freertos.c 或 app_freertos.c (G4系列使用 app_freertos.c)
|
||||
freertos_path = None
|
||||
possible_names = ["freertos.c", "app_freertos.c"]
|
||||
for name in possible_names:
|
||||
path = os.path.join(self.project_path, "Core", "Src", name)
|
||||
if os.path.exists(path):
|
||||
freertos_path = path
|
||||
break
|
||||
|
||||
if not freertos_path:
|
||||
InfoBar.error(
|
||||
title="未找到 freertos.c",
|
||||
content="未找到 Core/Src/freertos.c 文件,请确认工程路径。",
|
||||
title="未找到 FreeRTOS 文件",
|
||||
content="未找到 Core/Src/freertos.c 或 Core/Src/app_freertos.c 文件,请确认工程路径。",
|
||||
parent=self,
|
||||
duration=2500
|
||||
)
|
||||
@ -629,6 +637,31 @@ class DataInterface(QWidget):
|
||||
for t in task_list:
|
||||
desc = t.get("description", "")
|
||||
desc_wrapped = "\n ".join(textwrap.wrap(desc, 20))
|
||||
|
||||
# 检查是否是预设任务
|
||||
if t.get("preset_task"):
|
||||
# 使用预设任务的代码
|
||||
preset_task_name = t["preset_task"]
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
task_template_dir = CodeGenerator.get_assets_dir("User_code/task/template_task")
|
||||
preset_task_file = os.path.join(task_template_dir, f"{preset_task_name}.c")
|
||||
|
||||
if os.path.exists(preset_task_file):
|
||||
# 直接复制预设任务文件
|
||||
task_c_path = os.path.join(output_dir, f"{t['name']}.c")
|
||||
with open(preset_task_file, 'r', encoding='utf-8') as f:
|
||||
preset_code = f.read()
|
||||
|
||||
# 如果任务名称不同,需要替换函数名
|
||||
if preset_task_name != t["name"]:
|
||||
# 替换任务函数名
|
||||
preset_code = preset_code.replace(f"Task_{preset_task_name}", t["function"])
|
||||
preset_code = preset_code.replace(f" {preset_task_name} Task", f" {t['name']} Task")
|
||||
|
||||
save_with_preserve(task_c_path, preset_code)
|
||||
continue
|
||||
|
||||
# 使用默认模板生成任务代码
|
||||
context_task = {
|
||||
"task_name": t["name"],
|
||||
"task_function": t["function"],
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QWidget, QScrollArea
|
||||
from qfluentwidgets import (
|
||||
BodyLabel, TitleLabel, HorizontalSeparator, PushButton, PrimaryPushButton,
|
||||
LineEdit, SpinBox, DoubleSpinBox, CheckBox, TextEdit
|
||||
LineEdit, SpinBox, DoubleSpinBox, CheckBox, TextEdit, ComboBox
|
||||
)
|
||||
from qfluentwidgets import theme, Theme
|
||||
import yaml
|
||||
@ -76,12 +76,20 @@ class TaskConfigDialog(QDialog):
|
||||
self.add_btn = PrimaryPushButton("创建新任务")
|
||||
self.add_btn.setAutoDefault(False) # 禁止回车触发
|
||||
self.add_btn.setDefault(False)
|
||||
|
||||
# 新增:预设任务按钮
|
||||
self.preset_btn = PushButton("使用预设任务")
|
||||
self.preset_btn.setAutoDefault(False)
|
||||
self.preset_btn.setDefault(False)
|
||||
|
||||
self.del_btn = PushButton("删除当前任务")
|
||||
self.del_btn.setAutoDefault(False) # 禁止回车触发
|
||||
self.del_btn.setDefault(False)
|
||||
self.add_btn.clicked.connect(self.add_task)
|
||||
self.preset_btn.clicked.connect(self.add_preset_task)
|
||||
self.del_btn.clicked.connect(self.delete_current_task)
|
||||
btn_layout.addWidget(self.add_btn)
|
||||
btn_layout.addWidget(self.preset_btn)
|
||||
btn_layout.addWidget(self.del_btn)
|
||||
btn_layout.addStretch() # 添加/删除靠左,stretch在中间
|
||||
|
||||
@ -135,6 +143,274 @@ class TaskConfigDialog(QDialog):
|
||||
self.task_btn_layout.addWidget(btn)
|
||||
self.task_btn_layout.addStretch()
|
||||
|
||||
def get_preset_tasks(self):
|
||||
"""获取所有可用的预设任务"""
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
task_dir = CodeGenerator.get_assets_dir("User_code/task/template_task")
|
||||
preset_tasks = []
|
||||
|
||||
if not os.path.exists(task_dir):
|
||||
return preset_tasks
|
||||
|
||||
for filename in os.listdir(task_dir):
|
||||
if filename.endswith('.c') and not filename.endswith('.template'):
|
||||
task_name = os.path.splitext(filename)[0]
|
||||
preset_tasks.append(task_name)
|
||||
|
||||
return preset_tasks
|
||||
|
||||
def load_preset_task_config(self, task_name):
|
||||
"""从 yaml 配置文件中加载预设任务的配置"""
|
||||
try:
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
template_dir = CodeGenerator.get_assets_dir("User_code/task/template_task")
|
||||
config_file = os.path.join(template_dir, "task.yaml")
|
||||
|
||||
if not os.path.exists(config_file):
|
||||
return None
|
||||
|
||||
with open(config_file, 'r', encoding='utf-8') as f:
|
||||
config_data = yaml.safe_load(f)
|
||||
|
||||
if config_data and task_name in config_data:
|
||||
return config_data[task_name]
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"加载预设任务配置失败: {e}")
|
||||
return None
|
||||
|
||||
def load_preset_task_code(self, task_name):
|
||||
"""加载预设任务的代码内容"""
|
||||
from app.tools.code_generator import CodeGenerator
|
||||
task_dir = CodeGenerator.get_assets_dir("User_code/task/template_task")
|
||||
task_file = os.path.join(task_dir, f"{task_name}.c")
|
||||
|
||||
if os.path.exists(task_file):
|
||||
with open(task_file, 'r', encoding='utf-8') as f:
|
||||
return f.read()
|
||||
return None
|
||||
|
||||
def add_preset_task(self):
|
||||
"""添加预设任务"""
|
||||
preset_tasks = self.get_preset_tasks()
|
||||
if not preset_tasks:
|
||||
InfoBar.warning(
|
||||
title="无预设任务",
|
||||
content="未找到可用的预设任务模板",
|
||||
parent=self,
|
||||
duration=2000
|
||||
)
|
||||
return
|
||||
|
||||
# 创建自适应主题的对话框
|
||||
dialog = QDialog(self)
|
||||
dialog.setWindowTitle("选择预设任务")
|
||||
dialog.resize(600, 500)
|
||||
dialog.setModal(True)
|
||||
|
||||
layout = QVBoxLayout(dialog)
|
||||
layout.setContentsMargins(24, 24, 24, 24)
|
||||
layout.setSpacing(18)
|
||||
|
||||
# 固定内容区域
|
||||
fixed_content = QWidget()
|
||||
fixed_content.setFixedHeight(180) # 减少固定高度
|
||||
fixed_layout = QVBoxLayout(fixed_content)
|
||||
fixed_layout.setContentsMargins(0, 0, 0, 0)
|
||||
fixed_layout.setSpacing(18)
|
||||
|
||||
# 标题
|
||||
title_label = TitleLabel("选择预设任务模板")
|
||||
fixed_layout.addWidget(title_label)
|
||||
|
||||
# 说明文字
|
||||
desc_label = BodyLabel("选择一个预设任务模板,系统将自动复制相应的代码和配置")
|
||||
fixed_layout.addWidget(desc_label)
|
||||
|
||||
fixed_layout.addWidget(HorizontalSeparator())
|
||||
|
||||
# 任务选择
|
||||
select_layout = QHBoxLayout()
|
||||
select_layout.setSpacing(12)
|
||||
|
||||
select_label = BodyLabel("预设任务:")
|
||||
preset_combo = ComboBox()
|
||||
preset_combo.addItems(preset_tasks)
|
||||
preset_combo.setCurrentIndex(0)
|
||||
preset_combo.setMinimumWidth(160)
|
||||
|
||||
select_layout.addWidget(select_label)
|
||||
select_layout.addWidget(preset_combo)
|
||||
select_layout.addStretch()
|
||||
|
||||
fixed_layout.addLayout(select_layout)
|
||||
|
||||
# 参数信息 - 单行显示
|
||||
params_layout = QHBoxLayout()
|
||||
params_layout.setSpacing(24) # 适中的间距
|
||||
|
||||
self.info_freq = BodyLabel("")
|
||||
self.info_delay = BodyLabel("")
|
||||
self.info_stack = BodyLabel("")
|
||||
self.info_ctrl = BodyLabel("")
|
||||
|
||||
self.info_freq.setMinimumWidth(120)
|
||||
self.info_delay.setMinimumWidth(100)
|
||||
self.info_stack.setMinimumWidth(120)
|
||||
self.info_ctrl.setMinimumWidth(100)
|
||||
|
||||
params_layout.addWidget(self.info_freq)
|
||||
params_layout.addWidget(self.info_delay)
|
||||
params_layout.addWidget(self.info_stack)
|
||||
params_layout.addWidget(self.info_ctrl)
|
||||
params_layout.addStretch()
|
||||
|
||||
fixed_layout.addLayout(params_layout)
|
||||
fixed_layout.addStretch() # 在固定区域内保持紧凑
|
||||
|
||||
layout.addWidget(fixed_content)
|
||||
|
||||
# 弹性描述区域
|
||||
desc_layout = QVBoxLayout()
|
||||
desc_layout.setSpacing(8)
|
||||
|
||||
desc_title = BodyLabel("描述:")
|
||||
desc_title.setStyleSheet("font-weight: bold;")
|
||||
desc_layout.addWidget(desc_title)
|
||||
|
||||
self.preview_desc = TextEdit()
|
||||
self.preview_desc.setReadOnly(True)
|
||||
self.preview_desc.setMinimumHeight(60) # 最小高度
|
||||
desc_layout.addWidget(self.preview_desc)
|
||||
|
||||
layout.addLayout(desc_layout, stretch=1) # 弹性伸缩
|
||||
|
||||
# 按钮区域
|
||||
layout.addWidget(HorizontalSeparator())
|
||||
btn_layout = QHBoxLayout()
|
||||
btn_layout.addStretch()
|
||||
|
||||
cancel_btn = PushButton("取消")
|
||||
ok_btn = PrimaryPushButton("确定添加")
|
||||
|
||||
cancel_btn.clicked.connect(dialog.reject)
|
||||
ok_btn.clicked.connect(dialog.accept)
|
||||
|
||||
btn_layout.addWidget(cancel_btn)
|
||||
btn_layout.addWidget(ok_btn)
|
||||
layout.addLayout(btn_layout)
|
||||
|
||||
# 预览更新函数
|
||||
def update_preview():
|
||||
selected = preset_combo.currentText()
|
||||
self.update_preset_preview(selected)
|
||||
|
||||
preset_combo.currentTextChanged.connect(update_preview)
|
||||
|
||||
# 存储对话框状态
|
||||
self.current_preview_dialog = dialog
|
||||
self.preview_combo = preset_combo
|
||||
|
||||
# 初始化预览
|
||||
if preset_tasks:
|
||||
update_preview()
|
||||
|
||||
# 显示对话框
|
||||
if dialog.exec() == QDialog.Accepted:
|
||||
selected_task = preset_combo.currentText()
|
||||
self.save_form()
|
||||
new_idx = len(self.tasks)
|
||||
|
||||
# 从配置文件加载预设任务参数
|
||||
config = self.load_preset_task_config(selected_task)
|
||||
if config:
|
||||
new_task = self._make_task_obj({
|
||||
"name": config.get("name", selected_task),
|
||||
"frequency": config.get("frequency", 500),
|
||||
"delay": config.get("delay", 0),
|
||||
"stack": config.get("stack", 256),
|
||||
"description": config.get("description", ""),
|
||||
"freq_control": config.get("freq_control", True)
|
||||
})
|
||||
else:
|
||||
new_task = self._make_task_obj({"name": selected_task})
|
||||
|
||||
new_task["preset_task"] = selected_task
|
||||
|
||||
self.tasks.append(new_task)
|
||||
self.current_index = new_idx
|
||||
self.refresh_task_btns()
|
||||
self.show_task_form(self.tasks[self.current_index])
|
||||
|
||||
InfoBar.success(
|
||||
title="添加成功",
|
||||
content=f"已添加预设任务:{selected_task}",
|
||||
parent=self,
|
||||
duration=2000
|
||||
)
|
||||
|
||||
def update_preset_preview(self, task_name):
|
||||
"""更新预设任务预览信息"""
|
||||
# 从配置加载信息
|
||||
config = self.load_preset_task_config(task_name)
|
||||
if config:
|
||||
self.info_freq.setText(f"频率: {config.get('frequency', 500)} Hz")
|
||||
self.info_delay.setText(f"延时: {config.get('delay', 0)} ms")
|
||||
self.info_stack.setText(f"堆栈: {config.get('stack', 256)} Bytes")
|
||||
freq_ctrl = "启用" if config.get('freq_control', True) else "禁用"
|
||||
self.info_ctrl.setText(f"频率控制: {freq_ctrl}")
|
||||
|
||||
description = config.get('description', f'预设任务:{task_name}')
|
||||
self.preview_desc.setText(description)
|
||||
else:
|
||||
self.info_freq.setText("频率: 500 Hz")
|
||||
self.info_delay.setText("延时: 0 ms")
|
||||
self.info_stack.setText("堆栈: 256 Bytes")
|
||||
self.info_ctrl.setText("频率控制: 启用")
|
||||
self.preview_desc.setText(f"预设任务:{task_name}")
|
||||
|
||||
def on_preset_task_selected(self, task_name):
|
||||
"""预设任务选择事件(向后兼容)"""
|
||||
pass
|
||||
|
||||
def get_preset_task_description(self, task_name):
|
||||
"""获取预设任务的描述信息"""
|
||||
# 首先尝试从 yaml 配置中获取描述
|
||||
config = self.load_preset_task_config(task_name)
|
||||
if config and 'description' in config:
|
||||
return f"预设任务:{task_name}\n\n{config['description']}\n\n频率控制:{'启用' if config.get('freq_control', True) else '禁用'}\n运行频率:{config.get('frequency', 500)} Hz\n堆栈大小:{config.get('stack', 256)} Bytes\n初始延时:{config.get('delay', 0)} ms"
|
||||
|
||||
# 如果没有配置文件,则从代码注释中提取
|
||||
try:
|
||||
task_code = self.load_preset_task_code(task_name)
|
||||
if task_code:
|
||||
# 尝试从注释中提取描述
|
||||
lines = task_code.split('\n')
|
||||
description_lines = []
|
||||
in_comment = False
|
||||
|
||||
for line in lines[:20]: # 只检查前20行
|
||||
line = line.strip()
|
||||
if line.startswith('/*'):
|
||||
in_comment = True
|
||||
if 'Task' in line and line != '/*':
|
||||
description_lines.append(line.replace('/*', '').strip())
|
||||
continue
|
||||
elif line.endswith('*/'):
|
||||
in_comment = False
|
||||
break
|
||||
elif in_comment and line and not line.startswith('*'):
|
||||
description_lines.append(line)
|
||||
|
||||
if description_lines:
|
||||
return '\n'.join(description_lines)
|
||||
else:
|
||||
return f"预设任务:{task_name}\n这是一个预定义的任务模板,包含完整的实现代码。"
|
||||
else:
|
||||
return f"预设任务:{task_name}\n无法读取任务描述。"
|
||||
except Exception as e:
|
||||
return f"预设任务:{task_name}\n读取描述时出现错误:{str(e)}"
|
||||
|
||||
def add_task(self):
|
||||
self.save_form()
|
||||
new_idx = len(self.tasks)
|
||||
@ -302,5 +578,10 @@ class TaskConfigDialog(QDialog):
|
||||
}
|
||||
if freq_ctrl:
|
||||
task["frequency"] = freq
|
||||
|
||||
# 保留预设任务信息
|
||||
if "preset_task" in t:
|
||||
task["preset_task"] = t["preset_task"]
|
||||
|
||||
tasks.append(task)
|
||||
return tasks
|
||||
BIN
assets/.DS_Store
vendored
BIN
assets/.DS_Store
vendored
Binary file not shown.
BIN
assets/User_code/.DS_Store
vendored
BIN
assets/User_code/.DS_Store
vendored
Binary file not shown.
@ -1,113 +0,0 @@
|
||||
# User_code 目录结构说明
|
||||
|
||||
## 新的文件夹结构
|
||||
|
||||
所有外设、组件和设备的文件现在都存放在独立的子文件夹中,便于管理和维护。
|
||||
|
||||
### BSP (板级支持包)
|
||||
```
|
||||
bsp/
|
||||
├── bsp.h # BSP 总头文件
|
||||
├── describe.csv # 外设描述文件
|
||||
├── .gitkeep
|
||||
├── can/
|
||||
│ ├── can.c
|
||||
│ └── can.h
|
||||
├── fdcan/
|
||||
│ ├── fdcan.c
|
||||
│ └── fdcan.h
|
||||
├── uart/
|
||||
│ ├── uart.c
|
||||
│ └── uart.h
|
||||
├── spi/
|
||||
│ ├── spi.c
|
||||
│ └── spi.h
|
||||
├── i2c/
|
||||
│ ├── i2c.c
|
||||
│ └── i2c.h
|
||||
├── gpio/
|
||||
│ ├── gpio.c
|
||||
│ └── gpio.h
|
||||
├── pwm/
|
||||
│ ├── pwm.c
|
||||
│ └── pwm.h
|
||||
├── time/
|
||||
│ ├── time.c
|
||||
│ └── time.h
|
||||
├── dwt/
|
||||
│ ├── dwt.c
|
||||
│ └── dwt.h
|
||||
└── mm/
|
||||
├── mm.c
|
||||
└── mm.h
|
||||
```
|
||||
|
||||
### Component (组件)
|
||||
```
|
||||
component/
|
||||
├── describe.csv # 组件描述文件
|
||||
├── dependencies.csv # 组件依赖关系
|
||||
├── .gitkeep
|
||||
├── ahrs/
|
||||
├── capacity/
|
||||
├── cmd/
|
||||
├── crc16/
|
||||
├── crc8/
|
||||
├── error_detect/
|
||||
├── filter/
|
||||
├── freertos_cli/
|
||||
├── limiter/
|
||||
├── mixer/
|
||||
├── pid/
|
||||
├── ui/
|
||||
└── user_math/
|
||||
```
|
||||
|
||||
### Device (设备)
|
||||
```
|
||||
device/
|
||||
├── device.h # Device 总头文件
|
||||
├── config.yaml # 设备配置文件
|
||||
├── .gitkeep
|
||||
├── bmi088/
|
||||
├── buzzer/
|
||||
├── dm_imu/
|
||||
├── dr16/
|
||||
├── ist8310/
|
||||
├── led/
|
||||
├── motor/
|
||||
├── motor_dm/
|
||||
├── motor_lk/
|
||||
├── motor_lz/
|
||||
├── motor_odrive/
|
||||
├── motor_rm/
|
||||
├── motor_vesc/
|
||||
├── oid/
|
||||
├── ops9/
|
||||
├── rc_can/
|
||||
├── servo/
|
||||
├── vofa/
|
||||
├── ws2812/
|
||||
└── lcd_driver/ # LCD 驱动(原有结构)
|
||||
```
|
||||
|
||||
## 代码生成逻辑
|
||||
|
||||
代码生成器会:
|
||||
1. 首先尝试从子文件夹加载模板(如 `bsp/can/can.c`)
|
||||
2. 如果子文件夹不存在,回退到根目录加载(向后兼容)
|
||||
3. 生成时将文件展开到项目的扁平目录结构中(如 `User/bsp/can.c`)
|
||||
|
||||
## 优势
|
||||
|
||||
✅ **更好的组织**: 每个外设/组件的文件都在独立文件夹中
|
||||
✅ **便于管理**: 添加、删除、修改模板更加方便
|
||||
✅ **向后兼容**: 现有的扁平结构仍然可以正常工作
|
||||
✅ **清晰的结构**: 一目了然地看到所有可用的外设/组件
|
||||
|
||||
## 迁移说明
|
||||
|
||||
如果你添加新的外设/组件/设备:
|
||||
1. 在对应目录下创建新的子文件夹(小写命名)
|
||||
2. 将 .c 和 .h 文件放入子文件夹
|
||||
3. 代码生成器会自动识别并使用
|
||||
79
assets/User_code/bsp/fdcan/can.h
Normal file
79
assets/User_code/bsp/fdcan/can.h
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* @file can.h
|
||||
* @brief CAN兼容层 - 将CAN接口映射到FDCAN
|
||||
* @note 本文件用于FDCAN兼容CAN接口,设备层代码可以继续使用BSP_CAN_xxx接口
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "bsp/fdcan.h"
|
||||
|
||||
/* 类型映射 */
|
||||
typedef BSP_FDCAN_t BSP_CAN_t;
|
||||
typedef BSP_FDCAN_Callback_t BSP_CAN_Callback_t;
|
||||
typedef BSP_FDCAN_Format_t BSP_CAN_Format_t;
|
||||
typedef BSP_FDCAN_FrameType_t BSP_CAN_FrameType_t;
|
||||
typedef BSP_FDCAN_Message_t BSP_CAN_Message_t;
|
||||
typedef BSP_FDCAN_StdDataFrame_t BSP_CAN_StdDataFrame_t;
|
||||
typedef BSP_FDCAN_ExtDataFrame_t BSP_CAN_ExtDataFrame_t;
|
||||
typedef BSP_FDCAN_RemoteFrame_t BSP_CAN_RemoteFrame_t;
|
||||
typedef BSP_FDCAN_IdParser_t BSP_CAN_IdParser_t;
|
||||
|
||||
/* 常量映射 */
|
||||
#define BSP_CAN_MAX_DLC BSP_FDCAN_MAX_DLC
|
||||
#define BSP_CAN_DEFAULT_QUEUE_SIZE BSP_FDCAN_DEFAULT_QUEUE_SIZE
|
||||
#define BSP_CAN_TIMEOUT_IMMEDIATE BSP_FDCAN_TIMEOUT_IMMEDIATE
|
||||
#define BSP_CAN_TIMEOUT_FOREVER BSP_FDCAN_TIMEOUT_FOREVER
|
||||
#define BSP_CAN_TX_QUEUE_SIZE BSP_FDCAN_TX_QUEUE_SIZE
|
||||
|
||||
/* 枚举值映射 */
|
||||
#define BSP_CAN_1 BSP_FDCAN_1
|
||||
#define BSP_CAN_2 BSP_FDCAN_2
|
||||
#define BSP_CAN_3 BSP_FDCAN_3
|
||||
#define BSP_CAN_NUM BSP_FDCAN_NUM
|
||||
#define BSP_CAN_ERR BSP_FDCAN_ERR
|
||||
|
||||
#define BSP_CAN_FORMAT_STD_DATA BSP_FDCAN_FORMAT_STD_DATA
|
||||
#define BSP_CAN_FORMAT_EXT_DATA BSP_FDCAN_FORMAT_EXT_DATA
|
||||
#define BSP_CAN_FORMAT_STD_REMOTE BSP_FDCAN_FORMAT_STD_REMOTE
|
||||
#define BSP_CAN_FORMAT_EXT_REMOTE BSP_FDCAN_FORMAT_EXT_REMOTE
|
||||
|
||||
#define BSP_CAN_FRAME_STD_DATA BSP_FDCAN_FRAME_STD_DATA
|
||||
#define BSP_CAN_FRAME_EXT_DATA BSP_FDCAN_FRAME_EXT_DATA
|
||||
#define BSP_CAN_FRAME_STD_REMOTE BSP_FDCAN_FRAME_STD_REMOTE
|
||||
#define BSP_CAN_FRAME_EXT_REMOTE BSP_FDCAN_FRAME_EXT_REMOTE
|
||||
|
||||
/* 函数映射 */
|
||||
#define BSP_CAN_Init() BSP_FDCAN_Init()
|
||||
#define BSP_CAN_GetHandle(can) BSP_FDCAN_GetHandle(can)
|
||||
#define BSP_CAN_RegisterCallback(can, type, callback) \
|
||||
BSP_FDCAN_RegisterCallback(can, type, callback)
|
||||
#define BSP_CAN_Transmit(can, format, id, data, dlc) \
|
||||
BSP_FDCAN_Transmit(can, format, id, data, dlc)
|
||||
#define BSP_CAN_TransmitStdDataFrame(can, frame) \
|
||||
BSP_FDCAN_TransmitStdDataFrame(can, frame)
|
||||
#define BSP_CAN_TransmitExtDataFrame(can, frame) \
|
||||
BSP_FDCAN_TransmitExtDataFrame(can, frame)
|
||||
#define BSP_CAN_TransmitRemoteFrame(can, frame) \
|
||||
BSP_FDCAN_TransmitRemoteFrame(can, frame)
|
||||
#define BSP_CAN_RegisterId(can, can_id, queue_size) \
|
||||
BSP_FDCAN_RegisterId(can, can_id, queue_size)
|
||||
#define BSP_CAN_GetMessage(can, can_id, msg, timeout) \
|
||||
BSP_FDCAN_GetMessage(can, can_id, msg, timeout)
|
||||
#define BSP_CAN_GetQueueCount(can, can_id) \
|
||||
BSP_FDCAN_GetQueueCount(can, can_id)
|
||||
#define BSP_CAN_FlushQueue(can, can_id) \
|
||||
BSP_FDCAN_FlushQueue(can, can_id)
|
||||
#define BSP_CAN_RegisterIdParser(parser) \
|
||||
BSP_FDCAN_RegisterIdParser(parser)
|
||||
#define BSP_CAN_ParseId(original_id, frame_type) \
|
||||
BSP_FDCAN_ParseId(original_id, frame_type)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -21,19 +21,19 @@
|
||||
#define FDCAN1_FILTER_CONFIG_TABLE(X) \
|
||||
X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \
|
||||
X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0)
|
||||
#define FDCAN1_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */
|
||||
#define FDCAN1_GLOBAL_FILTER FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE
|
||||
#endif
|
||||
#ifdef FDCAN2_EN
|
||||
#define FDCAN2_FILTER_CONFIG_TABLE(X) \
|
||||
X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \
|
||||
X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0)
|
||||
#define FDCAN2_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */
|
||||
#define FDCAN2_GLOBAL_FILTER FDCAN_ACCEPT_IN_RX_FIFO1, FDCAN_ACCEPT_IN_RX_FIFO1, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE
|
||||
#endif
|
||||
#ifdef FDCAN3_EN
|
||||
#define FDCAN3_FILTER_CONFIG_TABLE(X) \
|
||||
X(0, FDCAN_STANDARD_ID, FDCAN_FILTER_MASK, 0x000 , 0x000 , 0) \
|
||||
X(1, FDCAN_EXTENDED_ID, FDCAN_FILTER_MASK, 0x00000000, 0x00000000, 0)
|
||||
#define FDCAN3_GLOBAL_FILTER FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE/* 全局过滤器参数(用于 HAL_FDCAN_ConfigGlobalFilter) */
|
||||
#define FDCAN3_GLOBAL_FILTER FDCAN_ACCEPT_IN_RX_FIFO1, FDCAN_ACCEPT_IN_RX_FIFO1, FDCAN_FILTER_REMOTE, FDCAN_FILTER_REMOTE
|
||||
#endif
|
||||
|
||||
/* ====宏展开实现==== */
|
||||
|
||||
@ -26,10 +26,18 @@ void BSP_Flash_EraseSector(uint32_t sector) {
|
||||
flash_erase.TypeErase = FLASH_TYPEERASE_SECTORS;
|
||||
flash_erase.VoltageRange = FLASH_VOLTAGE_RANGE_3;
|
||||
flash_erase.NbSectors = 1;
|
||||
#if defined(STM32H7)
|
||||
flash_erase.Banks = FLASH_BANK_1; // H7 requires Bank parameter
|
||||
#endif
|
||||
|
||||
HAL_FLASH_Unlock();
|
||||
#if defined(STM32H7)
|
||||
while (FLASH_WaitForLastOperation(50, FLASH_BANK_1) != HAL_OK)
|
||||
;
|
||||
#else
|
||||
while (FLASH_WaitForLastOperation(50) != HAL_OK)
|
||||
;
|
||||
#endif
|
||||
HAL_FLASHEx_Erase(&flash_erase, §or_error);
|
||||
HAL_FLASH_Lock();
|
||||
}
|
||||
@ -39,6 +47,24 @@ void BSP_Flash_EraseSector(uint32_t sector) {
|
||||
|
||||
void BSP_Flash_WriteBytes(uint32_t address, const uint8_t *buf, size_t len) {
|
||||
HAL_FLASH_Unlock();
|
||||
#if defined(STM32H7)
|
||||
// H7 uses FLASHWORD (32 bytes) programming
|
||||
uint8_t flash_word[32] __attribute__((aligned(32)));
|
||||
while (len > 0) {
|
||||
size_t chunk = (len < 32) ? len : 32;
|
||||
memset(flash_word, 0xFF, 32);
|
||||
memcpy(flash_word, buf, chunk);
|
||||
|
||||
while (FLASH_WaitForLastOperation(50, FLASH_BANK_1) != HAL_OK)
|
||||
;
|
||||
HAL_FLASH_Program(FLASH_TYPEPROGRAM_FLASHWORD, address, (uint32_t)flash_word);
|
||||
|
||||
address += 32;
|
||||
buf += chunk;
|
||||
len -= chunk;
|
||||
}
|
||||
#else
|
||||
// F4/F7 use byte programming
|
||||
while (len > 0) {
|
||||
while (FLASH_WaitForLastOperation(50) != HAL_OK)
|
||||
;
|
||||
@ -47,6 +73,7 @@ void BSP_Flash_WriteBytes(uint32_t address, const uint8_t *buf, size_t len) {
|
||||
buf++;
|
||||
len--;
|
||||
}
|
||||
#endif
|
||||
HAL_FLASH_Lock();
|
||||
}
|
||||
|
||||
|
||||
@ -5,4 +5,5 @@ error_detect,bsp/mm
|
||||
pid,component/filter
|
||||
filter,component/ahrs
|
||||
mixer,component/user_math.h
|
||||
ui,component/user_math.h
|
||||
ui,component/user_math.h
|
||||
kalman_filter,arm_math.h
|
||||
|
@ -11,4 +11,5 @@ limiter,限幅器
|
||||
mixer,混控器
|
||||
ui,用户交互
|
||||
user_math,用户自定义数学函数
|
||||
pid,PID控制器
|
||||
pid,PID控制器
|
||||
kalman_filter,卡尔曼滤波器
|
||||
|
@ -28,6 +28,9 @@
|
||||
#ifndef COMMAND_INTERPRETER_H
|
||||
#define COMMAND_INTERPRETER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
/* This config should be defined in FreeRTOSConfig.h. But due to the limition of CubeMX I put it here. */
|
||||
#define configCOMMAND_INT_MAX_OUTPUT_SIZE 512
|
||||
|
||||
|
||||
591
assets/User_code/component/kalman_filter/kalman_filter.c
Normal file
591
assets/User_code/component/kalman_filter/kalman_filter.c
Normal file
@ -0,0 +1,591 @@
|
||||
/*
|
||||
卡尔曼滤波器 modified from wang hongxi
|
||||
支持动态量测调整,使用ARM CMSIS DSP优化矩阵运算
|
||||
|
||||
主要特性:
|
||||
- 基于量测有效性的 H、R、K 矩阵动态调整
|
||||
- 支持不同传感器采样频率
|
||||
- 矩阵 P 防过度收敛机制
|
||||
- ARM CMSIS DSP 优化的矩阵运算
|
||||
- 可扩展架构,支持用户自定义函数(EKF/UKF/ESKF)
|
||||
|
||||
使用说明:
|
||||
1. 矩阵初始化:P、F、Q 使用标准初始化方式
|
||||
H、R 在使用自动调整时需要配置量测映射
|
||||
|
||||
2. 自动调整模式 (use_auto_adjustment = 1):
|
||||
- 提供 measurement_map:每个量测对应的状态索引
|
||||
- 提供 measurement_degree:H 矩阵元素值
|
||||
- 提供 mat_r_diagonal_elements:量测噪声方差
|
||||
|
||||
3. 固定模式 (use_auto_adjustment = 0):
|
||||
- 像初始化 P 矩阵那样正常初始化 z、H、R
|
||||
|
||||
4. 量测更新:
|
||||
- 在传感器回调函数中更新 measured_vector
|
||||
- 值为 0 表示量测无效
|
||||
- 向量在每次 KF 更新后会被重置为 0
|
||||
|
||||
5. 防过度收敛:
|
||||
- 设置 state_min_variance 防止 P 矩阵过度收敛
|
||||
- 帮助滤波器适应缓慢变化的状态
|
||||
|
||||
使用示例:高度估计
|
||||
状态向量 x =
|
||||
| 高度 |
|
||||
| 速度 |
|
||||
| 加速度 |
|
||||
|
||||
KF_t Height_KF;
|
||||
|
||||
void INS_Task_Init(void)
|
||||
{
|
||||
// 初始协方差矩阵 P
|
||||
static float P_Init[9] =
|
||||
{
|
||||
10, 0, 0,
|
||||
0, 30, 0,
|
||||
0, 0, 10,
|
||||
};
|
||||
|
||||
// 状态转移矩阵 F(根据运动学模型)
|
||||
static float F_Init[9] =
|
||||
{
|
||||
1, dt, 0.5*dt*dt,
|
||||
0, 1, dt,
|
||||
0, 0, 1,
|
||||
};
|
||||
|
||||
// 过程噪声协方差矩阵 Q
|
||||
static float Q_Init[9] =
|
||||
{
|
||||
0.25*dt*dt*dt*dt, 0.5*dt*dt*dt, 0.5*dt*dt,
|
||||
0.5*dt*dt*dt, dt*dt, dt,
|
||||
0.5*dt*dt, dt, 1,
|
||||
};
|
||||
|
||||
// 设置状态最小方差(防止过度收敛)
|
||||
static float state_min_variance[3] = {0.03, 0.005, 0.1};
|
||||
|
||||
// 开启自动调整
|
||||
Height_KF.use_auto_adjustment = 1;
|
||||
|
||||
// 量测映射:[气压高度对应状态1, GPS高度对应状态1, 加速度计对应状态3]
|
||||
static uint8_t measurement_reference[3] = {1, 1, 3};
|
||||
|
||||
// 量测系数(H矩阵元素值)
|
||||
static float measurement_degree[3] = {1, 1, 1};
|
||||
// 根据 measurement_reference 与 measurement_degree 生成 H 矩阵如下
|
||||
// (在当前周期全部量测数据有效的情况下)
|
||||
// |1 0 0|
|
||||
// |1 0 0|
|
||||
// |0 0 1|
|
||||
|
||||
// 量测噪声方差(R矩阵对角元素)
|
||||
static float mat_r_diagonal_elements[3] = {30, 25, 35};
|
||||
// 根据 mat_r_diagonal_elements 生成 R 矩阵如下
|
||||
// (在当前周期全部量测数据有效的情况下)
|
||||
// |30 0 0|
|
||||
// | 0 25 0|
|
||||
// | 0 0 35|
|
||||
|
||||
// 初始化卡尔曼滤波器(状态维数3,控制维数0,量测维数3)
|
||||
KF_Init(&Height_KF, 3, 0, 3);
|
||||
|
||||
// 设置矩阵初值
|
||||
memcpy(Height_KF.P_data, P_Init, sizeof(P_Init));
|
||||
memcpy(Height_KF.F_data, F_Init, sizeof(F_Init));
|
||||
memcpy(Height_KF.Q_data, Q_Init, sizeof(Q_Init));
|
||||
memcpy(Height_KF.measurement_map, measurement_reference,
|
||||
sizeof(measurement_reference));
|
||||
memcpy(Height_KF.measurement_degree, measurement_degree,
|
||||
sizeof(measurement_degree));
|
||||
memcpy(Height_KF.mat_r_diagonal_elements, mat_r_diagonal_elements,
|
||||
sizeof(mat_r_diagonal_elements));
|
||||
memcpy(Height_KF.state_min_variance, state_min_variance,
|
||||
sizeof(state_min_variance));
|
||||
}
|
||||
|
||||
void INS_Task(void const *pvParameters)
|
||||
{
|
||||
// 循环更新卡尔曼滤波器
|
||||
KF_Update(&Height_KF);
|
||||
vTaskDelay(ts);
|
||||
}
|
||||
|
||||
// 传感器回调函数示例:在数据就绪时更新 measured_vector
|
||||
void Barometer_Read_Over(void)
|
||||
{
|
||||
......
|
||||
INS_KF.measured_vector[0] = baro_height; // 气压计高度
|
||||
}
|
||||
|
||||
void GPS_Read_Over(void)
|
||||
{
|
||||
......
|
||||
INS_KF.measured_vector[1] = GPS_height; // GPS高度
|
||||
}
|
||||
|
||||
void Acc_Data_Process(void)
|
||||
{
|
||||
......
|
||||
INS_KF.measured_vector[2] = acc.z; // Z轴加速度
|
||||
}
|
||||
*/
|
||||
|
||||
#include "kalman_filter.h"
|
||||
|
||||
/* USER INCLUDE BEGIN */
|
||||
|
||||
/* USER INCLUDE END */
|
||||
|
||||
/* USER DEFINE BEGIN */
|
||||
|
||||
/* USER DEFINE END */
|
||||
|
||||
/* 私有函数声明 */
|
||||
static void KF_AdjustHKR(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 初始化卡尔曼滤波器并分配矩阵内存
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @param xhat_size 状态向量维度
|
||||
* @param u_size 控制向量维度(无控制输入时设为0)
|
||||
* @param z_size 量测向量维度
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_Init(KF_t *kf, uint8_t xhat_size, uint8_t u_size, uint8_t z_size) {
|
||||
if (kf == NULL) return -1;
|
||||
|
||||
kf->xhat_size = xhat_size;
|
||||
kf->u_size = u_size;
|
||||
kf->z_size = z_size;
|
||||
|
||||
kf->measurement_valid_num = 0;
|
||||
|
||||
/* 量测标志分配 */
|
||||
kf->measurement_map = (uint8_t *)user_malloc(sizeof(uint8_t) * z_size);
|
||||
memset(kf->measurement_map, 0, sizeof(uint8_t) * z_size);
|
||||
|
||||
kf->measurement_degree = (float *)user_malloc(sizeof(float) * z_size);
|
||||
memset(kf->measurement_degree, 0, sizeof(float) * z_size);
|
||||
|
||||
kf->mat_r_diagonal_elements = (float *)user_malloc(sizeof(float) * z_size);
|
||||
memset(kf->mat_r_diagonal_elements, 0, sizeof(float) * z_size);
|
||||
|
||||
kf->state_min_variance = (float *)user_malloc(sizeof(float) * xhat_size);
|
||||
memset(kf->state_min_variance, 0, sizeof(float) * xhat_size);
|
||||
|
||||
kf->temp = (uint8_t *)user_malloc(sizeof(uint8_t) * z_size);
|
||||
memset(kf->temp, 0, sizeof(uint8_t) * z_size);
|
||||
|
||||
/* 滤波数据分配 */
|
||||
kf->filtered_value = (float *)user_malloc(sizeof(float) * xhat_size);
|
||||
memset(kf->filtered_value, 0, sizeof(float) * xhat_size);
|
||||
|
||||
kf->measured_vector = (float *)user_malloc(sizeof(float) * z_size);
|
||||
memset(kf->measured_vector, 0, sizeof(float) * z_size);
|
||||
|
||||
kf->control_vector = (float *)user_malloc(sizeof(float) * u_size);
|
||||
memset(kf->control_vector, 0, sizeof(float) * u_size);
|
||||
|
||||
/* 状态估计 xhat x(k|k) */
|
||||
kf->xhat_data = (float *)user_malloc(sizeof(float) * xhat_size);
|
||||
memset(kf->xhat_data, 0, sizeof(float) * xhat_size);
|
||||
KF_MatInit(&kf->xhat, kf->xhat_size, 1, kf->xhat_data);
|
||||
|
||||
/* 先验状态估计 xhatminus x(k|k-1) */
|
||||
kf->xhatminus_data = (float *)user_malloc(sizeof(float) * xhat_size);
|
||||
memset(kf->xhatminus_data, 0, sizeof(float) * xhat_size);
|
||||
KF_MatInit(&kf->xhatminus, kf->xhat_size, 1, kf->xhatminus_data);
|
||||
|
||||
/* 控制向量 u */
|
||||
if (u_size != 0) {
|
||||
kf->u_data = (float *)user_malloc(sizeof(float) * u_size);
|
||||
memset(kf->u_data, 0, sizeof(float) * u_size);
|
||||
KF_MatInit(&kf->u, kf->u_size, 1, kf->u_data);
|
||||
}
|
||||
|
||||
/* 量测向量 z */
|
||||
kf->z_data = (float *)user_malloc(sizeof(float) * z_size);
|
||||
memset(kf->z_data, 0, sizeof(float) * z_size);
|
||||
KF_MatInit(&kf->z, kf->z_size, 1, kf->z_data);
|
||||
|
||||
/* 协方差矩阵 P(k|k) */
|
||||
kf->P_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
memset(kf->P_data, 0, sizeof(float) * xhat_size * xhat_size);
|
||||
KF_MatInit(&kf->P, kf->xhat_size, kf->xhat_size, kf->P_data);
|
||||
|
||||
/* 先验协方差矩阵 P(k|k-1) */
|
||||
kf->Pminus_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
memset(kf->Pminus_data, 0, sizeof(float) * xhat_size * xhat_size);
|
||||
KF_MatInit(&kf->Pminus, kf->xhat_size, kf->xhat_size, kf->Pminus_data);
|
||||
|
||||
/* 状态转移矩阵 F 及其转置 FT */
|
||||
kf->F_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
kf->FT_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
memset(kf->F_data, 0, sizeof(float) * xhat_size * xhat_size);
|
||||
memset(kf->FT_data, 0, sizeof(float) * xhat_size * xhat_size);
|
||||
KF_MatInit(&kf->F, kf->xhat_size, kf->xhat_size, kf->F_data);
|
||||
KF_MatInit(&kf->FT, kf->xhat_size, kf->xhat_size, kf->FT_data);
|
||||
|
||||
/* 控制矩阵 B */
|
||||
if (u_size != 0) {
|
||||
kf->B_data = (float *)user_malloc(sizeof(float) * xhat_size * u_size);
|
||||
memset(kf->B_data, 0, sizeof(float) * xhat_size * u_size);
|
||||
KF_MatInit(&kf->B, kf->xhat_size, kf->u_size, kf->B_data);
|
||||
}
|
||||
|
||||
/* 量测矩阵 H 及其转置 HT */
|
||||
kf->H_data = (float *)user_malloc(sizeof(float) * z_size * xhat_size);
|
||||
kf->HT_data = (float *)user_malloc(sizeof(float) * xhat_size * z_size);
|
||||
memset(kf->H_data, 0, sizeof(float) * z_size * xhat_size);
|
||||
memset(kf->HT_data, 0, sizeof(float) * xhat_size * z_size);
|
||||
KF_MatInit(&kf->H, kf->z_size, kf->xhat_size, kf->H_data);
|
||||
KF_MatInit(&kf->HT, kf->xhat_size, kf->z_size, kf->HT_data);
|
||||
|
||||
/* 过程噪声协方差矩阵 Q */
|
||||
kf->Q_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
memset(kf->Q_data, 0, sizeof(float) * xhat_size * xhat_size);
|
||||
KF_MatInit(&kf->Q, kf->xhat_size, kf->xhat_size, kf->Q_data);
|
||||
|
||||
/* 量测噪声协方差矩阵 R */
|
||||
kf->R_data = (float *)user_malloc(sizeof(float) * z_size * z_size);
|
||||
memset(kf->R_data, 0, sizeof(float) * z_size * z_size);
|
||||
KF_MatInit(&kf->R, kf->z_size, kf->z_size, kf->R_data);
|
||||
|
||||
/* 卡尔曼增益 K */
|
||||
kf->K_data = (float *)user_malloc(sizeof(float) * xhat_size * z_size);
|
||||
memset(kf->K_data, 0, sizeof(float) * xhat_size * z_size);
|
||||
KF_MatInit(&kf->K, kf->xhat_size, kf->z_size, kf->K_data);
|
||||
|
||||
/* 临时矩阵分配 */
|
||||
kf->S_data = (float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
kf->temp_matrix_data =
|
||||
(float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
kf->temp_matrix_data1 =
|
||||
(float *)user_malloc(sizeof(float) * xhat_size * xhat_size);
|
||||
kf->temp_vector_data = (float *)user_malloc(sizeof(float) * xhat_size);
|
||||
kf->temp_vector_data1 = (float *)user_malloc(sizeof(float) * xhat_size);
|
||||
|
||||
KF_MatInit(&kf->S, kf->xhat_size, kf->xhat_size, kf->S_data);
|
||||
KF_MatInit(&kf->temp_matrix, kf->xhat_size, kf->xhat_size,
|
||||
kf->temp_matrix_data);
|
||||
KF_MatInit(&kf->temp_matrix1, kf->xhat_size, kf->xhat_size,
|
||||
kf->temp_matrix_data1);
|
||||
KF_MatInit(&kf->temp_vector, kf->xhat_size, 1, kf->temp_vector_data);
|
||||
KF_MatInit(&kf->temp_vector1, kf->xhat_size, 1, kf->temp_vector_data1);
|
||||
|
||||
/* 初始化跳过标志 */
|
||||
kf->skip_eq1 = 0;
|
||||
kf->skip_eq2 = 0;
|
||||
kf->skip_eq3 = 0;
|
||||
kf->skip_eq4 = 0;
|
||||
kf->skip_eq5 = 0;
|
||||
|
||||
/* 初始化用户函数指针 */
|
||||
kf->User_Func0_f = NULL;
|
||||
kf->User_Func1_f = NULL;
|
||||
kf->User_Func2_f = NULL;
|
||||
kf->User_Func3_f = NULL;
|
||||
kf->User_Func4_f = NULL;
|
||||
kf->User_Func5_f = NULL;
|
||||
kf->User_Func6_f = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 获取量测并在启用自动调整时调整矩阵
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_Measure(KF_t *kf) {
|
||||
if (kf == NULL) return -1;
|
||||
|
||||
/* 根据量测有效性自动调整 H, K, R 矩阵 */
|
||||
if (kf->use_auto_adjustment != 0) {
|
||||
KF_AdjustHKR(kf);
|
||||
} else {
|
||||
memcpy(kf->z_data, kf->measured_vector, sizeof(float) * kf->z_size);
|
||||
memset(kf->measured_vector, 0, sizeof(float) * kf->z_size);
|
||||
}
|
||||
|
||||
memcpy(kf->u_data, kf->control_vector, sizeof(float) * kf->u_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 步骤1:先验状态估计 - xhat'(k) = F·xhat(k-1) + B·u
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_PredictState(KF_t *kf) {
|
||||
if (kf == NULL) return -1;
|
||||
|
||||
if (!kf->skip_eq1) {
|
||||
if (kf->u_size > 0) {
|
||||
/* 有控制输入: xhat'(k) = F·xhat(k-1) + B·u */
|
||||
kf->temp_vector.numRows = kf->xhat_size;
|
||||
kf->temp_vector.numCols = 1;
|
||||
kf->mat_status = KF_MatMult(&kf->F, &kf->xhat, &kf->temp_vector);
|
||||
|
||||
kf->temp_vector1.numRows = kf->xhat_size;
|
||||
kf->temp_vector1.numCols = 1;
|
||||
kf->mat_status = KF_MatMult(&kf->B, &kf->u, &kf->temp_vector1);
|
||||
kf->mat_status =
|
||||
KF_MatAdd(&kf->temp_vector, &kf->temp_vector1, &kf->xhatminus);
|
||||
} else {
|
||||
/* 无控制输入: xhat'(k) = F·xhat(k-1) */
|
||||
kf->mat_status = KF_MatMult(&kf->F, &kf->xhat, &kf->xhatminus);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 步骤2:先验协方差 - P'(k) = F·P(k-1)·F^T + Q
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_PredictCovariance(KF_t *kf) {
|
||||
if (kf == NULL) return -1;
|
||||
|
||||
if (!kf->skip_eq2) {
|
||||
kf->mat_status = KF_MatTrans(&kf->F, &kf->FT);
|
||||
kf->mat_status = KF_MatMult(&kf->F, &kf->P, &kf->Pminus);
|
||||
kf->temp_matrix.numRows = kf->Pminus.numRows;
|
||||
kf->temp_matrix.numCols = kf->FT.numCols;
|
||||
/* F·P(k-1)·F^T */
|
||||
kf->mat_status = KF_MatMult(&kf->Pminus, &kf->FT, &kf->temp_matrix);
|
||||
kf->mat_status = KF_MatAdd(&kf->temp_matrix, &kf->Q, &kf->Pminus);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 步骤3:卡尔曼增益 - K = P'(k)·H^T / (H·P'(k)·H^T + R)
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_CalcGain(KF_t *kf) {
|
||||
if (kf == NULL) return -1;
|
||||
|
||||
if (!kf->skip_eq3) {
|
||||
kf->mat_status = KF_MatTrans(&kf->H, &kf->HT);
|
||||
kf->temp_matrix.numRows = kf->H.numRows;
|
||||
kf->temp_matrix.numCols = kf->Pminus.numCols;
|
||||
/* H·P'(k) */
|
||||
kf->mat_status = KF_MatMult(&kf->H, &kf->Pminus, &kf->temp_matrix);
|
||||
kf->temp_matrix1.numRows = kf->temp_matrix.numRows;
|
||||
kf->temp_matrix1.numCols = kf->HT.numCols;
|
||||
/* H·P'(k)·H^T */
|
||||
kf->mat_status = KF_MatMult(&kf->temp_matrix, &kf->HT, &kf->temp_matrix1);
|
||||
kf->S.numRows = kf->R.numRows;
|
||||
kf->S.numCols = kf->R.numCols;
|
||||
/* S = H·P'(k)·H^T + R */
|
||||
kf->mat_status = KF_MatAdd(&kf->temp_matrix1, &kf->R, &kf->S);
|
||||
/* S^-1 */
|
||||
kf->mat_status = KF_MatInv(&kf->S, &kf->temp_matrix1);
|
||||
kf->temp_matrix.numRows = kf->Pminus.numRows;
|
||||
kf->temp_matrix.numCols = kf->HT.numCols;
|
||||
/* P'(k)·H^T */
|
||||
kf->mat_status = KF_MatMult(&kf->Pminus, &kf->HT, &kf->temp_matrix);
|
||||
/* K = P'(k)·H^T·S^-1 */
|
||||
kf->mat_status = KF_MatMult(&kf->temp_matrix, &kf->temp_matrix1, &kf->K);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 步骤4:状态更新 - xhat(k) = xhat'(k) + K·(z - H·xhat'(k))
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_UpdateState(KF_t *kf) {
|
||||
if (kf == NULL) return -1;
|
||||
|
||||
if (!kf->skip_eq4) {
|
||||
kf->temp_vector.numRows = kf->H.numRows;
|
||||
kf->temp_vector.numCols = 1;
|
||||
/* H·xhat'(k) */
|
||||
kf->mat_status = KF_MatMult(&kf->H, &kf->xhatminus, &kf->temp_vector);
|
||||
kf->temp_vector1.numRows = kf->z.numRows;
|
||||
kf->temp_vector1.numCols = 1;
|
||||
/* 新息: z - H·xhat'(k) */
|
||||
kf->mat_status = KF_MatSub(&kf->z, &kf->temp_vector, &kf->temp_vector1);
|
||||
kf->temp_vector.numRows = kf->K.numRows;
|
||||
kf->temp_vector.numCols = 1;
|
||||
/* K·新息 */
|
||||
kf->mat_status = KF_MatMult(&kf->K, &kf->temp_vector1, &kf->temp_vector);
|
||||
/* xhat = xhat' + K·新息 */
|
||||
kf->mat_status = KF_MatAdd(&kf->xhatminus, &kf->temp_vector, &kf->xhat);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 步骤5:协方差更新 - P(k) = P'(k) - K·H·P'(k)
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_UpdateCovariance(KF_t *kf) {
|
||||
if (kf == NULL) return -1;
|
||||
|
||||
if (!kf->skip_eq5) {
|
||||
kf->temp_matrix.numRows = kf->K.numRows;
|
||||
kf->temp_matrix.numCols = kf->H.numCols;
|
||||
kf->temp_matrix1.numRows = kf->temp_matrix.numRows;
|
||||
kf->temp_matrix1.numCols = kf->Pminus.numCols;
|
||||
/* K·H */
|
||||
kf->mat_status = KF_MatMult(&kf->K, &kf->H, &kf->temp_matrix);
|
||||
/* K·H·P'(k) */
|
||||
kf->mat_status = KF_MatMult(&kf->temp_matrix, &kf->Pminus, &kf->temp_matrix1);
|
||||
/* P = P' - K·H·P' */
|
||||
kf->mat_status = KF_MatSub(&kf->Pminus, &kf->temp_matrix1, &kf->P);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 执行完整的卡尔曼滤波周期(五大方程)
|
||||
*
|
||||
* 实现标准KF,并支持用户自定义函数钩子用于扩展(EKF/UKF/ESKF/AUKF)。
|
||||
* 每个步骤都可以通过 User_Func 回调函数替换。
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return float* 滤波后的状态估计值指针
|
||||
*/
|
||||
float *KF_Update(KF_t *kf) {
|
||||
if (kf == NULL) return NULL;
|
||||
|
||||
/* 步骤0: 量测获取和矩阵调整 */
|
||||
KF_Measure(kf);
|
||||
if (kf->User_Func0_f != NULL) kf->User_Func0_f(kf);
|
||||
|
||||
/* 步骤1: 先验状态估计 - xhat'(k) = F·xhat(k-1) + B·u */
|
||||
KF_PredictState(kf);
|
||||
if (kf->User_Func1_f != NULL) kf->User_Func1_f(kf);
|
||||
|
||||
/* 步骤2: 先验协方差 - P'(k) = F·P(k-1)·F^T + Q */
|
||||
KF_PredictCovariance(kf);
|
||||
if (kf->User_Func2_f != NULL) kf->User_Func2_f(kf);
|
||||
|
||||
/* 量测更新(仅在存在有效量测时执行) */
|
||||
if (kf->measurement_valid_num != 0 || kf->use_auto_adjustment == 0) {
|
||||
/* 步骤3: 卡尔曼增益 - K = P'(k)·H^T / (H·P'(k)·H^T + R) */
|
||||
KF_CalcGain(kf);
|
||||
if (kf->User_Func3_f != NULL) kf->User_Func3_f(kf);
|
||||
|
||||
/* 步骤4: 状态更新 - xhat(k) = xhat'(k) + K·(z - H·xhat'(k)) */
|
||||
KF_UpdateState(kf);
|
||||
if (kf->User_Func4_f != NULL) kf->User_Func4_f(kf);
|
||||
|
||||
/* 步骤5: 协方差更新 - P(k) = P'(k) - K·H·P'(k) */
|
||||
KF_UpdateCovariance(kf);
|
||||
} else {
|
||||
/* 无有效量测 - 仅预测 */
|
||||
memcpy(kf->xhat_data, kf->xhatminus_data, sizeof(float) * kf->xhat_size);
|
||||
memcpy(kf->P_data, kf->Pminus_data,
|
||||
sizeof(float) * kf->xhat_size * kf->xhat_size);
|
||||
}
|
||||
|
||||
/* 后处理钩子 */
|
||||
if (kf->User_Func5_f != NULL) kf->User_Func5_f(kf);
|
||||
|
||||
/* 防过度收敛:强制最小方差 */
|
||||
for (uint8_t i = 0; i < kf->xhat_size; i++) {
|
||||
if (kf->P_data[i * kf->xhat_size + i] < kf->state_min_variance[i])
|
||||
kf->P_data[i * kf->xhat_size + i] = kf->state_min_variance[i];
|
||||
}
|
||||
|
||||
/* 复制结果到输出 */
|
||||
memcpy(kf->filtered_value, kf->xhat_data, sizeof(float) * kf->xhat_size);
|
||||
|
||||
/* 附加后处理钩子 */
|
||||
if (kf->User_Func6_f != NULL) kf->User_Func6_f(kf);
|
||||
|
||||
return kf->filtered_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 重置卡尔曼滤波器状态
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
*/
|
||||
void KF_Reset(KF_t *kf) {
|
||||
if (kf == NULL) return;
|
||||
|
||||
memset(kf->xhat_data, 0, sizeof(float) * kf->xhat_size);
|
||||
memset(kf->xhatminus_data, 0, sizeof(float) * kf->xhat_size);
|
||||
memset(kf->filtered_value, 0, sizeof(float) * kf->xhat_size);
|
||||
kf->measurement_valid_num = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 根据量测有效性动态调整 H, R, K 矩阵
|
||||
*
|
||||
* 该函数根据当前周期中哪些量测有效(非零)来重建量测相关矩阵。
|
||||
* 支持具有不同采样率的异步传感器。
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
*/
|
||||
static void KF_AdjustHKR(KF_t *kf) {
|
||||
kf->measurement_valid_num = 0;
|
||||
|
||||
/* 复制并重置量测向量 */
|
||||
memcpy(kf->z_data, kf->measured_vector, sizeof(float) * kf->z_size);
|
||||
memset(kf->measured_vector, 0, sizeof(float) * kf->z_size);
|
||||
|
||||
/* 清空 H 和 R 矩阵 */
|
||||
memset(kf->R_data, 0, sizeof(float) * kf->z_size * kf->z_size);
|
||||
memset(kf->H_data, 0, sizeof(float) * kf->xhat_size * kf->z_size);
|
||||
|
||||
/* 识别有效量测并重建 z, H */
|
||||
for (uint8_t i = 0; i < kf->z_size; i++) {
|
||||
if (kf->z_data[i] != 0) { /* 非零表示有效量测 */
|
||||
/* 将有效量测压缩到 z */
|
||||
kf->z_data[kf->measurement_valid_num] = kf->z_data[i];
|
||||
kf->temp[kf->measurement_valid_num] = i;
|
||||
|
||||
/* 重建 H 矩阵行 */
|
||||
kf->H_data[kf->xhat_size * kf->measurement_valid_num +
|
||||
kf->measurement_map[i] - 1] = kf->measurement_degree[i];
|
||||
kf->measurement_valid_num++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 用有效量测方差重建 R 矩阵 */
|
||||
for (uint8_t i = 0; i < kf->measurement_valid_num; i++) {
|
||||
kf->R_data[i * kf->measurement_valid_num + i] =
|
||||
kf->mat_r_diagonal_elements[kf->temp[i]];
|
||||
}
|
||||
|
||||
/* 调整矩阵维度以匹配有效量测数量 */
|
||||
kf->H.numRows = kf->measurement_valid_num;
|
||||
kf->H.numCols = kf->xhat_size;
|
||||
kf->HT.numRows = kf->xhat_size;
|
||||
kf->HT.numCols = kf->measurement_valid_num;
|
||||
kf->R.numRows = kf->measurement_valid_num;
|
||||
kf->R.numCols = kf->measurement_valid_num;
|
||||
kf->K.numRows = kf->xhat_size;
|
||||
kf->K.numCols = kf->measurement_valid_num;
|
||||
kf->z.numRows = kf->measurement_valid_num;
|
||||
}
|
||||
|
||||
/* USER FUNCTION BEGIN */
|
||||
|
||||
/* USER FUNCTION END */
|
||||
199
assets/User_code/component/kalman_filter/kalman_filter.h
Normal file
199
assets/User_code/component/kalman_filter/kalman_filter.h
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
卡尔曼滤波器
|
||||
支持动态量测调整,使用ARM CMSIS DSP优化矩阵运算
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "arm_math.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* USER INCLUDE BEGIN */
|
||||
|
||||
/* USER INCLUDE END */
|
||||
|
||||
/* USER DEFINE BEGIN */
|
||||
|
||||
/* USER DEFINE END */
|
||||
|
||||
/* 内存分配配置 */
|
||||
#ifndef user_malloc
|
||||
#ifdef _CMSIS_OS_H
|
||||
#define user_malloc pvPortMalloc /* FreeRTOS堆分配 */
|
||||
#else
|
||||
#define user_malloc malloc /* 标准C库分配 */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* ARM CMSIS DSP 矩阵运算别名 */
|
||||
#define KF_Mat arm_matrix_instance_f32
|
||||
#define KF_MatInit arm_mat_init_f32
|
||||
#define KF_MatAdd arm_mat_add_f32
|
||||
#define KF_MatSub arm_mat_sub_f32
|
||||
#define KF_MatMult arm_mat_mult_f32
|
||||
#define KF_MatTrans arm_mat_trans_f32
|
||||
#define KF_MatInv arm_mat_inverse_f32
|
||||
|
||||
/* 卡尔曼滤波器主结构体 */
|
||||
typedef struct KF_s {
|
||||
/* 输出和输入向量 */
|
||||
float *filtered_value; /* 滤波后的状态估计输出 */
|
||||
float *measured_vector; /* 量测输入向量 */
|
||||
float *control_vector; /* 控制输入向量 */
|
||||
|
||||
/* 维度 */
|
||||
uint8_t xhat_size; /* 状态向量维度 */
|
||||
uint8_t u_size; /* 控制向量维度 */
|
||||
uint8_t z_size; /* 量测向量维度 */
|
||||
|
||||
/* 自动调整参数 */
|
||||
uint8_t use_auto_adjustment; /* 启用动态 H/R/K 调整 */
|
||||
uint8_t measurement_valid_num; /* 有效量测数量 */
|
||||
|
||||
/* 量测配置 */
|
||||
uint8_t *measurement_map; /* 量测到状态的映射 */
|
||||
float *measurement_degree; /* 每个量测的H矩阵元素值 */
|
||||
float *mat_r_diagonal_elements; /* 量测噪声方差(R对角线) */
|
||||
float *state_min_variance; /* 最小状态方差(防过度收敛) */
|
||||
uint8_t *temp; /* 临时缓冲区 */
|
||||
|
||||
/* 方程跳过标志(用于自定义用户函数) */
|
||||
uint8_t skip_eq1, skip_eq2, skip_eq3, skip_eq4, skip_eq5;
|
||||
|
||||
/* 卡尔曼滤波器矩阵 */
|
||||
KF_Mat xhat; /* 状态估计 x(k|k) */
|
||||
KF_Mat xhatminus; /* 先验状态估计 x(k|k-1) */
|
||||
KF_Mat u; /* 控制向量 */
|
||||
KF_Mat z; /* 量测向量 */
|
||||
KF_Mat P; /* 后验误差协方差 P(k|k) */
|
||||
KF_Mat Pminus; /* 先验误差协方差 P(k|k-1) */
|
||||
KF_Mat F, FT; /* 状态转移矩阵及其转置 */
|
||||
KF_Mat B; /* 控制矩阵 */
|
||||
KF_Mat H, HT; /* 量测矩阵及其转置 */
|
||||
KF_Mat Q; /* 过程噪声协方差 */
|
||||
KF_Mat R; /* 量测噪声协方差 */
|
||||
KF_Mat K; /* 卡尔曼增益 */
|
||||
KF_Mat S; /* 临时矩阵 S */
|
||||
KF_Mat temp_matrix, temp_matrix1; /* 临时矩阵 */
|
||||
KF_Mat temp_vector, temp_vector1; /* 临时向量 */
|
||||
|
||||
int8_t mat_status; /* 矩阵运算状态 */
|
||||
|
||||
/* 用户自定义函数指针(用于EKF/UKF/ESKF扩展) */
|
||||
void (*User_Func0_f)(struct KF_s *kf); /* 自定义量测处理 */
|
||||
void (*User_Func1_f)(struct KF_s *kf); /* 自定义状态预测 */
|
||||
void (*User_Func2_f)(struct KF_s *kf); /* 自定义协方差预测 */
|
||||
void (*User_Func3_f)(struct KF_s *kf); /* 自定义卡尔曼增益计算 */
|
||||
void (*User_Func4_f)(struct KF_s *kf); /* 自定义状态更新 */
|
||||
void (*User_Func5_f)(struct KF_s *kf); /* 自定义后处理 */
|
||||
void (*User_Func6_f)(struct KF_s *kf); /* 附加自定义函数 */
|
||||
|
||||
/* 矩阵数据存储指针 */
|
||||
float *xhat_data, *xhatminus_data;
|
||||
float *u_data;
|
||||
float *z_data;
|
||||
float *P_data, *Pminus_data;
|
||||
float *F_data, *FT_data;
|
||||
float *B_data;
|
||||
float *H_data, *HT_data;
|
||||
float *Q_data;
|
||||
float *R_data;
|
||||
float *K_data;
|
||||
float *S_data;
|
||||
float *temp_matrix_data, *temp_matrix_data1;
|
||||
float *temp_vector_data, *temp_vector_data1;
|
||||
} KF_t;
|
||||
|
||||
/* USER STRUCT BEGIN */
|
||||
|
||||
/* USER STRUCT END */
|
||||
|
||||
/**
|
||||
* @brief 初始化卡尔曼滤波器并分配矩阵内存
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @param xhat_size 状态向量维度
|
||||
* @param u_size 控制向量维度(无控制输入时设为0)
|
||||
* @param z_size 量测向量维度
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_Init(KF_t *kf, uint8_t xhat_size, uint8_t u_size, uint8_t z_size);
|
||||
|
||||
/**
|
||||
* @brief 获取量测并在启用自动调整时调整矩阵
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_Measure(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 步骤1:先验状态估计 - xhat'(k) = F·xhat(k-1) + B·u
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_PredictState(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 步骤2:先验协方差 - P'(k) = F·P(k-1)·F^T + Q
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_PredictCovariance(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 步骤3:卡尔曼增益 - K = P'(k)·H^T / (H·P'(k)·H^T + R)
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_CalcGain(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 步骤4:状态更新 - xhat(k) = xhat'(k) + K·(z - H·xhat'(k))
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_UpdateState(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 步骤5:协方差更新 - P(k) = P'(k) - K·H·P'(k)
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return int8_t 0对应没有错误
|
||||
*/
|
||||
int8_t KF_UpdateCovariance(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 执行完整的卡尔曼滤波周期(五大方程)
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
* @return float* 滤波后的状态估计值指针
|
||||
*/
|
||||
float *KF_Update(KF_t *kf);
|
||||
|
||||
/**
|
||||
* @brief 重置卡尔曼滤波器状态
|
||||
*
|
||||
* @param kf 卡尔曼滤波器结构体指针
|
||||
*/
|
||||
void KF_Reset(KF_t *kf);
|
||||
|
||||
/* USER FUNCTION BEGIN */
|
||||
|
||||
/* USER FUNCTION END */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@ -105,3 +105,8 @@ float HeatLimit_ShootFreq(float heat, float heat_limit, float cooling_rate,
|
||||
else
|
||||
return (heat_percent > 0.7f) ? stable_freq : 3.0f * stable_freq;
|
||||
}
|
||||
|
||||
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
@ -61,3 +61,7 @@ float PowerLimit_TargetPower(float power_limit, float power_buffer);
|
||||
*/
|
||||
float HeatLimit_ShootFreq(float heat, float heat_limit, float cooling_rate,
|
||||
float heat_increase, bool is_big);
|
||||
|
||||
/* USER CODE BEGIN */
|
||||
|
||||
/* USER CODE END */
|
||||
@ -1,4 +1,4 @@
|
||||
bsp,can,fdcan,dwt,gpio,i2c,mm,spi,uart,pwm,time,flash
|
||||
component,ahrs,capacity,cmd,crc8,crc16,error_detect,filter,FreeRTOS_CLI,limiter,mixer,pid,ui,user_math
|
||||
device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9,oid,lcd_driver
|
||||
device,dr16,bmi088,ist8310,motor,motor_rm,motor_dm,motor_vesc,motor_lk,motor_lz,motor_odrive,dm_imu,rc_can,servo,buzzer,led,ws2812,vofa,ops9,oid,lcd_driver,mrobot
|
||||
module,
|
||||
|
@ -259,4 +259,19 @@ devices:
|
||||
thread_signals: []
|
||||
files:
|
||||
header: "lcd.h"
|
||||
source: "lcd.c"
|
||||
source: "lcd.c"
|
||||
|
||||
mrobot:
|
||||
name: "MRobot CLI"
|
||||
description: "基于 FreeRTOS CLI 的嵌入式调试命令行系统,支持设备注册与监控、类 Unix 文件系统命令、htop 风格任务监控等"
|
||||
dependencies:
|
||||
bsp: ["uart", "mm"]
|
||||
component: ["freertos_cli"]
|
||||
bsp_requirements:
|
||||
- type: "uart"
|
||||
var_name: "BSP_UART_MROBOT"
|
||||
description: "用于 MRobot CLI 命令行交互"
|
||||
thread_signals: []
|
||||
files:
|
||||
header: "mrobot.h"
|
||||
source: "mrobot.c"
|
||||
@ -111,11 +111,21 @@ static int8_t MOTOR_DM_SendMITCmd(MOTOR_DM_t *motor, MOTOR_MIT_Output_t *output)
|
||||
uint16_t pos_tmp,vel_tmp,kp_tmp,kd_tmp,tor_tmp;
|
||||
uint16_t id = motor->param.can_id;
|
||||
|
||||
pos_tmp = float_to_uint(output->angle, DM_P_MIN , DM_P_MAX, 16);
|
||||
vel_tmp = float_to_uint(output->velocity, DM_V_MIN , DM_V_MAX, 12);
|
||||
/* 根据 reverse 参数调整控制值 */
|
||||
float angle = output->angle;
|
||||
float velocity = output->velocity;
|
||||
float torque = output->torque;
|
||||
if (motor->param.reverse) {
|
||||
angle = -angle;
|
||||
velocity = -velocity;
|
||||
torque = -torque;
|
||||
}
|
||||
|
||||
pos_tmp = float_to_uint(angle, DM_P_MIN , DM_P_MAX, 16);
|
||||
vel_tmp = float_to_uint(velocity, DM_V_MIN , DM_V_MAX, 12);
|
||||
kp_tmp = float_to_uint(output->kp, DM_KP_MIN, DM_KP_MAX, 12);
|
||||
kd_tmp = float_to_uint(output->kd, DM_KD_MIN, DM_KD_MAX, 12);
|
||||
tor_tmp = float_to_uint(output->torque, DM_T_MIN , DM_T_MAX, 12);
|
||||
tor_tmp = float_to_uint(torque, DM_T_MIN , DM_T_MAX, 12);
|
||||
|
||||
/* 打包数据 */
|
||||
data[0] = (pos_tmp >> 8);
|
||||
@ -151,6 +161,11 @@ static int8_t MOTOR_DM_SendPosVelCmd(MOTOR_DM_t *motor, float pos, float vel) {
|
||||
|
||||
uint8_t data[8] = {0};
|
||||
|
||||
/* 根据 reverse 参数调整控制值 */
|
||||
if (motor->param.reverse) {
|
||||
pos = -pos;
|
||||
vel = -vel;
|
||||
}
|
||||
|
||||
/* 直接发送浮点数数据 */
|
||||
memcpy(&data[0], &pos, 4); // 位置,低位在前
|
||||
@ -179,6 +194,11 @@ static int8_t MOTOR_DM_SendVelCmd(MOTOR_DM_t *motor, float vel) {
|
||||
|
||||
uint8_t data[4] = {0};
|
||||
|
||||
/* 根据 reverse 参数调整控制值 */
|
||||
if (motor->param.reverse) {
|
||||
vel = -vel;
|
||||
}
|
||||
|
||||
/* 直接发送浮点数数据 */
|
||||
memcpy(&data[0], &vel, 4); // 速度,低位在前
|
||||
|
||||
|
||||
874
assets/User_code/device/mrobot/mrobot.c
Normal file
874
assets/User_code/device/mrobot/mrobot.c
Normal file
@ -0,0 +1,874 @@
|
||||
/**
|
||||
* @file mrobot.c
|
||||
* @brief MRobot CLI 实现
|
||||
*/
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "device/mrobot.h"
|
||||
#include "component/freertos_cli.h"
|
||||
#include "bsp/uart.h"
|
||||
#include "bsp/mm.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <semphr.h>
|
||||
#include <cmsis_os2.h>
|
||||
|
||||
/* Private constants -------------------------------------------------------- */
|
||||
static const char *const CLI_WELCOME_MESSAGE =
|
||||
"\r\n"
|
||||
" __ __ _____ _ _ \r\n"
|
||||
" | \\/ | __ \\ | | | | \r\n"
|
||||
" | \\ / | |__) |___ | |__ ___ | |_ \r\n"
|
||||
" | |\\/| | _ // _ \\| '_ \\ / _ \\| __|\r\n"
|
||||
" | | | | | \\ \\ (_) | |_) | (_) | |_ \r\n"
|
||||
" |_| |_|_| \\_\\___/|_.__/ \\___/ \\__|\r\n"
|
||||
" ------------------------------------\r\n"
|
||||
" Welcome to use MRobot CLI. Type 'help' to view a list of registered commands.\r\n"
|
||||
"\r\n";
|
||||
|
||||
/* ANSI 转义序列 */
|
||||
#define ANSI_CLEAR_SCREEN "\033[2J\033[H"
|
||||
#define ANSI_CURSOR_HOME "\033[H"
|
||||
#define ANSI_BACKSPACE "\b \b"
|
||||
|
||||
/* Private types ------------------------------------------------------------ */
|
||||
/* CLI 上下文结构体 - 封装所有状态 */
|
||||
typedef struct {
|
||||
/* 设备管理 */
|
||||
MRobot_Device_t devices[MROBOT_MAX_DEVICES];
|
||||
uint8_t device_count;
|
||||
|
||||
/* 自定义命令 */
|
||||
CLI_Command_Definition_t *custom_cmds[MROBOT_MAX_CUSTOM_COMMANDS];
|
||||
uint8_t custom_cmd_count;
|
||||
|
||||
/* CLI 状态 */
|
||||
MRobot_State_t state;
|
||||
char current_path[MROBOT_PATH_MAX_LEN];
|
||||
|
||||
/* 命令缓冲区 */
|
||||
uint8_t cmd_buffer[MROBOT_CMD_BUFFER_SIZE];
|
||||
volatile uint8_t cmd_index;
|
||||
volatile bool cmd_ready;
|
||||
|
||||
/* UART 相关 */
|
||||
uint8_t uart_rx_char;
|
||||
volatile bool tx_complete;
|
||||
volatile bool htop_exit;
|
||||
|
||||
/* 输出缓冲区 */
|
||||
char output_buffer[MROBOT_OUTPUT_BUFFER_SIZE];
|
||||
|
||||
/* 初始化标志 */
|
||||
bool initialized;
|
||||
|
||||
/* 互斥锁 */
|
||||
SemaphoreHandle_t mutex;
|
||||
} MRobot_Context_t;
|
||||
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
static MRobot_Context_t ctx = {
|
||||
.device_count = 0,
|
||||
.custom_cmd_count = 0,
|
||||
.state = MROBOT_STATE_IDLE,
|
||||
.current_path = "/",
|
||||
.cmd_index = 0,
|
||||
.cmd_ready = false,
|
||||
.tx_complete = true,
|
||||
.htop_exit = false,
|
||||
.initialized = false,
|
||||
.mutex = NULL
|
||||
};
|
||||
|
||||
/* Private function prototypes ---------------------------------------------- */
|
||||
/* 命令处理函数 */
|
||||
static BaseType_t cmd_help(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
|
||||
static BaseType_t cmd_htop(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
|
||||
static BaseType_t cmd_cd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
|
||||
static BaseType_t cmd_ls(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
|
||||
static BaseType_t cmd_show(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
|
||||
|
||||
/* 内部辅助函数 */
|
||||
static void uart_tx_callback(void);
|
||||
static void uart_rx_callback(void);
|
||||
static void send_string(const char *str);
|
||||
static void send_prompt(void);
|
||||
static int format_float_va(char *buf, size_t size, const char *fmt, va_list args);
|
||||
|
||||
/* CLI 命令定义表 */
|
||||
static const CLI_Command_Definition_t builtin_commands[] = {
|
||||
{ "help", " --help: 显示所有可用命令\r\n", cmd_help, 0 },
|
||||
{ "htop", " --htop: 动态显示 FreeRTOS 任务状态 (按 'q' 退出)\r\n", cmd_htop, 0 },
|
||||
{ "cd", " --cd <path>: 切换目录\r\n", cmd_cd, 1 },
|
||||
{ "ls", " --ls: 列出当前目录内容\r\n", cmd_ls, 0 },
|
||||
{ "show", " --show [device] [count]: 显示设备信息\r\n", cmd_show, -1 },
|
||||
};
|
||||
#define BUILTIN_CMD_COUNT (sizeof(builtin_commands) / sizeof(builtin_commands[0]))
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 辅助函数实现 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/**
|
||||
* @brief 发送字符串到 UART(阻塞等待完成)
|
||||
*/
|
||||
static void send_string(const char *str) {
|
||||
if (str == NULL || *str == '\0') return;
|
||||
|
||||
ctx.tx_complete = false;
|
||||
BSP_UART_Transmit(BSP_UART_MROBOT, (uint8_t *)str, strlen(str), true);
|
||||
while (!ctx.tx_complete) { osDelay(1); }
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 发送命令提示符
|
||||
*/
|
||||
static void send_prompt(void) {
|
||||
char prompt[MROBOT_PATH_MAX_LEN + 32];
|
||||
snprintf(prompt, sizeof(prompt), MROBOT_USER_NAME "@" MROBOT_HOST_NAME ":%s$ ", ctx.current_path);
|
||||
send_string(prompt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART 发送完成回调
|
||||
*/
|
||||
static void uart_tx_callback(void) {
|
||||
ctx.tx_complete = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief UART 接收回调
|
||||
*/
|
||||
static void uart_rx_callback(void) {
|
||||
uint8_t ch = ctx.uart_rx_char;
|
||||
|
||||
/* htop 模式下检查退出键 */
|
||||
if (ctx.state == MROBOT_STATE_HTOP) {
|
||||
if (ch == 'q' || ch == 'Q' || ch == 27) {
|
||||
ctx.htop_exit = true;
|
||||
}
|
||||
BSP_UART_Receive(BSP_UART_MROBOT, &ctx.uart_rx_char, 1, false);
|
||||
return;
|
||||
}
|
||||
|
||||
/* 正常命令输入处理 */
|
||||
if (ch == '\r' || ch == '\n') {
|
||||
if (ctx.cmd_index > 0) {
|
||||
ctx.cmd_buffer[ctx.cmd_index] = '\0';
|
||||
ctx.cmd_ready = true;
|
||||
BSP_UART_Transmit(BSP_UART_MROBOT, (uint8_t *)"\r\n", 2, false);
|
||||
}
|
||||
} else if (ch == 127 || ch == 8) { /* 退格键 */
|
||||
if (ctx.cmd_index > 0) {
|
||||
ctx.cmd_index--;
|
||||
BSP_UART_Transmit(BSP_UART_MROBOT, (uint8_t *)ANSI_BACKSPACE, 3, false);
|
||||
}
|
||||
} else if (ch >= 32 && ch < 127 && ctx.cmd_index < sizeof(ctx.cmd_buffer) - 1) {
|
||||
ctx.cmd_buffer[ctx.cmd_index++] = ch;
|
||||
/* 回显:使用静态变量地址,避免异步发送时局部变量已失效 */
|
||||
BSP_UART_Transmit(BSP_UART_MROBOT, &ctx.uart_rx_char, 1, false);
|
||||
}
|
||||
|
||||
BSP_UART_Receive(BSP_UART_MROBOT, &ctx.uart_rx_char, 1, false);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
/* CLI 命令实现 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/**
|
||||
* @brief help 命令 - 显示帮助信息
|
||||
*/
|
||||
static BaseType_t cmd_help(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) {
|
||||
(void)pcCommandString;
|
||||
|
||||
int offset = snprintf(pcWriteBuffer, xWriteBufferLen,
|
||||
"MRobot CLI v2.0\r\n"
|
||||
"================\r\n"
|
||||
"Built-in Commands:\r\n");
|
||||
|
||||
for (size_t i = 0; i < BUILTIN_CMD_COUNT && offset < (int)xWriteBufferLen - 50; i++) {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
" %s", builtin_commands[i].pcHelpString);
|
||||
}
|
||||
|
||||
if (ctx.custom_cmd_count > 0) {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
"\r\nCustom Commands:\r\n");
|
||||
for (uint8_t i = 0; i < ctx.custom_cmd_count && offset < (int)xWriteBufferLen - 50; i++) {
|
||||
if (ctx.custom_cmds[i] != NULL) {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
" %s", ctx.custom_cmds[i]->pcHelpString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief htop 命令 - 设置 htop 模式标志
|
||||
*/
|
||||
static BaseType_t cmd_htop(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) {
|
||||
(void)pcCommandString;
|
||||
(void)pcWriteBuffer;
|
||||
(void)xWriteBufferLen;
|
||||
/* htop 模式在 MRobot_Run 中处理 */
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief cd 命令 - 切换目录
|
||||
*/
|
||||
static BaseType_t cmd_cd(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) {
|
||||
const char *param;
|
||||
BaseType_t param_len;
|
||||
|
||||
param = FreeRTOS_CLIGetParameter(pcCommandString, 1, ¶m_len);
|
||||
|
||||
if (param == NULL) {
|
||||
/* 无参数时切换到根目录 */
|
||||
strcpy(ctx.current_path, "/");
|
||||
snprintf(pcWriteBuffer, xWriteBufferLen, "Changed to: %s\r\n", ctx.current_path);
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
/* 安全复制路径参数 */
|
||||
char path[MROBOT_PATH_MAX_LEN];
|
||||
size_t copy_len = (size_t)param_len < sizeof(path) - 1 ? (size_t)param_len : sizeof(path) - 1;
|
||||
strncpy(path, param, copy_len);
|
||||
path[copy_len] = '\0';
|
||||
|
||||
/* 路径解析 */
|
||||
if (strcmp(path, "/") == 0 || strcmp(path, "..") == 0 || strcmp(path, "~") == 0) {
|
||||
strcpy(ctx.current_path, "/");
|
||||
} else if (strcmp(path, "dev") == 0 || strcmp(path, "/dev") == 0) {
|
||||
strcpy(ctx.current_path, "/dev");
|
||||
} else if (strcmp(path, "modules") == 0 || strcmp(path, "/modules") == 0) {
|
||||
strcpy(ctx.current_path, "/modules");
|
||||
} else {
|
||||
snprintf(pcWriteBuffer, xWriteBufferLen, "Error: Directory '%s' not found\r\n", path);
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
snprintf(pcWriteBuffer, xWriteBufferLen, "Changed to: %s\r\n", ctx.current_path);
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief ls 命令 - 列出目录内容
|
||||
*/
|
||||
static BaseType_t cmd_ls(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) {
|
||||
(void)pcCommandString;
|
||||
int offset = 0;
|
||||
|
||||
if (strcmp(ctx.current_path, "/") == 0) {
|
||||
snprintf(pcWriteBuffer, xWriteBufferLen,
|
||||
"dev/\r\n"
|
||||
"modules/\r\n");
|
||||
} else if (strcmp(ctx.current_path, "/dev") == 0) {
|
||||
offset = snprintf(pcWriteBuffer, xWriteBufferLen,
|
||||
"Device List (%d devices)\r\n\r\n",
|
||||
ctx.device_count);
|
||||
|
||||
if (ctx.device_count == 0) {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
" (No devices)\r\n");
|
||||
} else {
|
||||
/* 直接列出所有设备 */
|
||||
for (uint8_t i = 0; i < ctx.device_count && offset < (int)xWriteBufferLen - 50; i++) {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
" - %s\r\n", ctx.devices[i].name);
|
||||
}
|
||||
}
|
||||
} else if (strcmp(ctx.current_path, "/modules") == 0) {
|
||||
snprintf(pcWriteBuffer, xWriteBufferLen,
|
||||
"Module functions not yet implemented\r\n");
|
||||
}
|
||||
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief show 命令 - 显示设备信息
|
||||
*/
|
||||
static BaseType_t cmd_show(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString) {
|
||||
const char *param;
|
||||
const char *count_param;
|
||||
BaseType_t param_len, count_param_len;
|
||||
|
||||
/* 使用局部静态变量跟踪多次打印状态 */
|
||||
static uint32_t print_count = 0;
|
||||
static uint32_t current_iter = 0;
|
||||
static char target_device[MROBOT_DEVICE_NAME_LEN] = {0};
|
||||
|
||||
/* 首次调用时解析参数 */
|
||||
if (current_iter == 0) {
|
||||
/* 检查是否在 /dev 目录 */
|
||||
if (strcmp(ctx.current_path, "/dev") != 0) {
|
||||
snprintf(pcWriteBuffer, xWriteBufferLen,
|
||||
"Error: 'show' command only works in /dev directory\r\n"
|
||||
"Hint: Use 'cd /dev' to switch to device directory\r\n");
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
param = FreeRTOS_CLIGetParameter(pcCommandString, 1, ¶m_len);
|
||||
count_param = FreeRTOS_CLIGetParameter(pcCommandString, 2, &count_param_len);
|
||||
|
||||
/* 解析打印次数 */
|
||||
print_count = 1;
|
||||
if (count_param != NULL) {
|
||||
char count_str[16];
|
||||
size_t copy_len = (size_t)count_param_len < sizeof(count_str) - 1 ?
|
||||
(size_t)count_param_len : sizeof(count_str) - 1;
|
||||
strncpy(count_str, count_param, copy_len);
|
||||
count_str[copy_len] = '\0';
|
||||
int parsed = atoi(count_str);
|
||||
if (parsed > 0 && parsed <= 1000) {
|
||||
print_count = (uint32_t)parsed;
|
||||
}
|
||||
}
|
||||
|
||||
/* 保存目标设备名称 */
|
||||
if (param != NULL) {
|
||||
size_t copy_len = (size_t)param_len < sizeof(target_device) - 1 ?
|
||||
(size_t)param_len : sizeof(target_device) - 1;
|
||||
strncpy(target_device, param, copy_len);
|
||||
target_device[copy_len] = '\0';
|
||||
} else {
|
||||
target_device[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
int offset = 0;
|
||||
|
||||
/* 连续打印模式:清屏 */
|
||||
if (print_count > 1) {
|
||||
offset = snprintf(pcWriteBuffer, xWriteBufferLen, "%s[%lu/%lu]\r\n",
|
||||
ANSI_CLEAR_SCREEN,
|
||||
(unsigned long)(current_iter + 1),
|
||||
(unsigned long)print_count);
|
||||
}
|
||||
|
||||
if (target_device[0] == '\0') {
|
||||
/* 显示所有设备 */
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
"=== All Devices ===\r\n\r\n");
|
||||
|
||||
for (uint8_t i = 0; i < ctx.device_count && offset < (int)xWriteBufferLen - 100; i++) {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
"--- %s ---\r\n", ctx.devices[i].name);
|
||||
|
||||
if (ctx.devices[i].print_cb != NULL) {
|
||||
int written = ctx.devices[i].print_cb(ctx.devices[i].data,
|
||||
pcWriteBuffer + offset,
|
||||
xWriteBufferLen - offset);
|
||||
offset += (written > 0) ? written : 0;
|
||||
} else {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
" (No print function)\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.device_count == 0) {
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
" (No devices registered)\r\n");
|
||||
}
|
||||
} else {
|
||||
/* 显示指定设备 */
|
||||
const MRobot_Device_t *dev = MRobot_FindDevice(target_device);
|
||||
|
||||
if (dev == NULL) {
|
||||
snprintf(pcWriteBuffer, xWriteBufferLen,
|
||||
"Error: Device '%s' not found\r\n",
|
||||
target_device);
|
||||
current_iter = 0;
|
||||
return pdFALSE;
|
||||
}
|
||||
|
||||
offset += snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
"=== %s ===\r\n", dev->name);
|
||||
|
||||
if (dev->print_cb != NULL) {
|
||||
dev->print_cb(dev->data, pcWriteBuffer + offset, xWriteBufferLen - offset);
|
||||
} else {
|
||||
snprintf(pcWriteBuffer + offset, xWriteBufferLen - offset,
|
||||
" (No print function)\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* 判断是否继续打印 */
|
||||
current_iter++;
|
||||
if (current_iter < print_count) {
|
||||
osDelay(MROBOT_HTOP_REFRESH_MS);
|
||||
return pdTRUE;
|
||||
} else {
|
||||
current_iter = 0;
|
||||
return pdFALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
* htop 模式处理
|
||||
* ========================================================================== */
|
||||
static void handle_htop_mode(void) {
|
||||
send_string(ANSI_CLEAR_SCREEN);
|
||||
send_string("=== MRobot Task Monitor (Press 'q' to exit) ===\r\n\r\n");
|
||||
|
||||
/* 获取任务列表 */
|
||||
char task_buffer[1024];
|
||||
char display_line[128];
|
||||
|
||||
vTaskList(task_buffer);
|
||||
|
||||
/* 表头 */
|
||||
send_string("Task Name State Prio Stack Num\r\n");
|
||||
send_string("------------------------------------------------\r\n");
|
||||
|
||||
/* 解析并格式化任务列表 */
|
||||
char *line = strtok(task_buffer, "\r\n");
|
||||
while (line != NULL) {
|
||||
char name[17] = {0};
|
||||
char state_char = '?';
|
||||
int prio = 0, stack = 0, num = 0;
|
||||
|
||||
if (sscanf(line, "%16s %c %d %d %d", name, &state_char, &prio, &stack, &num) == 5) {
|
||||
const char *state_str;
|
||||
switch (state_char) {
|
||||
case 'R': state_str = "Running"; break;
|
||||
case 'B': state_str = "Blocked"; break;
|
||||
case 'S': state_str = "Suspend"; break;
|
||||
case 'D': state_str = "Deleted"; break;
|
||||
case 'X': state_str = "Ready "; break;
|
||||
default: state_str = "Unknown"; break;
|
||||
}
|
||||
|
||||
snprintf(display_line, sizeof(display_line),
|
||||
"%-16s %-8s %-4d %-8d %-4d\r\n",
|
||||
name, state_str, prio, stack, num);
|
||||
send_string(display_line);
|
||||
}
|
||||
line = strtok(NULL, "\r\n");
|
||||
}
|
||||
|
||||
/* 显示系统信息 */
|
||||
snprintf(display_line, sizeof(display_line),
|
||||
"------------------------------------------------\r\n"
|
||||
"System Tick: %lu | Free Heap: %lu bytes\r\n",
|
||||
(unsigned long)xTaskGetTickCount(),
|
||||
(unsigned long)xPortGetFreeHeapSize());
|
||||
send_string(display_line);
|
||||
|
||||
/* 检查退出 */
|
||||
if (ctx.htop_exit) {
|
||||
ctx.state = MROBOT_STATE_IDLE;
|
||||
ctx.htop_exit = false;
|
||||
send_string(ANSI_CLEAR_SCREEN);
|
||||
send_prompt();
|
||||
}
|
||||
|
||||
osDelay(MROBOT_HTOP_REFRESH_MS);
|
||||
}
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 公共 API 实现 */
|
||||
/* ========================================================================== */
|
||||
|
||||
void MRobot_Init(void) {
|
||||
if (ctx.initialized) return;
|
||||
|
||||
/* 创建互斥锁 */
|
||||
ctx.mutex = xSemaphoreCreateMutex();
|
||||
|
||||
/* 初始化状态(保留已注册的设备) */
|
||||
// 注意:不清除 devices 和 device_count,因为其他任务可能已经注册了设备
|
||||
ctx.custom_cmd_count = 0;
|
||||
ctx.state = MROBOT_STATE_IDLE;
|
||||
strcpy(ctx.current_path, "/");
|
||||
ctx.cmd_index = 0;
|
||||
ctx.cmd_ready = false;
|
||||
ctx.tx_complete = true;
|
||||
ctx.htop_exit = false;
|
||||
|
||||
/* 注册内置命令 */
|
||||
for (size_t i = 0; i < BUILTIN_CMD_COUNT; i++) {
|
||||
FreeRTOS_CLIRegisterCommand(&builtin_commands[i]);
|
||||
}
|
||||
|
||||
/* 注册 UART 回调 */
|
||||
BSP_UART_RegisterCallback(BSP_UART_MROBOT, BSP_UART_RX_CPLT_CB, uart_rx_callback);
|
||||
BSP_UART_RegisterCallback(BSP_UART_MROBOT, BSP_UART_TX_CPLT_CB, uart_tx_callback);
|
||||
|
||||
/* 启动 UART 接收 */
|
||||
BSP_UART_Receive(BSP_UART_MROBOT, &ctx.uart_rx_char, 1, false);
|
||||
|
||||
/* 等待用户按下回车 */
|
||||
while (ctx.uart_rx_char != '\r' && ctx.uart_rx_char != '\n') {
|
||||
osDelay(10);
|
||||
}
|
||||
|
||||
/* 发送欢迎消息和提示符 */
|
||||
send_string(CLI_WELCOME_MESSAGE);
|
||||
send_prompt();
|
||||
|
||||
ctx.initialized = true;
|
||||
}
|
||||
|
||||
void MRobot_DeInit(void) {
|
||||
if (!ctx.initialized) return;
|
||||
|
||||
/* 释放自定义命令内存 */
|
||||
for (uint8_t i = 0; i < ctx.custom_cmd_count; i++) {
|
||||
if (ctx.custom_cmds[i] != NULL) {
|
||||
BSP_Free(ctx.custom_cmds[i]);
|
||||
ctx.custom_cmds[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* 删除互斥锁 */
|
||||
if (ctx.mutex != NULL) {
|
||||
vSemaphoreDelete(ctx.mutex);
|
||||
ctx.mutex = NULL;
|
||||
}
|
||||
|
||||
ctx.initialized = false;
|
||||
}
|
||||
|
||||
MRobot_State_t MRobot_GetState(void) {
|
||||
return ctx.state;
|
||||
}
|
||||
|
||||
MRobot_Error_t MRobot_RegisterDevice(const char *name, void *data, MRobot_PrintCallback_t print_cb) {
|
||||
if (name == NULL || data == NULL) {
|
||||
return MROBOT_ERR_NULL_PTR;
|
||||
}
|
||||
|
||||
if (ctx.device_count >= MROBOT_MAX_DEVICES) {
|
||||
return MROBOT_ERR_FULL;
|
||||
}
|
||||
|
||||
/* 检查重名 */
|
||||
for (uint8_t i = 0; i < ctx.device_count; i++) {
|
||||
if (strcmp(ctx.devices[i].name, name) == 0) {
|
||||
return MROBOT_ERR_INVALID_ARG; /* 设备名已存在 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 线程安全写入 */
|
||||
if (ctx.mutex != NULL) {
|
||||
xSemaphoreTake(ctx.mutex, portMAX_DELAY);
|
||||
}
|
||||
|
||||
strncpy(ctx.devices[ctx.device_count].name, name, MROBOT_DEVICE_NAME_LEN - 1);
|
||||
ctx.devices[ctx.device_count].name[MROBOT_DEVICE_NAME_LEN - 1] = '\0';
|
||||
ctx.devices[ctx.device_count].data = data;
|
||||
ctx.devices[ctx.device_count].print_cb = print_cb;
|
||||
ctx.device_count++;
|
||||
|
||||
if (ctx.mutex != NULL) {
|
||||
xSemaphoreGive(ctx.mutex);
|
||||
}
|
||||
|
||||
return MROBOT_OK;
|
||||
}
|
||||
|
||||
MRobot_Error_t MRobot_UnregisterDevice(const char *name) {
|
||||
if (name == NULL) {
|
||||
return MROBOT_ERR_NULL_PTR;
|
||||
}
|
||||
|
||||
if (ctx.mutex != NULL) {
|
||||
xSemaphoreTake(ctx.mutex, portMAX_DELAY);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < ctx.device_count; i++) {
|
||||
if (strcmp(ctx.devices[i].name, name) == 0) {
|
||||
/* 移动后续设备 */
|
||||
for (uint8_t j = i; j < ctx.device_count - 1; j++) {
|
||||
ctx.devices[j] = ctx.devices[j + 1];
|
||||
}
|
||||
ctx.device_count--;
|
||||
|
||||
if (ctx.mutex != NULL) {
|
||||
xSemaphoreGive(ctx.mutex);
|
||||
}
|
||||
return MROBOT_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.mutex != NULL) {
|
||||
xSemaphoreGive(ctx.mutex);
|
||||
}
|
||||
return MROBOT_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
MRobot_Error_t MRobot_RegisterCommand(const char *command, const char *help_text,
|
||||
MRobot_CommandCallback_t callback, int8_t param_count) {
|
||||
if (command == NULL || help_text == NULL || callback == NULL) {
|
||||
return MROBOT_ERR_NULL_PTR;
|
||||
}
|
||||
|
||||
if (ctx.custom_cmd_count >= MROBOT_MAX_CUSTOM_COMMANDS) {
|
||||
return MROBOT_ERR_FULL;
|
||||
}
|
||||
|
||||
/* 动态分配命令结构体 */
|
||||
CLI_Command_Definition_t *cmd_def = BSP_Malloc(sizeof(CLI_Command_Definition_t));
|
||||
if (cmd_def == NULL) {
|
||||
return MROBOT_ERR_ALLOC;
|
||||
}
|
||||
|
||||
/* 初始化命令定义 */
|
||||
*(const char **)&cmd_def->pcCommand = command;
|
||||
*(const char **)&cmd_def->pcHelpString = help_text;
|
||||
*(pdCOMMAND_LINE_CALLBACK *)&cmd_def->pxCommandInterpreter = (pdCOMMAND_LINE_CALLBACK)callback;
|
||||
cmd_def->cExpectedNumberOfParameters = param_count;
|
||||
|
||||
/* 注册到 FreeRTOS CLI */
|
||||
FreeRTOS_CLIRegisterCommand(cmd_def);
|
||||
|
||||
ctx.custom_cmds[ctx.custom_cmd_count] = cmd_def;
|
||||
ctx.custom_cmd_count++;
|
||||
|
||||
return MROBOT_OK;
|
||||
}
|
||||
|
||||
uint8_t MRobot_GetDeviceCount(void) {
|
||||
return ctx.device_count;
|
||||
}
|
||||
|
||||
const MRobot_Device_t *MRobot_FindDevice(const char *name) {
|
||||
if (name == NULL) return NULL;
|
||||
|
||||
for (uint8_t i = 0; i < ctx.device_count; i++) {
|
||||
if (strcmp(ctx.devices[i].name, name) == 0) {
|
||||
return &ctx.devices[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int MRobot_Printf(const char *fmt, ...) {
|
||||
if (fmt == NULL || !ctx.initialized) return -1;
|
||||
|
||||
char buffer[MROBOT_OUTPUT_BUFFER_SIZE];
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int len = format_float_va(buffer, sizeof(buffer), fmt, args);
|
||||
va_end(args);
|
||||
|
||||
if (len > 0) {
|
||||
send_string(buffer);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 内部函数:格式化浮点数到缓冲区(va_list 版本)
|
||||
*/
|
||||
static int format_float_va(char *buf, size_t size, const char *fmt, va_list args) {
|
||||
if (buf == NULL || size == 0 || fmt == NULL) return 0;
|
||||
|
||||
char *buf_ptr = buf;
|
||||
size_t buf_remain = size - 1;
|
||||
|
||||
const char *p = fmt;
|
||||
while (*p && buf_remain > 0) {
|
||||
if (*p != '%') {
|
||||
*buf_ptr++ = *p++;
|
||||
buf_remain--;
|
||||
continue;
|
||||
}
|
||||
|
||||
p++; /* 跳过 '%' */
|
||||
|
||||
/* 处理 %% */
|
||||
if (*p == '%') {
|
||||
*buf_ptr++ = '%';
|
||||
buf_remain--;
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* 解析精度 %.Nf */
|
||||
int precision = 2; /* 默认精度 */
|
||||
if (*p == '.') {
|
||||
p++;
|
||||
precision = 0;
|
||||
while (*p >= '0' && *p <= '9') {
|
||||
precision = precision * 10 + (*p - '0');
|
||||
p++;
|
||||
}
|
||||
if (precision > 6) precision = 6;
|
||||
}
|
||||
|
||||
int written = 0;
|
||||
switch (*p) {
|
||||
case 'f': { /* 浮点数 */
|
||||
double val = va_arg(args, double);
|
||||
written = MRobot_FormatFloat(buf_ptr, buf_remain, (float)val, precision);
|
||||
break;
|
||||
}
|
||||
case 'd':
|
||||
case 'i': {
|
||||
int val = va_arg(args, int);
|
||||
written = snprintf(buf_ptr, buf_remain, "%d", val);
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
unsigned int val = va_arg(args, unsigned int);
|
||||
written = snprintf(buf_ptr, buf_remain, "%u", val);
|
||||
break;
|
||||
}
|
||||
case 'x': {
|
||||
unsigned int val = va_arg(args, unsigned int);
|
||||
written = snprintf(buf_ptr, buf_remain, "%x", val);
|
||||
break;
|
||||
}
|
||||
case 'X': {
|
||||
unsigned int val = va_arg(args, unsigned int);
|
||||
written = snprintf(buf_ptr, buf_remain, "%X", val);
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
const char *str = va_arg(args, const char *);
|
||||
if (str == NULL) str = "(null)";
|
||||
written = snprintf(buf_ptr, buf_remain, "%s", str);
|
||||
break;
|
||||
}
|
||||
case 'c': {
|
||||
int ch = va_arg(args, int);
|
||||
*buf_ptr = (char)ch;
|
||||
written = 1;
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
p++;
|
||||
if (*p == 'd' || *p == 'i') {
|
||||
long val = va_arg(args, long);
|
||||
written = snprintf(buf_ptr, buf_remain, "%ld", val);
|
||||
} else if (*p == 'u') {
|
||||
unsigned long val = va_arg(args, unsigned long);
|
||||
written = snprintf(buf_ptr, buf_remain, "%lu", val);
|
||||
} else if (*p == 'x' || *p == 'X') {
|
||||
unsigned long val = va_arg(args, unsigned long);
|
||||
written = snprintf(buf_ptr, buf_remain, *p == 'x' ? "%lx" : "%lX", val);
|
||||
} else {
|
||||
p--;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
*buf_ptr++ = '%';
|
||||
buf_remain--;
|
||||
if (buf_remain > 0) {
|
||||
*buf_ptr++ = *p;
|
||||
buf_remain--;
|
||||
}
|
||||
written = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (written > 0) {
|
||||
buf_ptr += written;
|
||||
buf_remain -= (size_t)written;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
*buf_ptr = '\0';
|
||||
return (int)(buf_ptr - buf);
|
||||
}
|
||||
|
||||
int MRobot_Snprintf(char *buf, size_t size, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
int len = format_float_va(buf, size, fmt, args);
|
||||
va_end(args);
|
||||
return len;
|
||||
}
|
||||
|
||||
int MRobot_FormatFloat(char *buf, size_t size, float val, int precision) {
|
||||
if (buf == NULL || size == 0) return 0;
|
||||
|
||||
int offset = 0;
|
||||
|
||||
/* 处理负数 */
|
||||
if (val < 0) {
|
||||
if (offset < (int)size - 1) buf[offset++] = '-';
|
||||
val = -val;
|
||||
}
|
||||
|
||||
/* 限制精度范围 */
|
||||
if (precision < 0) precision = 0;
|
||||
if (precision > 6) precision = 6;
|
||||
|
||||
/* 计算乘数 */
|
||||
int multiplier = 1;
|
||||
for (int i = 0; i < precision; i++) multiplier *= 10;
|
||||
|
||||
int int_part = (int)val;
|
||||
int frac_part = (int)((val - int_part) * multiplier + 0.5f);
|
||||
|
||||
/* 处理进位 */
|
||||
if (frac_part >= multiplier) {
|
||||
int_part++;
|
||||
frac_part -= multiplier;
|
||||
}
|
||||
|
||||
/* 格式化输出 */
|
||||
int written;
|
||||
if (precision > 0) {
|
||||
written = snprintf(buf + offset, size - offset, "%d.%0*d", int_part, precision, frac_part);
|
||||
} else {
|
||||
written = snprintf(buf + offset, size - offset, "%d", int_part);
|
||||
}
|
||||
return (written > 0) ? (offset + written) : offset;
|
||||
}
|
||||
|
||||
void MRobot_Run(void) {
|
||||
if (!ctx.initialized) return;
|
||||
|
||||
/* htop 模式 */
|
||||
if (ctx.state == MROBOT_STATE_HTOP) {
|
||||
handle_htop_mode();
|
||||
return;
|
||||
}
|
||||
|
||||
/* 处理命令 */
|
||||
if (ctx.cmd_ready) {
|
||||
ctx.state = MROBOT_STATE_PROCESSING;
|
||||
|
||||
/* 检查是否是 htop 命令 */
|
||||
if (strcmp((char *)ctx.cmd_buffer, "htop") == 0) {
|
||||
ctx.state = MROBOT_STATE_HTOP;
|
||||
ctx.htop_exit = false;
|
||||
} else {
|
||||
/* 处理其他命令 */
|
||||
BaseType_t more;
|
||||
do {
|
||||
ctx.output_buffer[0] = '\0';
|
||||
more = FreeRTOS_CLIProcessCommand((char *)ctx.cmd_buffer,
|
||||
ctx.output_buffer,
|
||||
sizeof(ctx.output_buffer));
|
||||
|
||||
if (ctx.output_buffer[0] != '\0') {
|
||||
send_string(ctx.output_buffer);
|
||||
}
|
||||
} while (more != pdFALSE);
|
||||
|
||||
send_prompt();
|
||||
ctx.state = MROBOT_STATE_IDLE;
|
||||
}
|
||||
|
||||
ctx.cmd_index = 0;
|
||||
ctx.cmd_ready = false;
|
||||
}
|
||||
|
||||
osDelay(10);
|
||||
}
|
||||
313
assets/User_code/device/mrobot/mrobot.h
Normal file
313
assets/User_code/device/mrobot/mrobot.h
Normal file
@ -0,0 +1,313 @@
|
||||
/**
|
||||
* @file mrobot.h
|
||||
* @brief MRobot CLI - 基于 FreeRTOS CLI 的嵌入式调试命令行系统
|
||||
*
|
||||
* 功能特性:
|
||||
* - 设备注册与监控(IMU、电机、传感器等)
|
||||
* - 类 Unix 文件系统命令(cd, ls, pwd)
|
||||
* - htop 风格的任务监控
|
||||
* - 自定义命令扩展
|
||||
* - 线程安全设计
|
||||
*
|
||||
* @example IMU 设备注册示例
|
||||
* @code
|
||||
* // 1. 定义 IMU 数据结构
|
||||
* typedef struct {
|
||||
* bool online;
|
||||
* float accl[3];
|
||||
* float gyro[3];
|
||||
* float euler[3]; // roll, pitch, yaw (deg)
|
||||
* float temp;
|
||||
* } MyIMU_t;
|
||||
*
|
||||
* MyIMU_t my_imu;
|
||||
*
|
||||
* // 2. 实现打印回调
|
||||
* static int print_imu(const void *data, char *buf, size_t size) {
|
||||
* const MyIMU_t *imu = (const MyIMU_t *)data;
|
||||
* return MRobot_Snprintf(buf, size,
|
||||
* " Status: %s\r\n"
|
||||
* " Accel : X=%.3f Y=%.3f Z=%.3f\r\n"
|
||||
* " Euler : R=%.2f P=%.2f Y=%.2f\r\n"
|
||||
* " Temp : %.1f C\r\n",
|
||||
* imu->online ? "Online" : "Offline",
|
||||
* imu->accl[0], imu->accl[1], imu->accl[2],
|
||||
* imu->euler[0], imu->euler[1], imu->euler[2],
|
||||
* imu->temp);
|
||||
* }
|
||||
*
|
||||
* // 3. 注册设备
|
||||
* MRobot_RegisterDevice("imu", &my_imu, print_imu);
|
||||
* @endcode
|
||||
*
|
||||
* @example 电机设备注册示例
|
||||
* @code
|
||||
* typedef struct {
|
||||
* bool online;
|
||||
* float angle; // deg
|
||||
* float speed; // RPM
|
||||
* float current; // A
|
||||
* } MyMotor_t;
|
||||
*
|
||||
* MyMotor_t motor[4];
|
||||
*
|
||||
* static int print_motor(const void *data, char *buf, size_t size) {
|
||||
* const MyMotor_t *m = (const MyMotor_t *)data;
|
||||
* return MRobot_Snprintf(buf, size,
|
||||
* " Status : %s\r\n"
|
||||
* " Angle : %.2f deg\r\n"
|
||||
* " Speed : %.1f RPM\r\n"
|
||||
* " Current: %.3f A\r\n",
|
||||
* m->online ? "Online" : "Offline",
|
||||
* m->angle, m->speed, m->current);
|
||||
* }
|
||||
*
|
||||
* // 注册 4 个电机
|
||||
* MRobot_RegisterDevice("motor0", &motor[0], print_motor);
|
||||
* MRobot_RegisterDevice("motor1", &motor[1], print_motor);
|
||||
* MRobot_RegisterDevice("motor2", &motor[2], print_motor);
|
||||
* MRobot_RegisterDevice("motor3", &motor[3], print_motor);
|
||||
* @endcode
|
||||
*
|
||||
* @example 自定义校准命令示例
|
||||
* @code
|
||||
* // 校准数据
|
||||
* static float gyro_offset[3] = {0};
|
||||
*
|
||||
* // 命令回调: cali gyro / cali accel / cali save
|
||||
* static long cmd_cali(char *buf, size_t size, const char *cmd) {
|
||||
* const char *param = FreeRTOS_CLIGetParameter(cmd, 1, NULL);
|
||||
*
|
||||
* if (param == NULL) {
|
||||
* return MRobot_Snprintf(buf, size, "Usage: cali <gyro|accel|save>\r\n");
|
||||
* }
|
||||
* if (strncmp(param, "gyro", 4) == 0) {
|
||||
* // 采集 1000 次陀螺仪数据求平均
|
||||
* MRobot_Snprintf(buf, size, "Calibrating gyro... keep IMU still!\r\n");
|
||||
* // ... 校准逻辑 ...
|
||||
* return 0;
|
||||
* }
|
||||
* if (strncmp(param, "save", 4) == 0) {
|
||||
* // 保存到 Flash
|
||||
* MRobot_Snprintf(buf, size, "Calibration saved to flash.\r\n");
|
||||
* return 0;
|
||||
* }
|
||||
* return MRobot_Snprintf(buf, size, "Unknown: %s\r\n", param);
|
||||
* }
|
||||
*
|
||||
* // 注册命令
|
||||
* MRobot_RegisterCommand("cali", "cali <gyro|accel|save>: IMU calibration\r\n", cmd_cali, -1);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include "bsp/uart.h"
|
||||
|
||||
/* Configuration ------------------------------------------------------------ */
|
||||
/* 可在编译时通过 -D 选项覆盖这些默认值 */
|
||||
|
||||
#ifndef MROBOT_MAX_DEVICES
|
||||
#define MROBOT_MAX_DEVICES 64 /* 最大设备数 */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_MAX_CUSTOM_COMMANDS
|
||||
#define MROBOT_MAX_CUSTOM_COMMANDS 16 /* 最大自定义命令数 */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_CMD_BUFFER_SIZE
|
||||
#define MROBOT_CMD_BUFFER_SIZE 128 /* 命令缓冲区大小 */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_OUTPUT_BUFFER_SIZE
|
||||
#define MROBOT_OUTPUT_BUFFER_SIZE 512 /* 输出缓冲区大小 */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_DEVICE_NAME_LEN
|
||||
#define MROBOT_DEVICE_NAME_LEN 32 /* 设备名最大长度 */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_PATH_MAX_LEN
|
||||
#define MROBOT_PATH_MAX_LEN 64 /* 路径最大长度 */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_HTOP_REFRESH_MS
|
||||
#define MROBOT_HTOP_REFRESH_MS 200 /* htop 刷新间隔 (ms) */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_USER_NAME
|
||||
#define MROBOT_USER_NAME "root" /* CLI 用户名 */
|
||||
#endif
|
||||
|
||||
#ifndef MROBOT_HOST_NAME
|
||||
#define MROBOT_HOST_NAME "MRobot" /* CLI 主机名 */
|
||||
#endif
|
||||
|
||||
/* Error codes -------------------------------------------------------------- */
|
||||
typedef enum {
|
||||
MROBOT_OK = 0, /* 成功 */
|
||||
MROBOT_ERR_FULL = -1, /* 容量已满 */
|
||||
MROBOT_ERR_NULL_PTR = -2, /* 空指针 */
|
||||
MROBOT_ERR_INVALID_ARG = -3, /* 无效参数 */
|
||||
MROBOT_ERR_NOT_FOUND = -4, /* 未找到 */
|
||||
MROBOT_ERR_ALLOC = -5, /* 内存分配失败 */
|
||||
MROBOT_ERR_BUSY = -6, /* 设备忙 */
|
||||
MROBOT_ERR_NOT_INIT = -7, /* 未初始化 */
|
||||
} MRobot_Error_t;
|
||||
|
||||
/* CLI 运行状态 */
|
||||
typedef enum {
|
||||
MROBOT_STATE_IDLE, /* 空闲状态,等待输入 */
|
||||
MROBOT_STATE_HTOP, /* htop 模式 */
|
||||
MROBOT_STATE_PROCESSING, /* 正在处理命令 */
|
||||
} MRobot_State_t;
|
||||
|
||||
/* Callback types ----------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief 设备打印回调函数类型
|
||||
* @param device_data 用户注册时传入的设备数据指针
|
||||
* @param buffer 输出缓冲区
|
||||
* @param buffer_size 缓冲区大小
|
||||
* @return 实际写入的字节数
|
||||
* @note 用户需要自行实现此函数来格式化设备数据
|
||||
*/
|
||||
typedef int (*MRobot_PrintCallback_t)(const void *device_data, char *buffer, size_t buffer_size);
|
||||
|
||||
/**
|
||||
* @brief 命令处理回调函数类型(与 FreeRTOS CLI 兼容)
|
||||
*/
|
||||
typedef long (*MRobot_CommandCallback_t)(char *pcWriteBuffer, size_t xWriteBufferLen, const char *pcCommandString);
|
||||
|
||||
/* Device structure --------------------------------------------------------- */
|
||||
typedef struct {
|
||||
char name[MROBOT_DEVICE_NAME_LEN]; /* 设备名称 */
|
||||
void *data; /* 用户设备数据指针 */
|
||||
MRobot_PrintCallback_t print_cb; /* 用户打印回调函数 */
|
||||
} MRobot_Device_t;
|
||||
|
||||
/* Public API --------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief 初始化 MRobot CLI 系统
|
||||
* @note 必须在 FreeRTOS 调度器启动后调用
|
||||
*/
|
||||
void MRobot_Init(void);
|
||||
|
||||
/**
|
||||
* @brief 反初始化 MRobot CLI 系统,释放资源
|
||||
*/
|
||||
void MRobot_DeInit(void);
|
||||
|
||||
/**
|
||||
* @brief 获取当前 CLI 状态
|
||||
* @return MRobot_State_t 当前状态
|
||||
*/
|
||||
MRobot_State_t MRobot_GetState(void);
|
||||
|
||||
/**
|
||||
* @brief 注册设备到 MRobot 系统
|
||||
* @param name 设备名称(会被截断到 MROBOT_DEVICE_NAME_LEN-1)
|
||||
* @param data 设备数据指针(不能为 NULL)
|
||||
* @param print_cb 打印回调函数(可为 NULL,但无法用 show 命令查看)
|
||||
* @return MRobot_Error_t 错误码
|
||||
*/
|
||||
MRobot_Error_t MRobot_RegisterDevice(const char *name, void *data, MRobot_PrintCallback_t print_cb);
|
||||
|
||||
/**
|
||||
* @brief 注销设备
|
||||
* @param name 设备名称
|
||||
* @return MRobot_Error_t 错误码
|
||||
*/
|
||||
MRobot_Error_t MRobot_UnregisterDevice(const char *name);
|
||||
|
||||
/**
|
||||
* @brief 注册自定义命令
|
||||
* @param command 命令名称
|
||||
* @param help_text 帮助文本
|
||||
* @param callback 命令回调函数
|
||||
* @param param_count 参数个数(-1 表示可变参数)
|
||||
* @return MRobot_Error_t 错误码
|
||||
*/
|
||||
MRobot_Error_t MRobot_RegisterCommand(const char *command, const char *help_text,
|
||||
MRobot_CommandCallback_t callback, int8_t param_count);
|
||||
|
||||
/**
|
||||
* @brief 获取已注册设备数量
|
||||
* @return 设备数量
|
||||
*/
|
||||
uint8_t MRobot_GetDeviceCount(void);
|
||||
|
||||
/**
|
||||
* @brief 根据名称查找设备
|
||||
* @param name 设备名称
|
||||
* @return 设备指针,未找到返回 NULL
|
||||
*/
|
||||
const MRobot_Device_t *MRobot_FindDevice(const char *name);
|
||||
|
||||
/**
|
||||
* @brief MRobot 主循环,在 CLI 任务中周期性调用
|
||||
* @note 建议调用周期 10ms
|
||||
*/
|
||||
void MRobot_Run(void);
|
||||
|
||||
/**
|
||||
* @brief 格式化输出到 CLI 终端(线程安全,支持浮点数)
|
||||
* @param fmt 格式字符串
|
||||
* @param ... 可变参数
|
||||
* @return 实际输出的字符数,失败返回负数
|
||||
*
|
||||
* @note 支持的格式说明符:
|
||||
* - %d, %i, %u, %x, %X, %ld, %lu, %lx : 整数
|
||||
* - %s, %c : 字符串/字符
|
||||
* - %f : 浮点数 (默认2位小数)
|
||||
* - %.Nf : 浮点数 (N位小数, N=0-6)
|
||||
* - %% : 百分号
|
||||
*
|
||||
* @example
|
||||
* MRobot_Printf("Euler: R=%.2f P=%.2f Y=%.2f\\r\\n", roll, pitch, yaw);
|
||||
*/
|
||||
int MRobot_Printf(const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief 格式化到缓冲区(用于回调函数,支持浮点数)
|
||||
* @note 格式说明符同 MRobot_Printf
|
||||
*
|
||||
* @example
|
||||
* static int print_imu(const void *data, char *buf, size_t size) {
|
||||
* const BMI088_t *imu = (const BMI088_t *)data;
|
||||
* return MRobot_Snprintf(buf, size,
|
||||
* " Accel: X=%.3f Y=%.3f Z=%.3f\\r\\n",
|
||||
* imu->accl.x, imu->accl.y, imu->accl.z);
|
||||
* }
|
||||
*/
|
||||
int MRobot_Snprintf(char *buf, size_t size, const char *fmt, ...);
|
||||
|
||||
/* Utility functions -------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* @brief 格式化浮点数为字符串(嵌入式环境不支持 %f)
|
||||
* @param buf 输出缓冲区
|
||||
* @param size 缓冲区大小
|
||||
* @param val 要格式化的浮点数
|
||||
* @param precision 小数位数 (0-6)
|
||||
* @return 写入的字符数
|
||||
*
|
||||
* @example
|
||||
* char buf[16];
|
||||
* MRobot_FormatFloat(buf, sizeof(buf), 3.14159f, 2); // "3.14"
|
||||
* MRobot_FormatFloat(buf, sizeof(buf), -0.001f, 4); // "-0.0010"
|
||||
*/
|
||||
int MRobot_FormatFloat(char *buf, size_t size, float val, int precision);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
700
assets/User_code/ioc/CtrBoard-H7_ALL.ioc
Normal file
700
assets/User_code/ioc/CtrBoard-H7_ALL.ioc
Normal file
@ -0,0 +1,700 @@
|
||||
#MicroXplorer Configuration settings - do not modify
|
||||
ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_4
|
||||
ADC1.Channel-1\#ChannelRegularConversion=ADC_CHANNEL_19
|
||||
ADC1.ClockPrescaler=ADC_CLOCK_ASYNC_DIV64
|
||||
ADC1.ContinuousConvMode=ENABLE
|
||||
ADC1.ConversionDataManagement=ADC_CONVERSIONDATA_DMA_CIRCULAR
|
||||
ADC1.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,OffsetNumber-0\#ChannelRegularConversion,OffsetSignedSaturation-0\#ChannelRegularConversion,NbrOfConversionFlag,master,ClockPrescaler,ContinuousConvMode,ConversionDataManagement,Rank-1\#ChannelRegularConversion,Channel-1\#ChannelRegularConversion,SamplingTime-1\#ChannelRegularConversion,OffsetNumber-1\#ChannelRegularConversion,OffsetSignedSaturation-1\#ChannelRegularConversion,NbrOfConversion
|
||||
ADC1.NbrOfConversion=2
|
||||
ADC1.NbrOfConversionFlag=1
|
||||
ADC1.OffsetNumber-0\#ChannelRegularConversion=ADC_OFFSET_NONE
|
||||
ADC1.OffsetNumber-1\#ChannelRegularConversion=ADC_OFFSET_NONE
|
||||
ADC1.OffsetSignedSaturation-0\#ChannelRegularConversion=DISABLE
|
||||
ADC1.OffsetSignedSaturation-1\#ChannelRegularConversion=DISABLE
|
||||
ADC1.Rank-0\#ChannelRegularConversion=1
|
||||
ADC1.Rank-1\#ChannelRegularConversion=2
|
||||
ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_32CYCLES_5
|
||||
ADC1.SamplingTime-1\#ChannelRegularConversion=ADC_SAMPLETIME_32CYCLES_5
|
||||
ADC1.master=1
|
||||
CAD.formats=
|
||||
CAD.pinconfig=
|
||||
CAD.provider=
|
||||
CORTEX_M7.BaseAddress-Cortex_Memory_Protection_Unit_Region0_Settings=0x24000000
|
||||
CORTEX_M7.CPU_DCache=Disabled
|
||||
CORTEX_M7.CPU_ICache=Disabled
|
||||
CORTEX_M7.Enable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_REGION_ENABLE
|
||||
CORTEX_M7.IPParameters=CPU_DCache,CPU_ICache,MPU_Control,Enable-Cortex_Memory_Protection_Unit_Region0_Settings,BaseAddress-Cortex_Memory_Protection_Unit_Region0_Settings,Size-Cortex_Memory_Protection_Unit_Region0_Settings,TypeExtField-Cortex_Memory_Protection_Unit_Region0_Settings,IsCacheable-Cortex_Memory_Protection_Unit_Region0_Settings,IsBufferable-Cortex_Memory_Protection_Unit_Region0_Settings
|
||||
CORTEX_M7.IsBufferable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_ACCESS_BUFFERABLE
|
||||
CORTEX_M7.IsCacheable-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_ACCESS_CACHEABLE
|
||||
CORTEX_M7.MPU_Control=__NULL
|
||||
CORTEX_M7.Size-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_REGION_SIZE_512B
|
||||
CORTEX_M7.TypeExtField-Cortex_Memory_Protection_Unit_Region0_Settings=MPU_TEX_LEVEL1
|
||||
Dma.ADC1.0.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.ADC1.0.EventEnable=DISABLE
|
||||
Dma.ADC1.0.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.ADC1.0.Instance=DMA1_Stream0
|
||||
Dma.ADC1.0.MemDataAlignment=DMA_MDATAALIGN_HALFWORD
|
||||
Dma.ADC1.0.MemInc=DMA_MINC_ENABLE
|
||||
Dma.ADC1.0.Mode=DMA_CIRCULAR
|
||||
Dma.ADC1.0.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD
|
||||
Dma.ADC1.0.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.ADC1.0.Polarity=HAL_DMAMUX_REQ_GEN_RISING
|
||||
Dma.ADC1.0.Priority=DMA_PRIORITY_LOW
|
||||
Dma.ADC1.0.RequestNumber=1
|
||||
Dma.ADC1.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
|
||||
Dma.ADC1.0.SignalID=NONE
|
||||
Dma.ADC1.0.SyncEnable=DISABLE
|
||||
Dma.ADC1.0.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
|
||||
Dma.ADC1.0.SyncRequestNumber=1
|
||||
Dma.ADC1.0.SyncSignalID=NONE
|
||||
Dma.Request0=ADC1
|
||||
Dma.Request1=SPI2_RX
|
||||
Dma.Request2=SPI2_TX
|
||||
Dma.Request3=UART5_RX
|
||||
Dma.RequestsNb=4
|
||||
Dma.SPI2_RX.1.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.SPI2_RX.1.EventEnable=DISABLE
|
||||
Dma.SPI2_RX.1.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.SPI2_RX.1.Instance=DMA1_Stream1
|
||||
Dma.SPI2_RX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.SPI2_RX.1.MemInc=DMA_MINC_ENABLE
|
||||
Dma.SPI2_RX.1.Mode=DMA_NORMAL
|
||||
Dma.SPI2_RX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.SPI2_RX.1.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.SPI2_RX.1.Polarity=HAL_DMAMUX_REQ_GEN_RISING
|
||||
Dma.SPI2_RX.1.Priority=DMA_PRIORITY_LOW
|
||||
Dma.SPI2_RX.1.RequestNumber=1
|
||||
Dma.SPI2_RX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
|
||||
Dma.SPI2_RX.1.SignalID=NONE
|
||||
Dma.SPI2_RX.1.SyncEnable=DISABLE
|
||||
Dma.SPI2_RX.1.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
|
||||
Dma.SPI2_RX.1.SyncRequestNumber=1
|
||||
Dma.SPI2_RX.1.SyncSignalID=NONE
|
||||
Dma.SPI2_TX.2.Direction=DMA_MEMORY_TO_PERIPH
|
||||
Dma.SPI2_TX.2.EventEnable=DISABLE
|
||||
Dma.SPI2_TX.2.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.SPI2_TX.2.Instance=DMA1_Stream2
|
||||
Dma.SPI2_TX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.SPI2_TX.2.MemInc=DMA_MINC_ENABLE
|
||||
Dma.SPI2_TX.2.Mode=DMA_NORMAL
|
||||
Dma.SPI2_TX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.SPI2_TX.2.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.SPI2_TX.2.Polarity=HAL_DMAMUX_REQ_GEN_RISING
|
||||
Dma.SPI2_TX.2.Priority=DMA_PRIORITY_LOW
|
||||
Dma.SPI2_TX.2.RequestNumber=1
|
||||
Dma.SPI2_TX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
|
||||
Dma.SPI2_TX.2.SignalID=NONE
|
||||
Dma.SPI2_TX.2.SyncEnable=DISABLE
|
||||
Dma.SPI2_TX.2.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
|
||||
Dma.SPI2_TX.2.SyncRequestNumber=1
|
||||
Dma.SPI2_TX.2.SyncSignalID=NONE
|
||||
Dma.UART5_RX.3.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.UART5_RX.3.EventEnable=DISABLE
|
||||
Dma.UART5_RX.3.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.UART5_RX.3.Instance=DMA1_Stream3
|
||||
Dma.UART5_RX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.UART5_RX.3.MemInc=DMA_MINC_ENABLE
|
||||
Dma.UART5_RX.3.Mode=DMA_NORMAL
|
||||
Dma.UART5_RX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.UART5_RX.3.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.UART5_RX.3.Polarity=HAL_DMAMUX_REQ_GEN_RISING
|
||||
Dma.UART5_RX.3.Priority=DMA_PRIORITY_LOW
|
||||
Dma.UART5_RX.3.RequestNumber=1
|
||||
Dma.UART5_RX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode,SignalID,Polarity,RequestNumber,SyncSignalID,SyncPolarity,SyncEnable,EventEnable,SyncRequestNumber
|
||||
Dma.UART5_RX.3.SignalID=NONE
|
||||
Dma.UART5_RX.3.SyncEnable=DISABLE
|
||||
Dma.UART5_RX.3.SyncPolarity=HAL_DMAMUX_SYNC_NO_EVENT
|
||||
Dma.UART5_RX.3.SyncRequestNumber=1
|
||||
Dma.UART5_RX.3.SyncSignalID=NONE
|
||||
FDCAN1.AutoRetransmission=ENABLE
|
||||
FDCAN1.CalculateBaudRateNominal=1000000
|
||||
FDCAN1.CalculateTimeBitNominal=1000
|
||||
FDCAN1.CalculateTimeQuantumNominal=200.0
|
||||
FDCAN1.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,RxFifo0ElmtsNbr,TxFifoQueueElmtsNbr,NominalPrescaler,StdFiltersNbr,NominalTimeSeg1,AutoRetransmission
|
||||
FDCAN1.NominalPrescaler=24
|
||||
FDCAN1.NominalTimeSeg1=3
|
||||
FDCAN1.RxFifo0ElmtsNbr=32
|
||||
FDCAN1.StdFiltersNbr=1
|
||||
FDCAN1.TxFifoQueueElmtsNbr=32
|
||||
FDCAN2.AutoRetransmission=ENABLE
|
||||
FDCAN2.CalculateBaudRateNominal=1000000
|
||||
FDCAN2.CalculateTimeBitNominal=1000
|
||||
FDCAN2.CalculateTimeQuantumNominal=200.0
|
||||
FDCAN2.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,MessageRAMOffset,RxFifo0ElmtsNbr,TxFifoQueueElmtsNbr,NominalPrescaler,StdFiltersNbr,NominalTimeSeg1,AutoRetransmission,RxFifo1ElmtsNbr
|
||||
FDCAN2.MessageRAMOffset=0x406
|
||||
FDCAN2.NominalPrescaler=24
|
||||
FDCAN2.NominalTimeSeg1=3
|
||||
FDCAN2.RxFifo0ElmtsNbr=32
|
||||
FDCAN2.RxFifo1ElmtsNbr=32
|
||||
FDCAN2.StdFiltersNbr=1
|
||||
FDCAN2.TxFifoQueueElmtsNbr=32
|
||||
FDCAN3.AutoRetransmission=ENABLE
|
||||
FDCAN3.CalculateBaudRateNominal=1000000
|
||||
FDCAN3.CalculateTimeBitNominal=1000
|
||||
FDCAN3.CalculateTimeQuantumNominal=200.0
|
||||
FDCAN3.ExtFiltersNbr=1
|
||||
FDCAN3.IPParameters=CalculateTimeQuantumNominal,CalculateTimeBitNominal,CalculateBaudRateNominal,MessageRAMOffset,RxFifo0ElmtsNbr,TxFifoQueueElmtsNbr,NominalPrescaler,StdFiltersNbr,NominalTimeSeg1,AutoRetransmission,RxFifo1ElmtsNbr,ExtFiltersNbr
|
||||
FDCAN3.MessageRAMOffset=0x812
|
||||
FDCAN3.NominalPrescaler=24
|
||||
FDCAN3.NominalTimeSeg1=3
|
||||
FDCAN3.RxFifo0ElmtsNbr=32
|
||||
FDCAN3.RxFifo1ElmtsNbr=32
|
||||
FDCAN3.StdFiltersNbr=1
|
||||
FDCAN3.TxFifoQueueElmtsNbr=32
|
||||
FREERTOS.IPParameters=Tasks01,configTOTAL_HEAP_SIZE
|
||||
FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.configTOTAL_HEAP_SIZE=0x10000
|
||||
File.Version=6
|
||||
GPIO.groupedBy=Group By Peripherals
|
||||
KeepUserPlacement=false
|
||||
MMTAppRegionsCount=0
|
||||
MMTConfigApplied=false
|
||||
Mcu.CPN=STM32H723VGT6
|
||||
Mcu.Family=STM32H7
|
||||
Mcu.IP0=ADC1
|
||||
Mcu.IP1=CORTEX_M7
|
||||
Mcu.IP10=OCTOSPI1
|
||||
Mcu.IP11=RCC
|
||||
Mcu.IP12=SPI1
|
||||
Mcu.IP13=SPI2
|
||||
Mcu.IP14=SYS
|
||||
Mcu.IP15=TIM1
|
||||
Mcu.IP16=TIM2
|
||||
Mcu.IP17=TIM3
|
||||
Mcu.IP18=TIM12
|
||||
Mcu.IP19=UART5
|
||||
Mcu.IP2=DEBUG
|
||||
Mcu.IP20=UART7
|
||||
Mcu.IP21=USART1
|
||||
Mcu.IP22=USART2
|
||||
Mcu.IP23=USART3
|
||||
Mcu.IP24=USART10
|
||||
Mcu.IP25=USB_OTG_HS
|
||||
Mcu.IP3=DMA
|
||||
Mcu.IP4=FDCAN1
|
||||
Mcu.IP5=FDCAN2
|
||||
Mcu.IP6=FDCAN3
|
||||
Mcu.IP7=FREERTOS
|
||||
Mcu.IP8=MEMORYMAP
|
||||
Mcu.IP9=NVIC
|
||||
Mcu.IPNb=26
|
||||
Mcu.Name=STM32H723VGTx
|
||||
Mcu.Package=LQFP100
|
||||
Mcu.Pin0=PE2
|
||||
Mcu.Pin1=PE3
|
||||
Mcu.Pin10=PC3_C
|
||||
Mcu.Pin11=PA0
|
||||
Mcu.Pin12=PA1
|
||||
Mcu.Pin13=PA2
|
||||
Mcu.Pin14=PA3
|
||||
Mcu.Pin15=PA5
|
||||
Mcu.Pin16=PA7
|
||||
Mcu.Pin17=PC4
|
||||
Mcu.Pin18=PC5
|
||||
Mcu.Pin19=PB0
|
||||
Mcu.Pin2=PC13
|
||||
Mcu.Pin20=PB1
|
||||
Mcu.Pin21=PB2
|
||||
Mcu.Pin22=PE7
|
||||
Mcu.Pin23=PE8
|
||||
Mcu.Pin24=PE9
|
||||
Mcu.Pin25=PE10
|
||||
Mcu.Pin26=PE11
|
||||
Mcu.Pin27=PE12
|
||||
Mcu.Pin28=PE13
|
||||
Mcu.Pin29=PE15
|
||||
Mcu.Pin3=PC14-OSC32_IN
|
||||
Mcu.Pin30=PB10
|
||||
Mcu.Pin31=PB11
|
||||
Mcu.Pin32=PB12
|
||||
Mcu.Pin33=PB13
|
||||
Mcu.Pin34=PB14
|
||||
Mcu.Pin35=PB15
|
||||
Mcu.Pin36=PD8
|
||||
Mcu.Pin37=PD9
|
||||
Mcu.Pin38=PD10
|
||||
Mcu.Pin39=PD11
|
||||
Mcu.Pin4=PC15-OSC32_OUT
|
||||
Mcu.Pin40=PD12
|
||||
Mcu.Pin41=PD13
|
||||
Mcu.Pin42=PA8
|
||||
Mcu.Pin43=PA9
|
||||
Mcu.Pin44=PA10
|
||||
Mcu.Pin45=PA11
|
||||
Mcu.Pin46=PA12
|
||||
Mcu.Pin47=PA13(JTMS/SWDIO)
|
||||
Mcu.Pin48=PA14(JTCK/SWCLK)
|
||||
Mcu.Pin49=PA15(JTDI)
|
||||
Mcu.Pin5=PH0-OSC_IN
|
||||
Mcu.Pin50=PC12
|
||||
Mcu.Pin51=PD0
|
||||
Mcu.Pin52=PD1
|
||||
Mcu.Pin53=PD2
|
||||
Mcu.Pin54=PD4
|
||||
Mcu.Pin55=PD5
|
||||
Mcu.Pin56=PD6
|
||||
Mcu.Pin57=PD7
|
||||
Mcu.Pin58=PB3(JTDO/TRACESWO)
|
||||
Mcu.Pin59=PB5
|
||||
Mcu.Pin6=PH1-OSC_OUT
|
||||
Mcu.Pin60=PB6
|
||||
Mcu.Pin61=VP_FREERTOS_VS_CMSIS_V2
|
||||
Mcu.Pin62=VP_OCTOSPI1_VS_octo
|
||||
Mcu.Pin63=VP_SYS_VS_tim23
|
||||
Mcu.Pin64=VP_MEMORYMAP_VS_MEMORYMAP
|
||||
Mcu.Pin7=PC0
|
||||
Mcu.Pin8=PC1
|
||||
Mcu.Pin9=PC2_C
|
||||
Mcu.PinsNb=65
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=
|
||||
Mcu.UserName=STM32H723VGTx
|
||||
MxCube.Version=6.15.0
|
||||
MxDb.Version=DB.6.0.150
|
||||
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.DMA1_Stream0_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA1_Stream1_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA1_Stream3_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.EXTI15_10_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.FDCAN1_IT0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.FDCAN1_IT1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.FDCAN2_IT0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.FDCAN2_IT1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.FDCAN3_IT0_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.FDCAN3_IT1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.ForceEnableDMAVector=true
|
||||
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:false\:false
|
||||
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||
NVIC.SPI2_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false\:false
|
||||
NVIC.SavedPendsvIrqHandlerGenerated=true
|
||||
NVIC.SavedSvcallIrqHandlerGenerated=true
|
||||
NVIC.SavedSystickIrqHandlerGenerated=true
|
||||
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:true\:false
|
||||
NVIC.TIM23_IRQn=true\:15\:0\:false\:false\:true\:false\:false\:true\:true
|
||||
NVIC.TimeBase=TIM23_IRQn
|
||||
NVIC.TimeBaseIP=TIM23
|
||||
NVIC.UART5_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.UART7_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.USART10_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.USART1_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.USART2_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.USART3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
PA0.Locked=true
|
||||
PA0.Signal=S_TIM2_CH1_ETR
|
||||
PA1.Locked=true
|
||||
PA1.Mode=OCTOSPI1_IOL_Port1L
|
||||
PA1.Signal=OCTOSPIM_P1_IO3
|
||||
PA10.Locked=true
|
||||
PA10.Mode=Asynchronous
|
||||
PA10.Signal=USART1_RX
|
||||
PA11.Mode=Device_Only_FS
|
||||
PA11.Signal=USB_OTG_HS_DM
|
||||
PA12.Mode=Device_Only_FS
|
||||
PA12.Signal=USB_OTG_HS_DP
|
||||
PA13(JTMS/SWDIO).Locked=true
|
||||
PA13(JTMS/SWDIO).Mode=Serial_Wire
|
||||
PA13(JTMS/SWDIO).Signal=DEBUG_JTMS-SWDIO
|
||||
PA14(JTCK/SWCLK).Locked=true
|
||||
PA14(JTCK/SWCLK).Mode=Serial_Wire
|
||||
PA14(JTCK/SWCLK).Signal=DEBUG_JTCK-SWCLK
|
||||
PA15(JTDI).Locked=true
|
||||
PA15(JTDI).Signal=GPIO_Input
|
||||
PA2.Locked=true
|
||||
PA2.Signal=S_TIM2_CH3
|
||||
PA3.Locked=true
|
||||
PA3.Mode=OCTOSPI1_IOL_Port1L
|
||||
PA3.Signal=OCTOSPIM_P1_IO2
|
||||
PA5.Locked=true
|
||||
PA5.Signal=ADCx_INP19
|
||||
PA7.GPIOParameters=GPIO_Label
|
||||
PA7.GPIO_Label=WS2812
|
||||
PA7.Locked=true
|
||||
PA7.Signal=S_TIM3_CH2
|
||||
PA8.Locked=true
|
||||
PA8.Mode=Clock-out-1
|
||||
PA8.Signal=RCC_MCO_1
|
||||
PA9.Locked=true
|
||||
PA9.Mode=Asynchronous
|
||||
PA9.Signal=USART1_TX
|
||||
PB0.Locked=true
|
||||
PB0.Mode=OCTOSPI1_IOL_Port1L
|
||||
PB0.Signal=OCTOSPIM_P1_IO1
|
||||
PB1.GPIOParameters=GPIO_Label
|
||||
PB1.GPIO_Label=IMU_HEAT
|
||||
PB1.Locked=true
|
||||
PB1.Signal=S_TIM3_CH4
|
||||
PB10.GPIOParameters=GPIO_Label
|
||||
PB10.GPIO_Label=LCD_BLK
|
||||
PB10.Locked=true
|
||||
PB10.Signal=GPIO_Output
|
||||
PB11.GPIOParameters=GPIO_Label
|
||||
PB11.GPIO_Label=LCD_RES
|
||||
PB11.Locked=true
|
||||
PB11.Signal=GPIO_Output
|
||||
PB12.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
||||
PB12.GPIO_Label=DCMI_REST
|
||||
PB12.GPIO_PuPd=GPIO_PULLUP
|
||||
PB12.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PB12.Locked=true
|
||||
PB12.PinState=GPIO_PIN_SET
|
||||
PB12.Signal=GPIO_Output
|
||||
PB13.GPIOParameters=GPIO_Speed
|
||||
PB13.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PB13.Locked=true
|
||||
PB13.Mode=Full_Duplex_Master
|
||||
PB13.Signal=SPI2_SCK
|
||||
PB14.Mode=Hardware Flow Control (RS485)
|
||||
PB14.Signal=USART3_DE
|
||||
PB15.GPIOParameters=GPIO_Label
|
||||
PB15.GPIO_Label=BUZZER
|
||||
PB15.Locked=true
|
||||
PB15.Signal=S_TIM12_CH2
|
||||
PB2.Locked=true
|
||||
PB2.Mode=O1_P1_CLK
|
||||
PB2.Signal=OCTOSPIM_P1_CLK
|
||||
PB3(JTDO/TRACESWO).GPIOParameters=GPIO_Speed
|
||||
PB3(JTDO/TRACESWO).GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PB3(JTDO/TRACESWO).Mode=TX_Only_Simplex_Unidirect_Master
|
||||
PB3(JTDO/TRACESWO).Signal=SPI1_SCK
|
||||
PB5.Locked=true
|
||||
PB5.Mode=FDCAN_Activate
|
||||
PB5.Signal=FDCAN2_RX
|
||||
PB6.Locked=true
|
||||
PB6.Mode=FDCAN_Activate
|
||||
PB6.Signal=FDCAN2_TX
|
||||
PC0.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
|
||||
PC0.GPIO_Label=ACCL_CS
|
||||
PC0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PC0.Locked=true
|
||||
PC0.PinState=GPIO_PIN_SET
|
||||
PC0.Signal=GPIO_Output
|
||||
PC1.GPIOParameters=GPIO_Speed
|
||||
PC1.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PC1.Mode=Full_Duplex_Master
|
||||
PC1.Signal=SPI2_MOSI
|
||||
PC12.Mode=Asynchronous
|
||||
PC12.Signal=UART5_TX
|
||||
PC13.GPIOParameters=PinState,GPIO_Label
|
||||
PC13.GPIO_Label=POWER_24V_2
|
||||
PC13.Locked=true
|
||||
PC13.PinState=GPIO_PIN_SET
|
||||
PC13.Signal=GPIO_Output
|
||||
PC14-OSC32_IN.GPIOParameters=PinState,GPIO_Label
|
||||
PC14-OSC32_IN.GPIO_Label=POWER_24V_1
|
||||
PC14-OSC32_IN.Locked=true
|
||||
PC14-OSC32_IN.PinState=GPIO_PIN_SET
|
||||
PC14-OSC32_IN.Signal=GPIO_Output
|
||||
PC15-OSC32_OUT.GPIOParameters=PinState,GPIO_Label
|
||||
PC15-OSC32_OUT.GPIO_Label=POWER_5V
|
||||
PC15-OSC32_OUT.Locked=true
|
||||
PC15-OSC32_OUT.PinState=GPIO_PIN_SET
|
||||
PC15-OSC32_OUT.Signal=GPIO_Output
|
||||
PC2_C.GPIOParameters=GPIO_Speed
|
||||
PC2_C.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PC2_C.Mode=Full_Duplex_Master
|
||||
PC2_C.Signal=SPI2_MISO
|
||||
PC3_C.GPIOParameters=GPIO_Speed,PinState,GPIO_Label
|
||||
PC3_C.GPIO_Label=GYRO_CS
|
||||
PC3_C.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PC3_C.Locked=true
|
||||
PC3_C.PinState=GPIO_PIN_SET
|
||||
PC3_C.Signal=GPIO_Output
|
||||
PC4.Locked=true
|
||||
PC4.Signal=ADCx_INP4
|
||||
PC5.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
||||
PC5.GPIO_Label=DCMI_PWDN
|
||||
PC5.GPIO_PuPd=GPIO_NOPULL
|
||||
PC5.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PC5.Locked=true
|
||||
PC5.PinState=GPIO_PIN_SET
|
||||
PC5.Signal=GPIO_Output
|
||||
PD0.Mode=FDCAN_Activate
|
||||
PD0.Signal=FDCAN1_RX
|
||||
PD1.Locked=true
|
||||
PD1.Mode=FDCAN_Activate
|
||||
PD1.Signal=FDCAN1_TX
|
||||
PD10.GPIOParameters=GPIO_Label
|
||||
PD10.GPIO_Label=LCD_DC
|
||||
PD10.Locked=true
|
||||
PD10.Signal=GPIO_Output
|
||||
PD11.Locked=true
|
||||
PD11.Mode=OCTOSPI1_IOL_Port1L
|
||||
PD11.Signal=OCTOSPIM_P1_IO0
|
||||
PD12.Mode=FDCAN_Activate
|
||||
PD12.Signal=FDCAN3_RX
|
||||
PD13.Locked=true
|
||||
PD13.Mode=FDCAN_Activate
|
||||
PD13.Signal=FDCAN3_TX
|
||||
PD2.Mode=Asynchronous
|
||||
PD2.Signal=UART5_RX
|
||||
PD4.Locked=true
|
||||
PD4.Mode=Hardware Flow Control (RS485)
|
||||
PD4.Signal=USART2_DE
|
||||
PD5.Locked=true
|
||||
PD5.Mode=Asynchronous
|
||||
PD5.Signal=USART2_TX
|
||||
PD6.Locked=true
|
||||
PD6.Mode=Asynchronous
|
||||
PD6.Signal=USART2_RX
|
||||
PD7.GPIOParameters=GPIO_Speed
|
||||
PD7.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PD7.Locked=true
|
||||
PD7.Mode=TX_Only_Simplex_Unidirect_Master
|
||||
PD7.Signal=SPI1_MOSI
|
||||
PD8.Mode=Asynchronous
|
||||
PD8.Signal=USART3_TX
|
||||
PD9.Mode=Asynchronous
|
||||
PD9.Signal=USART3_RX
|
||||
PE10.GPIOParameters=GPIO_Label
|
||||
PE10.GPIO_Label=ACCL_INT
|
||||
PE10.Locked=true
|
||||
PE10.Signal=GPXTI10
|
||||
PE11.Locked=true
|
||||
PE11.Mode=OCTOSPI1_Port1_NCS
|
||||
PE11.Signal=OCTOSPIM_P1_NCS
|
||||
PE12.GPIOParameters=GPIO_Label
|
||||
PE12.GPIO_Label=GYRO_INT
|
||||
PE12.Locked=true
|
||||
PE12.Signal=GPXTI12
|
||||
PE13.Signal=S_TIM1_CH3
|
||||
PE15.GPIOParameters=GPIO_Label
|
||||
PE15.GPIO_Label=LCD_CS
|
||||
PE15.Locked=true
|
||||
PE15.Signal=GPIO_Output
|
||||
PE2.Mode=Asynchronous
|
||||
PE2.Signal=USART10_RX
|
||||
PE3.Mode=Asynchronous
|
||||
PE3.Signal=USART10_TX
|
||||
PE7.Mode=Asynchronous
|
||||
PE7.Signal=UART7_RX
|
||||
PE8.Mode=Asynchronous
|
||||
PE8.Signal=UART7_TX
|
||||
PE9.Locked=true
|
||||
PE9.Signal=S_TIM1_CH1
|
||||
PH0-OSC_IN.Mode=HSE-External-Oscillator
|
||||
PH0-OSC_IN.Signal=RCC_OSC_IN
|
||||
PH1-OSC_OUT.Mode=HSE-External-Oscillator
|
||||
PH1-OSC_OUT.Signal=RCC_OSC_OUT
|
||||
PinOutPanel.RotationAngle=0
|
||||
ProjectManager.AskForMigrate=true
|
||||
ProjectManager.BackupPrevious=false
|
||||
ProjectManager.CompilerLinker=GCC
|
||||
ProjectManager.CompilerOptimize=6
|
||||
ProjectManager.ComputerToolchain=false
|
||||
ProjectManager.CoupleFile=true
|
||||
ProjectManager.CustomerFirmwarePackage=
|
||||
ProjectManager.DefaultFWLocation=true
|
||||
ProjectManager.DeletePrevious=true
|
||||
ProjectManager.DeviceId=STM32H723VGTx
|
||||
ProjectManager.FirmwarePackage=STM32Cube FW_H7 V1.12.1
|
||||
ProjectManager.FreePins=false
|
||||
ProjectManager.HalAssertFull=false
|
||||
ProjectManager.HeapSize=0x1000
|
||||
ProjectManager.KeepUserCode=true
|
||||
ProjectManager.LastFirmware=true
|
||||
ProjectManager.LibraryCopy=0
|
||||
ProjectManager.MainLocation=Core/Src
|
||||
ProjectManager.NoMain=false
|
||||
ProjectManager.PreviousToolchain=
|
||||
ProjectManager.ProjectBuild=false
|
||||
ProjectManager.ProjectFileName=CtrBoard-H7_ALL.ioc
|
||||
ProjectManager.ProjectName=CtrBoard-H7_ALL
|
||||
ProjectManager.ProjectStructure=
|
||||
ProjectManager.RegisterCallBack=
|
||||
ProjectManager.StackSize=0x2000
|
||||
ProjectManager.TargetToolchain=MDK-ARM V5.32
|
||||
ProjectManager.ToolChainLocation=
|
||||
ProjectManager.UAScriptAfterPath=
|
||||
ProjectManager.UAScriptBeforePath=
|
||||
ProjectManager.UnderRoot=false
|
||||
ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_ADC1_Init-ADC1-false-HAL-true,5-MX_TIM12_Init-TIM12-false-HAL-true,6-MX_SPI1_Init-SPI1-false-HAL-true,7-MX_SPI2_Init-SPI2-false-HAL-true,8-MX_TIM3_Init-TIM3-false-HAL-true,9-MX_USART1_UART_Init-USART1-false-HAL-true,10-MX_USART2_UART_Init-USART2-false-HAL-true,11-MX_USART3_UART_Init-USART3-false-HAL-true,12-MX_UART7_Init-UART7-false-HAL-true,13-MX_USART10_UART_Init-USART10-false-HAL-true,14-MX_FDCAN1_Init-FDCAN1-false-HAL-true,15-MX_FDCAN2_Init-FDCAN2-false-HAL-true,16-MX_FDCAN3_Init-FDCAN3-false-HAL-true,17-MX_TIM1_Init-TIM1-false-HAL-true,18-MX_TIM2_Init-TIM2-false-HAL-true,19-MX_OCTOSPI1_Init-OCTOSPI1-false-HAL-true,20-MX_USB_OTG_HS_PCD_Init-USB_OTG_HS-false-HAL-true,21-MX_UART5_Init-UART5-false-HAL-true,0-MX_CORTEX_M7_Init-CORTEX_M7-false-HAL-true
|
||||
RCC.ADCFreq_Value=96000000
|
||||
RCC.AHB12Freq_Value=240000000
|
||||
RCC.AHB4Freq_Value=240000000
|
||||
RCC.APB1Freq_Value=120000000
|
||||
RCC.APB2Freq_Value=120000000
|
||||
RCC.APB3Freq_Value=120000000
|
||||
RCC.APB4Freq_Value=120000000
|
||||
RCC.AXIClockFreq_Value=240000000
|
||||
RCC.CECFreq_Value=32000
|
||||
RCC.CKPERFreq_Value=64000000
|
||||
RCC.CortexFreq_Value=480000000
|
||||
RCC.CpuClockFreq_Value=480000000
|
||||
RCC.D1CPREFreq_Value=480000000
|
||||
RCC.D1PPRE=RCC_APB3_DIV2
|
||||
RCC.D2PPRE1=RCC_APB1_DIV2
|
||||
RCC.D2PPRE2=RCC_APB2_DIV2
|
||||
RCC.D3PPRE=RCC_APB4_DIV2
|
||||
RCC.DFSDMACLkFreq_Value=120000000
|
||||
RCC.DFSDMFreq_Value=120000000
|
||||
RCC.DIVM1=2
|
||||
RCC.DIVM2=2
|
||||
RCC.DIVN1=40
|
||||
RCC.DIVN2=16
|
||||
RCC.DIVP1=1
|
||||
RCC.DIVP1Freq_Value=480000000
|
||||
RCC.DIVP2Freq_Value=96000000
|
||||
RCC.DIVP3Freq_Value=48375000
|
||||
RCC.DIVQ1=4
|
||||
RCC.DIVQ1Freq_Value=120000000
|
||||
RCC.DIVQ2Freq_Value=96000000
|
||||
RCC.DIVQ3Freq_Value=48375000
|
||||
RCC.DIVR1Freq_Value=240000000
|
||||
RCC.DIVR2Freq_Value=96000000
|
||||
RCC.DIVR3Freq_Value=48375000
|
||||
RCC.EnbaleCSS=false
|
||||
RCC.FDCANFreq_Value=120000000
|
||||
RCC.FMCFreq_Value=240000000
|
||||
RCC.FamilyName=M
|
||||
RCC.HCLK3ClockFreq_Value=240000000
|
||||
RCC.HCLKFreq_Value=240000000
|
||||
RCC.HPRE=RCC_HCLK_DIV2
|
||||
RCC.HSE_VALUE=24000000
|
||||
RCC.I2C123Freq_Value=120000000
|
||||
RCC.I2C4Freq_Value=120000000
|
||||
RCC.IPParameters=ADCFreq_Value,AHB12Freq_Value,AHB4Freq_Value,APB1Freq_Value,APB2Freq_Value,APB3Freq_Value,APB4Freq_Value,AXIClockFreq_Value,CECFreq_Value,CKPERFreq_Value,CortexFreq_Value,CpuClockFreq_Value,D1CPREFreq_Value,D1PPRE,D2PPRE1,D2PPRE2,D3PPRE,DFSDMACLkFreq_Value,DFSDMFreq_Value,DIVM1,DIVM2,DIVN1,DIVN2,DIVP1,DIVP1Freq_Value,DIVP2Freq_Value,DIVP3Freq_Value,DIVQ1,DIVQ1Freq_Value,DIVQ2Freq_Value,DIVQ3Freq_Value,DIVR1Freq_Value,DIVR2Freq_Value,DIVR3Freq_Value,EnbaleCSS,FDCANFreq_Value,FMCFreq_Value,FamilyName,HCLK3ClockFreq_Value,HCLKFreq_Value,HPRE,HSE_VALUE,I2C123Freq_Value,I2C4Freq_Value,LPTIM1Freq_Value,LPTIM2Freq_Value,LPTIM345Freq_Value,LPUART1Freq_Value,LTDCFreq_Value,MCO1PinFreq_Value,MCO2PinFreq_Value,PLL2FRACN,PLL2_VCI_Range-AdvancedSettings,PLL2_VCO_SEL-AdvancedSettings,PLL3FRACN,PLL3_VCO_SEL-AdvancedSettings,PLLFRACN,PLLSourceVirtual,QSPIFreq_Value,RNGFreq_Value,RTCFreq_Value,SAI1Freq_Value,SAI4AFreq_Value,SAI4BFreq_Value,SDMMCFreq_Value,SPDIFRXFreq_Value,SPI123Freq_Value,SPI45Freq_Value,SPI6CLockSelection,SPI6Freq_Value,SWPMI1Freq_Value,SYSCLKFreq_VALUE,SYSCLKSource,Tim1OutputFreq_Value,Tim2OutputFreq_Value,TraceFreq_Value,USART16Freq_Value,USART234578Freq_Value,USBCLockSelection,USBFreq_Value,VCO1OutputFreq_Value,VCO2OutputFreq_Value,VCO3OutputFreq_Value,VCOInput1Freq_Value,VCOInput2Freq_Value,VCOInput3Freq_Value
|
||||
RCC.LPTIM1Freq_Value=120000000
|
||||
RCC.LPTIM2Freq_Value=120000000
|
||||
RCC.LPTIM345Freq_Value=120000000
|
||||
RCC.LPUART1Freq_Value=120000000
|
||||
RCC.LTDCFreq_Value=48375000
|
||||
RCC.MCO1PinFreq_Value=64000000
|
||||
RCC.MCO2PinFreq_Value=480000000
|
||||
RCC.PLL2FRACN=0
|
||||
RCC.PLL2_VCI_Range-AdvancedSettings=RCC_PLL2VCIRANGE_0
|
||||
RCC.PLL2_VCO_SEL-AdvancedSettings=RCC_PLL2VCOWIDE
|
||||
RCC.PLL3FRACN=0
|
||||
RCC.PLL3_VCO_SEL-AdvancedSettings=RCC_PLL3VCOMEDIUM
|
||||
RCC.PLLFRACN=0
|
||||
RCC.PLLSourceVirtual=RCC_PLLSOURCE_HSE
|
||||
RCC.QSPIFreq_Value=240000000
|
||||
RCC.RNGFreq_Value=48000000
|
||||
RCC.RTCFreq_Value=32000
|
||||
RCC.SAI1Freq_Value=120000000
|
||||
RCC.SAI4AFreq_Value=120000000
|
||||
RCC.SAI4BFreq_Value=120000000
|
||||
RCC.SDMMCFreq_Value=120000000
|
||||
RCC.SPDIFRXFreq_Value=120000000
|
||||
RCC.SPI123Freq_Value=120000000
|
||||
RCC.SPI45Freq_Value=120000000
|
||||
RCC.SPI6CLockSelection=RCC_SPI6CLKSOURCE_HSE
|
||||
RCC.SPI6Freq_Value=24000000
|
||||
RCC.SWPMI1Freq_Value=120000000
|
||||
RCC.SYSCLKFreq_VALUE=480000000
|
||||
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
|
||||
RCC.Tim1OutputFreq_Value=240000000
|
||||
RCC.Tim2OutputFreq_Value=240000000
|
||||
RCC.TraceFreq_Value=240000000
|
||||
RCC.USART16Freq_Value=120000000
|
||||
RCC.USART234578Freq_Value=120000000
|
||||
RCC.USBCLockSelection=RCC_USBCLKSOURCE_HSI48
|
||||
RCC.USBFreq_Value=48000000
|
||||
RCC.VCO1OutputFreq_Value=480000000
|
||||
RCC.VCO2OutputFreq_Value=192000000
|
||||
RCC.VCO3OutputFreq_Value=96750000
|
||||
RCC.VCOInput1Freq_Value=12000000
|
||||
RCC.VCOInput2Freq_Value=12000000
|
||||
RCC.VCOInput3Freq_Value=750000
|
||||
SH.ADCx_INP19.0=ADC1_INP19,IN19-Single-Ended
|
||||
SH.ADCx_INP19.ConfNb=1
|
||||
SH.ADCx_INP4.0=ADC1_INP4,IN4-Single-Ended
|
||||
SH.ADCx_INP4.ConfNb=1
|
||||
SH.GPXTI10.0=GPIO_EXTI10
|
||||
SH.GPXTI10.ConfNb=1
|
||||
SH.GPXTI12.0=GPIO_EXTI12
|
||||
SH.GPXTI12.ConfNb=1
|
||||
SH.S_TIM12_CH2.0=TIM12_CH2,PWM Generation2 CH2
|
||||
SH.S_TIM12_CH2.ConfNb=1
|
||||
SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1
|
||||
SH.S_TIM1_CH1.ConfNb=1
|
||||
SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM1_CH3.ConfNb=1
|
||||
SH.S_TIM2_CH1_ETR.0=TIM2_CH1,PWM Generation1 CH1
|
||||
SH.S_TIM2_CH1_ETR.ConfNb=1
|
||||
SH.S_TIM2_CH3.0=TIM2_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM2_CH3.ConfNb=1
|
||||
SH.S_TIM3_CH2.0=TIM3_CH2,PWM Generation2 CH2
|
||||
SH.S_TIM3_CH2.ConfNb=1
|
||||
SH.S_TIM3_CH4.0=TIM3_CH4,PWM Generation4 CH4
|
||||
SH.S_TIM3_CH4.ConfNb=1
|
||||
SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_4
|
||||
SPI1.CLKPolarity=SPI_POLARITY_HIGH
|
||||
SPI1.CalculateBaudRate=30.0 MBits/s
|
||||
SPI1.DataSize=SPI_DATASIZE_8BIT
|
||||
SPI1.Direction=SPI_DIRECTION_2LINES_TXONLY
|
||||
SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler,CLKPolarity
|
||||
SPI1.Mode=SPI_MODE_MASTER
|
||||
SPI1.VirtualType=VM_MASTER
|
||||
SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_32
|
||||
SPI2.CLKPhase=SPI_PHASE_2EDGE
|
||||
SPI2.CLKPolarity=SPI_POLARITY_HIGH
|
||||
SPI2.CalculateBaudRate=3.75 MBits/s
|
||||
SPI2.DataSize=SPI_DATASIZE_8BIT
|
||||
SPI2.Direction=SPI_DIRECTION_2LINES
|
||||
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,DataSize,BaudRatePrescaler,CLKPolarity,CLKPhase
|
||||
SPI2.Mode=SPI_MODE_MASTER
|
||||
SPI2.VirtualType=VM_MASTER
|
||||
TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
|
||||
TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM1.IPParameters=Channel-PWM Generation3 CH3,Channel-PWM Generation1 CH1,Period,Pulse-PWM Generation1 CH1,Pulse-PWM Generation3 CH3,Prescaler
|
||||
TIM1.Period=10000
|
||||
TIM1.Prescaler=24
|
||||
TIM1.Pulse-PWM\ Generation1\ CH1=5000
|
||||
TIM1.Pulse-PWM\ Generation3\ CH3=5000
|
||||
TIM12.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
|
||||
TIM12.IPParameters=Channel-PWM Generation2 CH2,Prescaler,Period
|
||||
TIM12.Period=2000-1
|
||||
TIM12.Prescaler=24-1
|
||||
TIM2.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
|
||||
TIM2.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM2.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation3 CH3,Period,Pulse-PWM Generation1 CH1,Pulse-PWM Generation3 CH3,Prescaler
|
||||
TIM2.Period=10000
|
||||
TIM2.Prescaler=24
|
||||
TIM2.Pulse-PWM\ Generation1\ CH1=5000
|
||||
TIM2.Pulse-PWM\ Generation3\ CH3=5000
|
||||
TIM3.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_ENABLE
|
||||
TIM3.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
|
||||
TIM3.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
|
||||
TIM3.IPParameters=Channel-PWM Generation4 CH4,Prescaler,Period,AutoReloadPreload,Channel-PWM Generation2 CH2
|
||||
TIM3.Period=10000-1
|
||||
TIM3.Prescaler=24-1
|
||||
UART5.BaudRate=100000
|
||||
UART5.IPParameters=Mode,WordLength,Parity,BaudRate
|
||||
UART5.Mode=MODE_RX
|
||||
UART5.Parity=PARITY_EVEN
|
||||
UART5.WordLength=WORDLENGTH_9B
|
||||
UART7.BaudRate=921600
|
||||
UART7.IPParameters=BaudRate
|
||||
USART1.BaudRate=921600
|
||||
USART1.IPParameters=VirtualMode-Asynchronous,BaudRate
|
||||
USART1.VirtualMode-Asynchronous=VM_ASYNC
|
||||
USART10.BaudRate=921600
|
||||
USART10.IPParameters=VirtualMode,BaudRate
|
||||
USART10.VirtualMode=VM_ASYNC
|
||||
USART2.BaudRate=921600
|
||||
USART2.IPParameters=VirtualMode-Asynchronous,VirtualMode-Hardware Flow Control (RS485),BaudRate
|
||||
USART2.VirtualMode-Asynchronous=VM_ASYNC
|
||||
USART2.VirtualMode-Hardware\ Flow\ Control\ (RS485)=VM_ASYNC
|
||||
USART3.BaudRate=921600
|
||||
USART3.IPParameters=VirtualMode-Asynchronous,VirtualMode-Hardware Flow Control (RS485),BaudRate
|
||||
USART3.VirtualMode-Asynchronous=VM_ASYNC
|
||||
USART3.VirtualMode-Hardware\ Flow\ Control\ (RS485)=VM_ASYNC
|
||||
USB_OTG_HS.IPParameters=VirtualMode-Device_Only_FS
|
||||
USB_OTG_HS.VirtualMode-Device_Only_FS=Device_Only_FS
|
||||
VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2
|
||||
VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2
|
||||
VP_MEMORYMAP_VS_MEMORYMAP.Mode=CurAppReg
|
||||
VP_MEMORYMAP_VS_MEMORYMAP.Signal=MEMORYMAP_VS_MEMORYMAP
|
||||
VP_OCTOSPI1_VS_octo.Mode=octo_mode
|
||||
VP_OCTOSPI1_VS_octo.Signal=OCTOSPI1_VS_octo
|
||||
VP_SYS_VS_tim23.Mode=TIM23
|
||||
VP_SYS_VS_tim23.Signal=SYS_VS_tim23
|
||||
board=custom
|
||||
rtos.0.ip=FREERTOS
|
||||
743
assets/User_code/ioc/DevC.ioc
Normal file
743
assets/User_code/ioc/DevC.ioc
Normal file
@ -0,0 +1,743 @@
|
||||
#MicroXplorer Configuration settings - do not modify
|
||||
ADC1.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_TEMPSENSOR
|
||||
ADC1.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV6
|
||||
ADC1.IPParameters=Rank-0\#ChannelRegularConversion,master,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler
|
||||
ADC1.NbrOfConversionFlag=1
|
||||
ADC1.Rank-0\#ChannelRegularConversion=1
|
||||
ADC1.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES
|
||||
ADC1.master=1
|
||||
ADC3.Channel-0\#ChannelRegularConversion=ADC_CHANNEL_8
|
||||
ADC3.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV6
|
||||
ADC3.IPParameters=Rank-0\#ChannelRegularConversion,Channel-0\#ChannelRegularConversion,SamplingTime-0\#ChannelRegularConversion,NbrOfConversionFlag,ClockPrescaler
|
||||
ADC3.NbrOfConversionFlag=1
|
||||
ADC3.Rank-0\#ChannelRegularConversion=1
|
||||
ADC3.SamplingTime-0\#ChannelRegularConversion=ADC_SAMPLETIME_3CYCLES
|
||||
CAD.formats=
|
||||
CAD.pinconfig=
|
||||
CAD.provider=
|
||||
CAN1.ABOM=DISABLE
|
||||
CAN1.BS1=CAN_BS1_6TQ
|
||||
CAN1.BS2=CAN_BS2_7TQ
|
||||
CAN1.CalculateBaudRate=1000000
|
||||
CAN1.CalculateTimeBit=1000
|
||||
CAN1.CalculateTimeQuantum=71.42857142857143
|
||||
CAN1.IPParameters=CalculateTimeQuantum,BS1,BS2,Prescaler,TXFP,ABOM,CalculateTimeBit,CalculateBaudRate,NART
|
||||
CAN1.NART=ENABLE
|
||||
CAN1.Prescaler=3
|
||||
CAN1.TXFP=ENABLE
|
||||
CAN2.BS1=CAN_BS1_6TQ
|
||||
CAN2.BS2=CAN_BS2_7TQ
|
||||
CAN2.CalculateBaudRate=1000000
|
||||
CAN2.CalculateTimeBit=1000
|
||||
CAN2.CalculateTimeQuantum=71.42857142857143
|
||||
CAN2.IPParameters=CalculateTimeQuantum,BS1,BS2,Prescaler,TXFP,CalculateTimeBit,CalculateBaudRate,NART
|
||||
CAN2.NART=ENABLE
|
||||
CAN2.Prescaler=3
|
||||
CAN2.TXFP=ENABLE
|
||||
Dma.I2C2_TX.2.Direction=DMA_MEMORY_TO_PERIPH
|
||||
Dma.I2C2_TX.2.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.I2C2_TX.2.Instance=DMA1_Stream7
|
||||
Dma.I2C2_TX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.I2C2_TX.2.MemInc=DMA_MINC_ENABLE
|
||||
Dma.I2C2_TX.2.Mode=DMA_NORMAL
|
||||
Dma.I2C2_TX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.I2C2_TX.2.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.I2C2_TX.2.Priority=DMA_PRIORITY_HIGH
|
||||
Dma.I2C2_TX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.I2C3_RX.7.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.I2C3_RX.7.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.I2C3_RX.7.Instance=DMA1_Stream2
|
||||
Dma.I2C3_RX.7.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.I2C3_RX.7.MemInc=DMA_MINC_ENABLE
|
||||
Dma.I2C3_RX.7.Mode=DMA_NORMAL
|
||||
Dma.I2C3_RX.7.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.I2C3_RX.7.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.I2C3_RX.7.Priority=DMA_PRIORITY_LOW
|
||||
Dma.I2C3_RX.7.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.Request0=SPI1_RX
|
||||
Dma.Request1=SPI1_TX
|
||||
Dma.Request2=I2C2_TX
|
||||
Dma.Request3=USART3_RX
|
||||
Dma.Request4=USART6_RX
|
||||
Dma.Request5=USART6_TX
|
||||
Dma.Request6=USART1_TX
|
||||
Dma.Request7=I2C3_RX
|
||||
Dma.Request8=USART1_RX
|
||||
Dma.RequestsNb=9
|
||||
Dma.SPI1_RX.0.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.SPI1_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.SPI1_RX.0.Instance=DMA2_Stream2
|
||||
Dma.SPI1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.SPI1_RX.0.MemInc=DMA_MINC_ENABLE
|
||||
Dma.SPI1_RX.0.Mode=DMA_NORMAL
|
||||
Dma.SPI1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.SPI1_RX.0.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.SPI1_RX.0.Priority=DMA_PRIORITY_VERY_HIGH
|
||||
Dma.SPI1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.SPI1_TX.1.Direction=DMA_MEMORY_TO_PERIPH
|
||||
Dma.SPI1_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.SPI1_TX.1.Instance=DMA2_Stream3
|
||||
Dma.SPI1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.SPI1_TX.1.MemInc=DMA_MINC_ENABLE
|
||||
Dma.SPI1_TX.1.Mode=DMA_NORMAL
|
||||
Dma.SPI1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.SPI1_TX.1.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.SPI1_TX.1.Priority=DMA_PRIORITY_HIGH
|
||||
Dma.SPI1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.USART1_RX.8.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.USART1_RX.8.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.USART1_RX.8.Instance=DMA2_Stream5
|
||||
Dma.USART1_RX.8.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.USART1_RX.8.MemInc=DMA_MINC_ENABLE
|
||||
Dma.USART1_RX.8.Mode=DMA_NORMAL
|
||||
Dma.USART1_RX.8.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.USART1_RX.8.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.USART1_RX.8.Priority=DMA_PRIORITY_MEDIUM
|
||||
Dma.USART1_RX.8.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.USART1_TX.6.Direction=DMA_MEMORY_TO_PERIPH
|
||||
Dma.USART1_TX.6.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.USART1_TX.6.Instance=DMA2_Stream7
|
||||
Dma.USART1_TX.6.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.USART1_TX.6.MemInc=DMA_MINC_ENABLE
|
||||
Dma.USART1_TX.6.Mode=DMA_NORMAL
|
||||
Dma.USART1_TX.6.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.USART1_TX.6.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.USART1_TX.6.Priority=DMA_PRIORITY_MEDIUM
|
||||
Dma.USART1_TX.6.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.USART3_RX.3.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.USART3_RX.3.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.USART3_RX.3.Instance=DMA1_Stream1
|
||||
Dma.USART3_RX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.USART3_RX.3.MemInc=DMA_MINC_ENABLE
|
||||
Dma.USART3_RX.3.Mode=DMA_NORMAL
|
||||
Dma.USART3_RX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.USART3_RX.3.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.USART3_RX.3.Priority=DMA_PRIORITY_HIGH
|
||||
Dma.USART3_RX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.USART6_RX.4.Direction=DMA_PERIPH_TO_MEMORY
|
||||
Dma.USART6_RX.4.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.USART6_RX.4.Instance=DMA2_Stream1
|
||||
Dma.USART6_RX.4.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.USART6_RX.4.MemInc=DMA_MINC_ENABLE
|
||||
Dma.USART6_RX.4.Mode=DMA_NORMAL
|
||||
Dma.USART6_RX.4.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.USART6_RX.4.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.USART6_RX.4.Priority=DMA_PRIORITY_MEDIUM
|
||||
Dma.USART6_RX.4.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
Dma.USART6_TX.5.Direction=DMA_MEMORY_TO_PERIPH
|
||||
Dma.USART6_TX.5.FIFOMode=DMA_FIFOMODE_DISABLE
|
||||
Dma.USART6_TX.5.Instance=DMA2_Stream6
|
||||
Dma.USART6_TX.5.MemDataAlignment=DMA_MDATAALIGN_BYTE
|
||||
Dma.USART6_TX.5.MemInc=DMA_MINC_ENABLE
|
||||
Dma.USART6_TX.5.Mode=DMA_NORMAL
|
||||
Dma.USART6_TX.5.PeriphDataAlignment=DMA_PDATAALIGN_BYTE
|
||||
Dma.USART6_TX.5.PeriphInc=DMA_PINC_DISABLE
|
||||
Dma.USART6_TX.5.Priority=DMA_PRIORITY_MEDIUM
|
||||
Dma.USART6_TX.5.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode
|
||||
FREERTOS.FootprintOK=true
|
||||
FREERTOS.INCLUDE_pcTaskGetTaskName=1
|
||||
FREERTOS.INCLUDE_uxTaskGetStackHighWaterMark2=1
|
||||
FREERTOS.INCLUDE_vTaskCleanUpResources=1
|
||||
FREERTOS.INCLUDE_xEventGroupSetBitFromISR=1
|
||||
FREERTOS.INCLUDE_xSemaphoreGetMutexHolder=1
|
||||
FREERTOS.INCLUDE_xTaskAbortDelay=1
|
||||
FREERTOS.INCLUDE_xTaskGetCurrentTaskHandle=1
|
||||
FREERTOS.INCLUDE_xTaskGetHandle=1
|
||||
FREERTOS.IPParameters=Tasks01,FootprintOK,configENABLE_FPU,configENABLE_BACKWARD_COMPATIBILITY,configRECORD_STACK_HIGH_ADDRESS,configCHECK_FOR_STACK_OVERFLOW,configGENERATE_RUN_TIME_STATS,configUSE_STATS_FORMATTING_FUNCTIONS,configTOTAL_HEAP_SIZE,INCLUDE_xTaskGetCurrentTaskHandle,INCLUDE_xTaskGetHandle,INCLUDE_uxTaskGetStackHighWaterMark2,INCLUDE_xEventGroupSetBitFromISR,INCLUDE_xTaskAbortDelay,INCLUDE_pcTaskGetTaskName,INCLUDE_xSemaphoreGetMutexHolder,INCLUDE_vTaskCleanUpResources,configUSE_APPLICATION_TASK_TAG
|
||||
FREERTOS.Tasks01=defaultTask,24,128,StartDefaultTask,Default,NULL,Dynamic,NULL,NULL
|
||||
FREERTOS.configCHECK_FOR_STACK_OVERFLOW=2
|
||||
FREERTOS.configENABLE_BACKWARD_COMPATIBILITY=0
|
||||
FREERTOS.configENABLE_FPU=1
|
||||
FREERTOS.configGENERATE_RUN_TIME_STATS=1
|
||||
FREERTOS.configRECORD_STACK_HIGH_ADDRESS=1
|
||||
FREERTOS.configTOTAL_HEAP_SIZE=0x10000
|
||||
FREERTOS.configUSE_APPLICATION_TASK_TAG=0
|
||||
FREERTOS.configUSE_STATS_FORMATTING_FUNCTIONS=1
|
||||
File.Version=6
|
||||
GPIO.groupedBy=Group By Peripherals
|
||||
I2C1.I2C_Mode=I2C_Fast
|
||||
I2C1.IPParameters=I2C_Mode
|
||||
I2C2.I2C_Mode=I2C_Fast
|
||||
I2C2.IPParameters=I2C_Mode
|
||||
I2C3.I2C_Mode=I2C_Fast
|
||||
I2C3.IPParameters=I2C_Mode
|
||||
KeepUserPlacement=false
|
||||
Mcu.CPN=STM32F407IGH6
|
||||
Mcu.Family=STM32F4
|
||||
Mcu.IP0=ADC1
|
||||
Mcu.IP1=ADC3
|
||||
Mcu.IP10=NVIC
|
||||
Mcu.IP11=RCC
|
||||
Mcu.IP12=RNG
|
||||
Mcu.IP13=SPI1
|
||||
Mcu.IP14=SPI2
|
||||
Mcu.IP15=SYS
|
||||
Mcu.IP16=TIM1
|
||||
Mcu.IP17=TIM3
|
||||
Mcu.IP18=TIM4
|
||||
Mcu.IP19=TIM5
|
||||
Mcu.IP2=CAN1
|
||||
Mcu.IP20=TIM7
|
||||
Mcu.IP21=TIM8
|
||||
Mcu.IP22=TIM10
|
||||
Mcu.IP23=USART1
|
||||
Mcu.IP24=USART3
|
||||
Mcu.IP25=USART6
|
||||
Mcu.IP26=USB_DEVICE
|
||||
Mcu.IP27=USB_OTG_FS
|
||||
Mcu.IP3=CAN2
|
||||
Mcu.IP4=CRC
|
||||
Mcu.IP5=DMA
|
||||
Mcu.IP6=FREERTOS
|
||||
Mcu.IP7=I2C1
|
||||
Mcu.IP8=I2C2
|
||||
Mcu.IP9=I2C3
|
||||
Mcu.IPNb=28
|
||||
Mcu.Name=STM32F407I(E-G)Hx
|
||||
Mcu.Package=UFBGA176
|
||||
Mcu.Pin0=PB8
|
||||
Mcu.Pin1=PB5
|
||||
Mcu.Pin10=PD0
|
||||
Mcu.Pin11=PC11
|
||||
Mcu.Pin12=PC10
|
||||
Mcu.Pin13=PA12
|
||||
Mcu.Pin14=PI6
|
||||
Mcu.Pin15=PG9
|
||||
Mcu.Pin16=PD1
|
||||
Mcu.Pin17=PA11
|
||||
Mcu.Pin18=PF0
|
||||
Mcu.Pin19=PA9
|
||||
Mcu.Pin2=PG14
|
||||
Mcu.Pin20=PC9
|
||||
Mcu.Pin21=PA8
|
||||
Mcu.Pin22=PH0-OSC_IN
|
||||
Mcu.Pin23=PC8
|
||||
Mcu.Pin24=PH1-OSC_OUT
|
||||
Mcu.Pin25=PF1
|
||||
Mcu.Pin26=PC6
|
||||
Mcu.Pin27=PG6
|
||||
Mcu.Pin28=PF6
|
||||
Mcu.Pin29=PH12
|
||||
Mcu.Pin3=PB4
|
||||
Mcu.Pin30=PG3
|
||||
Mcu.Pin31=PF10
|
||||
Mcu.Pin32=PH11
|
||||
Mcu.Pin33=PH10
|
||||
Mcu.Pin34=PC0
|
||||
Mcu.Pin35=PC1
|
||||
Mcu.Pin36=PC2
|
||||
Mcu.Pin37=PD14
|
||||
Mcu.Pin38=PA0-WKUP
|
||||
Mcu.Pin39=PA4
|
||||
Mcu.Pin4=PB3
|
||||
Mcu.Pin40=PC4
|
||||
Mcu.Pin41=PE13
|
||||
Mcu.Pin42=PC5
|
||||
Mcu.Pin43=PE9
|
||||
Mcu.Pin44=PE11
|
||||
Mcu.Pin45=PE14
|
||||
Mcu.Pin46=PB12
|
||||
Mcu.Pin47=PB13
|
||||
Mcu.Pin48=PA7
|
||||
Mcu.Pin49=PB0
|
||||
Mcu.Pin5=PA14
|
||||
Mcu.Pin50=PB14
|
||||
Mcu.Pin51=PB15
|
||||
Mcu.Pin52=VP_ADC1_TempSens_Input
|
||||
Mcu.Pin53=VP_ADC1_Vref_Input
|
||||
Mcu.Pin54=VP_CRC_VS_CRC
|
||||
Mcu.Pin55=VP_FREERTOS_VS_CMSIS_V2
|
||||
Mcu.Pin56=VP_RNG_VS_RNG
|
||||
Mcu.Pin57=VP_SYS_VS_Systick
|
||||
Mcu.Pin58=VP_TIM1_VS_ClockSourceINT
|
||||
Mcu.Pin59=VP_TIM3_VS_ClockSourceINT
|
||||
Mcu.Pin6=PA13
|
||||
Mcu.Pin60=VP_TIM4_VS_ClockSourceINT
|
||||
Mcu.Pin61=VP_TIM5_VS_ClockSourceINT
|
||||
Mcu.Pin62=VP_TIM7_VS_ClockSourceINT
|
||||
Mcu.Pin63=VP_TIM8_VS_ClockSourceINT
|
||||
Mcu.Pin64=VP_TIM10_VS_ClockSourceINT
|
||||
Mcu.Pin65=VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS
|
||||
Mcu.Pin7=PB9
|
||||
Mcu.Pin8=PB7
|
||||
Mcu.Pin9=PB6
|
||||
Mcu.PinsNb=66
|
||||
Mcu.ThirdPartyNb=0
|
||||
Mcu.UserConstants=
|
||||
Mcu.UserName=STM32F407IGHx
|
||||
MxCube.Version=6.15.0
|
||||
MxDb.Version=DB.6.0.150
|
||||
NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.CAN1_RX0_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.CAN1_RX1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.CAN1_TX_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.CAN2_RX0_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.CAN2_RX1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.CAN2_TX_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.DMA1_Stream1_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA1_Stream2_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA1_Stream7_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA2_Stream1_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA2_Stream2_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA2_Stream3_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA2_Stream5_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA2_Stream6_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DMA2_Stream7_IRQn=true\:5\:0\:true\:false\:true\:true\:false\:true\:true
|
||||
NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.EXTI0_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.EXTI3_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.EXTI4_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.EXTI9_5_IRQn=true\:5\:0\:true\:false\:true\:true\:true\:true\:true
|
||||
NVIC.ForceEnableDMAVector=true
|
||||
NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false\:false
|
||||
NVIC.OTG_FS_IRQn=true\:5\:0\:false\:false\:true\:true\:false\:true\:true
|
||||
NVIC.PendSV_IRQn=true\:15\:0\:false\:false\:false\:true\:false\:false\:false
|
||||
NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4
|
||||
NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:false\:false\:false\:false\:false
|
||||
NVIC.SavedPendsvIrqHandlerGenerated=true
|
||||
NVIC.SavedSvcallIrqHandlerGenerated=true
|
||||
NVIC.SavedSystickIrqHandlerGenerated=true
|
||||
NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:true\:false\:true\:false
|
||||
NVIC.TIM1_BRK_TIM9_IRQn=true\:5\:0\:false\:false\:true\:false\:false\:true\:true
|
||||
NVIC.TIM7_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.USART1_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.USART6_IRQn=true\:5\:0\:false\:false\:true\:true\:true\:true\:true
|
||||
NVIC.UsageFault_IRQn=true\:0\:0\:true\:false\:true\:false\:false\:false\:false
|
||||
PA0-WKUP.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
|
||||
PA0-WKUP.GPIO_Label=USER_KEY
|
||||
PA0-WKUP.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING
|
||||
PA0-WKUP.GPIO_PuPd=GPIO_PULLUP
|
||||
PA0-WKUP.Locked=true
|
||||
PA0-WKUP.Signal=GPXTI0
|
||||
PA11.Mode=Device_Only
|
||||
PA11.Signal=USB_OTG_FS_DM
|
||||
PA12.Mode=Device_Only
|
||||
PA12.Signal=USB_OTG_FS_DP
|
||||
PA13.Mode=Serial_Wire
|
||||
PA13.Signal=SYS_JTMS-SWDIO
|
||||
PA14.Mode=Serial_Wire
|
||||
PA14.Signal=SYS_JTCK-SWCLK
|
||||
PA4.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
||||
PA4.GPIO_Label=ACCL_CS
|
||||
PA4.GPIO_PuPd=GPIO_PULLUP
|
||||
PA4.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
|
||||
PA4.Locked=true
|
||||
PA4.PinState=GPIO_PIN_SET
|
||||
PA4.Signal=GPIO_Output
|
||||
PA7.GPIOParameters=GPIO_PuPd
|
||||
PA7.GPIO_PuPd=GPIO_PULLUP
|
||||
PA7.Locked=true
|
||||
PA7.Mode=Full_Duplex_Master
|
||||
PA7.Signal=SPI1_MOSI
|
||||
PA8.GPIOParameters=GPIO_Pu
|
||||
PA8.GPIO_Pu=GPIO_PULLUP
|
||||
PA8.Locked=true
|
||||
PA8.Mode=I2C
|
||||
PA8.Signal=I2C3_SCL
|
||||
PA9.Locked=true
|
||||
PA9.Mode=Asynchronous
|
||||
PA9.Signal=USART1_TX
|
||||
PB0.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
||||
PB0.GPIO_Label=GYRO_CS
|
||||
PB0.GPIO_PuPd=GPIO_PULLUP
|
||||
PB0.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
|
||||
PB0.Locked=true
|
||||
PB0.PinState=GPIO_PIN_SET
|
||||
PB0.Signal=GPIO_Output
|
||||
PB12.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
||||
PB12.GPIO_Label=SPI2_CS
|
||||
PB12.GPIO_PuPd=GPIO_PULLUP
|
||||
PB12.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
|
||||
PB12.Locked=true
|
||||
PB12.PinState=GPIO_PIN_SET
|
||||
PB12.Signal=GPIO_Output
|
||||
PB13.GPIOParameters=GPIO_PuPd
|
||||
PB13.GPIO_PuPd=GPIO_PULLUP
|
||||
PB13.Locked=true
|
||||
PB13.Mode=Full_Duplex_Master
|
||||
PB13.Signal=SPI2_SCK
|
||||
PB14.GPIOParameters=GPIO_PuPd
|
||||
PB14.GPIO_PuPd=GPIO_PULLUP
|
||||
PB14.Locked=true
|
||||
PB14.Mode=Full_Duplex_Master
|
||||
PB14.Signal=SPI2_MISO
|
||||
PB15.GPIOParameters=GPIO_PuPd
|
||||
PB15.GPIO_PuPd=GPIO_PULLUP
|
||||
PB15.Locked=true
|
||||
PB15.Mode=Full_Duplex_Master
|
||||
PB15.Signal=SPI2_MOSI
|
||||
PB3.GPIOParameters=GPIO_PuPd
|
||||
PB3.GPIO_PuPd=GPIO_PULLUP
|
||||
PB3.Locked=true
|
||||
PB3.Mode=Full_Duplex_Master
|
||||
PB3.Signal=SPI1_SCK
|
||||
PB4.GPIOParameters=GPIO_PuPd
|
||||
PB4.GPIO_PuPd=GPIO_PULLUP
|
||||
PB4.Locked=true
|
||||
PB4.Mode=Full_Duplex_Master
|
||||
PB4.Signal=SPI1_MISO
|
||||
PB5.Locked=true
|
||||
PB5.Mode=CAN_Activate
|
||||
PB5.Signal=CAN2_RX
|
||||
PB6.Locked=true
|
||||
PB6.Mode=CAN_Activate
|
||||
PB6.Signal=CAN2_TX
|
||||
PB7.Locked=true
|
||||
PB7.Mode=Asynchronous
|
||||
PB7.Signal=USART1_RX
|
||||
PB8.GPIOParameters=GPIO_Pu
|
||||
PB8.GPIO_Pu=GPIO_PULLUP
|
||||
PB8.Locked=true
|
||||
PB8.Mode=I2C
|
||||
PB8.Signal=I2C1_SCL
|
||||
PB9.GPIOParameters=GPIO_Pu
|
||||
PB9.GPIO_Pu=GPIO_PULLUP
|
||||
PB9.Locked=true
|
||||
PB9.Mode=I2C
|
||||
PB9.Signal=I2C1_SDA
|
||||
PC0.GPIOParameters=GPIO_Label
|
||||
PC0.GPIO_Label=HW0
|
||||
PC0.Locked=true
|
||||
PC0.Signal=GPIO_Input
|
||||
PC1.GPIOParameters=GPIO_Label
|
||||
PC1.GPIO_Label=HW1
|
||||
PC1.Locked=true
|
||||
PC1.Signal=GPIO_Input
|
||||
PC10.Locked=true
|
||||
PC10.Mode=Asynchronous
|
||||
PC10.Signal=USART3_TX
|
||||
PC11.Locked=true
|
||||
PC11.Mode=Asynchronous
|
||||
PC11.Signal=USART3_RX
|
||||
PC2.GPIOParameters=GPIO_Label
|
||||
PC2.GPIO_Label=HW2
|
||||
PC2.Locked=true
|
||||
PC2.Signal=GPIO_Input
|
||||
PC4.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
|
||||
PC4.GPIO_Label=ACCL_INT
|
||||
PC4.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING
|
||||
PC4.GPIO_PuPd=GPIO_PULLUP
|
||||
PC4.Locked=true
|
||||
PC4.Signal=GPXTI4
|
||||
PC5.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
|
||||
PC5.GPIO_Label=GYRO_INT
|
||||
PC5.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING
|
||||
PC5.GPIO_PuPd=GPIO_PULLUP
|
||||
PC5.Locked=true
|
||||
PC5.Signal=GPXTI5
|
||||
PC6.GPIOParameters=GPIO_Speed,GPIO_PuPd
|
||||
PC6.GPIO_PuPd=GPIO_PULLUP
|
||||
PC6.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PC6.Locked=true
|
||||
PC6.Signal=S_TIM8_CH1
|
||||
PC8.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label
|
||||
PC8.GPIO_Label=LASER
|
||||
PC8.GPIO_PuPd=GPIO_PULLUP
|
||||
PC8.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PC8.Locked=true
|
||||
PC8.Signal=S_TIM3_CH3
|
||||
PC9.GPIOParameters=GPIO_Pu
|
||||
PC9.GPIO_Pu=GPIO_PULLUP
|
||||
PC9.Locked=true
|
||||
PC9.Mode=I2C
|
||||
PC9.Signal=I2C3_SDA
|
||||
PD0.Locked=true
|
||||
PD0.Mode=CAN_Activate
|
||||
PD0.Signal=CAN1_RX
|
||||
PD1.Locked=true
|
||||
PD1.Mode=CAN_Activate
|
||||
PD1.Signal=CAN1_TX
|
||||
PD14.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label
|
||||
PD14.GPIO_Label=BUZZER
|
||||
PD14.GPIO_PuPd=GPIO_PULLUP
|
||||
PD14.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH
|
||||
PD14.Locked=true
|
||||
PD14.Signal=S_TIM4_CH3
|
||||
PE11.GPIOParameters=GPIO_Speed,GPIO_PuPd
|
||||
PE11.GPIO_PuPd=GPIO_PULLUP
|
||||
PE11.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PE11.Locked=true
|
||||
PE11.Signal=S_TIM1_CH2
|
||||
PE13.GPIOParameters=GPIO_Speed,GPIO_PuPd
|
||||
PE13.GPIO_PuPd=GPIO_PULLUP
|
||||
PE13.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PE13.Locked=true
|
||||
PE13.Signal=S_TIM1_CH3
|
||||
PE14.GPIOParameters=GPIO_Speed,GPIO_PuPd
|
||||
PE14.GPIO_PuPd=GPIO_PULLUP
|
||||
PE14.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PE14.Locked=true
|
||||
PE14.Signal=S_TIM1_CH4
|
||||
PE9.GPIOParameters=GPIO_Speed,GPIO_PuPd
|
||||
PE9.GPIO_PuPd=GPIO_PULLUP
|
||||
PE9.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PE9.Locked=true
|
||||
PE9.Signal=S_TIM1_CH1
|
||||
PF0.GPIOParameters=GPIO_Pu
|
||||
PF0.GPIO_Pu=GPIO_PULLUP
|
||||
PF0.Locked=true
|
||||
PF0.Mode=I2C
|
||||
PF0.Signal=I2C2_SDA
|
||||
PF1.GPIOParameters=GPIO_Pu
|
||||
PF1.GPIO_Pu=GPIO_PULLUP
|
||||
PF1.Locked=true
|
||||
PF1.Mode=I2C
|
||||
PF1.Signal=I2C2_SCL
|
||||
PF10.GPIOParameters=GPIO_Label
|
||||
PF10.GPIO_Label=ADC_BAT
|
||||
PF10.Locked=true
|
||||
PF10.Mode=IN8
|
||||
PF10.Signal=ADC3_IN8
|
||||
PF6.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label
|
||||
PF6.GPIO_Label=IMU_HEAT_PWM
|
||||
PF6.GPIO_PuPd=GPIO_PULLDOWN
|
||||
PF6.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PF6.Locked=true
|
||||
PF6.Signal=S_TIM10_CH1
|
||||
PG14.Locked=true
|
||||
PG14.Mode=Asynchronous
|
||||
PG14.Signal=USART6_TX
|
||||
PG3.GPIOParameters=GPIO_PuPd,GPIO_Label,GPIO_ModeDefaultEXTI
|
||||
PG3.GPIO_Label=CMPS_INT
|
||||
PG3.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING
|
||||
PG3.GPIO_PuPd=GPIO_PULLUP
|
||||
PG3.Locked=true
|
||||
PG3.Signal=GPXTI3
|
||||
PG6.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label
|
||||
PG6.GPIO_Label=CMPS_RST
|
||||
PG6.GPIO_PuPd=GPIO_PULLUP
|
||||
PG6.GPIO_Speed=GPIO_SPEED_FREQ_MEDIUM
|
||||
PG6.Locked=true
|
||||
PG6.PinState=GPIO_PIN_RESET
|
||||
PG6.Signal=GPIO_Output
|
||||
PG9.Locked=true
|
||||
PG9.Mode=Asynchronous
|
||||
PG9.Signal=USART6_RX
|
||||
PH0-OSC_IN.Mode=HSE-External-Oscillator
|
||||
PH0-OSC_IN.Signal=RCC_OSC_IN
|
||||
PH1-OSC_OUT.Mode=HSE-External-Oscillator
|
||||
PH1-OSC_OUT.Signal=RCC_OSC_OUT
|
||||
PH10.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label
|
||||
PH10.GPIO_Label=LED_B
|
||||
PH10.GPIO_PuPd=GPIO_PULLUP
|
||||
PH10.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PH10.Locked=true
|
||||
PH10.Signal=S_TIM5_CH1
|
||||
PH11.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label
|
||||
PH11.GPIO_Label=LED_G
|
||||
PH11.GPIO_PuPd=GPIO_PULLUP
|
||||
PH11.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PH11.Locked=true
|
||||
PH11.Signal=S_TIM5_CH2
|
||||
PH12.GPIOParameters=GPIO_Speed,GPIO_PuPd,GPIO_Label
|
||||
PH12.GPIO_Label=LED_R
|
||||
PH12.GPIO_PuPd=GPIO_PULLUP
|
||||
PH12.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PH12.Locked=true
|
||||
PH12.Signal=S_TIM5_CH3
|
||||
PI6.GPIOParameters=GPIO_Speed,GPIO_PuPd
|
||||
PI6.GPIO_PuPd=GPIO_PULLUP
|
||||
PI6.GPIO_Speed=GPIO_SPEED_FREQ_HIGH
|
||||
PI6.Signal=S_TIM8_CH2
|
||||
PinOutPanel.CurrentBGAView=Top
|
||||
PinOutPanel.RotationAngle=0
|
||||
ProjectManager.AskForMigrate=true
|
||||
ProjectManager.BackupPrevious=false
|
||||
ProjectManager.CompilerLinker=GCC
|
||||
ProjectManager.CompilerOptimize=6
|
||||
ProjectManager.ComputerToolchain=false
|
||||
ProjectManager.CoupleFile=true
|
||||
ProjectManager.CustomerFirmwarePackage=
|
||||
ProjectManager.DefaultFWLocation=true
|
||||
ProjectManager.DeletePrevious=true
|
||||
ProjectManager.DeviceId=STM32F407IGHx
|
||||
ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.28.3
|
||||
ProjectManager.FreePins=false
|
||||
ProjectManager.HalAssertFull=true
|
||||
ProjectManager.HeapSize=0x1000
|
||||
ProjectManager.KeepUserCode=true
|
||||
ProjectManager.LastFirmware=true
|
||||
ProjectManager.LibraryCopy=0
|
||||
ProjectManager.MainLocation=Core/Src
|
||||
ProjectManager.NoMain=false
|
||||
ProjectManager.PreviousToolchain=
|
||||
ProjectManager.ProjectBuild=false
|
||||
ProjectManager.ProjectFileName=DevC.ioc
|
||||
ProjectManager.ProjectName=DevC
|
||||
ProjectManager.ProjectStructure=
|
||||
ProjectManager.RegisterCallBack=
|
||||
ProjectManager.StackSize=0x1000
|
||||
ProjectManager.TargetToolchain=CMake
|
||||
ProjectManager.ToolChainLocation=
|
||||
ProjectManager.UAScriptAfterPath=
|
||||
ProjectManager.UAScriptBeforePath=
|
||||
ProjectManager.UnderRoot=false
|
||||
ProjectManager.functionlistsort=1-MX_GPIO_Init-GPIO-false-HAL-true,2-MX_DMA_Init-DMA-false-HAL-true,3-SystemClock_Config-RCC-false-HAL-false,4-MX_ADC1_Init-ADC1-false-HAL-true,5-MX_ADC3_Init-ADC3-false-HAL-true,6-MX_CAN1_Init-CAN1-false-HAL-true,7-MX_CAN2_Init-CAN2-false-HAL-true,8-MX_I2C1_Init-I2C1-false-HAL-true,9-MX_SPI1_Init-SPI1-false-HAL-true,10-MX_TIM4_Init-TIM4-false-HAL-true,11-MX_TIM5_Init-TIM5-false-HAL-true,12-MX_USART3_UART_Init-USART3-false-HAL-true,13-MX_TIM8_Init-TIM8-false-HAL-true,14-MX_CRC_Init-CRC-false-HAL-true,15-MX_RNG_Init-RNG-false-HAL-true,16-MX_I2C2_Init-I2C2-false-HAL-true,17-MX_I2C3_Init-I2C3-false-HAL-true,18-MX_SPI2_Init-SPI2-false-HAL-true,19-MX_TIM1_Init-TIM1-false-HAL-true,20-MX_TIM3_Init-TIM3-false-HAL-true,21-MX_TIM10_Init-TIM10-false-HAL-true,22-MX_USART1_UART_Init-USART1-false-HAL-true,23-MX_USART6_UART_Init-USART6-false-HAL-true,24-MX_TIM7_Init-TIM7-false-HAL-true,25-MX_USB_DEVICE_Init-USB_DEVICE-false-HAL-false
|
||||
RCC.48MHZClocksFreq_Value=48000000
|
||||
RCC.AHBFreq_Value=168000000
|
||||
RCC.APB1CLKDivider=RCC_HCLK_DIV4
|
||||
RCC.APB1Freq_Value=42000000
|
||||
RCC.APB1TimFreq_Value=84000000
|
||||
RCC.APB2CLKDivider=RCC_HCLK_DIV2
|
||||
RCC.APB2Freq_Value=84000000
|
||||
RCC.APB2TimFreq_Value=168000000
|
||||
RCC.CortexFreq_Value=168000000
|
||||
RCC.EthernetFreq_Value=168000000
|
||||
RCC.FCLKCortexFreq_Value=168000000
|
||||
RCC.FamilyName=M
|
||||
RCC.HCLKFreq_Value=168000000
|
||||
RCC.HSE_VALUE=12000000
|
||||
RCC.HSI_VALUE=16000000
|
||||
RCC.I2SClocksFreq_Value=192000000
|
||||
RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLM,PLLN,PLLQ,PLLQCLKFreq_Value,RCC_RTC_Clock_Source,RCC_RTC_Clock_SourceVirtual,RCC_RTC_Clock_Source_FROM_HSE,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S
|
||||
RCC.LSE_VALUE=32768
|
||||
RCC.LSI_VALUE=32000
|
||||
RCC.MCO2PinFreq_Value=168000000
|
||||
RCC.PLLCLKFreq_Value=168000000
|
||||
RCC.PLLM=6
|
||||
RCC.PLLN=168
|
||||
RCC.PLLQ=7
|
||||
RCC.PLLQCLKFreq_Value=48000000
|
||||
RCC.RCC_RTC_Clock_Source=RCC_RTCCLKSOURCE_LSI
|
||||
RCC.RCC_RTC_Clock_SourceVirtual=RCC_RTCCLKSOURCE_HSE_DIV30
|
||||
RCC.RCC_RTC_Clock_Source_FROM_HSE=RCC_RTCCLKSOURCE_HSE_DIV30
|
||||
RCC.RTCFreq_Value=32000
|
||||
RCC.RTCHSEDivFreq_Value=400000
|
||||
RCC.SYSCLKFreq_VALUE=168000000
|
||||
RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK
|
||||
RCC.VCOI2SOutputFreq_Value=384000000
|
||||
RCC.VCOInputFreq_Value=2000000
|
||||
RCC.VCOOutputFreq_Value=336000000
|
||||
RCC.VcooutputI2S=192000000
|
||||
SH.GPXTI0.0=GPIO_EXTI0
|
||||
SH.GPXTI0.ConfNb=1
|
||||
SH.GPXTI3.0=GPIO_EXTI3
|
||||
SH.GPXTI3.ConfNb=1
|
||||
SH.GPXTI4.0=GPIO_EXTI4
|
||||
SH.GPXTI4.ConfNb=1
|
||||
SH.GPXTI5.0=GPIO_EXTI5
|
||||
SH.GPXTI5.ConfNb=1
|
||||
SH.S_TIM10_CH1.0=TIM10_CH1,PWM Generation1 CH1
|
||||
SH.S_TIM10_CH1.ConfNb=1
|
||||
SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1
|
||||
SH.S_TIM1_CH1.ConfNb=1
|
||||
SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2
|
||||
SH.S_TIM1_CH2.ConfNb=1
|
||||
SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM1_CH3.ConfNb=1
|
||||
SH.S_TIM1_CH4.0=TIM1_CH4,PWM Generation4 CH4
|
||||
SH.S_TIM1_CH4.ConfNb=1
|
||||
SH.S_TIM3_CH3.0=TIM3_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM3_CH3.ConfNb=1
|
||||
SH.S_TIM4_CH3.0=TIM4_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM4_CH3.ConfNb=1
|
||||
SH.S_TIM5_CH1.0=TIM5_CH1,PWM Generation1 CH1
|
||||
SH.S_TIM5_CH1.ConfNb=1
|
||||
SH.S_TIM5_CH2.0=TIM5_CH2,PWM Generation2 CH2
|
||||
SH.S_TIM5_CH2.ConfNb=1
|
||||
SH.S_TIM5_CH3.0=TIM5_CH3,PWM Generation3 CH3
|
||||
SH.S_TIM5_CH3.ConfNb=1
|
||||
SH.S_TIM8_CH1.0=TIM8_CH1,PWM Generation1 CH1
|
||||
SH.S_TIM8_CH1.ConfNb=1
|
||||
SH.S_TIM8_CH2.0=TIM8_CH2,PWM Generation2 CH2
|
||||
SH.S_TIM8_CH2.ConfNb=1
|
||||
SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_16
|
||||
SPI1.CLKPhase=SPI_PHASE_2EDGE
|
||||
SPI1.CLKPolarity=SPI_POLARITY_HIGH
|
||||
SPI1.CalculateBaudRate=5.25 MBits/s
|
||||
SPI1.Direction=SPI_DIRECTION_2LINES
|
||||
SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,CLKPolarity,CLKPhase
|
||||
SPI1.Mode=SPI_MODE_MASTER
|
||||
SPI1.VirtualType=VM_MASTER
|
||||
SPI2.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_64
|
||||
SPI2.CLKPhase=SPI_PHASE_1EDGE
|
||||
SPI2.CLKPolarity=SPI_POLARITY_LOW
|
||||
SPI2.CalculateBaudRate=656.25 KBits/s
|
||||
SPI2.Direction=SPI_DIRECTION_2LINES
|
||||
SPI2.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,CLKPolarity,CLKPhase
|
||||
SPI2.Mode=SPI_MODE_MASTER
|
||||
SPI2.VirtualType=VM_MASTER
|
||||
TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
|
||||
TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
|
||||
TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4
|
||||
TIM1.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4,Period,Prescaler,Pulse-PWM Generation1 CH1,Pulse-PWM Generation2 CH2,Pulse-PWM Generation3 CH3,Pulse-PWM Generation4 CH4
|
||||
TIM1.Period=19999
|
||||
TIM1.Prescaler=167
|
||||
TIM1.Pulse-PWM\ Generation1\ CH1=0
|
||||
TIM1.Pulse-PWM\ Generation2\ CH2=0
|
||||
TIM1.Pulse-PWM\ Generation3\ CH3=0
|
||||
TIM1.Pulse-PWM\ Generation4\ CH4=1000
|
||||
TIM10.Channel=TIM_CHANNEL_1
|
||||
TIM10.IPParameters=Channel,Period
|
||||
TIM10.Period=4999
|
||||
TIM3.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM3.IPParameters=Channel-PWM Generation3 CH3,Period
|
||||
TIM3.Period=65535
|
||||
TIM4.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM4.IPParameters=Channel-PWM Generation3 CH3,Prescaler,Period
|
||||
TIM4.Period=65535
|
||||
TIM4.Prescaler=167
|
||||
TIM5.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
|
||||
TIM5.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
|
||||
TIM5.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3
|
||||
TIM5.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Prescaler,Period
|
||||
TIM5.Period=65535
|
||||
TIM5.Prescaler=0
|
||||
TIM7.IPParameters=Period,Prescaler
|
||||
TIM7.Period=9
|
||||
TIM7.Prescaler=83
|
||||
TIM8.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1
|
||||
TIM8.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2
|
||||
TIM8.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Prescaler,Period,Pulse-PWM Generation1 CH1,Pulse-PWM Generation2 CH2
|
||||
TIM8.Period=19999
|
||||
TIM8.Prescaler=167
|
||||
TIM8.Pulse-PWM\ Generation1\ CH1=1000
|
||||
TIM8.Pulse-PWM\ Generation2\ CH2=1000
|
||||
USART1.IPParameters=VirtualMode
|
||||
USART1.VirtualMode=VM_ASYNC
|
||||
USART3.BaudRate=100000
|
||||
USART3.IPParameters=VirtualMode,BaudRate,Parity,Mode
|
||||
USART3.Mode=MODE_RX
|
||||
USART3.Parity=PARITY_EVEN
|
||||
USART3.VirtualMode=VM_ASYNC
|
||||
USART6.IPParameters=VirtualMode
|
||||
USART6.VirtualMode=VM_ASYNC
|
||||
USB_DEVICE.CLASS_NAME_FS=CDC
|
||||
USB_DEVICE.IPParameters=VirtualMode-CDC_FS,VirtualModeFS,CLASS_NAME_FS
|
||||
USB_DEVICE.VirtualMode-CDC_FS=Cdc
|
||||
USB_DEVICE.VirtualModeFS=Cdc_FS
|
||||
USB_OTG_FS.IPParameters=VirtualMode
|
||||
USB_OTG_FS.VirtualMode=Device_Only
|
||||
VP_ADC1_TempSens_Input.Mode=IN-TempSens
|
||||
VP_ADC1_TempSens_Input.Signal=ADC1_TempSens_Input
|
||||
VP_ADC1_Vref_Input.Mode=IN-Vrefint
|
||||
VP_ADC1_Vref_Input.Signal=ADC1_Vref_Input
|
||||
VP_CRC_VS_CRC.Mode=CRC_Activate
|
||||
VP_CRC_VS_CRC.Signal=CRC_VS_CRC
|
||||
VP_FREERTOS_VS_CMSIS_V2.Mode=CMSIS_V2
|
||||
VP_FREERTOS_VS_CMSIS_V2.Signal=FREERTOS_VS_CMSIS_V2
|
||||
VP_RNG_VS_RNG.Mode=RNG_Activate
|
||||
VP_RNG_VS_RNG.Signal=RNG_VS_RNG
|
||||
VP_SYS_VS_Systick.Mode=SysTick
|
||||
VP_SYS_VS_Systick.Signal=SYS_VS_Systick
|
||||
VP_TIM10_VS_ClockSourceINT.Mode=Enable_Timer
|
||||
VP_TIM10_VS_ClockSourceINT.Signal=TIM10_VS_ClockSourceINT
|
||||
VP_TIM1_VS_ClockSourceINT.Mode=Internal
|
||||
VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT
|
||||
VP_TIM3_VS_ClockSourceINT.Mode=Internal
|
||||
VP_TIM3_VS_ClockSourceINT.Signal=TIM3_VS_ClockSourceINT
|
||||
VP_TIM4_VS_ClockSourceINT.Mode=Internal
|
||||
VP_TIM4_VS_ClockSourceINT.Signal=TIM4_VS_ClockSourceINT
|
||||
VP_TIM5_VS_ClockSourceINT.Mode=Internal
|
||||
VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT
|
||||
VP_TIM7_VS_ClockSourceINT.Mode=Enable_Timer
|
||||
VP_TIM7_VS_ClockSourceINT.Signal=TIM7_VS_ClockSourceINT
|
||||
VP_TIM8_VS_ClockSourceINT.Mode=Internal
|
||||
VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT
|
||||
VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Mode=CDC_FS
|
||||
VP_USB_DEVICE_VS_USB_DEVICE_CDC_FS.Signal=USB_DEVICE_VS_USB_DEVICE_CDC_FS
|
||||
board=custom
|
||||
rtos.0.ip=FREERTOS
|
||||
@ -197,7 +197,7 @@ int8_t CMD_Arbitrate(CMD_t *ctx) {
|
||||
}
|
||||
|
||||
/* 自动仲裁:优先级 PC > RC > NUC */
|
||||
CMD_InputSource_t candidates[] = {CMD_SRC_PC, CMD_SRC_RC, CMD_SRC_NUC};
|
||||
CMD_InputSource_t candidates[] = {CMD_SRC_RC, CMD_SRC_PC, CMD_SRC_NUC};
|
||||
const int num_candidates = sizeof(candidates) / sizeof(candidates[0]);
|
||||
|
||||
/* 如果当前输入源仍然在线且有效,保持使用 */
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
// static CMD_InputAdapter_t *g_adapters[CMD_SRC_NUM] = {0};
|
||||
CMD_InputAdapter_t *g_adapters[CMD_SRC_NUM] = {0};
|
||||
/* ========================================================================== */
|
||||
/* DR16 抽象实现 */
|
||||
/* DR16 适配器实现 */
|
||||
/* ========================================================================== */
|
||||
#if CMD_RC_DEVICE_TYPE == 0
|
||||
|
||||
@ -27,19 +27,19 @@ int8_t CMD_DR16_RC_GetInput(void *data, CMD_RawInput_t *output) {
|
||||
output->online[CMD_SRC_RC] = dr16->header.online;
|
||||
|
||||
/* 遥控器摇杆映射 */
|
||||
output->rc.joy_left.x = dr16->data.rc.ch_l_x;
|
||||
output->rc.joy_left.y = dr16->data.rc.ch_l_y;
|
||||
output->rc.joy_right.x = dr16->data.rc.ch_r_x;
|
||||
output->rc.joy_right.y = dr16->data.rc.ch_r_y;
|
||||
output->rc.joy_left.x = dr16->data.ch_l_x;
|
||||
output->rc.joy_left.y = dr16->data.ch_l_y;
|
||||
output->rc.joy_right.x = dr16->data.ch_r_x;
|
||||
output->rc.joy_right.y = dr16->data.ch_r_y;
|
||||
|
||||
/* 拨杆映射 */
|
||||
switch (dr16->data.rc.sw_l) {
|
||||
switch (dr16->data.sw_l) {
|
||||
case DR16_SW_UP: output->rc.sw[0] = CMD_SW_UP; break;
|
||||
case DR16_SW_MID: output->rc.sw[0] = CMD_SW_MID; break;
|
||||
case DR16_SW_DOWN: output->rc.sw[0] = CMD_SW_DOWN; break;
|
||||
default: output->rc.sw[0] = CMD_SW_ERR; break;
|
||||
}
|
||||
switch (dr16->data.rc.sw_r) {
|
||||
switch (dr16->data.sw_r) {
|
||||
case DR16_SW_UP: output->rc.sw[1] = CMD_SW_UP; break;
|
||||
case DR16_SW_MID: output->rc.sw[1] = CMD_SW_MID; break;
|
||||
case DR16_SW_DOWN: output->rc.sw[1] = CMD_SW_DOWN; break;
|
||||
@ -47,7 +47,7 @@ int8_t CMD_DR16_RC_GetInput(void *data, CMD_RawInput_t *output) {
|
||||
}
|
||||
|
||||
/* 拨轮映射 */
|
||||
output->rc.dial = dr16->data.rc.ch_res;
|
||||
output->rc.dial = dr16->data.ch_res;
|
||||
|
||||
return CMD_OK;
|
||||
}
|
||||
@ -60,10 +60,10 @@ int8_t CMD_DR16_PC_GetInput(void *data, CMD_RawInput_t *output) {
|
||||
output->online[CMD_SRC_PC] = dr16->header.online;
|
||||
|
||||
/* PC端鼠标映射 */
|
||||
output->pc.mouse.x = dr16->data.pc.mouse.x;
|
||||
output->pc.mouse.y = dr16->data.pc.mouse.y;
|
||||
output->pc.mouse.l_click = dr16->data.pc.mouse.l_click;
|
||||
output->pc.mouse.r_click = dr16->data.pc.mouse.r_click;
|
||||
output->pc.mouse.x = dr16->data.mouse.x;
|
||||
output->pc.mouse.y = dr16->data.mouse.y;
|
||||
output->pc.mouse.l_click = dr16->data.mouse.l_click;
|
||||
output->pc.mouse.r_click = dr16->data.mouse.r_click;
|
||||
|
||||
/* 键盘映射 */
|
||||
output->pc.keyboard.bitmap = dr16->raw_data.key;
|
||||
@ -83,7 +83,7 @@ CMD_DEFINE_ADAPTER(DR16_PC, cmd_dr16, CMD_SRC_PC, CMD_DR16_Init, CMD_DR16_PC_Get
|
||||
#endif /* CMD_RC_DEVICE_TYPE == 0 */
|
||||
|
||||
/* ========================================================================== */
|
||||
/* AT9S 抽象实现 (示例框架) */
|
||||
/* AT9S 适配器实现 (示例框架) */
|
||||
/* ========================================================================== */
|
||||
#if CMD_RC_DEVICE_TYPE == 1
|
||||
|
||||
@ -100,10 +100,10 @@ int8_t CMD_AT9S_GetInput(void *data, CMD_RawInput_t *output) {
|
||||
output->online[CMD_SRC_RC] = at9s->header.online;
|
||||
|
||||
/* TODO: 按照AT9S的数据格式进行映射 */
|
||||
output->joy_left.x = at9s->data.rc.ch_l_x;
|
||||
output->joy_left.y = at9s->data.rc.ch_l_y;
|
||||
output->joy_right.x = at9s->data.rc.ch_r_x;
|
||||
output->joy_right.y = at9s->data.rc.ch_r_y;
|
||||
output->joy_left.x = at9s->data.ch_l_x;
|
||||
output->joy_left.y = at9s->data.ch_l_y;
|
||||
output->joy_right.x = at9s->data.ch_r_x;
|
||||
output->joy_right.y = at9s->data.ch_r_y;
|
||||
|
||||
/* 拨杆映射需要根据AT9S的实际定义 */
|
||||
|
||||
@ -142,10 +142,6 @@ int8_t CMD_Adapter_InitAll(void) {
|
||||
CMD_Adapter_Register(&g_adapter_AT9S);
|
||||
#endif
|
||||
|
||||
/* 注册NUC适配器 */
|
||||
|
||||
/* 注册REF适配器 */
|
||||
|
||||
/* 初始化所有已注册的适配器 */
|
||||
for (int i = 0; i < CMD_SRC_NUM; i++) {
|
||||
if (g_adapters[i] != NULL && g_adapters[i]->init != NULL) {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include "cmd.h"
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 配置示例 */
|
||||
/* config示例 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/* 默认配置 */
|
||||
@ -37,35 +37,58 @@
|
||||
// /* CMD上下文 */
|
||||
// static CMD_t g_cmd_ctx;
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 队列创建示例 */
|
||||
/* ========================================================================== */
|
||||
// #if CMD_RCTypeTable_Index == 0
|
||||
// task_runtime.msgq.cmd.rc= osMessageQueueNew(3u, sizeof(DR16_t), NULL);
|
||||
// #elif CMD_RCTypeTable_Index == 1
|
||||
// task_runtime.msgq.cmd.rc= osMessageQueueNew(3u, sizeof(AT9S_t), NULL);
|
||||
// #endif
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 任务示例 */
|
||||
/* ========================================================================== */
|
||||
|
||||
/*
|
||||
* 初始化示例
|
||||
*/
|
||||
// void Example_CMD_Init(void) {
|
||||
// CMD_Init(&g_cmd_ctx, &g_cmd_config);
|
||||
// }
|
||||
// #if CMD_RCTypeTable_Index == 0
|
||||
// DR16_t cmd_dr16;
|
||||
// #elif CMD_RCTypeTable_Index == 1
|
||||
// AT9S_t cmd_at9s;
|
||||
// #endif
|
||||
// Shoot_CMD_t *cmd_for_shoot;
|
||||
// Chassis_CMD_t *cmd_for_chassis;
|
||||
// Gimbal_CMD_t *cmd_for_gimbal;
|
||||
|
||||
// /*
|
||||
// * 任务循环示例
|
||||
// */
|
||||
// void Example_CMD_Task(void) {
|
||||
// /* 一键更新 */
|
||||
// CMD_Update(&g_cmd_ctx);
|
||||
// static CMD_t cmd;
|
||||
|
||||
// void Task_cmd() {
|
||||
|
||||
// CMD_Init(&cmd, &Config_GetRobotParam()->cmd_param);
|
||||
|
||||
// while (1) {
|
||||
// #if CMD_RCTypeTable_Index == 0
|
||||
// osMessageQueueGet(task_runtime.msgq.cmd.rc, &cmd_dr16, NULL, 0);
|
||||
// #elif CMD_RCTypeTable_Index == 1
|
||||
// osMessageQueueGet(task_runtime.msgq.cmd.rc, &cmd_at9s, NULL, 0);
|
||||
// #endif
|
||||
// CMD_Update(&cmd);
|
||||
|
||||
// /* 获取命令发送到各模块 */
|
||||
// Chassis_CMD_t *chassis_cmd = CMD_GetChassisCmd(&g_cmd_ctx);
|
||||
// Gimbal_CMD_t *gimbal_cmd = CMD_GetGimbalCmd(&g_cmd_ctx);
|
||||
// Shoot_CMD_t *shoot_cmd = CMD_GetShootCmd(&g_cmd_ctx);
|
||||
|
||||
// /* 使用命令... */
|
||||
// (void)chassis_cmd;
|
||||
// (void)gimbal_cmd;
|
||||
// (void)shoot_cmd;
|
||||
// cmd_for_chassis = CMD_GetChassisCmd(&cmd);
|
||||
// cmd_for_gimbal = CMD_GetGimbalCmd(&cmd);
|
||||
// cmd_for_shoot = CMD_GetShootCmd(&cmd);
|
||||
// osMessageQueueReset(task_runtime.msgq.gimbal.cmd);
|
||||
// osMessageQueuePut(task_runtime.msgq.gimbal.cmd, cmd_for_gimbal, 0, 0);
|
||||
// osMessageQueueReset(task_runtime.msgq.shoot.cmd);
|
||||
// osMessageQueuePut(task_runtime.msgq.shoot.cmd, cmd_for_shoot, 0, 0);
|
||||
// osMessageQueueReset(task_runtime.msgq.chassis.cmd);
|
||||
// osMessageQueuePut(task_runtime.msgq.chassis.cmd, cmd_for_chassis, 0, 0);
|
||||
// }
|
||||
|
||||
// }
|
||||
|
||||
|
||||
|
||||
/* ========================================================================== */
|
||||
/* 架构说明 */
|
||||
/* ========================================================================== */
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
module_name,description
|
||||
cmd,命令系统,用于机器人指令处理和行为控制
|
||||
2_axis_gimbal,双轴云台控制模块,支持pitch和yaw轴控制
|
||||
3+3shoot,双级三摩擦轮发射机构模块
|
||||
|
658
assets/User_code/module/shoot/3+3shoot/shoot.c
Normal file
658
assets/User_code/module/shoot/3+3shoot/shoot.c
Normal file
@ -0,0 +1,658 @@
|
||||
/*
|
||||
* far♂蛇模块
|
||||
*/
|
||||
|
||||
/********************************* 使用示例 **********************************/
|
||||
/*1.配置config参数以及Config_ShootInit函数参数*/
|
||||
/*2.
|
||||
COMP_AT9S_CMD_t shoot_ctrl_cmd_rc;
|
||||
Shoot_t shoot;
|
||||
Shoot_CMD_t shoot_cmd;
|
||||
|
||||
void Task(void *argument) {
|
||||
|
||||
Config_ShootInit();
|
||||
Shoot_Init(&shoot,&Config_GetRobotParam()->shoot_param,SHOOT_CTRL_FREQ);
|
||||
Shoot_SetMode(&shoot,SHOOT_MODE_SINGLE); 关于模式选择:初始化一个模式
|
||||
|
||||
while (1) {
|
||||
|
||||
shoot_cmd.online =shoot_ctrl_cmd_rc.online;
|
||||
shoot_cmd.ready =shoot_ctrl_cmd_rc.shoot.ready;
|
||||
shoot_cmd.firecmd =shoot_ctrl_cmd_rc.shoot.firecmd;
|
||||
|
||||
shoot.mode =shoot_ctrl_cmd_rc.mode; 关于模式选择:或者用遥控器随时切换模式,二选一
|
||||
|
||||
Chassis_UpdateFeedback(&shoot);
|
||||
Shoot_Control(&shoot,&shoot_cmd);
|
||||
}
|
||||
}
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "shoot.h"
|
||||
#include "bsp/mm.h"
|
||||
#include "bsp/time.h"
|
||||
#include "component/filter.h"
|
||||
#include "component/user_math.h"
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
#define MAX_FRIC_RPM 7000.0f
|
||||
#define MAX_TRIG_RPM 1500.0f//这里可能也会影响最高发射频率,待测试
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
static bool last_firecmd;
|
||||
|
||||
float maxTrigrpm=1500.0f;
|
||||
/* Private function -------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* \brief 设置射击模式
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
* \param mode 要设置的模式
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_SetMode(Shoot_t *s, Shoot_Mode_t mode)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
s->mode=mode;
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 重置PID积分
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_ResetIntegral(Shoot_t *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
uint8_t fric_num = s->param->basic.fric_num;
|
||||
for(int i=0;i<fric_num;i++)
|
||||
{
|
||||
PID_ResetIntegral(&s->pid.fric_follow[i]);
|
||||
PID_ResetIntegral(&s->pid.fric_err[i]);
|
||||
}
|
||||
PID_ResetIntegral(&s->pid.trig);
|
||||
PID_ResetIntegral(&s->pid.trig_omg);
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 重置计算模块
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_ResetCalu(Shoot_t *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
uint8_t fric_num = s->param->basic.fric_num;
|
||||
for(int i=0;i<fric_num;i++)
|
||||
{
|
||||
PID_Reset(&s->pid.fric_follow[i]);
|
||||
PID_Reset(&s->pid.fric_err[i]);
|
||||
LowPassFilter2p_Reset(&s->filter.fric.in[i], 0.0f);
|
||||
LowPassFilter2p_Reset(&s->filter.fric.out[i], 0.0f);
|
||||
}
|
||||
PID_Reset(&s->pid.trig);
|
||||
PID_Reset(&s->pid.trig_omg);
|
||||
LowPassFilter2p_Reset(&s->filter.trig.in, 0.0f);
|
||||
LowPassFilter2p_Reset(&s->filter.trig.out, 0.0f);
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 重置输出
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_ResetOutput(Shoot_t *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
uint8_t fric_num = s->param->basic.fric_num;
|
||||
for(int i=0;i<fric_num;i++)
|
||||
{
|
||||
s->output.out_follow[i]=0.0f;
|
||||
s->output.out_err[i]=0.0f;
|
||||
s->output.out_fric[i]=0.0f;
|
||||
s->output.lpfout_fric[i]=0.0f;
|
||||
}
|
||||
s->output.outagl_trig=0.0f;
|
||||
s->output.outomg_trig=0.0f;
|
||||
s->output.outlpf_trig=0.0f;
|
||||
return SHOOT_OK;
|
||||
}
|
||||
//float last_angle=0.0f;
|
||||
//float speed=0.0f;
|
||||
//int8_t Shoot_CalufeedbackRPM(Shoot_t *s)
|
||||
//{
|
||||
// if (s == NULL) {
|
||||
// return SHOOT_ERR_NULL; // 参数错误
|
||||
// }
|
||||
//// static
|
||||
// float err;
|
||||
// err=CircleError(s->feedback.fric[0].rotor_abs_angle,last_angle,M_2PI);
|
||||
// speed=err/s->dt/M_2PI*60.0f;
|
||||
// last_angle=s->feedback.fric->rotor_abs_angle;
|
||||
|
||||
|
||||
// return SHOOT_OK;
|
||||
//}
|
||||
|
||||
/**
|
||||
* \brief 根据目标弹丸速度计算摩擦轮目标转速
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
* \param target_speed 目标弹丸速度,单位m/s
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_CaluTargetRPM(Shoot_t *s, float target_speed)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
switch(s->param->basic.projectileType)
|
||||
{
|
||||
case SHOOT_PROJECTILE_17MM:
|
||||
s->target_variable.fric_rpm=5000.0f;
|
||||
break;
|
||||
case SHOOT_PROJECTILE_42MM:
|
||||
s->target_variable.fric_rpm=4000.0f;
|
||||
break;
|
||||
}
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 根据发射弹丸数量及发射频率计算拨弹电机目标角度
|
||||
*
|
||||
* \param s 包含发射数据的结构体
|
||||
* \param cmd 包含射击指令的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_CaluTargetAngle(Shoot_t *s, Shoot_CMD_t *cmd)
|
||||
{
|
||||
if (s == NULL || s->var_trig.num_toShoot == 0) {
|
||||
return SHOOT_ERR_NULL;
|
||||
}
|
||||
float dt = s->timer.now - s->var_trig.time_lastShoot;
|
||||
float dpos;
|
||||
dpos = CircleError(s->target_variable.trig_angle, s->var_trig.trig_agl, M_2PI);
|
||||
if(dt >= 1.0f/s->param->basic.shot_freq && cmd->firecmd && dpos<=1.0f)
|
||||
{
|
||||
s->var_trig.time_lastShoot=s->timer.now;
|
||||
CircleAdd(&s->target_variable.trig_angle, M_2PI/s->param->basic.num_trig_tooth, M_2PI);
|
||||
s->var_trig.num_toShoot--;
|
||||
}
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
static float Shoot_CaluCoupledWeight(Shoot_t *s, uint8_t fric_index)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
|
||||
float Threshold;
|
||||
switch (s->param->basic.projectileType) {
|
||||
case SHOOT_PROJECTILE_17MM:
|
||||
Threshold=50.0f;
|
||||
break;
|
||||
case SHOOT_PROJECTILE_42MM:
|
||||
Threshold=400.0f;
|
||||
break;
|
||||
default:
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
float err;
|
||||
err=fabs((s->param->basic.ratio_multilevel[fric_index]
|
||||
*s->target_variable.fric_rpm)
|
||||
-s->feedback.fric[fric_index].rotor_speed);
|
||||
if (err<Threshold)
|
||||
{
|
||||
s->var_fric.coupled_control_weights=1.0f-(err*err)/(Threshold*Threshold);
|
||||
}
|
||||
else
|
||||
{
|
||||
s->var_fric.coupled_control_weights=0.0f;
|
||||
}
|
||||
return s->var_fric.coupled_control_weights;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 更新射击模块的电机反馈信息
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_UpdateFeedback(Shoot_t *s)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
uint8_t fric_num = s->param->basic.fric_num;
|
||||
for(int i = 0; i < fric_num; i++) {
|
||||
/* 更新摩擦轮电机反馈 */
|
||||
MOTOR_RM_Update(&s->param->motor.fric[i].param);
|
||||
MOTOR_RM_t *motor_fed = MOTOR_RM_GetMotor(&s->param->motor.fric[i].param);
|
||||
if(motor_fed!=NULL)
|
||||
{
|
||||
s->feedback.fric[i]=motor_fed->motor.feedback;
|
||||
}
|
||||
/* 滤波摩擦轮电机转速反馈 */
|
||||
s->var_fric.fil_rpm[i] = LowPassFilter2p_Apply(&s->filter.fric.in[i], s->feedback.fric[i].rotor_speed);
|
||||
/* 归一化摩擦轮电机转速反馈 */
|
||||
s->var_fric.normalized_fil_rpm[i] = s->var_fric.fil_rpm[i] / MAX_FRIC_RPM;
|
||||
if(s->var_fric.normalized_fil_rpm[i]>1.0f)s->var_fric.normalized_fil_rpm[i]=1.0f;
|
||||
if(s->var_fric.normalized_fil_rpm[i]<-1.0f)s->var_fric.normalized_fil_rpm[i]=-1.0f;
|
||||
/* 计算平均摩擦轮电机转速反馈 */
|
||||
s->var_fric.normalized_fil_avgrpm[s->param->motor.fric[i].level-1]+=s->var_fric.normalized_fil_rpm[i];
|
||||
}
|
||||
for (int i=1; i<MAX_NUM_MULTILEVEL; i++)
|
||||
{
|
||||
s->var_fric.normalized_fil_avgrpm[i]=s->var_fric.normalized_fil_avgrpm[i]/fric_num/MAX_NUM_MULTILEVEL;
|
||||
}
|
||||
/* 更新拨弹电机反馈 */
|
||||
MOTOR_RM_Update(&s->param->motor.trig);
|
||||
s->feedback.trig = *MOTOR_RM_GetMotor(&s->param->motor.trig);
|
||||
s->var_trig.trig_agl=s->param->basic.extra_deceleration_ratio*s->feedback.trig.gearbox_total_angle;
|
||||
while(s->var_trig.trig_agl<0)s->var_trig.trig_agl+=M_2PI;
|
||||
while(s->var_trig.trig_agl>=M_2PI)s->var_trig.trig_agl-=M_2PI;
|
||||
if (s->feedback.trig.motor.reverse) {
|
||||
s->var_trig.trig_agl = M_2PI - s->var_trig.trig_agl;
|
||||
}
|
||||
s->var_trig.fil_trig_rpm = LowPassFilter2p_Apply(&s->filter.trig.in, s->feedback.trig.feedback.rotor_speed);
|
||||
s->var_trig.trig_rpm = s->feedback.trig.feedback.rotor_speed / maxTrigrpm;
|
||||
if(s->var_trig.trig_rpm>1.0f)s->var_trig.trig_rpm=1.0f;
|
||||
if(s->var_trig.trig_rpm<-1.0f)s->var_trig.trig_rpm=-1.0f;
|
||||
|
||||
s->errtosee = s->feedback.fric[0].rotor_speed - s->feedback.fric[1].rotor_speed;
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 射击模块运行状态机
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
* \param cmd 包含射击指令的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/float a;
|
||||
int8_t Shoot_RunningFSM(Shoot_t *s, Shoot_CMD_t *cmd)
|
||||
{
|
||||
if (s == NULL || cmd == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
uint8_t fric_num = s->param->basic.fric_num;
|
||||
static float pos;
|
||||
if(s->mode==SHOOT_MODE_SAFE){
|
||||
for(int i=0;i<fric_num;i++)
|
||||
{
|
||||
MOTOR_RM_Relax(&s->param->motor.fric[i].param);
|
||||
}
|
||||
MOTOR_RM_Relax(&s->param->motor.trig);\
|
||||
pos=s->target_variable.trig_angle=s->var_trig.trig_agl;
|
||||
}
|
||||
else{
|
||||
switch(s->running_state)
|
||||
{
|
||||
case SHOOT_STATE_IDLE:/*熄火等待*/
|
||||
for(int i=0;i<fric_num;i++)
|
||||
{ /* 转速归零 */
|
||||
PID_ResetIntegral(&s->pid.fric_follow[i]);
|
||||
s->output.out_follow[i]=PID_Calc(&s->pid.fric_follow[i],0.0f,s->var_fric.normalized_fil_rpm[i],0,s->timer.dt);
|
||||
s->output.out_fric[i]=s->output.out_follow[i];
|
||||
s->output.lpfout_fric[i] = LowPassFilter2p_Apply(&s->filter.fric.out[i], s->output.out_fric[i]);
|
||||
MOTOR_RM_SetOutput(&s->param->motor.fric[i].param, s->output.lpfout_fric[i]);
|
||||
}
|
||||
|
||||
s->output.outagl_trig =PID_Calc(&s->pid.trig,pos,s->var_trig.trig_agl,0,s->timer.dt);
|
||||
s->output.outomg_trig =PID_Calc(&s->pid.trig_omg,s->output.outagl_trig,s->var_trig.trig_rpm,0,s->timer.dt);
|
||||
s->output.outlpf_trig =LowPassFilter2p_Apply(&s->filter.trig.out, s->output.outomg_trig);
|
||||
MOTOR_RM_SetOutput(&s->param->motor.trig, s->output.outlpf_trig);
|
||||
|
||||
/* 检查状态机 */
|
||||
if(cmd->ready)
|
||||
{
|
||||
Shoot_ResetCalu(s);
|
||||
Shoot_ResetIntegral(s);
|
||||
Shoot_ResetOutput(s);
|
||||
s->running_state=SHOOT_STATE_READY;
|
||||
}
|
||||
break;
|
||||
|
||||
case SHOOT_STATE_READY:/*准备射击*/
|
||||
for(int i=0;i<fric_num;i++)
|
||||
{
|
||||
uint8_t level=s->param->motor.fric[i].level-1;
|
||||
float target_rpm=s->param->basic.ratio_multilevel[level]
|
||||
*s->target_variable.fric_rpm/MAX_FRIC_RPM;
|
||||
/* 计算耦合控制权重 */
|
||||
float w=Shoot_CaluCoupledWeight(s,i);
|
||||
/* 计算跟随输出、计算修正输出 */
|
||||
s->output.out_follow[i]=PID_Calc(&s->pid.fric_follow[i],
|
||||
target_rpm,
|
||||
s->var_fric.normalized_fil_rpm[i],
|
||||
0,
|
||||
s->timer.dt);
|
||||
s->output.out_err[i]=w*PID_Calc(&s->pid.fric_err[i],
|
||||
s->var_fric.normalized_fil_avgrpm[s->param->motor.fric[i].level-1],
|
||||
s->var_fric.normalized_fil_rpm[i],
|
||||
0,
|
||||
s->timer.dt);
|
||||
/* 按比例缩放并加和输出 */
|
||||
ScaleSumTo1(&s->output.out_follow[i], &s->output.out_err[i]);
|
||||
s->output.out_fric[i]=s->output.out_follow[i]+s->output.out_err[i];
|
||||
/* 滤波 */
|
||||
s->output.lpfout_fric[i] = LowPassFilter2p_Apply(&s->filter.fric.out[i], s->output.out_fric[i]);
|
||||
/* 设置输出 */
|
||||
MOTOR_RM_SetOutput(&s->param->motor.fric[i].param, s->output.lpfout_fric[i]);
|
||||
}
|
||||
/* 设置拨弹电机输出 */
|
||||
s->output.outagl_trig =PID_Calc(&s->pid.trig,
|
||||
pos,
|
||||
s->var_trig.trig_agl,
|
||||
0,
|
||||
s->timer.dt);
|
||||
s->output.outomg_trig =PID_Calc(&s->pid.trig_omg,
|
||||
s->output.outagl_trig,
|
||||
s->var_trig.trig_rpm,
|
||||
0,
|
||||
s->timer.dt);
|
||||
s->output.outlpf_trig =LowPassFilter2p_Apply(&s->filter.trig.out, s->output.outomg_trig);
|
||||
MOTOR_RM_SetOutput(&s->param->motor.trig, s->output.outlpf_trig);
|
||||
|
||||
/* 检查状态机 */
|
||||
if(!cmd->ready)
|
||||
{
|
||||
Shoot_ResetCalu(s);
|
||||
Shoot_ResetOutput(s);
|
||||
s->running_state=SHOOT_STATE_IDLE;
|
||||
}
|
||||
else if(last_firecmd==false&&cmd->firecmd==true)
|
||||
{
|
||||
s->running_state=SHOOT_STATE_FIRE;
|
||||
/* 根据模式设置待发射弹数 */
|
||||
switch(s->mode)
|
||||
{
|
||||
case SHOOT_MODE_SINGLE:
|
||||
s->var_trig.num_toShoot=1;
|
||||
break;
|
||||
case SHOOT_MODE_BURST:
|
||||
s->var_trig.num_toShoot=s->param->basic.shot_burst_num;
|
||||
break;
|
||||
case SHOOT_MODE_CONTINUE:
|
||||
s->var_trig.num_toShoot=6666;
|
||||
break;
|
||||
default:
|
||||
s->var_trig.num_toShoot=0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SHOOT_STATE_FIRE:/*射击*/
|
||||
Shoot_CaluTargetAngle(s, cmd);
|
||||
for(int i=0;i<fric_num;i++)
|
||||
{
|
||||
uint8_t level=s->param->motor.fric[i].level-1;
|
||||
float target_rpm=s->param->basic.ratio_multilevel[level]
|
||||
*s->target_variable.fric_rpm/MAX_FRIC_RPM;
|
||||
/* 计算耦合控制权重 */
|
||||
float w=Shoot_CaluCoupledWeight(s,i);
|
||||
/* 计算跟随输出、计算修正输出 */
|
||||
s->output.out_follow[i]=PID_Calc(&s->pid.fric_follow[i],
|
||||
target_rpm,
|
||||
s->var_fric.normalized_fil_rpm[i],
|
||||
0,
|
||||
s->timer.dt);
|
||||
s->output.out_err[i]=w*PID_Calc(&s->pid.fric_err[i],
|
||||
s->var_fric.normalized_fil_avgrpm[s->param->motor.fric[i].level-1],
|
||||
s->var_fric.normalized_fil_rpm[i],
|
||||
0,
|
||||
s->timer.dt);
|
||||
/* 按比例缩放并加和输出 */
|
||||
ScaleSumTo1(&s->output.out_follow[i], &s->output.out_err[i]);
|
||||
s->output.out_fric[i]=s->output.out_follow[i]+s->output.out_err[i];
|
||||
/* 滤波 */
|
||||
s->output.lpfout_fric[i] = LowPassFilter2p_Apply(&s->filter.fric.out[i], s->output.out_fric[i]);
|
||||
/* 设置输出 */
|
||||
MOTOR_RM_SetOutput(&s->param->motor.fric[i].param, s->output.lpfout_fric[i]);
|
||||
}
|
||||
/* 设置拨弹电机输出 */
|
||||
s->output.outagl_trig =PID_Calc(&s->pid.trig,
|
||||
s->target_variable.trig_angle,
|
||||
s->var_trig.trig_agl,
|
||||
0,
|
||||
s->timer.dt);
|
||||
s->output.outomg_trig =PID_Calc(&s->pid.trig_omg,
|
||||
s->output.outagl_trig,
|
||||
s->var_trig.trig_rpm,
|
||||
0,
|
||||
s->timer.dt);
|
||||
s->output.outlpf_trig =LowPassFilter2p_Apply(&s->filter.trig.out, s->output.outomg_trig);
|
||||
MOTOR_RM_SetOutput(&s->param->motor.trig, s->output.outlpf_trig);
|
||||
|
||||
/* 检查状态机 */
|
||||
if(!cmd->firecmd)
|
||||
{
|
||||
s->running_state=SHOOT_STATE_READY;
|
||||
pos=s->var_trig.trig_agl;
|
||||
s->var_trig.num_toShoot=0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
s->running_state=SHOOT_STATE_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* 输出 */
|
||||
MOTOR_RM_Ctrl(&s->param->motor.fric[0].param);
|
||||
if(s->param->basic.fric_num>4)
|
||||
{
|
||||
MOTOR_RM_Ctrl(&s->param->motor.fric[4].param);
|
||||
}
|
||||
MOTOR_RM_Ctrl(&s->param->motor.trig);
|
||||
last_firecmd = cmd->firecmd;
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 射击模块堵塞检测状态机
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
* \param cmd 包含射击指令的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_JamDetectionFSM(Shoot_t *s, Shoot_CMD_t *cmd)
|
||||
{
|
||||
if (s == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
if(s->param->jamDetection.enable){
|
||||
switch (s->jamdetection.fsmState) {
|
||||
case SHOOT_JAMFSM_STATE_NORMAL:/* 正常运行 */
|
||||
/* 检测电流是否超过阈值 */
|
||||
if (s->feedback.trig.feedback.torque_current/1000.0f > s->param->jamDetection.threshold) {
|
||||
s->jamdetection.fsmState = SHOOT_JAMFSM_STATE_SUSPECTED;
|
||||
s->jamdetection.lastTime = s->timer.now; /* 记录怀疑开始时间 */
|
||||
}
|
||||
/* 正常运行射击状态机 */
|
||||
Shoot_RunningFSM(s, cmd);
|
||||
break;
|
||||
case SHOOT_JAMFSM_STATE_SUSPECTED:/* 怀疑堵塞 */
|
||||
/* 检测电流是否低于阈值 */
|
||||
if (s->feedback.trig.feedback.torque_current/1000.0f < s->param->jamDetection.threshold) {
|
||||
s->jamdetection.fsmState = SHOOT_JAMFSM_STATE_NORMAL;
|
||||
break;
|
||||
}
|
||||
/* 检测高阈值状态是否超过设定怀疑时间 */
|
||||
else if ((s->timer.now - s->jamdetection.lastTime) >= s->param->jamDetection.suspectedTime) {
|
||||
s->jamdetection.detected =true;
|
||||
s->jamdetection.fsmState = SHOOT_JAMFSM_STATE_CONFIRMED;
|
||||
break;
|
||||
}
|
||||
/* 正常运行射击状态机 */
|
||||
Shoot_RunningFSM(s, cmd);
|
||||
break;
|
||||
case SHOOT_JAMFSM_STATE_CONFIRMED:/* 确认堵塞 */
|
||||
/* 清空待发射弹 */
|
||||
s->var_trig.num_toShoot=0;
|
||||
/* 修改拨弹盘目标角度 */
|
||||
s->target_variable.trig_angle = s->var_trig.trig_agl-(M_2PI/s->param->basic.num_trig_tooth);
|
||||
/* 切换状态 */
|
||||
s->jamdetection.fsmState = SHOOT_JAMFSM_STATE_DEAL;
|
||||
/* 记录处理开始时间 */
|
||||
s->jamdetection.lastTime = s->timer.now;
|
||||
case SHOOT_JAMFSM_STATE_DEAL:/* 堵塞处理 */
|
||||
/* 正常运行射击状态机 */
|
||||
Shoot_RunningFSM(s, cmd);
|
||||
/* 给予0.3秒响应时间并检测电流小于20A,认为堵塞已解除 */
|
||||
if ((s->timer.now - s->jamdetection.lastTime)>=0.3f&&s->feedback.trig.feedback.torque_current/1000.0f < 20.0f) {
|
||||
s->jamdetection.fsmState = SHOOT_JAMFSM_STATE_NORMAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
s->jamdetection.fsmState = SHOOT_JAMFSM_STATE_NORMAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
s->jamdetection.fsmState = SHOOT_JAMFSM_STATE_NORMAL;
|
||||
s->jamdetection.detected = false;
|
||||
Shoot_RunningFSM(s, cmd);
|
||||
}
|
||||
|
||||
return SHOOT_OK;
|
||||
}
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
/**
|
||||
* \brief 初始化射击模块
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
* \param param 包含射击参数的结构体
|
||||
* \param target_freq 控制循环频率,单位Hz
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_Init(Shoot_t *s, Shoot_Params_t *param, float target_freq)
|
||||
{
|
||||
if (s == NULL || param == NULL || target_freq <= 0.0f) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
uint8_t fric_num = param->basic.fric_num;
|
||||
s->param=param;
|
||||
BSP_CAN_Init();
|
||||
/* 初始化摩擦轮PID和滤波器 */
|
||||
for(int i=0;i<fric_num;i++){
|
||||
MOTOR_RM_Register(¶m->motor.fric[i].param);
|
||||
PID_Init(&s->pid.fric_follow[i],
|
||||
KPID_MODE_CALC_D,
|
||||
target_freq,
|
||||
¶m->pid.fric_follow);
|
||||
PID_Init(&s->pid.fric_err[i],
|
||||
KPID_MODE_CALC_D,
|
||||
target_freq,
|
||||
¶m->pid.fric_err);
|
||||
LowPassFilter2p_Init(&s->filter.fric.in[i],
|
||||
target_freq,
|
||||
s->param->filter.fric.in);
|
||||
LowPassFilter2p_Init(&s->filter.fric.out[i],
|
||||
target_freq,
|
||||
s->param->filter.fric.out);
|
||||
}
|
||||
/* 初始化拨弹PID和滤波器 */
|
||||
MOTOR_RM_Register(¶m->motor.trig);
|
||||
switch(s->param->motor.trig.module)
|
||||
{
|
||||
case MOTOR_M3508:
|
||||
PID_Init(&s->pid.trig,
|
||||
KPID_MODE_CALC_D,
|
||||
target_freq,
|
||||
¶m->pid.trig_3508);
|
||||
PID_Init(&s->pid.trig_omg,
|
||||
KPID_MODE_CALC_D,
|
||||
target_freq,
|
||||
¶m->pid.trig_omg_3508);
|
||||
break;
|
||||
case MOTOR_M2006:
|
||||
PID_Init(&s->pid.trig,
|
||||
KPID_MODE_CALC_D,
|
||||
target_freq,
|
||||
¶m->pid.trig_2006);
|
||||
PID_Init(&s->pid.trig_omg,
|
||||
KPID_MODE_CALC_D,
|
||||
target_freq,
|
||||
¶m->pid.trig_omg_2006);
|
||||
break;
|
||||
default:
|
||||
return SHOOT_ERR_MOTOR;
|
||||
break;
|
||||
}
|
||||
LowPassFilter2p_Init(&s->filter.trig.in,
|
||||
target_freq,
|
||||
s->param->filter.trig.in);
|
||||
LowPassFilter2p_Init(&s->filter.trig.out,
|
||||
target_freq,
|
||||
s->param->filter.trig.out);
|
||||
|
||||
/* 归零变量 */
|
||||
memset(&s->var_trig,0,sizeof(s->var_trig));
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief 射击模块控制主函数
|
||||
*
|
||||
* \param s 包含射击数据的结构体
|
||||
* \param cmd 包含射击指令的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_Control(Shoot_t *s, Shoot_CMD_t *cmd)
|
||||
{
|
||||
if (s == NULL || cmd == NULL) {
|
||||
return SHOOT_ERR_NULL; // 参数错误
|
||||
}
|
||||
s->timer.now = BSP_TIME_Get_us() / 1000000.0f;
|
||||
s->timer.dt = (BSP_TIME_Get_us() - s->timer.lask_wakeup) / 1000000.0f;
|
||||
s->timer.lask_wakeup = BSP_TIME_Get_us();
|
||||
Shoot_CaluTargetRPM(s,233);
|
||||
|
||||
Shoot_JamDetectionFSM(s, cmd);
|
||||
// Shoot_CalufeedbackRPM(s);
|
||||
return SHOOT_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
243
assets/User_code/module/shoot/3+3shoot/shoot.h
Normal file
243
assets/User_code/module/shoot/3+3shoot/shoot.h
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* far♂蛇模块
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "main.h"
|
||||
#include "component/pid.h"
|
||||
#include "device/motor_rm.h"
|
||||
/* Exported constants ------------------------------------------------------- */
|
||||
#define MAX_FRIC_NUM 6
|
||||
#define MAX_NUM_MULTILEVEL 2 /* 多级发射级数 */
|
||||
|
||||
#define SHOOT_OK (0) /* 运行正常 */
|
||||
#define SHOOT_ERR_NULL (-1) /* 运行时发现NULL指针 */
|
||||
#define SHOOT_ERR_ERR (-2) /* 运行时发现了其他错误 */
|
||||
#define SHOOT_ERR_MODE (-3) /* 运行时配置了错误的Mode */
|
||||
#define SHOOT_ERR_MOTOR (-4) /* 运行时配置了不存在的电机类型 */
|
||||
#define SHOOT_ERR_MALLOC (-5) /* 内存分配失败 */
|
||||
/* Exported macro ----------------------------------------------------------- */
|
||||
/* Exported types ----------------------------------------------------------- */
|
||||
typedef enum {
|
||||
SHOOT_JAMFSM_STATE_NORMAL = 0,/* 常规状态 */
|
||||
SHOOT_JAMFSM_STATE_SUSPECTED, /* 怀疑状态 */
|
||||
SHOOT_JAMFSM_STATE_CONFIRMED, /* 确认状态 */
|
||||
SHOOT_JAMFSM_STATE_DEAL /* 处理状态 */
|
||||
}Shoot_JamDetectionFSM_State_t;
|
||||
typedef enum {
|
||||
SHOOT_STATE_IDLE = 0,/* 熄火 */
|
||||
SHOOT_STATE_READY, /* 准备射击 */
|
||||
SHOOT_STATE_FIRE /* 射击 */
|
||||
}Shoot_Running_State_t;
|
||||
|
||||
typedef enum {
|
||||
SHOOT_MODE_SAFE = 0,/* 安全模式 */
|
||||
SHOOT_MODE_SINGLE, /* 单发模式 */
|
||||
SHOOT_MODE_BURST, /* 多发模式 */
|
||||
SHOOT_MODE_CONTINUE,/* 连发模式 */
|
||||
SHOOT_MODE_NUM
|
||||
}Shoot_Mode_t;
|
||||
|
||||
typedef enum {
|
||||
SHOOT_PROJECTILE_17MM,
|
||||
SHOOT_PROJECTILE_42MM,
|
||||
}Shoot_Projectile_t;
|
||||
|
||||
typedef struct{
|
||||
MOTOR_RM_Param_t param;
|
||||
uint8_t level; /* 电机属于第几级发射;1起始 */
|
||||
}Shoot_MOTOR_RM_Param_t;
|
||||
|
||||
typedef struct {
|
||||
MOTOR_Feedback_t fric[MAX_FRIC_NUM];/* 摩擦轮电机反馈 */
|
||||
MOTOR_RM_t trig; /* 拨弹电机反馈 */
|
||||
|
||||
}Shoot_Feedback_t;
|
||||
|
||||
typedef struct{
|
||||
float fil_rpm[MAX_FRIC_NUM]; /* 滤波后的摩擦轮原始转速 */
|
||||
float normalized_fil_rpm[MAX_FRIC_NUM]; /* 归一化摩擦轮转速 */
|
||||
float normalized_fil_avgrpm[MAX_NUM_MULTILEVEL]; /* 归一化摩擦轮平均转速 */
|
||||
float coupled_control_weights; /* 耦合控制权重 */
|
||||
}Shoot_VARSForFricCtrl_t;
|
||||
|
||||
typedef struct{
|
||||
float time_lastShoot;/* 上次射击时间 */
|
||||
uint16_t num_toShoot;/* 剩余待发射弹数 */
|
||||
uint16_t num_shooted;/* 已发射弹数 */
|
||||
|
||||
float trig_agl; /*计算所有减速比后的拨弹盘的角度*/
|
||||
float fil_trig_rpm; /* 滤波后的拨弹电机转速*/
|
||||
float trig_rpm; /* 归一化拨弹电机转速 */
|
||||
}Shoot_VARSForTrigCtrl_t;
|
||||
|
||||
typedef struct {
|
||||
bool detected; /* 卡弹检测结果 */
|
||||
float lastTime;/* 用于记录怀疑状态或处理状态的开始时间 */
|
||||
Shoot_JamDetectionFSM_State_t fsmState; /* 卡弹检测状态机 */
|
||||
}Shoot_JamDetection_t;
|
||||
typedef struct {
|
||||
float out_follow[MAX_FRIC_NUM];
|
||||
float out_err[MAX_FRIC_NUM];
|
||||
float out_fric[MAX_FRIC_NUM];
|
||||
float lpfout_fric[MAX_FRIC_NUM];
|
||||
|
||||
float outagl_trig;
|
||||
float outomg_trig;
|
||||
float outlpf_trig;
|
||||
}Shoot_Output_t;
|
||||
|
||||
typedef struct {
|
||||
Shoot_Mode_t mode;/* 射击模式 */
|
||||
bool ready; /* 准备射击 */
|
||||
bool firecmd; /* 射击 */
|
||||
}Shoot_CMD_t;
|
||||
/* 底盘参数的结构体,包含所有初始化用的参数,通常是const,存好几组 */
|
||||
typedef struct {
|
||||
struct{
|
||||
Shoot_Projectile_t projectileType; /* 发射弹丸类型 */;
|
||||
size_t fric_num; /* 摩擦轮电机数量 */
|
||||
float ratio_multilevel[MAX_NUM_MULTILEVEL]; /* 多级发射各级速度比例 */
|
||||
float extra_deceleration_ratio; /*电机出轴到拨盘的额外减速比;没有写1*/
|
||||
size_t num_trig_tooth; /* 拨弹盘每圈弹丸数量 */
|
||||
float shot_freq; /* 射击频率,单位Hz */
|
||||
size_t shot_burst_num; /* 多发模式一次射击的数量 */
|
||||
}basic;/* 发射基础参数 */
|
||||
struct {
|
||||
bool enable; /* 是否启用卡弹检测 */
|
||||
float threshold; /* 卡弹检测阈值,单位A (dji2006建议设置为120A,dji3508建议设置为235A,根据实际测试调整)*/
|
||||
float suspectedTime;/* 卡弹怀疑时间,单位秒 */
|
||||
}jamDetection;/* 卡弹检测参数 */
|
||||
struct {
|
||||
Shoot_MOTOR_RM_Param_t fric[MAX_FRIC_NUM];
|
||||
MOTOR_RM_Param_t trig;
|
||||
}motor; /* 电机参数 */
|
||||
struct{
|
||||
KPID_Params_t fric_follow; /* 摩擦轮电机PID控制参数,用于跟随目标速度 */
|
||||
KPID_Params_t fric_err; /* 摩擦轮电机PID控制参数,用于消除转速误差 */
|
||||
KPID_Params_t trig_2006; /* 拨弹电机PID控制参数 */
|
||||
KPID_Params_t trig_omg_2006;/* 拨弹电机PID控制参数 */
|
||||
KPID_Params_t trig_3508; /* 拨弹电机PID控制参数 */
|
||||
KPID_Params_t trig_omg_3508;/* 拨弹电机PID控制参数 */
|
||||
}pid; /* PID参数 */
|
||||
struct {
|
||||
struct{
|
||||
float in; /* 反馈值滤波器截止频率 */
|
||||
float out; /* 输出值滤波器截止频率 */
|
||||
}fric;
|
||||
struct{
|
||||
float in; /* 反馈值滤波器截止频率 */
|
||||
float out; /* 输出值滤波器截止频率 */
|
||||
}trig;
|
||||
} filter;/* 滤波器截止频率参数 */
|
||||
} Shoot_Params_t;
|
||||
|
||||
typedef struct {
|
||||
float now; /* 当前时间,单位秒 */
|
||||
uint64_t lask_wakeup; /* 上次唤醒时间,单位微秒 */
|
||||
float dt; /* 两次唤醒间隔时间,单位秒 */
|
||||
}Shoot_Timer_t;
|
||||
|
||||
/*
|
||||
* 运行的主结构体,所有这个文件里的函数都在操作这个结构体
|
||||
* 包含了初始化参数,中间变量,输出变量
|
||||
*/
|
||||
typedef struct {
|
||||
Shoot_Timer_t timer; /* 计时器 */
|
||||
Shoot_Params_t *param; /* 发射参数 */
|
||||
/* 模块通用 */
|
||||
Shoot_Mode_t mode; /* 射击模式 */
|
||||
/* 反馈信息 */
|
||||
Shoot_Feedback_t feedback;
|
||||
/* 控制信息*/
|
||||
Shoot_Running_State_t running_state; /* 运行状态机 */
|
||||
Shoot_JamDetection_t jamdetection; /* 卡弹检测控制信息 */
|
||||
Shoot_VARSForFricCtrl_t var_fric; /* 摩擦轮控制信息 */
|
||||
Shoot_VARSForTrigCtrl_t var_trig; /* 角度计算控制信息 */
|
||||
Shoot_Output_t output; /* 输出信息 */
|
||||
/* 目标控制量 */
|
||||
struct {
|
||||
float fric_rpm; /* 目标摩擦轮转速 */
|
||||
float trig_angle;/* 目标拨弹位置 */
|
||||
}target_variable;
|
||||
|
||||
/* 反馈控制用的PID */
|
||||
struct {
|
||||
KPID_t fric_follow[MAX_FRIC_NUM];/* 摩擦轮PID主结构体 */
|
||||
KPID_t fric_err[MAX_FRIC_NUM]; /* 摩擦轮PID主结构体 */
|
||||
KPID_t trig; /* 拨弹PID主结构体 */
|
||||
KPID_t trig_omg; /* 拨弹PID主结构体 */
|
||||
} pid;
|
||||
|
||||
/* 滤波器 */
|
||||
struct {
|
||||
struct{
|
||||
LowPassFilter2p_t in[MAX_FRIC_NUM]; /* 反馈值滤波器 */
|
||||
LowPassFilter2p_t out[MAX_FRIC_NUM];/* 输出值滤波器 */
|
||||
}fric;
|
||||
struct{
|
||||
LowPassFilter2p_t in; /* 反馈值滤波器 */
|
||||
LowPassFilter2p_t out;/* 输出值滤波器 */
|
||||
}trig;
|
||||
} filter;
|
||||
|
||||
float errtosee; /*调试用*/
|
||||
|
||||
} Shoot_t;
|
||||
|
||||
/* Exported functions prototypes -------------------------------------------- */
|
||||
|
||||
/**
|
||||
* \brief 初始化发射
|
||||
*
|
||||
* \param s 包含发射数据的结构体
|
||||
* \param param 包含发射参数的结构体指针
|
||||
* \param target_freq 任务预期的运行频率
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_Init(Shoot_t *s, Shoot_Params_t *param, float target_freq);
|
||||
|
||||
/**
|
||||
* \brief 设置发射模式
|
||||
*
|
||||
* \param s 包含发射数据的结构体
|
||||
* \param mode 包含发射模式的枚举
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_SetMode(Shoot_t *s, Shoot_Mode_t mode);
|
||||
|
||||
/**
|
||||
* \brief 更新反馈
|
||||
*
|
||||
* \param s 包含发射数据的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_UpdateFeedback(Shoot_t *s);
|
||||
|
||||
/**
|
||||
* \brief 初始化发射
|
||||
*
|
||||
* \param s 包含发射数据的结构体
|
||||
* \param cmd 包含发射命令的结构体
|
||||
*
|
||||
* \return 函数运行结果
|
||||
*/
|
||||
int8_t Shoot_Control(Shoot_t *s, Shoot_CMD_t *cmd);
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@ -18,6 +18,9 @@
|
||||
/* USER STRUCT END */
|
||||
|
||||
/* Private function --------------------------------------------------------- */
|
||||
/* USER PRIVATE CODE BEGIN */
|
||||
|
||||
/* USER PRIVATE CODE END */
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void {{task_function}}(void *argument) {
|
||||
(void)argument; /* 未使用argument,消除警告 */
|
||||
|
||||
96
assets/User_code/task/template_task/atti_esti.c
Normal file
96
assets/User_code/task/template_task/atti_esti.c
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
atti_esti Task
|
||||
带有pwm温控的纯陀螺仪(BMI088)姿态解算任务(无磁力计,赛场环境一般不适用)。
|
||||
控制IMU加热到指定温度防止温漂,收集IMU数据给AHRS算法。
|
||||
收集BMI088的数据,解算后得到四元数,转换为欧拉角之后放到消息队列中,
|
||||
等待其他任务取用。
|
||||
陀螺仪使用前需要校准,校准结果保存在bmi088_cali结构体中,需要自行实现。
|
||||
*/
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "task/user_task.h"
|
||||
/* USER INCLUDE BEGIN */
|
||||
|
||||
#include "bsp/mm.h"
|
||||
#include "bsp/pwm.h"
|
||||
#include "component/ahrs.h"
|
||||
#include "component/pid.h"
|
||||
#include "device/bmi088.h"
|
||||
/* USER INCLUDE END */
|
||||
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
/* USER STRUCT BEGIN */
|
||||
BMI088_t bmi088;
|
||||
AHRS_t gimbal_ahrs;
|
||||
AHRS_Magn_t magn;
|
||||
AHRS_Eulr_t eulr_to_send;
|
||||
KPID_t imu_temp_ctrl_pid;
|
||||
|
||||
/*默认校准参数*/
|
||||
BMI088_Cali_t cali_bmi088 = {
|
||||
.gyro_offset = {0.0f, 0.0f, 0.0f},
|
||||
};
|
||||
|
||||
static const KPID_Params_t imu_temp_ctrl_pid_param = {
|
||||
.k = 0.15f,
|
||||
.p = 1.0f,
|
||||
.i = 0.0f,
|
||||
.d = 0.0f,
|
||||
.i_limit = 1.0f,
|
||||
.out_limit = 1.0f,
|
||||
};
|
||||
|
||||
/* USER STRUCT END */
|
||||
|
||||
/* Private function --------------------------------------------------------- */
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void Task_atti_esti(void *argument) {
|
||||
(void)argument; /* 未使用argument,消除警告 */
|
||||
|
||||
|
||||
osDelay(ATTI_ESTI_INIT_DELAY); /* 延时一段时间再开启任务 */
|
||||
|
||||
/* USER CODE INIT BEGIN */
|
||||
BMI088_Init(&bmi088, &cali_bmi088);
|
||||
AHRS_Init(&gimbal_ahrs, &magn, BMI088_GetUpdateFreq(&bmi088));
|
||||
PID_Init(&imu_temp_ctrl_pid, KPID_MODE_NO_D,
|
||||
1.0f / BMI088_GetUpdateFreq(&bmi088), &imu_temp_ctrl_pid_param);
|
||||
BSP_PWM_Start(BSP_PWM_IMU_HEAT);
|
||||
|
||||
/* USER CODE INIT END */
|
||||
|
||||
while (1) {
|
||||
/* USER CODE BEGIN */
|
||||
BMI088_WaitNew();
|
||||
BMI088_AcclStartDmaRecv();
|
||||
BMI088_AcclWaitDmaCplt();
|
||||
|
||||
BMI088_GyroStartDmaRecv();
|
||||
BMI088_GyroWaitDmaCplt();
|
||||
|
||||
/* 锁住RTOS内核防止数据解析过程中断,造成错误 */
|
||||
osKernelLock();
|
||||
/* 接收完所有数据后,把数据从原始字节加工成方便计算的数据 */
|
||||
BMI088_ParseAccl(&bmi088);
|
||||
BMI088_ParseGyro(&bmi088);
|
||||
|
||||
/* 根据设备接收到的数据进行姿态解析 */
|
||||
AHRS_Update(&gimbal_ahrs, &bmi088.accl, &bmi088.gyro, &magn);
|
||||
|
||||
/* 根据解析出来的四元数计算欧拉角 */
|
||||
AHRS_GetEulr(&eulr_to_send, &gimbal_ahrs);
|
||||
osKernelUnlock();
|
||||
|
||||
/* 在此处用消息队列传递imu数据 */
|
||||
/* osMessageQueuePut( ... ); */
|
||||
|
||||
/* 控制IMU加热器 */
|
||||
BSP_PWM_SetComp(BSP_PWM_IMU_HEAT, PID_Calc(&imu_temp_ctrl_pid, 40.5f,
|
||||
bmi088.temp, 0.0f, 0.0f));
|
||||
/* USER CODE END */
|
||||
}
|
||||
|
||||
}
|
||||
52
assets/User_code/task/template_task/cli.c
Normal file
52
assets/User_code/task/template_task/cli.c
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
cli Task
|
||||
|
||||
*/
|
||||
|
||||
/* Includes ----------------------------------------------------------------- */
|
||||
#include "task/user_task.h"
|
||||
/* USER INCLUDE BEGIN */
|
||||
#include "device/mrobot.h"
|
||||
/* USER INCLUDE END */
|
||||
|
||||
/* Private typedef ---------------------------------------------------------- */
|
||||
/* Private define ----------------------------------------------------------- */
|
||||
/* Private macro ------------------------------------------------------------ */
|
||||
/* Private variables -------------------------------------------------------- */
|
||||
/* USER STRUCT BEGIN */
|
||||
|
||||
/* USER STRUCT END */
|
||||
|
||||
/* Private function --------------------------------------------------------- */
|
||||
/* USER PRIVATE CODE BEGIN */
|
||||
/**
|
||||
* @brief hello 命令回调
|
||||
* @note 命令回调必须返回 0 (pdFALSE) 表示完成,返回非0会继续调用
|
||||
*/
|
||||
static long Cli_Hello(char *buffer, size_t size, const char *cmd) {
|
||||
(void)cmd; /* 未使用cmd,消除警告 */
|
||||
MRobot_Snprintf(buffer, size, "Ciallo~(∠・ω< )⌒★\r\n");
|
||||
return 0; /* 返回0表示命令执行完成 */
|
||||
}
|
||||
/* USER PRIVATE CODE END */
|
||||
/* Exported functions ------------------------------------------------------- */
|
||||
void Task_cli(void *argument) {
|
||||
(void)argument; /* 未使用argument,消除警告 */
|
||||
|
||||
|
||||
osDelay(CLI_INIT_DELAY); /* 延时一段时间再开启任务 */
|
||||
|
||||
/* USER CODE INIT BEGIN */
|
||||
/* 初始化 MRobot CLI 系统 */
|
||||
MRobot_Init();
|
||||
MRobot_RegisterCommand("hello", " --hello: 打印问候语\r\n", Cli_Hello, -1);
|
||||
/* USER CODE INIT END */
|
||||
|
||||
while (1) {
|
||||
/* USER CODE BEGIN */
|
||||
/* 运行 MRobot 主循环 */
|
||||
MRobot_Run();
|
||||
/* USER CODE END */
|
||||
}
|
||||
|
||||
}
|
||||
28
assets/User_code/task/template_task/task.yaml
Normal file
28
assets/User_code/task/template_task/task.yaml
Normal file
@ -0,0 +1,28 @@
|
||||
atti_esti:
|
||||
name: "atti_esti"
|
||||
frequency: 1000
|
||||
delay: 0
|
||||
stack: 512
|
||||
freq_control: false
|
||||
description: |
|
||||
带有PWM温控的纯陀螺仪(BMI088)姿态解算任务
|
||||
功能特点:
|
||||
- 控制IMU加热到指定温度防止温漂
|
||||
- 收集BMI088数据给AHRS算法进行姿态解算
|
||||
- 解算后得到四元数,转换为欧拉角放到消息队列
|
||||
- 使用PID控制IMU温度到40.5°C
|
||||
- 运行频率1000Hz,提供高精度姿态信息
|
||||
注意事项:
|
||||
- 陀螺仪使用前需要校准,校准结果保存在bmi088_cali结构体中
|
||||
- 无磁力计版本,适用于干净的电磁环境
|
||||
- 需要配置PWM通道用于IMU加热控制
|
||||
cli:
|
||||
name: "cli"
|
||||
frequency: 500
|
||||
delay: 0
|
||||
stack: 1024
|
||||
freq_control: false
|
||||
description: |
|
||||
命令行接口任务
|
||||
通过串口实现的虚拟终端,配合putty食用更佳
|
||||
需要freertos_cli组件支持,还有mrobot设备驱动
|
||||
Loading…
Reference in New Issue
Block a user