FreeRTOS基础六:中断管理2

news2024/11/13 22:40:22

在中断中使用队列

FreeRTOS的队列可以方便的实现中断传递数据到任务。但是如果数据到来的频率的非常高,导致中断触发频繁,则这种方式是非常不高效的。正如一些Demo所实现的,在UART中断中接收串口数据,然后放到队列中,然后任务从队列中读数据。使用这种方法只是起到了演示作用,并不具有实战价值。

更高效的方案例如:

  • 使用DMA来实现外设(如UART)和内存缓冲的数据传输,这样数据传输时就没有软件导致的CPU负担,当一块数据传输完成时,使用任务通知来通知任务,使得任务唤醒然后开始处理数据。
  • 如果DMA不可用,则可以使用内存缓冲区来缓存中断单次收到的数据,当一块数据传输完成时,使用任务通知来通知任务,使得任务唤醒然后开始处理数据。
  • 对于只需简单处理的数据,则可以直接在中断中处理,然后将处理的结果通过队列或者任务通知技术发送给任务。

队列相关的API

为了方便演示,首先介绍一下队列相关的内核函数的使用方法。

//作用:在中断函数中向队列的头部放入一个数据,即插入数据到队头
BaseType_t xQueueSendToFrontFromISR( 
    QueueHandle_t xQueue,
    void *pvItemToQueue
    BaseType_t *pxHigherPriorityTaskWoken
);

//作用:向队列的尾部插入一个数据,即入队
//xQueueSendFromISR()函数的作用与之相同
BaseType_t xQueueSendToBackFromISR( 
    QueueHandle_t xQueue,
    void *pvItemToQueue
    BaseType_t *pxHigherPriorityTaskWoken
);

参数xQueue:队列的句柄。

参数pvItemToQueue:发送到队列中的数据的指针,指针指向的数据将被拷贝到队列元素中。

参数pxHigherPriorityTaskWoken:任务切换标志的指针,详见上一篇的讲解。

返回:pdPASS,代表插入成功;errQUEUE_FULL,代表队列已满无法插入。

中断嵌套

数值优先级和逻辑优先级

假设UART1中断优先级寄存器是UP_REG,SPI1中断优先级寄存器是SP_REG。我们设置UP_REG=1,SP_REG=2,那么这里写入寄存器的的1和2就是数值优先级。

所谓逻辑优先级,就是两个或者多个中断在同时发生时,逻辑优先级高的优先响应。另一方面如果系统支持中断嵌套,则也会定义了这样的情形:当逻辑优先级低的中断A正在响应中,另一个逻辑优先级高B的触发时,B会暂时打断A的执行,进而使得系统嵌套执行B的中断函数,等B响应完后,再恢复A的执行。

有些单片机,其优先级寄存器中的数值优先级越大,则对应的逻辑优先级就越高,例如STC 51单片机。而我们常用的CM3/CM4内核,则与之相反,数值优先级越大,则对应的逻辑优先级就越低。

configMAX_SYSCALL_INTERRUPT_PRIORITY

这个宏定义在FreeRTOSConfig.h中,除此之外还有一个宏configMAX_API_CALL_INTERRUPT_PRIORITY与这个宏作用相同,只不过有些移植平台用的前者,有些用的是后者。对于CM3/CM4内核,使用的是configMAX_SYSCALL_INTERRUPT_PRIORITY。

这个宏定义一个逻辑优先级阈值,逻辑优先级低于等于这个阈值的中断将被FreeRTOS内核管理,且可以在这些中断的ISR中使用FreeRTOS的中断安全版本API(即xxxFromISR)

  • 对于CM3/CM4内核,configMAX_SYSCALL_INTERRUPT_PRIORITY 不能设置为 0
  • 逻辑优先级低于等于configMAX_SYSCALL_INTERRUPT_PRIORITY 对应的逻辑优先级的中断受内核管理,当代码运行进入到FreeRTOS实现的临界区(critical section)时,这些中断是被内核临时屏蔽的,也就是即便达到了中断触发条件也不会触发硬件中断,ISR不会立刻执行,只有退出临界区后才能执行ISR,会导致中断处理有延迟。在这些中断的ISR中是可以使用FreeRTOS的中断安全版本的API的。
  • 逻辑优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY对应的逻辑优先级的中断,不受内核行为影响,不会被内核屏蔽其响应,表现为和原始硬件定义的行为一样。在这些中断的ISR中是不能使用FreeRTOS的任何API。一般对于时序要求严格的中断,需要配置为高于configMAX_SYSCALL_INTERRUPT_PRIORITY对应的优先级,例如电机控制信号等。

