stm32开发之实现代码之间解耦(借助链接文件和关键字section)

前言

  1. 借鉴rt-thread组件自动初始化功能,实现一个组件初始化的模板

代码

头文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-9     shchl   first version
 *
 * @note 链接文件添加
    __os_init_start = .;
    KEEP(*(SORT(.bsp_init_fn*)))
    __os_init_end = .;
 */

#ifndef APP_THREADX_NETXDUO_BSP_AUTO_INIT_H
#define APP_THREADX_NETXDUO_BSP_AUTO_INIT_H
#define bsp_section(x)               __attribute__((section(x)))
#define bsp_used                     __attribute__((used))
typedef int (*init_fn_t)(void);

#define     INIT_EXPORT(fn, level)                                                       \
            bsp_used const init_fn_t __os_init_##fn bsp_section(".bsp_init_fn." level) = fn

void bsp_components_app_init(const init_fn_t *start_ptr,const init_fn_t *end_ptr);

#endif //APP_THREADX_NETXDUO_BSP_AUTO_INIT_H

原文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-9     shchl   first version
 */

#include "bsp.h"

/**
 * @brief 自定义app区间初始化
 * @param start_ptr 起始函数指针地址
 * @param end_ptr   结束函数指针地址
 */
void bsp_components_app_init(const init_fn_t *start_ptr,const init_fn_t *end_ptr) {
    volatile const init_fn_t *fn_ptr;
    for (fn_ptr = start_ptr; fn_ptr < end_ptr; fn_ptr++) {
        (*fn_ptr)();
    }
}

链接文件修改

在这里插入图片描述

示例 以netx duo 应用组件为例(模拟tcp client)

相关宏定义

#define NET_X_APP_EXPORT(fn)    INIT_EXPORT(fn, "8.1")

源文件

static int net_x_duo_component_init_start() {
    /* 初始化NetX */
    nx_system_initialize();
    return NX_SUCCESS;
}

INIT_EXPORT(net_x_duo_component_init_start, "8.0");


static int nex_x_duo_component_init_end() {
    return NX_SUCCESS;
}

INIT_EXPORT(nex_x_duo_component_init_end, "9.0");



/**
  * @brief  Application NetXDuo Initialization.
  * @param memory_ptr: memory pointer
  * @retval int
  */
UINT MX_NetXDuo_Init() {

    bsp_components_app_init(&__os_init_net_x_duo_component_init_start,
                            &__os_init_nex_x_duo_component_init_end);

    return NX_SUCCESS;
}

组件注入

int app_netx_tcp_client_init() {

    tx_log("app_netx_tcp_client_init\r\n");

    return NX_SUCCESS;
}

NET_X_APP_EXPORT(app_netx_tcp_client_init);

通过map映射文件也可以观察出函数地址之间的关系

在这里插入图片描述

执行结果(解耦成功)

在这里插入图片描述

keil里面的话(xxx.sct文件,这个就是连接文件)

在这里插入图片描述

在这里插入图片描述

验证

将组件注入的代码添加到keil工程中

  1. 这里为了简单点,直接添加到main文件中
#include "system.h"
#include "SysTick.h"
#include "usart.h"	
#include "led.h"
#include "tftlcd.h"
#include "picture.h"
#define bsp_section(x)               __attribute__((section(x)))
#define bsp_used                     __attribute__((used))
typedef int (*init_fn_t)(void);

#define     INIT_EXPORT(fn, level)                                                       \
            bsp_used const init_fn_t __os_init_##fn bsp_section(".bsp_init_fn." level) = fn


#define NET_X_APP_EXPORT(fn)    INIT_EXPORT(fn, "8.1")
						
						
						
void bsp_components_app_init(const init_fn_t *start_ptr,const init_fn_t *end_ptr) {
    volatile const init_fn_t *fn_ptr;
    for (fn_ptr = start_ptr; fn_ptr < end_ptr; fn_ptr++) {
        (*fn_ptr)();
    }
}
						
						
static int net_x_duo_component_init_start() {
    /* 初始化NetX */
    
    return 0;
}

INIT_EXPORT(net_x_duo_component_init_start, "8.0");


static int nex_x_duo_component_init_end() {
    return 0;
}

INIT_EXPORT(nex_x_duo_component_init_end, "9.0");


