IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 单片机工程经验 - 时间片 -> 正文阅读

[嵌入式]单片机工程经验 - 时间片

单片机工程经验 - 时间片

时间片

时间片很好理解,就是把一个任务分成若干个片段,每过一个时间节点就执行一个片段。在无操作系统的情况下,时间片可以非常有效的完成多个任务。它的本质是定时器的复用。

顺序执行

我们来考虑最简单的情况,一盏灯不断闪烁。最简单的方法就是先点亮一盏灯,等待500ms后熄灭,再等待500ms后点亮,如此往复不断循环,大多数的单片机教程里也是这么写的,因为这样很容易理解。

void mian()
{
	while(1)
	{
		open_led();
		delay(500);
		close_led();
		delay(500);
	}
}

这里的delay通常使用的是for循环的方法,因为单片机每次执行语句都需要一个时钟周期的时间,只要算好delay的时间需要多少个时间周期就可以准确的进行延时。

但是这里有个问题,因为在delay中需要一直执行空语句,它会一直霸占MCU,其他代码无法执行,多任务就无法进行。

多任务

如果此时我们需要一盏灯亮灭500ms,另一盏灯亮灭300ms该怎么实现?

其实很简单,我们先找到500和300的最大公约数,也就是100,然后只要delay一次就将计数值加一,这样只要知道计数值是不是就能知道过去了多少时间呢。

void mian()
{
	static unsigned int tick = 0;
	while(1)
	{
		delay(100);
		tick++;
		if(tick%10 == 0)
		{
			open_led();
		}
		else if(tick % 5 == 0)
		{
			close_led();
		}
		
		if(tick%6 == 0)
		{
			open_led_2();
		}
		else if(tick % 3 == 0)
		{
			close_led_2();
		}
	}
}

tick*100就是当前程序已经走过了多少ms,对于第一盏灯,只要tick能被10整除,就开灯,如果不能被10整除但能被5整除就灭灯,这样这盏灯就能在500ms关、1000ms开、1500ms关、2000ms开,第二盏灯也同理。

时间片

经过上述变种我们发现,只要将需要做的所有任务的间隔时间取最大公约数,然后通过计数就能实现多任务工作。

但是通常为了简单,我们会直接取一个非常小的时间来计数,比如1ms,这既符合人类的数字使用习惯,也能很好的被几乎所有整数整除。但是这里我们就要思考一个问题,延时1ms就真的是1ms执行一次嘛?

显然不是,因为即使你写的delay再怎么精准,其他的代码执行也同样需要时间,也许今天的代码执行需要0.5ms,那么你的时间片就是1.5ms,明天的代码执行需要0.7ms,那么你的时间片就是1.7ms。而你如果还是当1ms来计算时间,这种误差会不断的堆叠,最后造成不可预知的后果。

幸好我们的单片机都至少有个硬件定时器,它的时间完全独立于程序,如果将程序放进它的定时器中断中执行就完全不需要考虑由程序执行引起的时间偏移问题。

但这样就真的没有问题了嘛?

我们考虑以下情况,假设我们定时器中断1ms进入一次,而中断中的程序完全执行需要1.3ms,那么会发生什么后果?

上一次中断程序还没执行完全下一次中断已经到来,这样程序会完全陷入到中断中去。这样一来程序的其他中断可能由于优先级问题而完全不会进入,非中断代码则会完全不执行,因此时间片的选择需要大于你的程序执行时间。

大部分时候,我们的中断优先级是需要高于时间片的,因此将程序放在定时器中断中似乎并不是很好的选择。

简易框架

显然存在一种更好的方法,那就是把时间片的计数放到中断中,而将程序放到主循环里,这样既能保证时间片的准确,又能保证其他中断不被时间片的程序影响。这里简单介绍一个时间片框架

static unsigned char flag_1ms;
static unsigned char flag_10ms;
static unsigned char flag_100ms;
static unsigned char flag_1000ms;

void timer_irq() //1ms中断中调用
{
	static unsigned char tick_1ms;
	static unsigned char tick_10ms;
	static unsigned char tick_100ms;
	tick_1ms++;
	if(tick_1ms >= 10)
	{
		tick_1ms = 0;
		flag_10ms = 1;
		tick_10ms++;
		if(tick_10ms >= 10)
		{
			tick_10ms = 0;
			flag_100ms = 1;
			tick_100ms++;
			if(tick_100ms >= 10)
			{
				tick_100ms = 0;
				flag_1000ms = 1;
			}
		}
	}
}

void timer_loop()// while(1)大循环中调用
{
	if(flag_1ms == 1)
	{
		flag_1ms = 0;
		// 1ms时间片程序
	}
	if(flag_10ms == 1)
	{
		flag_10ms = 0;
		// 10ms时间片程序
	}
	if(flag_100ms == 1)
	{
		flag_100ms = 0;
		// 100ms时间片程序
	}
	if(flag_1000ms == 1)
	{
		flag_1000ms = 0;
		// 1000ms时间片程序
	}
}

在定时器中断调用timer_irq()在while(1)大循环中调用timer_loop(),然后将所有的时间片程序写在timer_loop()中,这样就能很好的实现时间片轮询系统了。

当然这个系统还很简陋,但它基本能适用所有单片机,了解基本原理,你也可以实现自己的时间片系统。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-02-16 13:16:43  更:2022-02-16 13:17:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:41:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码