FreeRTOS教程6 互斥量

这篇具有很好参考价值的文章主要介绍了FreeRTOS教程6 互斥量。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、准备材料

正点原子stm32f407探索者开发板V2.4

STM32CubeMX软件(Version 6.10.0)

Keil µVision5 IDE(MDK-Arm)

野火DAP仿真器

XCOM V2.6串口助手

2、学习目标

本文主要学习 FreeRTOS 互斥量的相关知识,包括优先级翻转问题、优先级继承、死锁现象、创建/删除互斥量 和 获取/释放互斥量等知识

3、前提知识

3.1、优先级翻转问题

使用二值信号量用于进程间同步时可能会出现优先级翻转的问题,什么是“优先级翻转”问题呢?考虑如下所述的任务运行过程

  • 在 t1 时刻,低优先级的任务 TaskLP 切入运行状态,并且获取到了一个二值信号量 Binary Semaphores
  • 在 t2 时刻,高优先级的任务 TaskHP 请求获取二值信号量 Binary Semaphores ,但是由于 TaskLP 还未释放该二值信号量,所以在 t3 时刻,任务 TaskHP 进入阻塞状态等待二值信号量被释放
  • 在 t4 时刻,中等优先级的任务 TaskMP 进入就绪状态,由于不需要获取二值信号量,因此抢占低优先级任务任务 TaskLP 切入运行状态
  • 在 t5 时刻,任务 TaskMP 运行结束,任务 TaskLP 再次切入运行状态
  • 在 t6 时刻,任务 TaskLP 运行结束,释放二值信号量 Binary Semaphores,此时任务 TaskHP 从等待二值信号量的阻塞状态切入运行状态
  • 在t7时刻,任务 TaskHP 运行结束

根据上述流程读者可以发现一个问题,即在 t4 时刻中等优先级的任务 TaskMP 先于高优先级的任务 TaskHP 抢占了处理器,这破坏了 FreeRTOS 基于优先级抢占式执行的原则,我们将这种情况称为优先级翻转问题,上述描述的任务运行过程具体时刻流程图如下图所示

优先级翻转可能是一个严重的问题,但在小型嵌入式系统中,通常可以在系统设计时通过考虑如何访问资源来避免该问题

3.2、优先级继承

为了解决使用二值信号量可能会出现的优先级翻转问题,对二值信号量做了改进,增加了一种名为 “优先级继承” 的机制,改进后的实例称为了互斥量,注意虽然互斥量可以减缓优先级翻转问题的出现,但是并不能完全杜绝

接下来我们来通过例子介绍什么是优先级继承?

仍然考虑由 “3.1、优先级翻转问题” 小节中提出的任务运行过程的例子,具体流程如下所述,读者可以细心理解其中的不同之处

  • 在 t1 时刻,低优先级的任务 TaskLP 切入运行状态,并且获取到了一个互斥量 Mutexes
  • 在 t2 时刻,高优先级的任务 TaskHP 请求获取互斥量 Mutexes ,但是由于 TaskLP 还未释放该互斥量,所以在 t3 时刻,任务 TaskHP 进入阻塞状态等待互斥量被释放,但是与二值信号量不同的是,此时 FreeRTOS 将任务 TaskLP 的优先级临时提高到与任务 TaskHP 一致的优先级,也即高优先级
  • 在 t4 时刻,中等优先级的任务 TaskMP 进入就绪状态发生任务调度,但是由于任务 TaskLP 此时优先级被提高到了高优先级,因此任务 TaskMP 仍然保持就绪状态等待优先级较高的任务执行完毕
  • 在 t5 时刻,任务 TaskLP 执行完毕释放互斥量 Mutexes,此时任务 TaskHP 抢占处理器切入运行状态,并恢复任务 TaskLP 原来的优先级
  • 在 t6 时刻,任务 TaskHP 执行完毕,此时轮到任务 TaskMP 执行
  • 在 t7 时刻,任务 TaskMP 运行结束

根据互斥量的上述任务流程读者可以发现与二值信号量的不同之处,上述描述的任务运行过程具体时刻流程图如下图所示

3.3、什么是互斥量?

互斥量/互斥锁是一种特殊类型的二进制信号量,用于控制对在两个或多个任务之间共享资源的访问