int app_netx_tcp_client_init() {

    printf("app_netx_tcp_client_init\r\n");

    return 0;
}

NET_X_APP_EXPORT(app_netx_tcp_client_init);

/*******************************************************************************
* 函 数 名         : main
* 函数功能		   : 主函数
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
int main()
{
	u8 i=0;
	u16 color=0;
	
	HAL_Init();                     //初始化HAL库 
	SystemClock_Init(8,336,2,7);   //设置时钟,168Mhz
	SysTick_Init(168);
	USART1_Init(115200);
	
 bsp_components_app_init(&__os_init_net_x_duo_component_init_start,
                            &__os_init_nex_x_duo_component_init_end);



	while(1)
	{

		delay_ms(10);		
	}
}

查看keil的map文件

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

结论

在keil中,不需要去修改链接文件,也可以实现组件自动注入,唯一的耦合,就是需要在合适的地方调用bsp_components_app_init 函数即可

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
解耦控制器是一种常用的控制器设计方法,可以将多输入多输出系统分解为多个互相独立的单输入单输出系统进行控制,从而简化系统的控制问题。 在 keil 软件中实现解耦控制器需要进行以下步骤: 1. 定义控制系统的状态空间模型,包括状态变量、输入变量和输出变量。 2. 根据系统的状态空间模型,设计解耦控制器的状态反馈矩阵和输出反馈矩阵。 3. 将状态反馈矩阵和输出反馈矩阵转换为 keil 软件中的矩阵形式。 4. 在 keil 软件中编写控制程序,包括状态观测器、状态反馈控制器和输出反馈控制器等模块。 5. 将程序下载到 stm32 单片机上,并进行实验验证。 具体实现过程可以参考以下代码: ```c #include <stm32f10x.h> #include <math.h> #define PI 3.1415926 /* 定义状态变量 */ float x[2] = {0.0f, 0.0f}; float y[2] = {0.0f, 0.0f}; /* 定义输入变量 */ float u[2] = {0.0f, 0.0f}; /* 定义输出变量 */ float y1 = 0.0f; float y2 = 0.0f; /* 定义状态反馈矩阵 */ float K[2][2] = {{0.0f, 0.0f}, {0.0f, 0.0f}}; /* 定义输出反馈矩阵 */ float L[2] = {0.0f, 0.0f}; /* 定义控制器参数 */ float alpha = 0.5f; float beta = 0.5f; /* 定义控制器周期 */ float T = 0.01f; /* 定义控制器输入 */ float r1 = 0.0f; float r2 = 0.0f; /* 状态观测器 */ void state_observer(float y1, float y2, float u1, float u2) { x[0] = alpha * x[0] + beta * (y1 - L[0] * x[1] - L[1] * y2 + K[0][0] * u1 + K[0][1] * u2); x[1] = alpha * x[1] + beta * (y2 - L[1] * x[0] - L[0] * y1 + K[1][0] * u1 + K[1][1] * u2); } /* 状态反馈控制器 */ void state_feedback_controller(float r1, float r2) { u[0] = -K[0][0] * x[0] - K[0][1] * x[1] + r1; u[1] = -K[1][0] * x[0] - K[1][1] * x[1] + r2; } /* 输出反馈控制器 */ void output_feedback_controller(float y1, float y2) { y1 = L[0] * x[0] + L[1] * x[1]; y2 = L[1] * x[0] + L[0] * x[1]; } int main(void) { /* 初始化控制器 */ K[0][0] = 1.0f; K[0][1] = 0.0f; K[1][0] = 0.0f; K[1][1] = 1.0f; L[0] = 1.0f; L[1] = 1.0f; /* 循环控制 */ while(1) { /* 获取控制器输入 */ r1 = sin(2 * PI * T); r2 = cos(2 * PI * T); /* 获取控制器输出 */ output_feedback_controller(y1, y2); /* 获取系统状态 */ state_observer(y1, y2, u[0], u[1]); /* 进行状态反馈控制 */ state_feedback_controller(r1, r2); /* 延时控制器周期 */ for(uint32_t i=0; i<10000; i++); } } ``` 注意:以上代码仅为示例代码,实际应用中需要根据具体系统进行修改和优化,以满足系统要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

詩不诉卿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值