单片机关键任务优先级的实现学习

与总体产品联调时,需要各个单机系统严格按照总体要求,进行数据输出,时间的偏差将出现系统异常,控制失败等不稳定情况产生,甚至影响到产品安全。

因此必须确保某些关键任务的优先执行。单片机任务优先级一般有两种方式实现,基于单片机中断服务的中断函数进行实现基于实时操作系统的任务调度实现

基于中断服务函数实现的任务优先级对单片机硬件资源有要求,而对于实时操作系统的任务调度方式,仅需一个定时器就可完成多任务多优先级的管理。

参与某产品联调时,总体要求每间隔5ms向总控发
送一次关键数据。

当系统联调运行时,总控会产生超时报警,报警内容是通信超时。

经过排查排除了硬件问题、电磁干扰问题、程序逻辑错误未正常发送数据等问题。

通过报警时间比对,发现该报警出现时间没有规律性。通过示波器查看发现,其发送数据周期没有严格按照5ms 间隔时间发送,发送时间落在 5ms 区间段内,任意时间点都可能会进行关键数据的传递,无法预测下次一次发送数据的准确时间,当系统在规定时间内未接收到数据时,产生系统报警。

经过对程序进行逻辑分析,出现问题原因是单片机运
行任务是顺序执行,只有轮到发送数据任务执行时,才能发送数据,如果其他任务占用执行时间过长,将会导致发送任务不能在5ms时间内再次获得运行机会,因此也无法按时发送数据,造成数据超时问题。

在这里插入图片描述

1 关键任务优先执行方法
1.1 查找问题

下位机程序任务流程如图1所示:

下位机程序按照项目功能需求,将不同功能划分为不
同任务,根据每个任务特点,制定的间隔时间不一致,

如 对RS485等通信口监听时,其响应时间在50ms满足要求,自然环境下温度变化缓慢,因此温度采集500ms一次也满足要求。通过计时器进行技术,当5ms时置位5ms任务标志位,10ms时置位5ms和10ms任务标志位,通过任务标志位定义了任务执行频率,优先级高的任务得到更多执行次数。该种任务执行方式称为任务协同方式,当一个任务执行时,必须等到该任务执行完成,才能执行下一个任务。当某一时刻,多个时间任务被置位时,其按照顺序结构运行程序,任务需要排队执行,实时性不高。

下位机程序使用任务协同方式进行运行,分别定义了
5ms,10ms,20ms,50ms,100ms,200ms,500ms 等任务。

所有的任务基于顺序执行,其中5ms程序critical_task
作为关键任务。某个时刻,如定时器在计数到500ms时,其上的5ms,10ms,20ms,50ms,100ms,200ms 时间标志位被置位,任务均得到执行,导致500ms这一时刻需要顺序执行很多任务,如在5ms内不能执行完全部任务,那么下一次的关键任务程序 critical_task 将不能按时被执行,导致输出超时情况产生。 为解决超时问题,必须提升critical_task 任务的优先级,提升任务优先级的方式较多,常用的方式有中断服务函数(前后台系统)、实时操作系统实现。

1.2 关键任务任务由前后台系统保证

单片机是单核处理器,不能同时执行多个任务。

从主程序架构上看,该种顺序执行方式不能保证关键
任务critical_task 的优先执行。因此应该使用某种方式
能够中断当前正在顺序执行的任务,转向执行优先级较高的任务。

单片机中断是指正在执行一项任务A,然后突然停止
任务A去执行任务B,执行完任务B再回来继续执行任务
A 的过程。单片机中断有很多触发源,如定时器中断、外部按键中断、通信发送、接收数据中断,每个中断源都可以打断正在执行的任务,转向执行中断任务,中断任务执行完毕后,继续回到当前的任务进行未完成的操作,利用单片机的中断特性,能够保证某些代码的及时执行。将某些关键任务放入中断服务函数中,就能打断顺序执行任务而优先执行中断任务,使用该种方式提升了关键任务的优先级。
在这里插入图片描述

