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) |
小窍门:把定义中的变量名去除就是变量类型
objectivec
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();
}
代码实现
objectivec
// @file init.h
#ifndef __INIT_H
#define __INIT_H
#include "stm32f10x.h"
// 声明函数指针数据类型
typedef void (*PINIT_T)(void);
// 声明全部硬件的初始化函数
extern void DEVICE_Init(void);
#endif
objectivec
// @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)();
}
}
可将原代码中的
objectivec
LED_Init(); // led灯的初始化
BEEP_Init(); // BEEP的初始化
Systick_init(); // 滴答定时器的初始化
KEY_Init(); // 按键的初始化
My_EXTI_Init(); // EXTI初始化
所有的初始化用init取代
objectivec
DEVICE_Init();// 所有硬件的初始化
命令匹配优化
objectivec
// 字符串匹配
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
objectivec
#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
objectivec
#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
objectivec
#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则会熄灭