(学习日记)2024.03.10:UCOSIII第十二节:多优先级

写在前面:
由于时间的不足与学习的碎片化,写博客变得有些奢侈。
但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。
既然如此
不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质,以便于日后搜索起来更加容易。


标题的结构如下:“类型”:“知识点”——“简短的解释”
部分内容由于保密协议无法上传。


点击此处进入学习日记的总目录

2024.03.10

  • 二十五、UCOSIII:多优先级
    • 1、定义优先级相关全局变量
    • 2、修改OSInit()函数
    • 3、修改任务控制块TCB
    • 4、修改OSTaskCreate()函数
    • 5、修改OS_IdleTaskInit()函数
    • 6、修改OSStart()函数
    • 7、修改PendSV_Handler()函数
    • 8、修改OSTimeDly()函数
    • 9、修改OSSched()函数
    • 10、修改OSTimeTick()函数
  • 二十六、UCOSIII:修改main()函数
    • 1、修改部分:
    • 2、实验现象

二十五、UCOSIII:多优先级

在本章之前,OS还没有到优先级,只支持两个任务互相切换,从本章开始,任务中我们开始加入优先级的功能。 在μC/OS-III中,数字优先级越小,逻辑优先级越高。

1、定义优先级相关全局变量

在支持任务多优先级的时候,需要在os.h头文件添加两个优先级相关的全局变量

/* 在os.h中定义 */
/* 当前优先级 */
OS_EXT            OS_PRIO                OSPrioCur;
/* 最高优先级 */
OS_EXT            OS_PRIO                OSPrioHighRdy;

2、修改OSInit()函数

刚刚新添加的优先级相关的全部变量,需要在OSInit()函数中进行初始化
其实OS中定义的所有的全局变量都是在OSInit()中初始化的。

void OSInit (OS_ERR *p_err)
{/* 配置OS初始状态为停止态 */OSRunning =  OS_STATE_OS_STOPPED;/* 初始化两个全局TCB,这两个TCB用于任务切换 */OSTCBCurPtr = (OS_TCB *)0;OSTCBHighRdyPtr = (OS_TCB *)0;/* 初始化优先级变量 */OSPrioCur                       = (OS_PRIO)0;OSPrioHighRdy                   = (OS_PRIO)0;/* 初始化优先级表 */OS_PrioInit();/* 初始化就绪列表 */OS_RdyListInit();/* 初始化空闲任务 */OS_IdleTaskInit(p_err);if (*p_err != OS_ERR_NONE) {return;}
}

3、修改任务控制块TCB

在任务控制块中,加入优先级字段Prio
优先级Prio的数据类型为OS_PRIO, 宏展开后是8位的整型,所以只支持255个优先级。

struct os_tcb {CPU_STK         *StkPtr;CPU_STK_SIZE    StkSize;/* 任务延时周期个数 */OS_TICK         TaskDelayTicks;/* 任务优先级 */OS_PRIO         Prio;/* 就绪列表双向链表的下一个指针 */OS_TCB          *NextPtr;/* 就绪列表双向链表的前一个指针 */OS_TCB          *PrevPtr;
};

4、修改OSTaskCreate()函数

