STM32实战项目-状态机函数应用

news2024/11/15 11:54:01

前言:

本章主要介绍一下,状态机在工程中的应用,下面我会通过这种方式点亮LED灯,来演示他的妙用。

目录

1、状态机应用

1.1流水灯函数

1.1.1led.h

1.1.2led.c

1.2状态机函数

1.2.1定义举常量

1.2.2结构体封装


1、状态机应用

有限状态机是一种概念思想,把复杂的控制逻辑分解成有限个稳定状态,组成闭环系统,通过事件触发,让状态机按设定的顺序处理事务;

单片机C语言的状态机编程,是利用条件选择语句(switch -- case)切换状态,通过函数内部指令改变状态机状态,让程序按设定的顺序执行。

如上图所示:五个状态分别对应五个流程分别对应五种状态,我们可以使用结构体封装,保存五个状态的函数的指针。 

1.1流水灯函数

为了方便程序移植,阅读,我们自己定义源文件 LED.C和头文件LED.H头文件中放,流水灯函数的声明和定义,源文件中放函数的实现。 

1.1.1led.h

/¶¨Òåö¾ÙÀàÐÍ
typedef enum
{
	LED1 = (uint8_t)0x01,
	LED2 = (uint8_t)0x02,
	LED3 = (uint8_t)0x03,
}LED_Num_t;

//¶¨Òå½á¹¹ÌåÀàÐÍ
typedef struct
{
	void (*LED_ON)(uint8_t);     //´ò¿ª
	void (*LED_OFF)(uint8_t);    //¹Ø±Õ
	void (*LED_Flip)(uint8_t);   //·­×ª
} LED_t;

/* extern variables-----------------------------------------------------------*/
extern LED_t  LED;

1.1.2led.c

static void LED_ON(uint8_t); 
static void LED_OFF(uint8_t);
static void LED_Flip(uint8_t);

/* Public variables-----------------------------------------------------------*/
LED_t LED = 
{
	LED_ON,
	LED_OFF,
	LED_Flip
};


static void LED_ON(uint8_t LED_Num)
{
	//Ìõ¼þÑ¡ÔñÓï¾ä
	switch(LED_Num)
	{
		case LED1: HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_SET); break;
		case LED2: HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_SET); break;
		case LED3: HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,GPIO_PIN_SET); break;
		default: System.Assert_Failed();
	}
}
static void LED_OFF(uint8_t LED_Num)
{
	//Ìõ¼þÑ¡ÔñÓï¾ä
	switch(LED_Num)
	{
		case LED1: HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,GPIO_PIN_RESET); break;
		case LED2: HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,GPIO_PIN_RESET); break;
		case LED3: HAL_GPIO_WritePin(LED3_GPIO_Port,LED3_Pin,GPIO_PIN_RESET); break;
		default: System.Assert_Failed();
	}
}

static void LED_Flip(uint8_t LED_Num)
{
	//Ìõ¼þÑ¡ÔñÓï¾ä
	switch(LED_Num)
	{
		case LED1: HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin); break;
		case LED2: HAL_GPIO_TogglePin(LED2_GPIO_Port,LED2_Pin); break;
		case LED3: HAL_GPIO_TogglePin(LED3_GPIO_Port,LED3_Pin); break;
		default: System.Assert_Failed();
	}
}

 我们可以看到在led.c函数中,我们封装的三个函数指针分别实现了,led的开、关、和翻转,至于ON,OFF,TogglePin 这些都是HAL库自己定义的我们可以看看他的函数实现,如下图所示:

 至于端口和引脚,这个在我们使用cubemax的时候,配置好参数的时候,已经自动初始化完成了。

1.2状态机函数

1.2.1定义举常量

 首先定义五个枚举常量,不同常量对应不同选择,也就会有不同的状态。

//¶¨Òåö¾ÙÀàÐÍ
typedef enum
{
	STA1   = (uint8_t)0x01, 
	STA2   = (uint8_t)0x02, 
	STA3   = (uint8_t)0x03, 
	STA4   = (uint8_t)0x04, 
	STA5   = (uint8_t)0x05,
} STA_Machine_Status_t;

1.2.2结构体封装

使用结构体封装五个函数指针,方便在运行函数中进行调用,具体代码如下:

//¶¨Òå½á¹¹ÌåÀàÐÍ
typedef struct
{
	STA_Machine_Status_t  ucSTA_Machine_Status;  //״̬»ú״̬
	
	void (*Fun_STA1)(void); 
	void (*Fun_STA2)(void);
	void (*Fun_STA3)(void);
	void (*Fun_STA4)(void);
	void (*Fun_STA5)(void);
} STA_Machine_t;

 这五个函数指针指向五个函数,分别实现led的亮灭,所以函数内部又调用了led的函数,具体代码如下:

void Fun_STA1()
{
	HAL_Delay(500);      //ÑÓʱ500ms
	LED.LED_Flip(LED1);  //·­×ªLED1,ÃðµÆ
	LED.LED_Flip(LED2);  //·­×ªLED2,ÃðµÆ
	LED.LED_Flip(LED3);  //·­×ªLED3,ÃðµÆ
	
	//״̬»úÇл»ÖÁ״̬2
	STA_Machine.ucSTA_Machine_Status = STA2;
}

void Fun_STA2()
{
	HAL_Delay(500);      //ÑÓʱ500ms
	LED.LED_ON(LED1);    //LED1ÁÁµÆ
	LED.LED_OFF(LED2);   //LED2ÃðµÆ
	LED.LED_OFF(LED3);   //LED3ÃðµÆ
	
	//״̬»úÇл»ÖÁ״̬3
	STA_Machine.ucSTA_Machine_Status = STA3;
}

void Fun_STA3()
{
	HAL_Delay(500);      //ÑÓʱ500ms
	LED.LED_OFF(LED1);   //LED1ÃðµÆ
	LED.LED_ON(LED2);    //LED2ÁÁµÆ
	LED.LED_OFF(LED3);   //LED3ÃðµÆ
	
	//״̬»úÇл»ÖÁ״̬4
	STA_Machine.ucSTA_Machine_Status = STA4;
}

void Fun_STA4()
{
	HAL_Delay(500);      //ÑÓʱ500ms
	LED.LED_OFF(LED1);   //LED1ÃðµÆ
	LED.LED_OFF(LED2);   //LED2ÃðµÆ
	LED.LED_ON(LED3);    //LED3ÁÁµÆ
	
	//״̬»úÇл»ÖÁ״̬5
	STA_Machine.ucSTA_Machine_Status = STA5;
}

void Fun_STA5()
{
	HAL_Delay(500);      //ÑÓʱ500ms
	LED.LED_ON(LED1);    //LED1ÁÁµÆ
	LED.LED_ON(LED2);    //LED2ÁÁµÆ
	LED.LED_ON(LED3);    //LED3ÁÁµÆ
	
	//״̬»úÇл»ÖÁ³õʼ״̬1
	STA_Machine.ucSTA_Machine_Status = STA1;
}

这样的话一个完整的状态机就完成了,我们软件框架并没有改变,只是将调用的run函数内部进行了修改。整体的框架如下图所示:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/393132.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设计模式-01

1,设计模式概述 1.1 软件设计模式的产生背景 "设计模式"最初并不是出现在软件设计中,而是被用于建筑领域的设计中。 1977年美国著名建筑大师、加利福尼亚大学伯克利分校环境结构中心主任克里斯托夫亚历山大(Christopher Alexand…

VUE3使用JSON编辑器

1、先看看效果图,可以自行选择展示效果 2、这是我在vue3项目中使用的JSON编辑器,首先引入第三方插件 npm install json-editor-vue3yarn add json-editor-vue33、引入到项目中 // 导入模块 import JsonEditorVue from json-editor-vue3// 注册组件 …

【pytorch onnx】Pytorch导出ONNX及模型可视化教程

文章目录1 背景介绍2 实验环境3 torch.onnx.export函数简介4 单输入网络导出ONNX模型代码实操5 多输入网络导出ONNX模型代码实操6 ONNX模型可视化7 ir_version和opset_version修改8 致谢原文来自于地平线开发者社区,未来会持续发布深度学习、板端部署的相关优质文章…

RocketMQ5.1控制台的安装与启动

RocketMQ控制台的安装与启动下载修改配置开放端口号重启防火墙添加依赖编译 rocketmq-dashboard运行 rocketmq-dashboard本地访问rocketmq无法发送消息失败问题。connect to <公网ip:10911> failed下载 下载地址 修改配置 修改其src/main/resources中…

【操作系统原理实验】银行家算法模拟实现

选择一种高级语言如C/C等,编写一个银行家算法的模拟实现程序。1) 设计相关数据结构;2) 实现系统资源状态查看、资源请求的输入等模块;3) 实现资源的预分配及确认或回滚程序;4) 实现系统状态安全检查程序;5) 组装各模块…

TCP模拟HTTP请求

HTTP的特性HTTP是构建于TCP/IP协议之上,是应用层协议,默认端口号80HTTP协议是无连接无状态的HTTP报文请求报文HTTP协议是以ASCⅡ码传输,建立在TCP/IP协议之上的应用层规范。HTTP请求报文由请求行(request line)、请求头…

Flutter 自定义今日头条版本的组件,及底部按钮切换静态样式

这里写目录标题1. 左右滑动实现标题切换,点击标题也可实现切换;2. 自定义KeepAliveWrapper 缓存页面;2.2 使用3. 底部导航切换;4. 自定义中间大导航;5.AppBar自定义顶部按钮图标、颜色6. Tabbar TabBarView实现类似头条…

iOS开发之UIStackView基本运用

