FreeRTOS初级篇----任务管理

2023-05-16

一、任务状态

再FreeRTOS中,CPU同一时刻只执行一个任务,只不过是所有任务切换的速度特别快,默认1ms切换一次任务,所以宏观上来看就是CPU再同时运行所有任务。
根据任务的执行情况,任务有四种状态。
1、运行态Running
2、就绪态Ready
3、阻塞态Blocked
4、挂起态Suspended
不论什么任务,他的状态肯定是上述的四种之一。
1、运行态Running:运行态就是正在执行的任务所处的状态,同一时刻只有一个任务能处于运行态,此任务拥有CPU的控制权。
2、就绪态Ready:就绪态就是任务目前可以正常运行,但是还没有轮到她,CPU正在被其他任务使用,所以他必须等待CPU控制权被释放出来,然后去获取CPU执行任务。
3、阻塞态Blocked:阻塞态就是任务被堵住了,因为任务正在等待某一事件发生,若事件不发生,则阻塞态的任务就会一直被堵着,得不到执行,直到他所等待的事件发生。比如等待信号量、消息队列等而处于的状态就是阻塞态,另外调用FreeRTOS中的延迟函数也会使任务进入阻塞态。
4、挂起态Suspended:跟阻塞态差不多,任务都得不到执行,必须有特定的条件才能执行。挂起态的任务会退出任务调度系统,调度器看不到此任务。进入挂起态唯一的方法就是使用vTaskSuspend()函数,参数传入NULL就会把自己挂起。

void vTaskSuspend( TaskHandle_t xTaskToSuspend ); 

如果要让任务退出挂起态,只能由别的任务来实现。
使用vTaskResume ()xTaskResumeFromISR()这两个函数来取消别的任务的挂起状态,将任务从挂起态恢复。
任务状态转换图:
在这里插入图片描述
实验:
创建3个任务,在任务1中,程序运行10个tick的时候,把任务3挂起,运行20个tick的时候,把任务3在唤醒。在任务2中,延时10个tick,使自己进行阻塞态。

TaskHandle_t xHandleTask1;
TaskHandle_t xHandleTask2;
TaskHandle_t xHandleTask3;
void Task1(void * param)
{
	TickType_t TickCountOld = xTaskGetTickCount();
	TickType_t TickCountNew;
	while(1)
	{
		TickCountNew = xTaskGetTickCount();
		
		Task1RunningFlag = 1;
		Task2RunningFlag = 0;
		Task3RunningFlag = 0;
		printf("A");
		if(TickCountNew - TickCountOld == 10)
		{
			vTaskSuspend(xHandleTask3);
		}
		if(TickCountNew - TickCountOld == 20)
		{
			vTaskResume(xHandleTask3);
		}	
	}	
}
void Task2(void * param)
{
	while(1)
	{
		Task1RunningFlag = 0;
		Task2RunningFlag = 1;
		Task3RunningFlag = 0;
		printf("a");
		vTaskDelay(10);
	}	
}
StackType_t xTask3Stack[100];
StaticTask_t xTask3Tcb;
void Task3(void * param)
{
	while(1)
	{
		Task1RunningFlag = 0;
		Task2RunningFlag = 0;
		Task3RunningFlag = 1;
		printf("1");
	}	
}
StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTcb;
void vApplicationGetIdleTaskMemory(StaticTask_t * * ppxIdleTaskTCBBuffer, StackType_t * * ppxIdleTaskStackBuffer, uint32_t * pulIdleTaskStackSize)
{
	*ppxIdleTaskTCBBuffer = &xIdleTaskTcb;
	*ppxIdleTaskStackBuffer = xIdleTaskStack;
	*pulIdleTaskStackSize = 100;
}
int main( void )
{
	prvSetupHardware();
	printf("Hello World!\r\n");

	xTaskCreate(Task1,"Task1",100,NULL,1,&xHandleTask1);
	xTaskCreate(Task2,"Task2",100,NULL,1,&xHandleTask2);
	xHandleTask3 = xTaskCreateStatic(Task3,"Task3",100,NULL,1,xTask3Stack,&xTask3Tcb);

	vTaskStartScheduler();
	return 0;
}