单片机中断源的产生有很多方式,与产品联调问题是
不能在5ms时准确的进行数据传输,因此需要在5ms时产生一次任务中断,以执行发送任务。为了满足上述要求,选择定时器中断可满足要求。

定时器中断是指单片机内部有一个从0开始向上(向
下)计数的计数器,每一次计数时间均相同,设置一个计
数目标值,当计数器计数到目标值时,会产生一个计数中断,中断后单片机可以打断当前正在执行的程序跳转执行中断服务程序。在中断服务程序中,清除中断服务向量,使得计数器归0重新计数,以此不断循环达到每隔一定时间就产生一次服务中断的工作模式。

在这里插入图片描述

我们将原程序中的critical_task任务从5ms任务重
移除,添加到 Count5ms_OnInterrupt 中断服务程序中,通过前后台方式实现打断其他正在执行任务来保证
critical_task 的优先执行。程序更改后critical_task
能够5ms一次准确输出,系统报警现象被消除。采用此种方法虽然简单,但是突出问题有几个:
(1)使用中断方式来保证优先级需要占用一个中断
来完成,浪费资源。
(2)当有多个关键任务需要执行时,会出现中断嵌
套,关键任务仍然会被打断执行。
(3)违背了中断中只执行不耗时简单操作的原则,
仍然存在隐患。
(4)不能对不同任务进行不同权重的CPU使用权划
分。


C51 单片机任务协同的实现可以通过定时器中断和任务标志位来完成。在 C51 中,定时器的配置和中断处理稍有不同于现代的 ARM Cortex 系列单片机,但基本原理是相似的。下面是一个简单的示例程序,演示如何使用 C51 编写一个任务协同的程序,涉及10ms、30ms、50ms、100ms 的任务执行:

#include <REG51.H>// 定义任务标志位
bit task_10ms_flag = 0;
bit task_30ms_flag = 0;
bit task_50ms_flag = 0;
bit task_100ms_flag = 0;// 定义定时器0的初值
#define TIMER0_INIT_VALUE 65536 - (12000 / 12)  // 12MHz晶振,计时1ms// 定时器0中断处理函数
void Timer0_ISR(void) interrupt 1
{static unsigned char count_10ms = 0;static unsigned char count_30ms = 0;static unsigned char count_50ms = 0;static unsigned char count_100ms = 0;// 10ms任务count_10ms++;if (count_10ms >= 10){count_10ms = 0;task_10ms_flag = 1;}// 30ms任务count_30ms++;if (count_30ms >= 30){count_30ms = 0;task_30ms_flag = 1;}// 50ms任务count_50ms++;if (count_50ms >= 50){count_50ms = 0;task_50ms_flag = 1;}// 100ms任务count_100ms++;if (count_100ms >= 100){count_100ms = 0;task_100ms_flag = 1;}
}void main(void)
{// 初始化定时器0TMOD = 0x01;  // 定时器0工作在模式1TH0 = TIMER0_INIT_VALUE >> 8;  // 预设初值TL0 = TIMER0_INIT_VALUE & 0xFF;TR0 = 1;  // 启动定时器0ET0 = 1;  // 允许定时器0中断EA = 1;   // 允许总中断while (1){// 执行10ms任务if (task_10ms_flag){task_10ms_flag = 0;// 在此处执行10ms的任务}// 执行30ms任务if (task_30ms_flag){task_30ms_flag = 0;// 在此处执行30ms的任务}// 执行50ms任务if (task_50ms_flag){task_50ms_flag = 0;// 在此处执行50ms的任务}// 执行100ms任务if (task_100ms_flag){task_100ms_flag = 0;// 在此处执行100ms的任务}}
}

程序说明:

  • 定时器设置:使用定时器0(TMOD = 0x01),工作在模式1下,计时器1ms。通过中断每1ms计时,并根据计数器判断是否到达设定的任务执行时间。

  • 任务标志位:使用四个标志位 task_10ms_flagtask_30ms_flagtask_50ms_flagtask_100ms_flag 来表示对应的任务是否需要执行。

  • 任务执行:在主循环中,根据任务标志位的状态执行对应的任务,每次任务完成后将对应的标志位清零。