void OSTaskCreate (OS_TCB        *p_tcb,OS_TASK_PTR   p_task,
void          *p_arg,OS_PRIO       prio,			//(1)CPU_STK       *p_stk_base,CPU_STK_SIZE  stk_size,OS_ERR        *p_err)
{CPU_STK       *p_sp;CPU_SR_ALLOC();			//(2)/* 初始化TCB为默认值 */OS_TaskInitTCB(p_tcb);			//(3)/* 初始化栈 */p_sp = OSTaskStkInit( p_task,p_arg,p_stk_base,stk_size );p_tcb->Prio = prio;			//(4)p_tcb->StkPtr = p_sp;p_tcb->StkSize = stk_size;/* 进入临界段 */OS_CRITICAL_ENTER();			//(5)/* 将任务添加到就绪列表 */			//(6)OS_PrioInsert(p_tcb->Prio);OS_RdyListInsertTail(p_tcb);/* 退出临界段 */OS_CRITICAL_EXIT();			//(7)*p_err = OS_ERR_NONE;
}
  • (1):在函数形参中,加入优先级字段。任务的优先级由用户在创建任务的时候通过形参Prio传进来。
  • (2):定义一个局部变量,用来存CPU关中断前的中断状态,因为接下来将任务添加到就绪列表这段代码属于临界短代码,需要关中断。
  • (3):初始化TCB为默认值,其实就是全部初始化为0OS_TaskInitTCB()函数在os_task.c的开头定义
void  OS_TaskInitTCB (OS_TCB  *p_tcb)
{p_tcb->StkPtr             = (CPU_STK       *)0;p_tcb->StkSize            = (CPU_STK_SIZE   )0u;p_tcb->TaskDelayTicks     = (OS_TICK       )0u;p_tcb->Prio               = (OS_PRIO        )OS_PRIO_INIT;//OS_PRIO_INIT是任务TCB初始化的时候给的默认的一个优先级,宏展开等于OS_CFG_PRIO_MAX, 这是一个不会被OS使用到的优先级。//OS_PRIO_INIT具体在os.h中定义。p_tcb->NextPtr            = (OS_TCB        *)0;p_tcb->PrevPtr            = (OS_TCB        *)0;
}
  • (4):将形参传进来的优先级存到任务控制块TCB的优先级字段。
  • (5):进入临界段。
  • (6):将任务插入就绪列表,这里需要分成两步来实现:
    1、根据优先级置位优先级表中的相应位置;
    2、将任务TCB放到OSRdyList[优先级]中,如果同一个优先级有多个任务,那么这些任务的TCB就会被放到OSRdyList[优先级]串成一个双向链表。
  • (7):退出临界段。

5、修改OS_IdleTaskInit()函数

修改OS_IdleTaskInit()函数,是因为该函数调用了任务创建函数OSTaskCreate()OSTaskCreate()我们刚刚加入了优先级, 所以这里我们要跟空闲任务分配一个优先级

/* 空闲任务初始化 */
void  OS_IdleTaskInit(OS_ERR  *p_err)
{/* 初始化空闲任务计数器 */OSIdleTaskCtr = (OS_IDLE_CTR)0;/* 创建空闲任务 */OSTaskCreate( (OS_TCB     *)&OSIdleTaskTCB,(OS_TASK_PTR )OS_IdleTask,(void       *)0,(OS_PRIO)(OS_CFG_PRIO_MAX - 1u),(1)(CPU_STK    *)OSCfg_IdleTaskStkBasePtr,(CPU_STK_SIZE)OSCfg_IdleTaskStkSize,(OS_ERR     *)p_err );
}

空闲任务是μC/OS-III的内部任务,在OSInit()中被创建,在系统没有任何用户任务运行的情况下, 空闲任务就会被运行,优先级最低,即等于OS_CFG_PRIO_MAX- 1u

6、修改OSStart()函数

加入优先级之后,OSStart()函数需要修改,具体哪一个任务最先运行,由优先级决定

/* 启动RTOS,将不再返回 */
void OSStart (OS_ERR *p_err)
{
if ( OSRunning == OS_STATE_OS_STOPPED ) {
#if 0/* 手动配置任务1先运行 */OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;
#endif/* 寻找最高的优先级 */OSPrioHighRdy   = OS_PrioGetHighest();(1)OSPrioCur       = OSPrioHighRdy;/* 找到最高优先级的TCB */OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;(2)OSTCBCurPtr     = OSTCBHighRdyPtr;/* 标记OS开始运行 */OSRunning       = OS_STATE_OS_RUNNING;/* 启动任务切换,不会返回 */OSStartHighRdy();/* 不会运行到这里,运行到这里表示发生了致命的错误 */*p_err = OS_ERR_FATAL_RETURN;} else {*p_err = OS_STATE_OS_RUNNING;}
}
  • (1):调取OS_PrioGetHighest()函数从全局变量优先级表OSPrioTbl[]获取最高的优先级, 放到OSPrioHighRdy这个全局变量中, 然后把OSPrioHighRdy的值再赋给当前优先级OSPrioCur这个全局变量。在任务切换的时候需要用到OSPrioHighRdyOSPrioCur这两个全局变量。
  • (2):根据OSPrioHighRdy的值, 作为全局变量OSRdyList[]的下标索引找到最高优先级任务的TCB,传给全局变量OSTCBHighRdyPtr, 然后再将OSTCBHighRdyPtr赋值给OSTCBCurPtr。在任务切换的时候需要使用到OSTCBHighRdyPtrOSTCBCurPtr这两个全局变量。

7、修改PendSV_Handler()函数

PendSV_Handler()函数中添加了优先级相关的代码。
有关PendSV_Handler()这个函数的具体讲解要参考《任务切换》这个章节,这里不再赘述。

;*******************************************************************
;                          PendSVHandler异常
;*******************************************************************OS_CPU_PendSVHandler_nosave; OSPrioCur   = OSPrioHighRdyLDR     R0, =OSPrioCurLDR     R1, =OSPrioHighRdyLDRB    R2, [R1]STRB    R2, [R0]; OSTCBCurPtr = OSTCBHighRdyPtr
LDR     R0, = OSTCBCurPtr
LDR     R1, = OSTCBHighRdyPtr
LDR     R2, [R1]
STR     R2, [R0]LDR     R0, [R2]
LDMIA   R0!, {R4-R11}MSR     PSP, R0
ORR     LR, LR, #0x04
CPSIE   I
BX      LRNOPENDP

8、修改OSTimeDly()函数

任务调用OSTimeDly()函数之后,任务就处于阻塞态,需要将任务从就绪列表中移除

/* 阻塞延时 */
void  OSTimeDly(OS_TICK dly)
{
#if 0/* 设置延时时间 */OSTCBCurPtr->TaskDelayTicks = dly;/* 进行任务调度 */OSSched();
#endifCPU_SR_ALLOC();		//(1)/* 进入临界区 */OS_CRITICAL_ENTER();		//(2)/* 设置延时时间 */OSTCBCurPtr->TaskDelayTicks = dly;/* 从就绪列表中移除 *///OS_RdyListRemove(OSTCBCurPtr);OS_PrioRemove(OSTCBCurPtr->Prio);		//(3)/* 退出临界区 */OS_CRITICAL_EXIT();		//(4)/* 任务调度 */OSSched();
}
  • (1):定义一个局部变量,用来存CPU关中断前的中断状态,因为接下来将任务从就绪列表移除这段代码属于临界短代码,需要关中断。
  • (2):进入临界段
  • (3):将任务从就绪列表移除, 这里只需将任务在优先级表中对应的位清除即可,暂时不需要把任务TCB从OSRdyList[]中移除, 因为接下来OSTimeTick()函数还是通过扫描OSRdyList[]来判断任务的延时时间是否到期。当我们加入了时基列表之后, 当任务调用OSTimeDly()函数进行延时,就可以把任务的TCB从就绪列表删除,然后把任务TCB插入时基列表, OSTimeTick()函数判断任务的延时是否到期只需通过扫描时基列表即可,时基列表在下一个章节实现。 所以这里暂时不能把TCB从就绪列表中删除,只是将任务优先级在优先级表中对应的位清除来达到任务不处于就绪态的目的。
  • (4):退出临界段。

9、修改OSSched()函数

任务调度函数OSSched()不再是之前的两个任务轮流切换,需要根据优先级来调度, 被迭代的代码已经通过条件编译屏蔽。

void OSSched(void)
{
#if 0/* 如果当前任务是空闲任务,那么就去尝试执行任务1或者任务2,看看他们的延时时间是否结束,如果任务的延时时间均没有到期,那就返回继续执行空闲任务 */if ( OSTCBCurPtr == &OSIdleTaskTCB ){if (OSRdyList[0].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;}else if (OSRdyList[1].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;}else{return;   /* 任务延时均没有到期则返回,继续执行空闲任务 */}}else{/*如果是task1或者task2的话,检查下另外一个任务,如果另外的任务不在延时中,就切换到该任务,否则,判断下当前任务是否应该进入延时状态,如果是的话,就切换到空闲任务。否则就不进行任何切换 */if (OSTCBCurPtr == OSRdyList[0].HeadPtr){if (OSRdyList[1].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[1].HeadPtr;} else if (OSTCBCurPtr->TaskDelayTicks != 0) {OSTCBHighRdyPtr = &OSIdleTaskTCB;} else {/* 返回,不进行切换,因为两个任务都处于延时中 */return;}}else if (OSTCBCurPtr == OSRdyList[1].HeadPtr){if (OSRdyList[0].HeadPtr->TaskDelayTicks == 0){OSTCBHighRdyPtr = OSRdyList[0].HeadPtr;}else if (OSTCBCurPtr->TaskDelayTicks != 0){OSTCBHighRdyPtr = &OSIdleTaskTCB;}else{/* 返回,不进行切换,因为两个任务都处于延时中 */return;}}}/* 任务切换 */OS_TASK_SW();
#endifCPU_SR_ALLOC();		//(1)/* 进入临界区 */OS_CRITICAL_ENTER();		//(2)/* 查找最高优先级的任务 */		//(3)OSPrioHighRdy   = OS_PrioGetHighest();OSTCBHighRdyPtr = OSRdyList[OSPrioHighRdy].HeadPtr;/* 如果最高优先级的任务是当前任务则直接返回,不进行任务切换 */		//(4)if (OSTCBHighRdyPtr == OSTCBCurPtr){/* 退出临界区 */OS_CRITICAL_EXIT();return;}/* 退出临界区 */OS_CRITICAL_EXIT();		//(5)/* 任务切换 */OS_TASK_SW();		//(6)
}
  • (1):定义一个局部变量,用来存CPU关中断前的中断状态,因为接下来查找最高优先级这段代码属于临界短代码,需要关中断。
  • (2):进入临界段。
  • (3):查找最高优先级任务。
  • (4):判断最高优先级任务是不是当前任务,如果是则直接返回,否则将继续往下执行,最后执行任务切换。
  • (5):退出临界段。
  • (6):任务切换。

10、修改OSTimeTick()函数

OSTimeTick()函数在SysTick中断服务函数中被调用,是一个周期函数,具体用于扫描就绪列表OSRdyList[], 判断任务的延时时间是否到期,如果到期则将任务在优先级表中对应的位置位, 被迭代的代码则通过条件编译屏蔽。

void  OSTimeTick (void)
{unsigned int i;CPU_SR_ALLOC();		//(1)/* 进入临界区 */OS_CRITICAL_ENTER();		//(2)/* 扫描就绪列表中所有任务的TaskDelayTicks,如果不为0,则减1 */
#if 0for (i=0; i<OS_CFG_PRIO_MAX; i++){if (OSRdyList[i].HeadPtr->TaskDelayTicks > 0){OSRdyList[i].HeadPtr->TaskDelayTicks --;}}
#endiffor (i=0; i<OS_CFG_PRIO_MAX; i++) 		//(3){if (OSRdyList[i].HeadPtr->TaskDelayTicks > 0){OSRdyList[i].HeadPtr->TaskDelayTicks --;if (OSRdyList[i].HeadPtr->TaskDelayTicks == 0){/* 为0则表示延时时间到,让任务就绪 *///OS_RdyListInsert (OSRdyList[i].HeadPtr);OS_PrioInsert(i);}}}/* 退出临界区 */OS_CRITICAL_EXIT();		//(4)/* 任务调度 */OSSched();
}
  • (1):定义一个局部变量,用来存CPU关中断前的中断状态, 因为接下来扫描就绪列表OSRdyList[]这段代码属于临界短代码,需要关中断。
  • (2):进入临界段。
  • (3):扫描就绪列表OSRdyList[],判断任务的延时时间是否到期, 如果到期则将任务在优先级表中对应的位置位。
  • (4):退出临界段。

二十六、UCOSIII:修改main()函数

1、修改部分:

在这里插入图片描述

/*
*******************************************************************
*                             全局变量
*******************************************************************
*/uint32_t flag1;
uint32_t flag2;
uint32_t flag3;/*
*******************************************************************
*                        TCB & STACK &任务声明
*******************************************************************
*/
#define  TASK1_STK_SIZE       128
#define  TASK2_STK_SIZE       128
#define  TASK3_STK_SIZE       128static   OS_TCB    Task1TCB;
static   OS_TCB    Task2TCB;
static   OS_TCB    Task3TCB;static   CPU_STK   Task1Stk[TASK1_STK_SIZE];
static   CPU_STK   Task2Stk[TASK2_STK_SIZE];
static   CPU_STK   Task3Stk[TASK2_STK_SIZE];void     Task1( void *p_arg );
void     Task2( void *p_arg );
void     Task3( void *p_arg );/*
*******************************************************************
*                             函数声明
*******************************************************************
*/
void delay(uint32_t count);/*
*******************************************************************
*                             main()函数
*******************************************************************
*/
/*
* 注意事项:1、该工程使用软件仿真,debug需选择 Ude Simulator
*           2、在Target选项卡里面把晶振Xtal(Mhz)的值改为25,默认是12,
*              改成25是为了跟system_ARMCM3.c中定义的__SYSTEM_CLOCK相同,
*              确保仿真的时候时钟一致
*/
int main(void)
{OS_ERR err;/* CPU初始化:1、初始化时间戳 */CPU_Init();/* 关闭中断 */CPU_IntDis();/* 配置SysTick 10ms 中断一次 */OS_CPU_SysTickInit (10);/* 初始化相关的全局变量 */OSInit(&err);		//(1)/* 创建任务 */OSTaskCreate( (OS_TCB*)&Task1TCB,(OS_TASK_PTR )Task1,(void *)0,(OS_PRIO)1,		//(2)(CPU_STK*)&Task1Stk[0],(CPU_STK_SIZE)  TASK1_STK_SIZE,(OS_ERR *)&err );OSTaskCreate( (OS_TCB*)&Task2TCB,(OS_TASK_PTR )Task2,(void *)0,(OS_PRIO)2,		//(3)(CPU_STK*)&Task2Stk[0],(CPU_STK_SIZE)  TASK2_STK_SIZE,(OS_ERR *)&err );OSTaskCreate( (OS_TCB*)&Task3TCB,(OS_TASK_PTR )Task3,(void *)0,(OS_PRIO)3,		//(4)(CPU_STK*)&Task3Stk[0],(CPU_STK_SIZE)  TASK3_STK_SIZE,(OS_ERR *)&err );
#if 0
/* 将任务加入到就绪列表 */		//(5)OSRdyList[0].HeadPtr = &Task1TCB;OSRdyList[1].HeadPtr = &Task2TCB;
#endif/* 启动OS,将不再返回 */OSStart(&err);
}/*
*******************************************************************
*                              函数实现
*******************************************************************
*/
/* 软件延时 */
void delay (uint32_t count)
{for (; count!=0; count--);
}void Task1( void *p_arg )
{for ( ;; ) {flag1 = 1;OSTimeDly(2);flag1 = 0;OSTimeDly(2);}
}void Task2( void *p_arg )
{for ( ;; ) {flag2 = 1;OSTimeDly(2);flag2 = 0;OSTimeDly(2);}
}void Task3( void *p_arg )
{for ( ;; ) {flag3 = 1;OSTimeDly(2);flag3 = 0;OSTimeDly(2);}
}
  • (1):加入了优先级相关的全局变量OSPrioCurOSPrioHighRdy的初始化。
  • (2)、(3)和(4):为每个任务分配了优先级,任务1的优先级为1,任务2的优先级为2,任务3的优先级为3
  • (5):将任务插入就绪列表这部分功能由OSTaskCreate()实现,这里通过条件编译屏蔽掉。

2、实验现象

进入软件调试,全速运行程序,从逻辑分析仪中可以看到三个任务的波形是完全同步,就好像CPU在同时干三件事情
在这里插入图片描述

任务开始的启动过程具体见图
在这里插入图片描述
上图是任务1、2和3刚开始启动时的软件仿真波形图,系统从启动到任务1开始运行前花的时间为TIME1, 等于0.26MS

任务1开始运行,然后调用OSTimeDly(1)进入延时,随后进行任务切换,切换到任务2开始运行, 从任务1切换到任务2花费的时间等于TIME2-TIME1,等于0.01MS
任务2开始运行,然后调用OSTimeDly(1)进入延时, 随后进行任务切换,切换到任务3开始运行,从任务2切换到任务3花费的时间等于TIME3-TIME1,等于0.01MS
任务3开始运行,然后调用OSTimeDly(1)进入延时,随后进行任务切换,这个时候我们创建的3个任务都处于延时状态, 那么系统就切换到空闲任务,在三个任务延时未到期之前,系统一直都是在运行空闲任务。

当第一个SysTick中断产生, 中断服务函数会调用OSTimeTick()函数扫描每个任务的延时是否到期,因为是延时1个SysTick周期, 所以第一个SysTick中断产生就意味着延时都到期,任务1、2和3依次进入就绪态,再次回到任务本身接着运行, 将自身的Flag清零,然后任务1、2和3又依次调用OSTimeDly(1)进入延时状态,直到下一个SysTick中断产生前, 系统都处在空闲任务中,一直这样循环下去。

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

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

相关文章

中国城市统计年鉴、中国县域统计年鉴、中国财政统计年鉴、中国税务统计年鉴、中国科技统计年鉴、中国卫生统计年鉴​

统计年鉴是指以统计图表和分析说明为主&#xff0c;通过高度密集的统计数据来全面、系统、连续地记录年度经济、社会等各方面发展情况的大型工具书来获取统计数据资料。 统计年鉴是进行各项经济、社会研究的必要前提。而借助于统计年鉴&#xff0c;则是研究者常用的途径。目前国…

透视地下世界:管道挖掘切面可视化的革命性突破

在城市化进程不断加速的今天&#xff0c;地下管道作为城市“生命线”的重要组成部分&#xff0c;其安全、高效运行显得尤为关键。然而&#xff0c;传统的管道挖掘与检测方式往往存在着诸多不足&#xff0c;如效率低下、安全隐患大等。如今&#xff0c;随着技术的飞速发展&#…

IEEE802.11v协议介绍

IEEE802.11v协议简介 协议全称:无线网络管理(Wireless Network Management) 批准日期:2011年2月 协议状态:并入802.11-2012 协议别名:BSS过渡管理 主要功能 支持AP和STA间交换:关于RF环境和拓扑状态的信息,以协助STA进行漫游决策支持STA之间交换:关于RF环境状态的信…

史上最牛Linux详解,看完直接带你由入门到精通!

第一部分&#xff1a;入门 第二部分&#xff1a;成为一名linux高级用户&#xff1a; 第三部分&#xff1a;成为一名Linux系统管理员 第四部分&#xff1a;成为一名Linux服务器管理员 因文章内容过长&#xff0c;目录先放这些&#xff0c;因为接下来还要放一些内容 小编13年上海…

[C++核心编程](九):类和对象——多态**

目录 多态的分类 多态的原理剖析 多态的优点 纯虚函数和抽象类 虚析构和纯虚析构 多态是C面向对象三大特性之一 多态的分类 静态多态 -函数重载和运算符重载属于静态多态&#xff0c;复用函数名 -函数地址早绑定-编译阶段确定函数地址 动态多态 -派生类和虚函数实现运行…

Linux中mysql的安装、远程访问、基础操作、文件导入

Linux中mysql的安装、远程访问、基础操作、文件导入 cheet card1. 安装1. 使用root账号安装mysql 2. 启动mysql并创建root、管理员两个账号3. 基础操作3.1 数据库的查看、创建、修改、删除3.2 mysql的数据类型3.3 数据表的基本操作3.4 数据表结构的修改3.5 表中数据的增、删、改…

STM32F407_外部中断

这里写目录标题 前言1、EXTI概述2、外部中断配置流程完整代码 前言 注释很详细&#xff0c;放心食用。 1、EXTI概述 STM32F4的每个IO都可以作为外部中断的中断输入口&#xff0c;这点也是STM32F4的强大之处。STM32F407的中断控制器支持22个外部中断/事件请求。每个中断线上都设…

嵌入式常用5种通信协议

简介&#xff1a; 嵌入式常用五种通信协议为&#xff1a;UART、RS232、RS485、IIC、SPI。 由于这几种通信协议十分相似又有区别&#xff0c;所以分组记忆&#xff0c;红色的为一组&#xff0c;蓝色的为一组。 ①组都有两条线&#xff0c;且都是异步通信没得时钟线&#xff0c…

Redis基本使用

Redis基本使用 1.通用命令2.基本数据类型2.1 String2.2 Hash2.3 List2.4 Set2.5 SortedSet 3. SpringDataRedis3.1 简介3.2 快速代码示例3.3 序列化 1.通用命令 针对所有数据类型的操作可以在Redis官方文档查看。以下是通用的命令。 KEYS&#xff1a;查看符合模板的所有key D…

基于boost库的搜索引擎项目

文章目录 一、项目背景二、什么样的搜索引擎三、搜索引擎的宏观图原理四、Parse模块4.1下载boost库源代码4.2提取boost库中以.html为结尾的文件4.2.1 boost库的简单使用 4.3数据清洗(去标签化)4.3.1数据清洗的具体实现 4.4将清洗后的数据写入到raw.txt文件中 五、正排索引 vs 倒…

阿里云服务器租用费用一个月多少钱?5元1个月

阿里云服务器一个月多少钱&#xff1f;最便宜5元1个月。阿里云轻量应用服务器2核2G3M配置61元一年&#xff0c;折合5元一个月&#xff0c;2核4G服务器30元3个月&#xff0c;2核2G3M带宽服务器99元12个月&#xff0c;轻量应用服务器2核4G4M带宽165元12个月&#xff0c;4核16G服务…

了解关键字

关键字 定义&#xff1a;被Java语言赋予了特殊含义&#xff0c;用做专门用途的字符串&#xff08;或单词&#xff09; HelloWorld案例中&#xff0c;出现的关键字有 class、public 、 static 、 void 等&#xff0c;这些单词已经被Java定义好了。 特点&#xff1a;全部关键字都…