互斥锁可以被视为一个与正在共享的资源相关联的令牌,对于合法访问资源的任务,它必须首先成功 “获取” 令牌,成为资源的持有者,当持有者完成对资源的访问之后,其需要 ”归还” 令牌,只有 “归还” 令牌之后,该令牌才可以再次被其他任务所 “获取” ,这样保证了互斥的对共享资源的访问,上述机制如下图所示 (注释1)

3.4、死锁现象

“死锁” 是使用互斥锁进行互斥的另一个潜在陷阱,当两个任务因为都在等待对方占用的资源而无法继续进行时,就会发生死锁,考虑如下所述的情况

  1. 任务 A 执行并成功获取互斥量 X
  2. 任务 A 被任务 B 抢占
  3. 任务 B 在尝试获取互斥量 X 之前成功获取互斥量 Y,但互斥量 X 由任务 A 持有,因此对任务 B 不可用,任务 B 选择进入阻塞状态等待互斥量 X 被释放
  4. 任务 A 继续执行,它尝试获取互斥量 Y,但互斥量 Y 由任务 B 持有,所以对于任务 A 来说是不可用的,任务 A 选择进入阻塞状态等待待释放的互斥量 Y

经过上述的这样一个过程,读者可以发现任务 A 在等待任务 B 释放互斥量 Y ,而任务 B 在等待任务 A 释放互斥量 X ,两个任务都在阻塞状态无法执行,从而导致 ”死锁“ 现象的发生,与优先级翻转一样,避免 “死锁” 的最佳方法是在设计时考虑其潜在影响,并设计系统以确保不会发生死锁

3.5、什么是递归互斥量?

任务也有可能与自身发生死锁,如果任务尝试多次获取相同的互斥体而不首先返回互斥体,就会发生这种情况,考虑以下设想:

  1. 任务成功获取互斥锁
  2. 在持有互斥体的同时,任务调用库函数
  3. 库函数的实现尝试获取相同的互斥锁,并进入阻塞状态等待互斥锁变得可用

在此场景结束时,任务处于阻塞状态以等待互斥体返回,但任务已经是互斥体持有者。 由于任务处于阻塞状态等待自身,因此发生了死锁

通过使用递归互斥体代替标准互斥体可以避免这种类型的死锁,同一任务可以多次 “获取” 递归互斥锁,并且只有在每次 “获取” 递归互斥锁之后都调用一次 “释放” 递归互斥锁,才会返回该互斥锁

因此递归互斥量可以视为特殊的互斥量,一个互斥量被一个任务获取之后就不能再次获取,其他任务想要获取该互斥量必须等待这个任务释放该互斥连,但是递归互斥量可以被一个任务重复获取多次,当然每次获取必须与一次释放配对使用

注意不管是互斥量,还是递归互斥量均存在优先级继承机制,但是由于 ISR 并不是任务,因此互斥量和递归互斥量不能在中断中使用

3.5、创建互斥量

互斥量在使用之前必须先创建,因为互斥量分为互斥量和递归互斥量两种,所以 FreeRTOS 也提供了不同的 API 函数,具体如下所述

/**
  * @brief  动态分配内存创建互斥信号量函数
  * @retval 创建互斥信号量的句柄
  */
SemaphoreHandle_t xSemaphoreCreateMutex(void);

/**
  * @brief  静态分配内存创建互斥信号量函数
  * @param  pxMutexBuffer:指向StaticSemaphore_t类型的变量,该变量将用于保存互斥锁型信号量的状态
  * @retval 返回成功创建后的互斥锁的句柄,如果返回NULL则表示内存不足创建失败
  */
SemaphoreHandle_t xSemaphoreCreateMutexStatic(StaticSemaphore_t *pxMutexBuffer);

/**
  * @brief  动态分配内存创建递归互斥信号量函数
  * @retval 创建递归互斥信号量的句柄,如果返回NULL则表示内存不足创建失败
  */
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(void);

/**
  * @brief  动态分配内存创建二值信号量函数
  * @param  pxMutexBuffer:指向StaticSemaphore_t类型的变量,该变量将用于保存互斥锁型信号量的状态
  */
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex(
								StaticSemaphore_t pxMutexBuffer);

3.6、获取互斥量

获取互斥量直接使用获取信号量的函数即可,但对于递归互斥量需要专门的获取函数,具体如下所述