输出结果:
在这里插入图片描述
图中两条灰色虚线之间的空隙代表2ms,可以看到,任务2每次停止运行10ms,说明任务2调用vTaskDelay(10);函数使自己进入阻塞态10个tick,任务3在10个tick后,被任务1调用vTaskSuspend(xHandleTask3);函数,使其被挂起,然后又在10个tick后,调用vTaskResume(xHandleTask3);函数,唤醒任务3,任务3重新运行。

二、延时函数

FreeRTOS中提供了两个延时函数。
1、

vTaskDelay(const TickType_t xTicksToDelay );`

此函数的延时时间是任务前一次结束的时间到任务后一次开始的时间是xTicksToDelay ms。不管任务一次的运行时间是长还是短,延时的是一次结束到下次开始的时间。
在这里插入图片描述

2、

BaseType_t xTaskDelayUntil( TickType_t * const pxPreviousWakeTime, const TickType_t xTimeIncrement ) 

此函数的延时时间是任务前一次开始的时间到任务后一次开始的时间。不管任务一次的运行时间是长还是短,延时的是一次开始到下次开始的时间。这种延时可以让任务周期性的被执行。
在这里插入图片描述

三、空闲任务及其钩子函数

空闲任务里面会执行一些清理工作,清理任务产生的无用内存。
比如在vTaskDelete( TaskHandle_t xTaskToDelete )任务删除函数中,有下面的一段话,大致意思是,如果任务自己删除自己,这样就不会完成一些清理工作,必须由空闲任务完成清理工作,来释放内存。
在这里插入图片描述
实验:
main函数创建任务2,任务2里面不断的创建任务1,任务1自己删除自己。

void Task1(void * param)
{
	while(1)
	{
		printf("A");
		vTaskDelete(NULL);
	}
}
void Task2(void * param)
{
	TaskHandle_t xHandleTask1;
	BaseType_t xReturn;
	while(1)
	{
		printf("a");
		xReturn = xTaskCreate(Task1,"Task1",1024,NULL,2,&xHandleTask1);
		if(xReturn != pdPASS)
		{
			printf("Task1 create fail!\r\n");
		}
	}	
}
int main( void )
{
	prvSetupHardware();
	printf("Hello World!\r\n");

	xTaskCreate(Task2,"Task2",100,NULL,1,NULL);
	
	vTaskStartScheduler();
	return 0;
}

输出结果:
在这里插入图片描述
可以看到,程序正常运行几次之后,在创建任务就失败了,因为任务1自己删除自己产生的无用内存没有被释放,直到所有内存空间都被用完了,任务2在创建任务就创建失败。
这样我们知道了,在空闲任务里面会清理自我删除的任务,那么空闲任务是在哪里被创建的呢?
进入启动任务调度器函数vTaskStartScheduler( )。可以看到空闲任务是在这里面被创建的。
在这里插入图片描述
在这里插入图片描述
在里面,既可以静态创建也可以动态创建。
除了清理自我删除的任务,空闲任务还会做一些其他的事情,比如执行后台需要连续执行的函数、测量系统的空闲时间、进入省电模式等。
用户可以修改空闲任务函数,在里面执行一些自己需要的代码,但是这样就会破坏FreeRTOS的文件,所以FreeRTOS为空闲任务提供了一个钩子函数,类似ST公司HAL库中的一些中断函数中,为用户提供的回调函数。用户可以在钩子函数中填写自己的代码,然后空闲任务内部会调用这个钩子函数,从而去执行用户自己的代码。
进入空闲任务函数,可以看到他在内部会调用钩子函数。
在这里插入图片描述
对于钩子函数,也有一些要求。钩子函数不能导致空闲任务进入阻塞状态或暂停状态。空闲任务被阻塞了,那么可能永远也不会被唤醒。所以空闲任务必须处于运行态和就绪态两种状态之一。而且钩子函数也不能太过复杂,执行的时候要非常高效的执行,不能占用太长的时间。而且钩子函数千万不能和任务函数一样,用死循环结束,否则钩子函数就退不出去了。
实验:
首先定义宏,使能空闲任务钩子函数。

#define configUSE_IDLE_HOOK			1

编写任务1、2和钩子函数。任务1、2的内容跟上面的一样,只不过是加了flag便于观察现象。钩子函数也是之加入了标志位观察现象。

void Task1(void * param)
{
	while(1)
	{
		Task1RunningFlag = 1;
		Task2RunningFlag = 0;
		IdleRunningFlag = 0;
		printf("1");
		vTaskDelete(NULL);
	}
}
void Task2(void * param)
{
	TaskHandle_t xHandleTask1;
	BaseType_t xReturn;
	while(1)
	{
		Task1RunningFlag = 0;
		Task2RunningFlag = 1;
		IdleRunningFlag = 0;
		printf("2");
		xReturn = xTaskCreate(Task1,"Task1",1024,NULL,2,&xHandleTask1);
		if(xReturn != pdPASS)
		{
			printf("Task1 create fail!\r\n");
		}
	}	
}
void vApplicationIdleHook(void)
{
	Task1RunningFlag = 0;
	Task2RunningFlag = 0;
	IdleRunningFlag = 1;
	printf("0");
}
int main( void )
{
	prvSetupHardware();
	printf("Hello World!\r\n");
	
	xTaskCreate(Task2,"Task2",100,NULL,0,NULL);

	vTaskStartScheduler();
	return 0;
}

注意:要把任务2的优先级设置为0,与空闲任务同一个优先级,否则空闲任务得不到执行,同样也不能清理内存。
输出结果:
在这里插入图片描述在这里插入图片描述
可以看到,程序一直在运行,任务2创建任务1也能一直创建成功。任务1执行完,然后删除自己,这样优先级为0的任务2和空闲任务才能运行,二者交替运行,在空闲任务中,会把任务1删除自己产生的内存碎片清理掉,然后任务2继续创建任务1,每次空闲任务都会清理任务1的碎片,这样就会一直由空闲的内存来创建任务1了。

四、任务调度

之前说过,FreeRTOS中,高优先级任务优先执行,同优先级任务交替执行,这其实只是FreeRTOS中的一种调度方式,除此之外,还有别的任务调度方式。
任务调度方式有3部分可以选择,一个是不同优先级任务之间是否可以抢占,另一个是同优先级任务之间的切换方式,最后一个是空闲任务是否礼让。
FreeRTOSConfig.h文件中,通过三个宏是来配置上面所说的任务调度模式,分别是configUSE_PREEMPTIONconfigUSE_TIME_SLICINGconfigIDLE_SHOULD_YIELD
一、 configUSE_PREEMPTION
configUSE_PREEMPTION为1,高优先级的任务优先执行,能抢占低优先级任务的CPU控制权,这也是FreeRTOS默认的任务调度模式。
实验:
创建三个任务,其中任务3优先级最高。

void Task1(void * param)
{
	while(1)
	{
		Task1RunningFlag = 1;
		Task2RunningFlag = 0;
		Task3RunningFlag = 0;
		IdleRunningFlag = 0;
		printf("1");
	}
}
void Task2(void * param)
{
	TaskHandle_t xHandleTask1;
	BaseType_t xReturn;
	while(1)
	{
		Task1RunningFlag = 0;
		Task2RunningFlag = 1;
		Task3RunningFlag = 0;
		IdleRunningFlag = 0;
		printf("2");
	}	
}
void Task3(void * param)
{
	const TickType_t xDelay5ms = pdMS_TO_TICKS(5UL)
	while(1)
	{
		Task1RunningFlag = 0;
		Task2RunningFlag = 0;
		Task3RunningFlag = 1;
		IdleRunningFlag = 0;
		printf("3");
		vTaskDelay(xDelay5ms);
	}	
}
void vApplicationIdleHook(void)
{
	Task1RunningFlag = 0;
	Task2RunningFlag = 0;
	Task3RunningFlag = 0;
	IdleRunningFlag = 1;
	printf("0");
}

int main( void )
{
	prvSetupHardware();
	printf("Hello World!\r\n");

	xTaskCreate(Task1,"Task1",100,NULL,0,NULL);
	xTaskCreate(Task2,"Task2",100,NULL,0,NULL);
	xTaskCreate(Task3,"Task3",100,NULL,2,NULL);

	vTaskStartScheduler();
	return 0;
}

输出结果:
在这里插入图片描述
可以看到,任务3执行的时候,其他任务得不到执行,只有在任务3进入阻塞态后,任务1、2和空闲任务才会交替执行,等任务3退出阻塞态后,立刻执行任务3。

configUSE_PREEMPTION为0,所有优先级的任务都不能抢占CPU,只能等待正在执行的任务把CPU释放出来后,才能获取CPU控制,得到执行。
FreeRTOSConfig.h文件中,把宏 configUSE_PREEMPTION更改为0,然后重新执行上面的任务。
输出结果:
在这里插入图片描述
可以看到,任务3优先级最高,先执行一次,然后进入阻塞态,然后任务1执行,由于任务1自己不进入阻塞态,所以他会一直执行下去,即使更高优先级的任务3退出阻塞态,也得不到执行。
二、configUSE_TIME_SLICING
configUSE_TIME_SLICING用来配置同优先级任务的调度模式。
configUSE_TIME_SLICING 为1,则同优先级任务交替执行,也可以叫时间片轮转,每个任务轮流执行一段时间。此模式也是FreeRTOS默认的模式。从上面的实验可以看到同优先级任务交替执行的现象,这里就不再演示了。
configUSE_TIME_SLICING 为0,时间片不轮转,同优先级任务不会主动切换,而是要等发生一个任务调度,才会被动的切换任务。下面是实验演示,代码还是之前的,只不过是把宏configUSE_TIME_SLICING设置为了0。
输出结果:
在这里插入图片描述
可以看到,任务3休眠期间,只有1个低优先级任务会被执行,只有当任务3退出阻塞态重新执行,也就是发生一次任务调度之后,低优先级任务才会被切换。之前是在任务3一次阻塞期间,其余3个0优先级任务都会交替执行,而这种模式下只会执行1个任务。

三、configIDLE_SHOULD_YIELD
configIDLE_SHOULD_YIELD决定空闲任务是否礼让其他任务。礼让的意思就是空闲任务执行一次就发生一次任务调度,从而让CPU去执行其他的程序。空闲任务实际上内部也是一个while(1)死循环,在循环内部调用钩子函数并且根据宏configIDLE_SHOULD_YIELD选择是循环一次发生调度还是循环多次在发生调度。
configIDLE_SHOULD_YIELD为1,则空闲任务会礼让其他任务,内部while(1)循环执行一次就立刻发生调度,去执行别的任务。
波形图:
在这里插入图片描述
可以看到,空闲任务执行的时间每次都很短,说明空闲任务只执行了很短的时间就不执行了,去执行别的任务。
configIDLE_SHOULD_YIELD为1,则空闲任务不会礼让其他任务,空闲任务和其他的任务有同等的地位,执行时间也都是差不多相同的。
波形图:
在这里插入图片描述
可以看到,此时的空闲任务的执行时间明显变长了很多,他和任务1、2的执行时间都是差不多的。
根据上面三种情况,可以实现不同的任务调度模式。
在这里插入图片描述
通常第一种情况使用的最多,其余四种任务调度方式几乎不怎么用到。也就是configUSE_PREEMPTIONconfigUSE_TIME_SLICINGconfigIDLE_SHOULD_YIELD这三个宏都配置为1。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS初级篇----任务管理 的相关文章

  • MOS管开关电路应用及MOS管原理、选型

    目录 硬件基础 MOS管原理 使用 开关电路应用0 写在前面 xff1a 1 MOS管基本原理及分类1 1 MOS管分类1 2 MOS管导通原理1 3 MOS管输出特性曲线1 4 MOS管的转移特性1 5 MOS管的寄生二极管 xff1a
  • MQTT服务器搭建和ESP32实现MQTT代码

    文章目录 1 MQTT介绍 xff1a 1 1 需求介绍1 2 MQTT介绍 xff1a 2 具体实现 xff1a 2 1 库推荐2 2 配置MQTT的服务器Broker xff1a 2 3 PubSubClient库使用 xff1a 3
  • 三极管从入门到精通

    文章目录 摘要1 基础1 1 PN结1 2 三极管 2 三极管模拟电路知识2 1 I V特性曲线2 2 极限参数解释2 3 基本共射极放大电路2 4 小信号模型2 5 用小信号模型分析基本共射极放大电路 3 三极管实际模拟电路应用图3 1
  • Type-C接口简单介绍-面向单片机应用

    Type C接口简单介绍 面向单片机应用 1 绪论 用单片机做一些东西时 xff0c Type C接口逐渐替代了MicroUSB接口 但不像MicroUSB那样只有5V GND D 43 D ID五个接口 xff0c Type C接口有24
  • 嵌入式硬件:放大器电路仿真

    文章目录 说明同向放大电路反向放大电路放大器滤波电路低通滤波电路proteus仿真TINA TI仿真 窄带滤波电路preteus仿真TINA TI仿真 参考 说明 书上的放大电路图很多都是理论图 xff0c 和实际应用有所差异 比如下面这个
  • git 切换分支

    1 查看所有分支 git branch a 2 查看当前分支 号表示当前分支 git branch 3 切换分支 git checkout 39 分支名 39 4 修改代码仓库 git remote set url origin 39 仓库
  • 嵌入式安卓开发:使用Camera2获取相机

    文章目录 Camera2介绍Camera2的主要API类介绍CameraManager通过CameraManage获取Cameracharacteristics通过CameraManage获取CameraDevice从CameraDevic
  • ESP32的VSPI和HSPI

    说明 SPI共有4根线 xff0c MOSI MISO CS CLK xff0c 在ESP32中对应规则如下表 xff1a ESP32共有4个SPI xff0c 但是用户能够使用的只有2个SPI xff0c 分为VSPI和HSPI 引脚接口
  • Android Studio添加EasyPemissions

    问题描述 按照EasyPermissions主页描述的那样添加完依赖后 xff0c 在程序中使用还是报错 xff1a Failed to resolve pub devrel easypermissions 0 3 0 解决方法 首先 xf
  • ROS:话题编程 订阅者Subscriber的简单实现

    1 xff08 1 xff09 编写一个C 43 43 话题订阅者 该例程将订阅 turtle1 pose话题 xff0c 消息类型turtlesim Pose include lt ros ros h gt include 34 turt
  • 浅谈操作系统-启动过程

    前言 时光匆碌 xff0c 不知不觉都大三了 xff0c 在众多的专业课的学习中也算是找到了一些乐趣 xff0c 纸上得来终觉浅 xff0c 所以决定完整的回顾一下整个操作系统的知识 xff0c 为了理论与实践相结合 xff0c 以学校实验
  • 串口调试常见问题和排查方法

    串口UART作为嵌入式应用和通讯领域中最常用的接口之一 xff0c 接口协议虽然简单 xff0c 但在实际应用中不同设备之间的通讯也会存在各种小问题 xff0c 下面对使用中各种常见的问题做下总结和梳理 xff0c 可作为调试参考 串口可分
  • 3 POSIX 多任务及同步机制-拓展实验 条件变量与生产者-消费者问题

    3 POSIX 多任务及同步机制 拓展实验 条件变量与生产者 消费者问题 一 xff0e 实验目的 理解进程 线程同步问题 掌握POSIX条件变量机制的使用方法 深入理解在动态并发环境下 xff0c 进程 线程在运行过程中的资源竞争应发的问
  • 深度优先搜索DFS和广度优先搜索BFS

    相关博客链接 xff1a https www cnblogs com rjgcs p 5198467 html https blog csdn net xiaobo Clanguage article details 88085074 ht
  • 埋头努力之前得先看清方向

    埋头努力之前得先看清方向 写在工作半年 xff0c 第一次拿到绩效结果后 工作和学生时代最大的不同在于 xff0c 工作之后很多事情是消耗型的 xff0c 领导和组织看重的是输出 xff0c 而个人的成长和提升需要自己全权负责 这两者之间是
  • 周末写点轻松的吧

    一直觉得 有一段跟自己独处的时光是很幸福的事情 难得的双休日 xff0c 中午太阳很好 xff0c 照在绿萝上 xff0c 嫩嫩绿绿的叶子很漂亮 前几周去花市买了盆栀子花 xff0c 整整一大盆 xff0c 上面布满了花苞 以前见过开了花的
  • 为什么大部分的C/C++码农都成不了高级工程师?真实原因是缺少核心能力!

    一般来说技术团队的金字塔顶尖往往是技术最牛的人做底层架构师 xff08 或高级工程师 xff09 所以底层架构师在广大码农中的占比大概平均不到 20 然而80 码农干上许多年都是重复以下内容 xff0c 所以做不了架构师 xff0c 正在辛
  • kaggle邮箱不能验证+安装python的Speedml库

    注册kaggle账号遇到一些问题 下面是具体问题和解决方案 希望遇到同样问题的小伙伴不要再踩到坑啦 1kaggle邮箱不能验证You did not enter the correct captcha response Please try
  • 用程序验证生日“悖论”

    生日 悖论 其实并不是悖论 xff0c 它是说在一个人数超过23人的集体中 xff0c 至少有两个人生日在同一天的概率约为0 5 因为这个理论上的概率与人们的直觉不符 xff0c 才会被称为 悖论 我们可以用一个简单的小程序验证它哦 xff
  • python 中 defaultdict 的用法

    场景 xff1a 统计一个字符串列表中每个字符串的频数 一个明显的方法是建立一个键是字符串 xff0c 值是频数的字典 方法1 xff1a word count 61 for word in document if word in word

随机推荐

  • K近邻算法所面临的维数灾难问题

    K近邻算法的基本思想 K近邻算法是一种常用的监督学习方法 xff0c 其原理非常简单 xff1a 给定测试样本 xff0c 基于某种距离找出训练集中与其最靠近的K个训练样本 xff0c 然后基于这K个邻居的信息来进行预测 两个基本要素 xf
  • Android广播发送机制剖析【android广播系列二】

    上篇博客大致说了说广播的注册机制 xff0c 动态注册和静态注册广播的原理还不一样 xff0c 动态广播最后HashMap中了 xff0c 最后放到mReceiverResolver中 xff0c 以后当ActivityManagerSer
  • 观察者模式--Java设计模式

    观察者模式定义 xff1a 定义了对象之间的一对多的依赖 xff0c 这样一来 xff0c 当一个对象发生改变状态的时候 xff0c 它的所有依赖者都会收到通知并自动更新 参考如下图 xff1a 观察者设计模式也叫发布 订阅模式 也可以称作
  • Android——RuntimePermission介绍

    1 介绍 androidM版本上 xff0c 对permission的管理做了部分改动 xff0c 针对dangerous permission xff0c 不在安装的时候给予权限 xff0c 而是在运行过程中咨询用户是否给予app响应的权
  • Android中launcherMode="singleTask"详解【android源码解析六】

    android中launcherMode有4中属性 xff1a standard 默认 xff0c singleTop xff0c singleTask和 singleInstance xff1b 网上有好多例子讲解这四种关系的 xff1a
  • Android闹钟最终版【android源码闹钟解析】

    我以前写了个复杂闹钟的demo xff0c 参见 Android闹钟 复杂版 大明进化十五 但是里面的bug有一些 xff0c 好多人留言 xff0c 所以我就看看源码 xff0c 找找原因 xff1f 顺便把源码代码整理出来 xff0c
  • Smali--Dalvik虚拟机指令语言-->【android_smali语法学习一】

    最近一周在研究rom移植 xff0c 所以就对Smali语言学习了一下 xff0c Smali语言其实就是Davlik的寄存器语言 xff1b Smali语言就是android的应用程序 apk通过apktool反编译出来的都有一个smal
  • 程序员平均月薪过万,想当程序员的话,大学学那些专业会更好呢?

    在互联网时代 xff0c 程序员成为炙手可热的职业 虽然加班累成狗 xff0c 也有可能面临英年早秃的局面 xff0c 但是不得不说程序员的工资高于很多很多传统行业职位的工资 据统计 xff0c 应届程序员毕业生在一线城市平均月薪达到8k
  • android4.0自定义锁屏总结【android锁屏研究一】

    最近搬家了 xff0c 从北京 gt 深圳 xff0c 除了天气有点不同外 xff0c 其他的都差不多 xff0c 工作性质和以前也类似 xff01 纪念一下自己的迁移 题外话 转载请表明出处 xff1a http blog csdn ne
  • android系统锁屏详解【android锁屏解析二】

    谷歌的代码写的确实不错 xff0c 我很幸运 xff0c 一开始接触代码就赶上了谷歌这个开源的系统 xff0c 让我的视野开阔了很多 xff0c 也让我看到了优秀的代码工程师写到的代码 心怀感恩之心 题记 我的有篇文章说了这个锁屏 xff0
  • 单片机学习笔记8--按键和外部中断(基于百问网STM32F103系列教程)

    第八章 按键和外部中断 第一节 按键原理 GPIO内部上拉较弱 xff0c 可根据满足电路需求选择是用内部的上拉还是自己外接上拉 根据原理图可知 xff0c 当按键松开时 xff0c 单片机引脚连接在高电平上 xff0c GPIO口输入高电
  • ARM架构与编程6--重定位(基于百问网ARM架构与编程教程视频)

    一 启动程序流程 我们之前讲过 xff0c 单片机有根据boot的不同 xff0c 有三种启动方式 xff1a boot0boot1启动模式0Xflash启动10系统存储器11内置SRAM 单片机上电复位后 xff0c 运行main函数 以
  • LVGL8.1版本笔记

    之前学过LVGL6 xff0c 现在版本更新到LVGL8了 xff0c 学习下新版本 xff0c 本文主要是记录一些LVGL8的新特性 xff0c 区别和lvgl6的不同之处 lv task handler 的作用 链接 lv task h
  • STM32F407定时器输入捕获

    STM32F407定时器一共有14个 其中分为基本定时器 通用定时器 高级定时器 具体功能如上图所示 下面介绍下输入捕获模式 输入捕获 xff1a 通过检测TIMx CHx上的边沿信号 在边沿信号发生跳变的时候 将当前的定时器的值 TIMx
  • 几种常见的存储器

    存储器分为易失性存储器和非易失性存储器 其中的易失性是指存储器掉电是否能保存数据 易失性存储器 xff1a 就是我们常说的RAM xff0c 这种存储器掉电后所有数据都消失 xff0c 不会被保存 xff0c 重新上电之后 xff0c 原来
  • FreeRTOS初级篇----优先级实验

    FreeRTOS创建任务时 xff0c 可以设置任务的优先级 在FreeRTOS中优先级的值越小 xff0c 优先级越低 xff0c 其他的RTOS都是优先级值越小 xff0c 优先级越高 xff0c 这点需要注意 任务优先级实验 xff1
  • FreeRTOS初级篇----删除任务

    任务既然可以被创建 xff0c 那么自然也可以被删除 xff0c 对于某些执行一次或几次就不需要的任务来说 xff0c 可以在执行完成后 xff0c 把此任务删除 xff0c 可以通过别的任务将其删除 xff0c 也可以任务自己删除自己 任
  • FreeRTOS初级篇----一个函数创建多个任务

    之前说过 xff0c 创建任务的时候 xff0c 可以传递给任务参数 xff0c 下面通过实验 xff0c 对一个任务函数传入不同的参数展示如何使用一个函数创建多个任务 任务函数 xff1a 把传入的数据转换为int型数据然后打印出来 sp
  • 大学生想要通过看书自学编程,却始终没成功,是因为你没有技巧!

    在大学里面 xff0c 有很多的方式来学习编程 xff0c 从在线教程到完成在线课程 xff0c 到密集编程的新手训练营 教程都很棒 xff0c 但它们通常只给你基础知识 与此同时 xff0c 在线教程和线下课程可能非常昂贵 xff0c 虽
  • FreeRTOS初级篇----任务管理

    一 任务状态 再FreeRTOS中 xff0c CPU同一时刻只执行一个任务 xff0c 只不过是所有任务切换的速度特别快 xff0c 默认1ms切换一次任务 xff0c 所以宏观上来看就是CPU再同时运行所有任务 根据任务的执行情况 xf