configKERNEL_INTERRUPT_PRIORITY

这个宏定义在FreeRTOSConfig.h中。这个宏用于定义内核中断(对于CM3/CM4就是SysTick中断和PendSV中断)使用的优先级,FreeRTOS要求这个宏的值设置为当前硬件系统的最低逻辑优先级对应的值

对于CM3和CM4内核,这个宏的值直接被写入到SysTcik和PendSV的中断优先级寄存器中去了。由于CM3/CM4内核的优先级寄存器数值越大,其优先级越低,所以这个宏要设置为255。

  • 如果你的目标移植平台没有使用configMAX_SYSCALL_INTERRUPT_PRIORITY宏而只使用了configKERNEL_INTERRUPT_PRIORITY,则只能在优先级为configKERNEL_INTERRUPT_PRIORITY对应的优先级的ISR中使用FreeRTOS的中断安全版API(xxxFromISR)。
  • 对于CM3和CM4内核,一般做法是,将configKERNEL_INTERRUPT_PRIORITY设置为最低优先级对应的值,而把configMAX_SYSCALL_INTERRUPT_PRIORITY设置成高于configKERNEL_INTERRUPT_PRIORITY对应的优先级高的值。

configPRIO_BITS

这个宏定义在FreeRTOSConfig.h中。用于定义当前单片机的优先级使用了几位进行编码,例如对于STM32F103就是4。这个宏不影响FreeRTOS系统功能,不是必须定义的,如果定义了,则FreeRTOS可以使用运行时断言机制帮我们检查中断配置的正确性。但是单独只定义这个宏没意义,还需要启用FreeRTOS的断言机制。

为了能让FreeRTOS帮我们检查,开发者需要在FreeRTOSConfig.h定义configASSERT()的实现,configASSERT()的行为和标准C的assert()函数一样,是实现了运行时断言机制,当参数为真(true)时,检查通过,当参数为0(false)时,检查失败,应该及时停止程序运行并进行错误提示。建议在开发阶段启用断言机制,等开发稳定后,再屏蔽断言,毕竟断言是需要运行代码的,增加了代码量和CPU开销。

只要开发者定义了configASSERT,则内核会将configASSERT_DEFINED定义为1,否则内核会将configASSERT_DEFINED定义为0。只有当configASSERT_DEFINED为1的情况下,内核才会启用相关的断言检查机制。因此建议在开发阶段启用断言机制,即提供configASSERT的定义,等开发稳定后,再注释configASSERT的定义。

一种可能的configASSERT实现如下:

//断言不通过时,禁止中断,这样调度器停止工作,然后进入无限循环
#define configASSERT( x ) \
    if( ( x ) == 0 ) { taskDISABLE_INTERRUPTS(); for( ;; ); }

configLIBRARY_LOWEST_INTERRUPT_PRIORITY和configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY

实际上这个2宏不是FreeRTOS需要的,不是必须定义的,内核代码中根本没有用到这2个宏。之所以定义这2个宏,是为了方便定义前面说到的

configKERNEL_INTERRUPT_PRIORITY 和 configMAX_SYSCALL_INTERRUPT_PRIORITY 。

只要正确理解了configKERNEL_INTERRUPT_PRIORITY 和 configMAX_SYSCALL_INTERRUPT_PRIORITY ,就可以直接定义他们,而不需要使用这2个宏,引入更多的宏反而会使代码复杂难懂。

FreeRTOS中断嵌套例子分析

假设某个单片机,有7个不同数值优先级1~7,且逻辑优先级定义为数值越高,优先级也越高。

由于FreeRTOS规定要配置内核中断优先级为最低,所以configKERNEL_INTERRUPT_PRIORITY配置为1;同时把configMAX_SYSCALL_INTERRUPT_PRIORITY配置为3。如下图所示。

 

  • 优先级1~3的中断受内核管理,当代码运行进入到FreeRTOS实现的临界区(critical section)时,这些中断是被内核临时屏蔽的,也就是即便达到了中断触发条件也不会触发硬件中断,ISR不会立刻执行,只有退出临界区后才能执行ISR,会导致中断处理有延迟。同时这些中断的ISR中是可以使用FreeRTOS的中断安全版本的API的。
  • 优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY对应的优先级的,即4~7的优先级,不受内核调度器的影响,表现为和原始硬件行为一样。但要注意在这些中断的ISR中是不能使用FreeRTOS的任何API。一般对于时序要求严格的中断,需要配置为高于configMAX_SYSCALL_INTERRUPT_PRIORITY对应的优先级,例如电机控制信号等。