注意事项:

  • 定时器配置:根据具体的晶振频率和需求调整 TIMER0_INIT_VALUE 的值,确保定时器产生1ms的中断。

  • 任务执行顺序:任务按照设定的时间间隔执行,且串行执行,适合简单控制任务。

  • 实时性:由于是基于定时器中断,任务的实时性取决于定时器的精确性和系统负载。

这个简单的示例展示了如何在 C51 单片机上实现基于定时器和任务标志位的任务协同方式,适用于对实时性要求不是非常高的简单控制和数据采集应用。


在上述的程序中,的确存在一种可能性,即30ms和50ms的任务同时在处理的情况。这是因为任务标志位 task_30ms_flagtask_50ms_flag 可能会在同一个定时器中断周期内同时被置位,从而导致它们在主循环中几乎同时被检测到并执行对应的任务代码段。

要解决这个问题,可以考虑以下几点改进:

  1. 任务优先级管理:在任务标志位设置时,考虑将更高优先级的任务标志位先置位,确保高优先级任务优先执行。例如,在定时器中断处理函数中,先处理100ms任务标志位,然后是50ms、30ms、最后是10ms任务标志位。

  2. 任务执行顺序控制:在主循环中,确保每次只处理一个任务标志位,并且每个任务完成后清除对应的标志位。这样可以避免同时处理多个任务的情况。

  3. 优化任务时间间隔:考虑调整任务的时间间隔,使得不同任务的触发时间点尽可能错开,减少同时触发的可能性。

下面是改进后的代码示例,演示如何根据任务的优先级顺序处理任务标志位:

#include <REG51.H>// 定义任务标志位
bit task_10ms_flag = 0;
bit task_30ms_flag = 0;
bit task_50ms_flag = 0;
bit task_100ms_flag = 0;// 定义定时器0的初值
#define TIMER0_INIT_VALUE 65536 - (12000 / 12)  // 12MHz晶振,计时1ms// 定时器0中断处理函数
void Timer0_ISR(void) interrupt 1
{static unsigned char count_10ms = 0;static unsigned char count_30ms = 0;static unsigned char count_50ms = 0;static unsigned char count_100ms = 0;// 100ms任务count_100ms++;if (count_100ms >= 100){count_100ms = 0;task_100ms_flag = 1;}// 50ms任务if (count_100ms % 50 == 0){task_50ms_flag = 1;}// 30ms任务if (count_100ms % 30 == 0){task_30ms_flag = 1;}// 10ms任务count_10ms++;if (count_10ms >= 10){count_10ms = 0;task_10ms_flag = 1;}
}void main(void)
{// 初始化定时器0TMOD = 0x01;  // 定时器0工作在模式1TH0 = TIMER0_INIT_VALUE >> 8;  // 预设初值TL0 = TIMER0_INIT_VALUE & 0xFF;TR0 = 1;  // 启动定时器0ET0 = 1;  // 允许定时器0中断EA = 1;   // 允许总中断while (1){// 执行100ms任务if (task_100ms_flag){task_100ms_flag = 0;// 在此处执行100ms的任务}// 执行50ms任务if (task_50ms_flag){task_50ms_flag = 0;// 在此处执行50ms的任务}// 执行30ms任务if (task_30ms_flag){task_30ms_flag = 0;// 在此处执行30ms的任务}// 执行10ms任务if (task_10ms_flag){task_10ms_flag = 0;// 在此处执行10ms的任务}}
}

改进说明:

  • 优先级处理:在定时器中断处理函数中,先处理更高优先级的任务标志位(例如100ms任务),然后逐级处理较低优先级的任务标志位。这样可以确保在同一个定时器中断周期内只有一个任务标志位被置位。

  • 顺序执行:在主循环中,每次只检测并执行一个任务标志位的任务,确保任务的顺序执行,并在每个任务完成后清除对应的标志位。