/**
  * @brief  获取信号量函数
  * @param  xSemaphore:正在获取的信号量的句柄
  * @param  xTicksToWait:等待信号量变为可用的时间
  * @retval 成功获取信号量则返回pdTRUE, xTicksToWait过期,信号量不可用,则返回pdFALSE
  */
BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);

/**
  * @brief  获取递归互斥量
  * @param  xMutex:正在获得的互斥锁的句柄
  * @param  xTicksToWait:等待信号量变为可用的时间
  * @retval 成功获取信号量则返回pdTRUE, xTicksToWait过期,信号量不可用,则返回pdFALSE
  */
BaseType_t xSemaphoreTakeRecursive(SemaphoreHandle_t xMutex,
								   TickType_t xTicksToWait);

3.7、释放互斥量

释放互斥量直接使用释放信号量的函数即可,但对于递归互斥量需要专门的释放函数,具体如下所述

/**
  * @brief  释放信号量函数
  * @param  xSemaphore:要释放的信号量的句柄
  * @retval 成功释放信号量则返回pdTRUE, 若发生错误,则返回pdFALSE
  */
BaseType_t xSemaphoreGive(SemaphoreHandle_t xSemaphore);

/**
  * @brief  释放递归互斥量
  * @param  xMutex:正在释放或“给出”的互斥锁的句柄
  * @retval 成功释放递归互斥量后返回pdTRUE
  */
BaseType_t xSemaphoreGiveRecursive(SemaphoreHandle_t xMutex);

3.8、删除互斥量

直接使用信号量的删除函数即可,具体如下所述

/**
  * @brief  获取信号量函数
  * @param  xSemaphore:要删除的信号量的句柄
  * @retval None
  */
void vSemaphoreDelete(SemaphoreHandle_t xSemaphore);

4、实验一:优先级翻转问题

4.1、实验目标

既然实验是讨论优先级翻转问题,那么我们来复现 “3.1、优先级翻转问题” 小节中所描述到的任务运行过程,具体如下所述

  1. 创建一个二值信号量 BinarySem_PI,用于演示优先级翻转问题
  2. 创建一个低优先级任务 Task_Low ,在该任务中获取二值信号量 BinarySem_PI ,并通过延时模拟长时间连续运行,运行结束后释放该二值信号量,整个过程会通过串口输出提示信息
  3. 创建一个中等优先级任务 Task_Middle,该任务负责在 Task_Low 模拟长时间连续运行期间抢占其处理器控制权限
  4. 创建一个高优先级任务 Task_High,该任务总是尝试获取二值信号量 BinarySem_PI

4.2、CubeMX相关配置

首先读者应按照"FreeRTOS教程1 基础知识"章节配置一个可以正常编译通过的 FreeRTOS 空工程,然后在此空工程的基础上增加本实验所提出的要求

本实验需要初始化 USART1 作为输出信息渠道,具体配置步骤请阅读“STM32CubeMX教程9 USART/UART 异步通信”,如下图所示

单击 Middleware and Software Packs/FREERTOS,在 Configuration 中单击 Tasks and Queues 选项卡双击默认任务修改其参数,然后增加另外两个不同优先级的任务,具体如下图所示

然后在 Configuration 中单击 Timers and Semaphores ,在 Binary Semaphores 中单击 Add 按钮新增加一个名为 BinarySem_PI 的二值信号量,具体如下图所示

配置 Clock Configuration 和 Project Manager 两个页面,接下来直接单击 GENERATE CODE 按钮生成工程代码即可

4.3、添加其他必要代码

按照 “STM32CubeMX教程9 USART/UART 异步通信” 实验 “6、串口printf重定向” 小节增加串口 printf 重定向代码,具体不再赘述

首先应该在 freertos.c 中添加信号量相关 API 和 printf() 函数的头文件,如下所述

/*freertos.c中添加头文件*/
#include "semphr.h"
#include "stdio.h"

然后在该文件中实现三个不同优先级的任务,主要是一些串口输出给用户的提示信息,方便演示实验目的,具体如下所述