对于支持中断嵌套的硬件平台,则在FreeRTOS中的正确做法是,配置configKERNEL_INTERRUPT_PRIORITY为最低逻辑优先级对应的值,而把configMAX_SYSCALL_INTERRUPT_PRIORITY设置成逻辑优先级高于configKERNEL_INTERRUPT_PRIORITY对应的逻辑优先级的值。

CM3/CM4内核中断

中断优先级寄存器

CM3/CM4内核的数值优先级越大,则对应的逻辑优先级就越低。

CM3/CM4使用8bit大小的寄存器编码内核异常中断和处理外部中断的优先级,而单片机厂家为了简化设计,通常只使用这8bit的高n位,例如STM32F103就只使用了高4位。这样一来,每个中断优先级寄存器的高4位是可以正常读写的,而低4位写无效,读始终是0。

如下图所示,向一个STM32F103单片机的中断A的优先级寄存器中写入数据0101_1111,向中断B的优先级寄存器中写入数据0111_1111,由于只有高4位有效,因此中断A的数值优先级是5,中断B的数值优先级是7,A的优先级高于B。

请注意,在FreeRTOS中,对于CM3和CM4,configKERNEL_INTERRUPT_PRIORITY和configMAX_SYSCALL_INTERRUPT_PRIORITY配置的值就是直接写入到优先级寄存器中的值,例如将configKERNEL_INTERRUPT_PRIORITY配置为255,则对应的优先级数值为15;将configMAX_SYSCALL_INTERRUPT_PRIORITY配置为191,则对应的优先级数值为11。优先级寄存器中未实现的位可用1填充。

SysTick和PendSV的优先级是通过core_cm3.h中定义的SCB_Type寄存器组中的SHP寄存器组去设置的。具体来说就是地址为0xE000_ED20寄存器,其最高8位用于设置SysTick的优先级,次高8位是设置PendSV的优先级。

//代码来自CM3的port.c
#define portNVIC_PENDSV_PRI	  
    ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 16UL )
#define portNVIC_SYSTICK_PRI  
    ( ( ( uint32_t ) configKERNEL_INTERRUPT_PRIORITY ) << 24UL )

/* Make PendSV and SysTick the lowest priority interrupts. */
portNVIC_SYSPRI2_REG |= portNVIC_PENDSV_PRI; //设置PendSV中断优先级
portNVIC_SYSPRI2_REG |= portNVIC_SYSTICK_PRI; //设置SysTick中断优先级

但是ST的标准库的NVIC_Init则需要的是优先级数值参数,库函数NVIC_Init内部会将数值移位到高4位,再写入优先级寄存器中。

//优先级分组4,高4位全部用于定义抢占优先级,而不使用子优先级
//设置USART1的优先级数值为13
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 13;    //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //不用
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

中断分组

为了更好的控制中断的响应顺序,CM3将中断的优先级划分为抢占(PreemptPriority)优先级和子优先级(SubPriority)。也就是将8bit宽度的优先级寄存器的高n位编码抢占(PreemptPriority)优先级,剩余的低位编码子优先级(SubPriority)。具体如何划分,就是通过SCB_Type寄存器组的AIRCR寄存器的[10:8]位段来设置,有8种情况可选,即8个组,如下图:

为了节省成本和降低芯片设计复杂度,芯片设计厂商会裁掉优先级寄存器(IP和SHP寄存器)的低几个位。根据约定,厂商需要在芯片头文件中(例如stm32f10x.h)定义__NVIC_PRIO_BITS这个宏,这个宏值表示用多少位来编码优先级,通常这个值是4。

不出所料,STM32F103简化了优先级寄存器,裁调了最低四位,只使用高四位来编码优先级,因此只有AIRCR[10:8] = 3~7才是有相互区分意义的。如下图所示。