通过这样的改进,可以有效避免30ms和50ms任务同时在处理的情况,保证任务执行的可控性和稳定性。

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

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

相关文章

[小试牛刀-习题练]《计算机组成原理》之指令系统

一、选择题 0.【指令-课本习题】某计算机按字节编址&#xff0c;指令字长固定且只有两种指令格式&#xff0c;其中三地址指令29条&#xff0c;二地址指令107条&#xff0c;每个地址字段为6位&#xff0c;则指令字长至少应该是&#xff08;A&#xff09; A.24位 B. 26位 C. 28位…

ctfshow web sql注入 web242--web249

web242 into outfile 的使用 SELECT ... INTO OUTFILE file_name[CHARACTER SET charset_name][export_options]export_options:[{FIELDS | COLUMNS}[TERMINATED BY string]//分隔符[[OPTIONALLY] ENCLOSED BY char][ESCAPED BY char]][LINES[STARTING BY string][TERMINATED…

记一次:poi填充Word模板

前言&#xff1a;笔者在实际工作中需要生成一些报告&#xff0c;但报告的模板是固定的&#xff0c;指定位置需要替换数据或图片&#xff0c;因此总结一下 正题&#xff1a;话不多说&#xff0c;直接贴上工具类吧 package com.lhkj.iot.controller.poi;import java.io.File; i…

Unity丧尸围城Demo总结

1.BasePanel和UIManager 子类面板继承BasePanel&#xff0c;UIManager实现动态创建面板&#xff0c;展示面板&#xff0c;隐藏面板&#xff0c;得到面板 &#xff08;1&#xff09;单例类 &#xff08;2&#xff09;canvas设置为预制体&#xff0c;将新创建的面板设置为该子类 …

【面试题】网络IO多路复用模型之异步事件

目录 异步事件模型的概念 工作流程&#xff1a; WSAEventSelect模型的优势和不足 代码&#xff1a; 异步事件模型的概念 WSAEventSelect模型是WindowsSockets提供的另外一个有用的异步I/O模型。该模型允许一个或多个套接字上接收以事件为基础的网络事件通知。Windows Sock…

面试专区|【40道移动端测试高频题整理(附答案背诵版)】

iOS应用和Android应用测试有什么侧重点&#xff1f; iOS应用和Android应用测试的侧重点略有不同&#xff0c;主要表现在以下几个方面&#xff1a; 分辨率和屏幕尺寸&#xff1a;Android设备的分辨率和屏幕尺寸多种多样&#xff0c;因此&#xff0c;需要测试更多的分辨率和屏幕…

2.Mybatics_映射器与参数

文章目录 映射器与参数一.XML映射器1.创建工具类2.SQL语句操作:3.模糊查询4.返回多个聚合函数的结果5.返回分组后的结果 二.不同个数参数的处理1.单个参数2.对象参数3.多个参数4.传入一个map类型的参数5.添加注册方法引出service层概念 映射器与参数 一.XML映射器 1.创建工具…

Android系统层屏蔽弹出停止运行对话框

项目场景&#xff1a; 车载项目&#xff0c;ATC8257-Android9.0系统平台&#xff0c;福田汽车P3系列项目 项目使用高德公版地图前提是无法获得任何高德定制服务&#xff0c;每次刷完机去切换语言系统会弹出"高德地图已停止运行"弹窗&#xff0c;严重影响用户使用体…

【第三版 系统集成项目管理工程师】第6章 数据工程

持续更新。。。。。。。。。。。。。。。 【第三版】第六章 数据工程 6.1数据采集和预处理6.1.1 数据采集 P2346.1.2 数据预处理6.1.3 数据预处理方法1.缺失数据的预处理-P2352.异常数据的预处理-P2363.不一致数据的预处理-P2364.重复数据的预处理-P2365.格式不符数据的预处理…

面经总结dd

java基础: 为什么重写hashcode和equals? hash码由对象的内存地址或者对象的属性计算而出,可以作为键值对的键例如hashmap中的key通过hashcode高低位异或计算比如在hashmap中,hashcode是确定桶的位置,然后通过equals()方法找到正确的对象,即认为不同的对象有着相同的桶(…

Perl 循环

Perl 循环 Perl 是一种功能强大的编程语言,广泛用于文本处理、系统管理、网络编程等领域。在 Perl 中,循环是控制程序流程的关键组成部分,它允许我们重复执行代码块,直到满足特定的条件。本文将详细介绍 Perl 中的各种循环结构,包括 for 循环、while 循环、until 循环、f…

uniApp 封装VUEX

Vuex Store (index.js) import Vue from vue; import Vuex from vuex; import Cookies from js-cookie;Vue.use(Vuex);const saveStateKeys [vuex_user, vuex_token, vuex_demo];const initialState {vuex_user: { name: 用户信息 },vuex_token: Cookies.get(token) || ,vue…

UE5 03-物体碰撞检测

在你需要碰撞的物体上添加一个碰撞检测组件 碰撞预设 设置为NoCollision,这样移动过程中就不会有物理碰撞阻挡效果,只负责检测是否碰撞,比较难解释,如果学过Unity的话,可以把它理解成 Collision 为 Trigger

My sql 安装,环境搭建

以下以MySQL 8.0.36为例。 一、下载软件 1.下载地址官网&#xff1a;https://www.mysql.com 2. 打开官网&#xff0c;点击DOWNLOADS 然后&#xff0c;点击 MySQL Community(GPL) Downloads 3. 点击 MySQL Community Server 4.点击Archives选择合适版本 5.选择后下载第二个…

密码学复习

目录 基础 欧拉函数 欧拉函数φ(n)定义 计算方法的技巧 当a=a_1*a_2*……*a_n时 欧拉定理 剩余系 一些超简单密码 维吉尼亚 密钥fox 凯撒(直接偏移) 凯特巴氏(颠倒字母表) 摩斯密码(字母对应电荷线) 希尔(hill)密码 一些攻击 RSA 求uf+vg=1 快速幂模m^…

Python | Leetcode Python题解之第213题打家劫舍II

题目&#xff1a; 题解&#xff1a; class Solution:def rob(self, nums: List[int]) -> int:def robRange(start: int, end: int) -> int:first nums[start]second max(nums[start], nums[start 1])for i in range(start 2, end 1):first, second second, max(fi…

Bootstrap 图片

Bootstrap 图片 Bootstrap 是一个流行的前端框架,它提供了一套丰富的工具和组件,用于快速开发响应式和移动优先的网页。在本文中,我们将探讨如何使用 Bootstrap 来处理和展示图片,包括图片的响应式设计、图片样式和图片布局。 响应式图片 Bootstrap 通过其栅格系统提供了…

人工智能在物流领域的应用,智慧物流大有可为!

物流是复合型服务产业&#xff0c;作为经济的重要组成部分&#xff0c;受到人工智能技术的深刻影响。物流行业的人工智能应用也将助推人工智能技术的发展&#xff0c;人工智能技术应用于物流行业&#xff0c;应用领域包括以下方向&#xff1a; 第一、车货匹配系统 使用人工智…

CSS弹性布局:打造响应式与灵活的网页设计

一、弹性布局是什么&#xff1f; 弹性布局&#xff08;Flexbox&#xff09;是一种CSS布局模型&#xff0c;它提供了一种更加高效的方式来对容器中的项目进行布局、对齐和分配空间。与传统的布局方式相比&#xff0c;Flexbox旨在提供一个更加灵活的方式来布局复杂的网页结构&am…

AI智能音箱用2×15W立体声功放芯片NTP8918

智能音箱是近年来非常受欢迎的智能家居产品之一&#xff0c;它集成了人工智能技术和音频技术&#xff0c;能够为用户提供语音助手、音乐播放、智能家居控制等多种功能。其中&#xff0c;音频输出是智能音箱的核心功能之一&#xff0c;而功放芯片则是实现音频放大的关键组成部分…