/*低优先级任务*/
void AppTask_Low(void *argument)
{
  /* USER CODE BEGIN AppTask_Low */
  /* Infinite loop */
	uint8_t str1[]="Task_Low take it\r\n";
	uint8_t str2[]="Task_Low give it\r\n";
	uint8_t str3[]="return Task_Low\r\n";
	for(;;)
	{
		//获取信号量
		if(xSemaphoreTake(BinarySem_PIHandle, pdMS_TO_TICKS(200))==pdTRUE)  
		{
			printf("%s",str1);
			//模拟任务连续运行
			HAL_Delay(500);		
			printf("%s",str3);
			HAL_Delay(500);
			printf("%s",str2);
			//释放信号量
			xSemaphoreGive(BinarySem_PIHandle);		
		}
	}
  /* USER CODE END AppTask_Low */
}

/*中等优先级任务*/
void AppTask_Middle(void *argument)
{
  /* USER CODE BEGIN AppTask_Middle */
  /* Infinite loop */
	uint8_t strMid[]="Task_Middle is running\r\n";
	for(;;)
	{
		printf("%s", strMid);
		vTaskDelay(500);
	}
  /* USER CODE END AppTask_Middle */
}

/*高优先级任务*/
void AppTask_High(void *argument)
{
  /* USER CODE BEGIN AppTask_High */
  /* Infinite loop */
	uint8_t strHigh1[]="Into Task_High\r\n";
	uint8_t strHigh2[]="Task_High get token\r\n";
	uint8_t strHigh3[]="Task_High give token\r\n";
	for(;;)
	{
		printf("%s",strHigh1);
		//获取信号量
		if(xSemaphoreTake(BinarySem_PIHandle, portMAX_DELAY)==pdTRUE)  
		{
			printf("%s",strHigh2);
			printf("%s",strHigh3);
			//释放信号量
			xSemaphoreGive(BinarySem_PIHandle);	
		}
		vTaskDelay(500);
	}
  /* USER CODE END AppTask_High */
}

在 "FreeRTOS教程5 信号量" 文章 ”3.2、创建信号量“ 小节中曾提到,信号量被创建完之后是无效的,但是这里我们需要让刚创建的二值信号量有效,否则 Task_High 和 Task_Low 都将无法获取二值信号量,因此最后修改二值信号量的初始值为 1 即可,具体如下所示

/*将初始值0修改为1*/
BinarySem_PIHandle = osSemaphoreNew(1, 1, &BinarySem_PI_attributes);

4.4、烧录验证

烧录程序,打开串口助手,按住开发板复位按键,目的是为了让串口助手接收程序从最开始输出的信息,这里我们只分析第一轮,因为延时、语句执行等微小的时间差异会导致第二轮任务进入阻塞和退出阻塞的时间与第一轮有差异,如下所述为第一轮详细的任务执行流程

  1. 当创建完三个不同优先级的任务后不会立即得到执行,而是进入就绪状态等待调度器的启动
  2. 当调度器启动之后会按照优先级从最高优先级开始执行,因此串口输出 “Into Task_High” 表示进入高优先级任务,然后在高优先级任务 Task_High 中获得二值信号量,然后立马释放二值信号量,最后进入 500ms 的阻塞状态
  3. 当高优先级任务进入阻塞状态后,接下来会执行就绪状态的中等优先级任务 Task_Middle ,该任务无具体功能,仅仅通过串口输出 “Task_Middle is running”,然后同样进入 500ms 的阻塞状态
  4. 由于高优先级和中等优先级任务都进入阻塞状态,这时才轮到低优先级任务 Task_Low 执行,低优先级任务 Task_Low 成功获取到二值信号量并通过串口输出 “Task_Low take it” ,然后利用 500ms 的 HAL 库延时函数模拟连续运行
  5. 在 Task_Low 连续运行期间,在其即将执行完第一个 HAL_Delay(500); 时,高优先级任务 Task_High 从 500ms 的阻塞状态恢复,然后尝试获取已经被 Task_Low 获取的二值信号量,结果就是进入阻塞状态等待 Task_Low 释放二值信号量
  6. 紧接着 Task_Middle 从 500ms 的阻塞状态恢复,通过串口输出 “Task_Middle is running”,接着再次进入 500ms 阻塞状态
  7. 由于高优先级和中等优先级任务再次进入阻塞状态,因此调度器返回 Task_Low 被抢占时的程序处继续执行,因此 Task_Low 通过串口输出 “return Task_Low” ,然后利用第二个 HAL_Delay(500); 继续模拟长时间运行
  8. 在 Task_Low 第二个 HAL_Delay(500); 即将执行完毕时,Task_Middle 再次从 500ms 的阻塞状态恢复,通过串口输出 “Task_Middle is running” ,然后再次进入 500ms 阻塞状态(这里 Task_High 由于不是因为延时进入的阻塞状态所以未恢复运行状态)
  9. 最后返回 Task_Low 任务,释放二值信号量,一旦 Task_Low 任务释放二值信号量,等待二值信号量的高优先级任务 Task_High 会立马退出阻塞状态成功获取到二值信号量,并会通过串口输出 “Task_High get token“