那么对于STM32F103只有4个组可以选择, 如下,其中NVIC_PriorityGroup_4是FreeRTOS推荐的组别设置,因为FreeRTOS没有实现子优先级。也就是FreeRTOS推荐只使用抢占优先级,忽略子优先级的影响。

#define NVIC_PriorityGroup_0   ((uint32_t)0x700) /* 抢占优先级0 bits 子优先级 4 bits */
#define NVIC_PriorityGroup_1   ((uint32_t)0x600) /* 抢占优先级1 bits 子优先级 3 bits */
#define NVIC_PriorityGroup_2   ((uint32_t)0x500) /* 抢占优先级2 bits 子优先级 2 bits  */
#define NVIC_PriorityGroup_3   ((uint32_t)0x400) /* 抢占优先级3 bits 子优先级 1 bits  */
#define NVIC_PriorityGroup_4   ((uint32_t)0x300) /* 抢占优先级4 bits 子优先级 0 bits  */

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); //设置优先级分组

那么抢占优先级和子优先级的区别是什么呢? 

(1)抢占优先级的不同可以形成中断嵌套,抢占优先级高的可以打断抢占优先级低的,形成中断嵌套。相同的抢占优先级不能相互打断,即如果两个抢占优先级相同的中断前后发生的话,后来的中断不能打断前一个中断。

(2)如果多个抢占优先级相同的中断同时发生的话,则看子优先级,子优先级高的先响应。

(3)如果抢占级别和子优先级别都一样时,按照中断的地址来响应,地址低的先响应。

关于优先级分组的设置,其实在绝大多数情况下,优先级的分组都要预先经过计算论证,并且在开机初始化时一次性地设置好,以后就再也不动它了。——《CM3权威指南》

BASEPRI 寄存器

对于有这个寄存器的CM3和CM4,FreeRTOS内核使用BASEPRI 寄存器来实现临界区。这允许RTOS内核只屏蔽中断的一个子集,因此提供了一个灵活的中断嵌套模型。

通过BASEPRI 中设置一个非0的优先级阈值,这样逻辑优先级低于等于这个阈值的中断都会全部被临时屏蔽调,而逻辑优先级高于这个阈值的中断不受影响。向BASEPRI写入0时就会停止屏蔽中断(所以对于CM3/CM4,configMAX_SYSCALL_INTERRUPT_PRIORITY的值不能是0,否则进入临界区无法实现)

说到这里想必你已经知道了前面configMAX_SYSCALL_INTERRUPT_PRIORITY宏的作用了,是的,在FreeRTOS中,这个宏正是写入到BASEPRI 寄存器的值,以此来实现临界区。如下内核源码所示:

//进入临界区
void vPortEnterCritical( void )
{
    //#define portDISABLE_INTERRUPTS()	vPortRaiseBASEPRI()
    //portDISABLE_INTERRUPTS()等价于vPortRaiseBASEPRI()
	portDISABLE_INTERRUPTS(); 
	uxCriticalNesting++;

	if( uxCriticalNesting == 1 )
	{
		configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );
	}
}

//将basepri寄存器设置为configMAX_SYSCALL_INTERRUPT_PRIORITY配置的值
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

	__asm
	{
		/* Set BASEPRI to the max syscall priority to effect a critical
		section. */
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}
}

//退出临界区
//PortSetBASEPRI( 0 )定义在portmacro.h中,作用就是设置BASEPRI为0,也就是取消屏蔽。
void vPortExitCritical( void )
{
	configASSERT( uxCriticalNesting );
	uxCriticalNesting--;
	if( uxCriticalNesting == 0 )
	{
       //#define portENABLE_INTERRUPTS()	vPortSetBASEPRI( 0 )
       //等价于vPortSetBASEPRI( 0 )
		portENABLE_INTERRUPTS();  
	}
}

我们可以把这一些需要受内核管理的中断,优先级设置的低一些,把另一些不允许关闭的中断优先级设置的高一些,然后通过BASEPRI这个寄存器把优先级低于某个值的(优先级寄存器的值大于等于某个值的)中断一口气全屏蔽掉,这样我们在进入临界段前,只保存BASEPRI的值就好了。FreeRTOS中也是这么做的。

