STM32中的shell框架搭建

STM32和电脑的关系

  •     可以将上位机给下位机发送的信息当做是控制命令
  •     下位机给上位机发送的信息当做是硬件本身的状态 

初始化函数的优化

批量化调用同类型函数,有同样的数据类型,放一块 - 数组 

定义一个数组, 函数指针数组, 数组中包含的都是一个一个的函数指针, 就是函数的首地址 

|--LED_Init--|--BEEP_Init--|--UART_Init--|--...--|--....--|--0--|将近期所有的初始化函数放到一个数组里

回忆知识:函数指针:

C语言指针进阶(一)——深入详解“函数指针”与“指针函数”-CSDN博客

以下变量的类型:

int a;int
int* pa;int*
int a[5];int [5]
int (*p)(void);int (*)(void)

小窍门:把定义中的变量名去除就是变量类型

    typedef  int (*p_t)(void);


	p_t arr[] = {LED_Init, BEEP_Init, UART_Init};

	for(int i = 0; i < 3; i++){
		p_t p;
		p = arr[i];
		p();
	}

代码实现

// @file init.h
#ifndef __INIT_H 
#define __INIT_H

#include "stm32f10x.h"

// 声明函数指针数据类型 
typedef void (*PINIT_T)(void);

// 声明全部硬件的初始化函数 
extern void DEVICE_Init(void);


#endif
// @file  init.c
#include "init.h"
#include "led.h"
#include "beep.h"
#include "systick.h"
#include "key.h"
#include "exti.h"
#include "uart.h"

// 定义函数指针数组, 存储所有初始化函数的首地址
static PINIT_T init_func[] = {
	LED_Init,			// led灯初始化
	BEEP_Init,		// beep初始化 
	Systick_init,	// 滴答定时器初始化
	KEY_Init,			// 按键初始化
	My_EXTI_Init,	// 中断初始化 
	UART_Init,		// 串口初始化 
	0
};

void DEVICE_Init(void)
{
	// pfunc存储数组首地址
	// pfunc存储数组下表为0存储区的首地址
	PINIT_T* pfunc = init_func;
	for(; *pfunc; pfunc++){
		(*pfunc)(); 
	}
}

可将原代码中的

	LED_Init(); // led灯的初始化
	BEEP_Init(); // BEEP的初始化
	Systick_init(); // 滴答定时器的初始化 
	KEY_Init();			// 按键的初始化
	My_EXTI_Init(); // EXTI初始化 

所有的初始化用init取代

DEVICE_Init();// 所有硬件的初始化

命令匹配优化

		// 字符串匹配 
		if(!strcmp(buf, "led on")){
			LED_On(); // 开灯 
			UART_Puts("LED ON");
		}else if(!strcmp(buf, "led off")){
			LED_Off(); // 关灯 
			UART_Puts("LED OFF");
		}else if(!strcmp(buf, "beep on")){
			BEEP_On(); // 打开蜂鸣器 
			UART_Puts("BEEP ON");
		}else if(!strcmp(buf, "beep off")){
			BEEP_Off(); // 关闭蜂鸣器 
			UART_Puts("BEEP OFF");
		}else{
			UART_Puts("invalid command\n");
		}
		UART_Puts("\n");

在main函数中,接收来自cpu发送的字符串进行判断,需要单个去进行匹配,这时候新建cmd.h和cmd.c专门优化这部分匹配,适配后期的匹配

cmd.h


#ifndef __CMD_H  
#define __CMD_H

#include "stm32f10x.h"

// 声明函数指针数据类型 
typedef void (*cb_t)(void); //这里需要注意对函数指针进行typedef的定义方法,而不是typedef void (* )(void) p_t

// 声明命令的数据类型 
typedef struct{
	char* name;
	cb_t callback; 
}cmd_t;

// 用于匹配函数 
extern cmd_t* find_cmd(char* name);//这里要注意返回的cmd_t类型的结构体,需要用地址来取


#endif

cmd.c

#include "cmd.h"
#include "led.h"
#include "beep.h"
#include "string.h"

// 定义描述所有命令的数组 
cmd_t cmd[] = {
	{"led on", LED_On},
	{"led off", LED_Off},
	{"beep on", BEEP_On},
	{"beep off", BEEP_Off}
};
// 获取数组长度 
#define  CMD_NUM(x)   (sizeof(x) / sizeof(x[0])) //使用宏的方式进行定义,方便后期调用

// 命令匹配函数 
// 参数 - 用户输入的操作命令 
// 和某个命令匹配成功, 需要传递给其它函数什么数据,可以直接调用对应的函数呢?
cmd_t* find_cmd(char* name)
{
	int i = 0;
	for(i = 0; i < CMD_NUM(cmd); i++){
		if(!strcmp(name, cmd[i].name))
			return &cmd[i];// 返回匹配成功命令的首地址
	} 
	
	return 0;
}

main.c

#include "stm32f10x.h"
#include "led.h"
#include "beep.h"
#include "system.h"
#include "systick.h"
#include "key.h"
#include "exti.h"
#include "uart.h"
#include "string.h"  // strcmp函数声明 
#include "init.h"
#include "cmd.h"


#define  BUF_LEN   128
static char buf[BUF_LEN]; // 定义数组存储从上位机读取到的字符串 
static cmd_t* pcmd;


int main(void){
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //--|--
	
	DEVICE_Init();// 所有硬件的初始化


	while(1){
		// 下位机->上位机:请输入命令 
		UART_Puts("please input your command:");
		// buf = "led on"/"led off"/"beep on"/"beep off"
		// 上位机发送的命令在buf数组中
		UART_Gets(buf, BUF_LEN); 
		
		// 命令匹配, 参数就是上位机输入的命令 
		pcmd = find_cmd(buf);
		if(pcmd != 0) // 匹配成功
			pcmd->callback(); // 调用对应的函数
		else
			UART_Puts("invalid command\n");
		UART_Puts("\n");
	}

}


实验效果


从上位机给下位机发送led on,STM32主板中的LED会亮,发送led off则会熄灭

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值