从上述过程可知,从 Task_Low 获取二值信号量之后到第一轮结束,Task_High 等待 Task_Low 释放二值信号量,等待期间中等优先级的任务 Task_Middle 却先于高优先级任务 Task_High 得到了执行,这就是所谓的优先级翻转问题,上述过程所述的实际串口输出如下图所示

4.5、互斥量的应用

首先在 STM32CubeMX 中单击 Middleware and Software Packs/FREERTOS,在 Configuration 中单击 Mutexes 选项卡,单击 Add 按钮增加互斥量 Mutex_PI ,具体如下图所示

然后将上述实验使用的所有二值信号量句柄 BinarySem_PIHandle 修改为互斥量 Mutex_PIHandle,不需要做其他任何操作,烧录程序即可

打开串口助手,观察串口助手的输出,如下所述为第一轮详细的任务执行流程

  1. 前4个步骤与 ”4.4、烧录验证“ 小节一致,只不过从二值信号量修改为互斥量
  2. 在第5步时,高优先级任务 Task_High 从 500ms 的阻塞状态恢复,输出 ”Into Task_High“ ,然后尝试获取已经被 Task_Low 获取的互斥量,结果就是进入阻塞状态等待 Task_Low 释放互斥量,同时将 Task_Low 的优先级临时提高到和高优先级任务 Task_High 一样的优先级
  3. 紧接着 Task_Middle 从 500ms 的阻塞状态恢复,但是由于现在 Task_Low 任务的优先级要高于中等优先级任务 Task_Middle ,因此不能抢占 Task_Low 任务,故无法执行任务体输出 ”Task_Middle is running“ ,所以其状态变为就绪状态,它将等待所有高优先级的任务执行完后才会执行
  4. 于是优先级被临时提高到高优先级的任务 Task_Low 继续执行其函数体内容,输出 ”return Task_Low“ ,然后执行第二个 HAL_Delay(500); ,最后释放互斥量,通过串口输出 ”Task_Low give it“
  5. 一旦互斥量被 Task_Low 释放,处于阻塞状态的 Task_High 就会立马恢复运行状态获取到互斥量,所以会通过串口输出 ”Task_High get token“ 和 ”Task_High give token“ ,同时当互斥量被 Task_High 任务成功获取之后,会将任务 Task_Low 临时提高的优先级恢复到其原来的低优先级,最后 Task_High 调用延时函数进入 500ms 的阻塞状态
  6. 当高优先级任务 Task_High 进入阻塞状态后,系统内现在剩余就绪状态的中等优先级任务 Task_Middle 和 低优先级任务 Task_Low ,所以轮到 Task_Middle 任务执行,其将通过串口输出 ”Task_Middle is runing“ ,至此一轮结束

读者可以自行对比将二值信号量更换为互斥量之后的串口输出结果,可以发现在步骤4中,中等优先级的任务 Task_Middle 不再先于高优先级的任务 Task_High 得到执行,上述整个过程串口数据的完整输出如下图所示

5、注释详解

注释1:图片来源于 Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf

参考资料

STM32Cube高效开发教程(基础篇)

Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf文章来源地址https://www.toymoban.com/news/detail-841056.html