作为对比,uC/OS的临界区是通过PRIMASK寄存器实现的,这个寄存器比BASEPRI寄存器更强势,他可以屏蔽系统中除了系统异常NMI和HardFault外的其余所有中断,keil开发环境下的__enable_irq();__disable_irq();就是操作的这个寄存器 。相比较来说,FreeRTOS的实现更加灵活合理,为开发者提供了更多的选择余地,因为有些应用场合下,例如像电机控制信号等时序严格的中断是不能被屏蔽的。

题外话:

  • CM0没有BASEPRI寄存器。对于CM0这种没有BASEPRI寄存器的,FreeRTOS才是通过PRIMASK寄存器实现临界区的。
  • FreeRTOS不推荐使用子优先级,是因为只有抢占优先级位域才参与和BASEPRI的比较,子优先级和保留位不参与和BASEPRI的比较。

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

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

相关文章

华为OD机试关于无输入截止条件的ACM输入逻辑

无输入截止条件的ACM输入 华为OD机试题中有一些题目是没有输入截止条件的,比如 华为OD机试 - 数字游戏(Java & JS & Python)_伏城之外的博客-CSDN博客 从输入描述来看,每组有两行输入,但是并没有告诉我们具体有几组? 那么输入该如何截止呢? 此时,有两种输入…

CF 1326D Prefix-Suffix Palindrome(最长回文前后缀)

CF 1326D Prefix-Suffix Palindrome(最长回文前后缀) Problem - D2 - Codeforces 大意&#xff1a;给出一个字符串 S &#xff0c; 找出满足以下条件的字符串 T。 1. 字符串 T 尽可能长 并且 |T| ≤ |S| 2.字符串 T 由 S 的一个前缀和后缀拼接而成 &#xff0c; T 是回文串…

2023-08-19 LeetCode每日一题(两整数相加)

2023-08-19每日一题 一、题目编号 2235. 两整数相加二、题目链接 点击跳转到题目位置 三、题目描述 给你两个整数 num1 和 num2&#xff0c;返回这两个整数的和。 示例 1&#xff1a; 示例 2&#xff1a; 提示&#xff1a; -100 < num1, num2 < 100 四、解题代…

攻防世界-fileinclude

原题 解题思路 题目已经告诉了&#xff0c;flag在flag.php中&#xff0c;先查看网页源代码&#xff08;快捷键CTRLU&#xff09;。 通过抓包修改&#xff0c;可以把lan变量赋值flag。在cookie处修改。新打开的网页没有cookie&#xff0c;直接添加“Cookie: languagephp://filte…

29、简单通过git把项目远程提交到gitee

简单通过git把项目远程提交到gitee 1、在gitee上创建一个仓库 2、在要提交的项目文件夹打开git 输入 git init 初始化git 然后设置下用户名和邮箱 git config --global user.name “username” git config --global user.email “yourEmail” 因为我是要把文件简单提交到…

回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SCN随机配置网络多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本介绍程序设计参考资料 效果一览 基本…

PNP结算方法(后面可能有空再补充了)

一些pnp的实验结论&#xff1a; &#xff08;1&#xff09;yaw角稳定性上&#xff1a; 在opencv中&#xff0c; SOLVEPNP_UPNPSOLVEPNP_EPNPSOLVEPNP_DLS>>SOLVEPNP_IPPE>SOLVEPNP_AP3P>SOLVEPNP_ITERATIVE 固定一个识别物体检查结算的yaw角在这张图中l1是ippe&…

Vue-9.集成(.editorconfig、.eslintrc.js、.prettierrc)

介绍 同时使用 .editorconfig、.prettierrc 和 .eslintrc.js 是很常见的做法&#xff0c;因为它们可以在不同层面上帮助确保代码的格式一致性和质量。这种组合可以在开发过程中提供全面的代码维护和质量保证。然而&#xff0c;这也可能增加一些复杂性&#xff0c;需要谨慎配置…

恢复NuGet包_解决:System.BadImageFormatException:无法加载文件或程序集

C#工程 主要是开发了一个 web api接口&#xff0c;这个工程源码去年还可以的&#xff0c;今年换了一个电脑打开工程就报错。 错误提示如下&#xff1a; 在 Microsoft.CodeAnalysis.CSharp.CommandLine.Program.Main(String[] args) Test1 System.BadImageFormatEx…

人脸识别技术在社会安全与便利中的应用