UIStackView UIStackView是基于自动布局AutoLayout,创建可以动态适应设备方向、屏幕尺寸和可用空间的任何变化的用户界面。UIStackView管理其ArrangedSubview属性中所有视图的布局。这些视图根据它们在数组中的顺序沿堆栈视图的轴排列。由axis, distribution, align…

java医院云HIS系统:融合B/S版电子病历系统 能与公卫、PACS等各类外部系统融合

医院HIS系统源码 云HIS系统源码:SaaS运维平台完整文档 有源码,有演示 java基层医院云his系统 融合B/S版电子病历系统,支持电子病历4级 拥有自主知识产权。 看演示及源码可私信我哦! 一、系统概述 一款满足二甲医院、基层医疗机构…

九、会话技术CookieSession

会话技术 1,会话跟踪技术的概述 对于会话跟踪这四个词,我们需要拆开来进行解释,首先要理解什么是会话,然后再去理解什么是会话跟踪: 会话:用户打开浏览器,访问web服务器的资源,会话建立,直到有…

3D目标检测(二)—— 直接处理点云的3D目标检测网络VoteNet、H3DNet

前言上次介绍了基于Point-Based方法处理点云的模块,3D目标检测(一)—— 基于Point-Based方法的PointNet点云处理系列,其中相关的模块则是构成本次要介绍的,直接在点云的基础上进行3D目标检测网络的基础。VoteNet对于直接在点云上预…

科目一《综合素质》

目录综合素质重点题型分布注意事项章节分解第一章 职业理念第一节 教育观1. 教育观(基本内涵)一字不差背过第二节 学生观2. 学生观 一字不差背过第三节 教师观3. 教师观 一字不差背过第二章 教育法律法规第一节 教师的权利与义务第二节 学生的权利及其保…

QT基础入门【Demo篇】QString的相关操作

&#x1f4a2;&#x1f4a2;目录总览&#x1f4a2;&#x1f4a2;&#xff1a;QT基础入门目录总览 QString支持的操作符号有&#xff1a; 用于字符串之间比较&#xff1a;"!" "<" "<" "" ">" 用于字符串之间传递&a…

第九章 多机系统

考柿时间是3.9 文章目录多机系统并行性发展及计算机系统的分类开发并行性的途径计算机系统的分类(Flynn分类)SISD与片内并行&#xff08;芯片内的并行机制&#xff09;SIMD分成两个子类&#xff1a;MIMD分为两类&#xff08;**主要区别就是它们是否有共享的内存**、单系统映像&…

MTK平台修改AP 5G模式下所支持的频宽

代码路径 vendor/mediatek/kernel_modules/connectivity/wlan/core/gen4m/common/wlan_lib.c 将 prWifiVar->ucAp5gBandwidth (uint8_t) wlanCfgGetUint32( -- prAdapter, "Ap5gBw", MAX_BW_80MHZ); prAdapter, "Ap5gBw&quo…

Windows下UXP插件开发环境搭建及程序试运行

从PS2021开始&#xff0c;Adobe官方引入了新的插件平台&#xff1a;UXP&#xff0c;它的最终目标任务是取代现有的CEP&#xff0c;所以赶紧来提前做一下准备吧&#xff0c;我对这方面也一直很感兴趣&#xff0c;但是这方面的中文资料太少了&#xff0c;然后在网上查了一些资料和…

【剧前爆米花--爪哇岛寻宝】包装类的装拆箱和泛型的擦除机制

作者&#xff1a;困了电视剧 专栏&#xff1a;《数据结构--Java》 文章分布&#xff1a;这是关于数据结构的基础之一泛型的文章&#xff0c;希望对你有所帮助。 目录 包装类 装箱 装箱源码小细节 拆箱 泛型 什么是泛型 泛型编译的擦除机制 不能实例化泛型类型数组 包装…

LicenseBox Crack,对服务器的要求最低

LicenseBox Crack,对服务器的要求最低 LicenseBox是用于管理基于PHP的软件、WordPress插件或主题、主题、插件和WordPress的更新和许可的完整软件。它易于安装&#xff0c;对服务器的要求最低&#xff0c;用户友好的界面&#xff0c;无限脚本的使用为您的创造力打开了大门。 Li…

基于STM32的水质浑浊度和PH值监测系统设计(仿真+程序+讲解)

基于STM32的水质浑浊度和PH值监测系统设计(仿真程序讲解&#xff09; 仿真图proteus 8.9 程序编译器&#xff1a;keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;C0077 这里写目录标题演示讲解视频1.主要功能2.仿真3. 程序4.资料清单&下载链接演示讲解视频 基于…

基于JSP的网上书店的设计与实现

技术&#xff1a;Java、JSP等摘要&#xff1a;近年来&#xff0c;随着互联网的迅速普及&#xff0c;网络已经走进了千家万户&#xff0c;作为信息交流的一种平台&#xff0c;它给我们的日常生活带来了很大的便利。今天&#xff0c;各种各样的网站已经深入到了我们的日常生活&am…