到了这里,关于FreeRTOS教程6 互斥量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32】FreeRTOS互斥量学习

    互斥量(Mutex) 互斥量又称互斥信号量(本质也是一种信号量,不具备传递数据功能),是一种特殊的二值信号量,它和信号量不同的是,它支持互斥量所有权、递归访问以及防止优先级翻转的特性。比如有两个任务,A在运行,B就运行不了。 实验:创建三个任务,从高到低

    2024年02月13日
    浏览(39)
  • FreeRTOS源码分析-9 互斥信号量

    目录 1 优先级翻转问题 2 互斥信号量概念及其应用 2.2FreeRTOS互斥信号量介绍 2.3FreeRTOS互斥信号量工作原理 3 互斥信号量函数应用 3.1功能分析 3.2API详解 3.3功能实现 4 递归互斥信号量函数应用 4.1死锁现象 ​编辑 4.2API详解 4.3解决死锁 5 互斥信号量实现原理 5.1互斥信号量创建

    2024年02月14日
    浏览(40)
  • FreeRTOS源码分析-10 互斥信号量

    目录   1 事件标志组概念及其应用 1.1 事件标志组定义 1.2 FreeRTOS事件标志组介绍 1.3 FreeRTOS事件标志组工作原理 2 事件标志组应用 2.1 功能需求 2.2 API  2.3 功能实现 3 事件标志组原理 3.1 事件标志组控制块 3.2 事件标志组获取标志位 3.3 等待事件标志触发 3.4 事件标志组设置标志

    2024年02月14日
    浏览(37)
  • 【正点原子Linux连载】第五章 RKMedia编译和使用 摘自【正点原子】ATK-DLRV1126系统开发手册

    5.1 RKMedia编译 Rkmedia是RK官方封装一层简易的API,把RGA、MPP、RKNN等等这些接口封装成高级的接口。在SDK官方的源码目录下,运行以下命令进行跳转: cd external/rkmedia/examples/ ls 运行命令结果如下所示: 图4.12.1.1 rkmedia官方的demo 里面有很多C文件的代码,可以结合Rockchip_Developer_G

    2024年02月08日
    浏览(85)
  • 互斥锁、自旋锁、原子操作的使用场景

    一,互斥锁 原理: 互斥锁属于sleep-waiting类型的锁,例如在一个双核的机器上有两个线程(线程A和线程B),它们分别运行在Core0和Core1上。假设线程A想要通过pthread_mutex_lock操作去得到一个临界区的锁,而此时这个锁正被线程B所持有,那么线程A就会被阻塞,Core0会在此时进行上

    2023年04月10日
    浏览(31)
  • 【FreeRTOS】互斥量的使用与逐步实现

    在FreeRTOS中,互斥量是一种用于保护共享资源的同步机制。它通过二进制信号量的方式,确保在任意时刻只有一个任务可以获取互斥量并访问共享资源,其他任务将被阻塞。使用互斥量的基本步骤包括创建互斥量、获取互斥量、访问共享资源和释放互斥量。互斥量在FreeRTOS中起

    2024年02月10日
    浏览(26)
  • 正点原子LoRa模块的使用

    所用单片机为STM32F407,此篇为当时做电赛时未记录,但是现在忘了所以重新记录一下,防止自己忘记。总的来说就是用串口给LoRa模块发送AT指令来配置模块,然后单片机想要发数据也是使用串口发送出去。 MD0引脚配置为推挽输出模式,并配置为下拉, AUX引脚配置为输入模式

    2024年02月08日
    浏览(37)
  • 【正点原子Linux连载】第三章 RV1126开发环境搭建 摘自【正点原子】ATK-DLRV1126系统开发手册

    1)实验平台:正点原子RV1126 Linux开发板 2)平台购买地址:https://detail.tmall.com/item.htm?id=692176265749 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/thread-340252-1-1.html 3.1 rv1126的环境配置 在上章节里面我们已经安装好Ubuntu,此时的Ubuntu还是不能做开发的,因为还有很多环

    2024年02月04日
    浏览(49)
  • 【正点原子STM32连载】 第四十章 IIC实验 摘自【正点原子】APM32E103最小系统板使用指南

    1)实验平台:正点原子APM32E103最小系统板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban 本章将介绍使用APM32E103驱动板载的EEPROM进行读写操作。通过本章的学习,读者将学习到使用GPIO模拟

    2024年02月21日
    浏览(47)
  • 【正点原子STM32连载】第十章 跑马灯实验 摘自【正点原子】APM32E103最小系统板使用指南

    1)实验平台:正点原子APM32E103最小系统板 2)平台购买地址:https://detail.tmall.com/item.htm?id=609294757420 3)全套实验源码+手册+视频下载地址: http://www.openedv.com/docs/boards/xiaoxitongban 跑马灯程序是嵌入式开发的一个经典程序,类似于学习C语言时,编写的“Hello World”程序。跑马灯本

    2024年02月02日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包