引言&#xff1a;随着人工智能的快速发展&#xff0c;人脸识别技术已经成为一种实时、高效的身份验证和安全监控手段。它的广泛应用可以帮助识别犯罪嫌疑人、寻找失踪人口等&#xff0c;为社会安全和公共利益做出了重要贡献。本文将详细探讨人脸识别技术的原理、应用&#xff0…

【Rust日报】2023-08-18 RustShip:一个新的 Rust 播客

探索 Rust 编译器基准测试套件 在最近关于 Rust 编译器 CI&#xff08;持续集成&#xff09;和基准测试基础设施的文章中&#xff0c;作者承诺写一篇关于运行时基准测试的博客文章&#xff0c;这是 Rust 编译器基准测试套件的新补充。然而&#xff0c;在这样做之前&#xff0c;…

春秋云镜 CVE-2020-13933

春秋云镜 CVE-2020-13933 Shiro < 1.6.0 验证绕过漏洞 靶标介绍 Apahce Shiro 由于处理身份验证请求时出错 存在 权限绕过漏洞&#xff0c;远程攻击者可以发送特制的HTTP请求&#xff0c;绕过身份验证过程并获得对应用程序的未授权访问。 启动场景 漏洞利用 exp /admin…

读发布!设计与部署稳定的分布式系统(第2版)笔记33_混沌工程

1. 康威定律 1.1. 梅尔文康威 1.1.1. Melvin Conway 1.1.2. 1968年 1.1.3. 在设计系统时&#xff0c;组织受制于其自身的沟通结构&#xff0c;这使得它设计的系统结构与沟通结构相一致。 1.1.3.1. 社会学现象 1.2. 要在系统内部或系统之间构建接口&#xff0c;两个人必须…

基于 Vercel TiDB Serverless 的 chatbot

作者&#xff1a; shiyuhang0 原文来源&#xff1a; https://tidb.net/blog/7b5fcdc9 # 前言 TiDB Serverless 去年就有和 Vercel 的集成了&#xff0c;同时还有一个 bookstore template 方便大家体验。但个人感觉 bookstore 不够炫酷&#xff0c;借 2023 TiDB hackthon 的…

使用Python从Ditto数据库中读取历史图片

在本文中&#xff0c;我们将探讨如何使用Python编程语言从Ditto剪贴板管理工具的数据库中读取历史中您复制粘贴过的图片。我们将讲解编程的过程&#xff0c;并提供示例代码来帮助您理解如何实现这个功能。 C:\pythoncode\blog\showdbimage.py Ditto数据库 Ditto使用SQLite数…

车载APP软件外包开发流程

车载APP的开发流程涉及多个阶段&#xff0c;从概念到发布都需要仔细的规划和执行。以下是一个一般性的车载APP开发流程概述&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1.需求分析和规划&#xff…

VMWare Workstation 17 Pro 网络设置 桥接模式 网络地址转换(NAT)模式 仅主机模式

文章目录 网络模式配网要求CentOSDHCP虚拟网络桥接模式默认配置测试手动配置测试 网络地址转发模式 (NAT)还原配置虚拟网络配置默认配置测试手动配置测试 仅主机模式 网络模式 桥接模式: 主机与虚拟机对等, 虚拟机注册到主机所在的局域网, 会占用该网络的IP该局域网内的所有机…

【COMP282 LEC3 LEC4 LEC5】

LEC 3 Overloading 超载 1. Two functions can have the same name if they have different parameters 2. The compiler will use the one whose parameters match the ones you pass in Performing Addition “” 重载一个operator &#xff0c;这个operator函数被定义…

[线程/C]基础

文章目录 1. 线程介绍2. 创建线程2.1 线程函数2.2 创建线程 3. 线程退出4. 线程回收4.1 线程函数4.2 回收子线程数据4.2.1 使用子线程栈4.2.2 使用全局变量4.2.3 使用主线程栈 5. 线程分离6. 其他线程函数6.1 线程取消6.2 线程ID的比较 1. 线程介绍 线程是轻量级的进程&#x…

C语言入门教程,C语言学习教程(非常详细)第二章 c语言初探

第一个C语言程序 我们有两种方式从计算机获得信息&#xff1a;一是看屏幕上的文字、图片、视频等&#xff0c;二是听从喇叭发出来的声音。让喇叭发出声音目前还比较麻烦&#xff0c;我们先来看看如何在屏幕上显示一些文字吧。 在屏幕上显示文字非常简单&#xff0c;只需要一个…