单片机裸机编程-时机管理
对于 RTOS 实时操作系统,我们是通过 TASK(任务)进行底层操作的,这与裸机编程中的函数(fun)类似。不同的任务或函数实现不同的功能,在RTOS中,单片机有信号量、队列等不同任务之间的通信机制,但对于裸机编程来说就引出了一个问题:不同任务或函数是如何配合工作的呢?换句话说,单片机是如何知道什么时候该做什么事情,或者为什么做完一件事之后再做另一件事呢?
1、裸机的逻辑轮询
在裸机编程中,任务的执行顺序通常是固定的,由程序的流程控制语句(如 if、while、switch 等)决定。程序从入口点开始,按顺序执行代码,直到遇到分支或循环。当然,也可以通过中断来实现某些功能。
例如,以下代码展示了通过全局变量的状态来控制不同函数的执行逻辑:
void main() {while (1) {if (sensor_data_ready) { // 检查传感器数据是否准备好process_sensor_data();}if (button_pressed) { // 检查按钮是否被按下handle_button_press();}update_display(); // 更新显示}
}
在这个例子中,程序通过全局变量(sensor_data_ready 和 button_pressed)来判断是否执行某个函数。
也就是说,在不同的执行函数之间的通信使用的是全局变量,或者说是标志位。我们通过if,switch这样的逻辑语句让单片机知道在什么情况下该做什么事,所以只需要一直轮询下去即可。
这种方式简单直接,但存在以下问题:
-
耦合性高:全局变量的使用使得代码之间的耦合性增加,难以维护和扩展。
-
灵活性差:任务的执行顺序固定,难以动态调整。
2、使用状态机进行任务管理
为了改善上述问题,我们可以引入 状态机 的概念,对不同的任务进行局部管理。状态机通过定义不同的状态和状态之间的转换条件,使得代码更加模块化和灵活。例如:
typedef enum {STATE_IDLE,STATE_PROCESS_SENSOR,STATE_HANDLE_BUTTON,STATE_UPDATE_DISPLAY
} StateTypeDef;StateTypeDef currentState = STATE_IDLE;void main() {while (1) {switch (currentState) {case STATE_IDLE:if (sensor_data_ready) {currentState = STATE_PROCESS_SENSOR;} else if (button_pressed) {currentState = STATE_HANDLE_BUTTON;}break;case STATE_PROCESS_SENSOR:process_sensor_data();currentState = STATE_IDLE;break;case STATE_HANDLE_BUTTON:handle_button_press();currentState = STATE_IDLE;break;case STATE_UPDATE_DISPLAY:update_display();currentState = STATE_IDLE;break;}}
}
通过状态机,我们可以清晰地定义每个任务的执行条件和状态转换逻辑,从而提高代码的可读性和可维护性。
3、在裸机中实现时间片轮询
进一步思考,我们可以在裸机编程中借鉴 RTOS 的时间片轮询机制。虽然裸机没有 RTOS 内核的支持,但可以通过定时器中断来实现类似的效果。例如:
-
设置定时器中断:配置定时器以固定频率(如 10ms)触发中断。
-
维护任务状态:在定时器中断中维护一个任务状态数组,记录每个任务的执行状态和剩余时间片。
-
轮询任务执行:在主循环中,根据任务状态数组依次执行每个任务的一部分。
示例代码如下:
#define TASK_COUNT 3
#define TIME_QUANTUM 10 // 时间片大小,单位为毫秒typedef struct {void (*taskFunc)(void); // 任务函数指针int remainingTime; // 剩余时间片
} TaskTypeDef;TaskTypeDef tasks[TASK_COUNT] = {{process_sensor_data, TIME_QUANTUM},{handle_button_press, TIME_QUANTUM},{update_display, TIME_QUANTUM}
};void Timer_ISR(void) {static int tick = 0;tick++;
}void main() {int currentTask = 0;while (1) {if (tasks[currentTask].remainingTime > 0) {tasks[currentTask].taskFunc(); // 执行当前任务tasks[currentTask].remainingTime--;}currentTask = (currentTask + 1) % TASK_COUNT; // 轮询下一个任务}
}
通过这种方式,我们可以在裸机中实现类似 RTOS 的时间片轮询机制,使得任务的执行更加公平和灵活。
个人喜欢使用状态机进行裸机编程,这样直接是多个代码块直接的裸机判断。也就相当于是有多个while(1)循环,方便代码的管理和调试。在不同的state模式下执行不同的小模块代码。
相关文章:
单片机裸机编程-时机管理
对于 RTOS 实时操作系统,我们是通过 TASK(任务)进行底层操作的,这与裸机编程中的函数(fun)类似。不同的任务或函数实现不同的功能,在RTOS中,单片机有信号量、队列等不同任务之间的通…...
Bugku CTF CRYPTO
Bugku CTF CRYPTO 文章目录 Bugku CTF CRYPTO聪明的小羊ok[-<>]散乱的密文.!? 聪明的小羊 描 述: 一只小羊翻过了2个栅栏 fa{fe13f590lg6d46d0d0} 分 析:栅栏密码,分2栏,一个栏里有11个 ①手动解密 f a { f e 1 3 f 5 9 0 l g 6 d 4 …...
【洛谷】【ARC100E】Or Plus Max(高维前缀和)
传送门:Or Plus Max 高维前缀和 题目描述 長さ 2N の整数列 A0, A1, ..., A2N−1 があります。(添字が 0 から始まることに注意) 1 ≤ K ≤ 2N−1 を満たすすべての整数 K について、次の問題を解いてください。 i,j を整数と…...
宿主机的 root 是否等于 Docker 容器的 root?
在 Docker 容器化技术中,宿主机的 root 和 容器的 root 并不完全相同,尽管它们都称作 “root 用户”。这里需要明确的是,Docker 容器与宿主机之间存在隔离机制,容器内的 root 用户和宿主机的 root 用户有一些关键的区别。 1. 宿主…...
SmolLM2:多阶段训练策略优化和高质量数据集,小型语言模型同样可以实现卓越的性能表现
SmolLM2 采用创新的四阶段训练策略,在仅使用 1.7B 参数的情况下,成功挑战了大型语言模型的性能边界: 在 MMLU-Pro 等测试中超越 Qwen2.5-1.5B 近 6 个百分点数学推理能力(GSM8K、MATH)优于 Llama3.2-1B在代码生成和文…...
云原生降本之路:技术创新与应用解析
随着云计算的快速发展,云原生技术已成为企业降低成本、提高效率的重要手段。本文基于腾讯云容器技术专家孟凡杰的PPT内容,深入探讨了云原生技术在降低企业成本方面的应用,包括资源利用现状、成本优化思路、Kubernetes中的资源分配、横向与纵向…...
《Effective Objective-C》阅读笔记(中)
目录 接口与API设计 用前缀避免命名空间冲突 提供“全能初始化方法” 实现description方法 尽量使用不可变对象 使用清晰而协调的命名方式 方法命名 编辑类与协议命名 为私有方法名加前缀 理解OC错误模型 理解NSCopying协议 协议与分类 通过委托与数据源协议进行…...
Hbase客户端API——语句大全
目录 创建表: 插入数据: 删除数据: 修改数据: 查询数据:Get 查询数据:Scan 查询数据:过滤查询 创建表: 检验: 插入数据: 验证 一次多条数据插入 验证&…...
MQ(Message Queue)
目录 MQ(Message Queue)基本概念 为什么要使用消息队列? 使用消息队列有什么缺点? 如何保证消息不丢失?(如何保证消息的可靠性传输?/如何处理消息丢失的问题?) 通用的MQ场景: RabbitMQ如何保证消息不丢失? 生产者丢数据…...
SQL进阶实战技巧:汽车转向次数分析 | 真实场景案例
目录 0 问题描述 1 数据准备 2 问题分析 3 小结 关键技术总结 0 问题描述 现有一组实际汽车在平整路面安全行驶数据,每秒记录一次汽车的车头绝对指向,车头方向记为[0-360)度,部分数据如下,完整数据后附文件。...
青少年软件编程(C语言)等级三级考试试题(2)
Minecraft 题目描述 Minecraft 是一个几乎无所不能的沙盒游戏,玩家可以利用游戏内的各种资源进行创造,搭建自己的世界。 在 Minecraft 中,基本的建筑元素是边长为 1 个单位的立方体,Tony 想用 N 个这种小立方体搭建一个长方体&…...
计算机网络————(三)
前文二 前文一 Websocket协议 是一种存在TCP协议之上的协议 当客户端需要了解服务器是否更新就需要不断给客户端发送请求询问是否更新,这行会造成服务端压力很大 而Websocket相当于服务器一旦更新了就会给客户端发送消息表明自己更新了,类似客户端订阅…...
【音视频】音视频录制、播放原理
一、音视频录制原理 通常,音视频录制的步骤如下图所示: 我们分别从音频和视频开始采样,通过麦克风和摄像头来接受我们的音频信息和图像信息,这通常是同时进行的,不过,通常视频的采集会比音频的采集慢&…...
如何用python将pdf转为text并提取其中的图片
要将 PDF 转为文本并提取其中的图片,可以使用 Python 的几个库来实现: PDF 转文本:使用 PyMuPDF 或 pdfplumber 来提取文本。提取图片:使用 PyMuPDF 或 pdf2image 来提取图像。 以下是实现的步骤和代码示例: 1. 安装…...
deepseek 导出导入模型(docker)
前言 实现导出导入deepseek 模型。deepseek 安装docker下参考 docker 导出模型 实际生产环境建议使用docker-compose.yml进行布局,然后持久化ollama模型数据到本地参考 echo "start ollama" docker start ollama#压缩容器内文件夹,然后拷贝…...
基于Redis 的分布式 session 图解
Redis 分布式 Session 工作原理 1. 传统 Session 的问题 在传统单服务器环境中,HTTP Session 存储在应用服务器的内存中。这在分布式系统中会导致问题: 用户的请求可能被分发到不同服务器,导致会话不一致服务器宕机会导致会话丢失需要依赖…...
Vue进阶之AI智能助手项目(四)——ChatGPT的调用和开发
AI智能助手项目 前端接口部分src/api/index.tssrc/utils/request/index.tspost方法httpHttpOptionsrc/utils/request/axios.tsLayout布局页面-viewsexception异常页面src/views/exception/404/index.vuesrc/views/exception/500/index.vueLayout布局页面src/views/chat/layout/…...
DeepSeek-R1本地部署保姆级教程
一、DeepSeek-R1本地部署配置要求 (一)轻量级模型 ▌DeepSeek-R1-1.5B 内存容量:≥8GB 显卡需求:支持CPU推理(无需独立GPU) 适用场景:本地环境验证测试/Ollama集成调试 (二&a…...
【deepseek】本地部署+webui访问
背景 最近deepseek很火,但是官网的老是被限流使用,还有就是自己也想着玩一玩,于是准备在自己电脑跑一个 直接附上结果地址mydeepseek 准备工作 windows和linux都可 我这里选择linux,ubuntu系统 安装ollama 看下图࿰…...
deepseek部署:ELK + Filebeat + Zookeeper + Kafka
## 1. 概述 本文档旨在指导如何在7台机器上部署ELK(Elasticsearch, Logstash, Kibana)堆栈、Filebeat、Zookeeper和Kafka。该部署方案适用于日志收集、处理和可视化场景。 ## 2. 环境准备 ### 2.1 机器分配 | 机器编号 | 主机名 | IP地址 | 部署组件 |-…...
博客系统笔记总结 2( Linux 相关)
Linux 基本使用和程序部署 基本命令 文件操作 显示当前目录下的文件 ls:显示当前目录下的文件 ll:以列表的形式展示,包括隐藏文件 进入目录 && 显示当前路径 cd:进入目录(后面跟相对路径或者绝对路径&…...
Flutter - 基础Widget
Flutter 中万物皆 Widget,基础Widget 同步对应 Android View. 普通文本 Text /*** 控制文本样式统一使用 style:TextStyle, 例:fontSize(字体大小),color(颜色),shadows(阴影)等等* 控制文本布局需单独设置:* textAlign(文不对齐方式)* te…...
如何在 Linux 上安装和配置 Zsh
文章目录 如何在 Linux 上安装和配置 Zsh1. 安装 Zsh1.1 在 Ubuntu/Debian 上安装1.2 在 CentOS/RHEL/Fedora 上安装1.3 在 Arch Linux 上安装1.4 验证 Zsh 安装 2. 设置 Zsh 为默认 Shell2.1 验证默认 shell 3. 配置 Zsh3.1 使用 Oh My Zsh3.1.1 安装 Oh My Zsh3.1.2 启用插件…...
【System Verilog and UVM基础入门26】Verdi使用教程指南
《Verdi使用教程指南 》 下载链接: https://download.csdn.net/download/TommiWei/90429701https://download.csdn.net/download/TommiWei/90429701 朋友你好,不管你是否使用过Verdi这款EDA仿真工具。 不管你是否还在寻找免费的使用教材。 不管你是否…...
3dtiles平移旋转工具制作
3dtiles平移旋转缩放原理及可视化工具实现 背景 平时工作中,通过cesium平台来搭建一个演示场景是很常见的事情。一般来说,演示场景不需要多完善的功能,但是需要一批三维模型搭建,如厂房、电力设备、园区等。在实际搭建过程中&…...
【STL专题】优先级队列priority_queue的使用和模拟实现,巧妙利用仿函数解决优先级
欢迎来到 CILMY23的博客 🏆本篇主题为:优先级队列priority_queue的使用和模拟实现,巧妙利用仿函数解决优先级 🏆个人主页:CILMY23-CSDN博客 🏆系列专栏: C | C语言 | 数据结构与算法 | Linux…...
数据开发面试:DQL,
DQL常见面试题 where 和 having 的区别 三个排序开窗函数的区别 left join 用where 筛选 和 用on筛选的区别 ON 子句:用于定义连接条件,不会丢失左表的行。 WHERE 子句:用于过滤连接后的结果集,可能会丢失左表中没有匹配的行 …...
学习Flask:Day 2:模板与表单开发
学习目标:前后端混合开发 # 添加模板渲染 from flask import render_templateapp.route(/profile) def profile():return render_template(profile.html, username"开发者",skills[Vue, JavaScript]) ✅ 实践任务: 创建templates目录 使用J…...
最长递增子序列(贪心算法)思路+源码
文章目录 题目[](https://leetcode.cn/problems/longest-increasing-subsequence/)算法原理源码总结题目 首先,要掌握动态规划加二分查找 算法原理 1.回顾dp的解法 状态表示:dp[i]表示:以i位置的元素为结尾的所有的子序列中,最长递增子序列的长度 状态转移方程:dp[i]= m…...
Orange 开源项目 - 集成百度智能云-千帆大模型
1 集成百度智能云-千帆大模型 百度智能云-千帆ModelBuilder百度智能云千帆大模型服务与开发平台ModelBuilder(以下简称千帆ModelBuilder)是面向企业开发者的一站式大模型开发及服务运行平台。千帆ModelBuilder不仅提供了包括文心一言底层模型和第三方开源…...
