STM32CubeMX+FreeRTOS学习[3]-计数信号量(Lu)
- 格式:docx
- 大小:875.66 KB
- 文档页数:8
《STM32Cube高效开发教程》读书笔记目录一、前言 (2)1.1 书籍简介 (3)1.2 编写目的 (4)二、STM32Cube概述 (5)2.1 STM32Cube的意义 (6)2.2 STM32Cube的主要特点 (7)三、安装与配置 (9)3.1 STM32Cube的安装 (10)3.2 开发环境的配置 (11)四、创建项目 (12)4.1 新建项目 (13)4.2 项目设置 (14)五、HAL库介绍 (15)5.1 HAL库简介 (16)5.2 HAL库的主要组件 (18)六、STM32最小系统 (19)6.1 STM32最小系统的组成 (21)6.2 STM32最小系统的应用 (22)七、GPIO操作 (24)7.1 GPIO的基本概念 (25)7.2 GPIO的操作方法 (26)八、中断系统 (28)8.1 中断的基本概念 (29)8.2 中断的处理过程 (31)九、定时器 (33)9.1 定时器的功能介绍 (34)9.2 定时器的操作方法 (36)十五、文件系统 (37)一、前言随着科技的飞速发展,嵌入式系统已广泛应用于我们生活的方方面面,从智能手机到自动驾驶汽车,其重要性不言而喻。
而STM32作为一款广泛应用的微控制器系列,以其高性能、低功耗和丰富的外设资源赢得了广大开发者的青睐。
为了帮助开发者更好地掌握STM32系列微控制器的开发技巧,提升开发效率,我们特别推出了《STM32Cube 高效开发教程》。
本书以STM32Cube为核心,通过生动的实例和详细的讲解,全面介绍了STM32系列微控制器的开发过程。
无论是初学者还是有一定基础的开发者,都能从中找到适合自己的学习内容。
通过本书的学习,读者将能够更加深入地理解STM32的内部结构和工作原理,掌握其编程方法和调试技巧,从而更加高效地进行嵌入式系统的开发和应用。
在科技日新月异的今天,STM32系列微控制器将继续扮演着举足轻重的角色。
FreeRTOS学习笔记使用注意:FreeRTOS与ucOS相比,需要修改启动文件。
1.任务创建包含FreeRTOS.h //这个是必须要包含的// 和task.h。
调用API函数:xTaskCreatepvTaskCode:函数指针(函数名)。
pcName:描述性任务名,只是用于辅助调试。
可以通过FreeRTOSConfig.h第100行的configMAX_TASK_NAME_LEN来改变描述名长度。
usStackDepth:任务栈大小。
建议为64的整数倍。
pvParameters:任务参数,void * 类型。
不用写NULL。
uxPriority:任务优先级。
值越大优先级越高。
同等优先级时,按照os heart进行时间片轮转。
xTaskHandle:任务句柄。
改变该任务优先级、删除任务等时才会用到。
不用写NULL。
2.开始多任务vTaskStartScheduler()3.如何多任务切换调用API函数:vTaskDelay(unsigned int time)Time为多少个os heart。
4.时间片轮转例子创建两个任务xTaskCreate(USART1_Task, "USART1", 256, (void *)str1, 3, NULL);xTaskCreate(USART2_Task, "USART2", 256, (void *)str2, 3, NULL);相同优先级,波特率可以设置低一些。
然后就会看到这就是时间片轮转。
5.系统心跳频率在FreeRTOSConfig.h第97行的configTICK_RATE_HZ,源码使用1000HZ,就是1ms,如果为200就是200HZ,5ms。
相关宏:portTICK_RATE_MS。
6.vTaskDelayUntil和vTaskDelay不同,这个函数不包括函数运行时间,而vTaskDelayUntil包括。
stm32标准库函数说明
STM32标准库函数是为了方便开发者使用STM32微控制器而提供的一系列函数和库。
这些库函数提供了许多常用的功能,如GPIO操作、定时器操作、串口通信、ADC转换等。
以下是一些常见的STM32标准库函数及其说明:
GPIO 初始化函数:用于配置GPIO(General-Purpose Input/Output)的引脚模式(输入、输出、复用等)和参数(输出类型、输出速度、上拉/下拉等)。
定时器初始化函数:用于配置定时器的模式(计数器模式、PWM模式等)和参数(时钟源、自动重载值等)。
串口初始化函数:用于配置串口通信的参数(波特率、数据位、停止位、奇偶校验等)。
ADC 初始化函数:用于配置ADC(Analog-to-Digital Converter)的参数(转换模式、分辨率等)。
中断初始化函数:用于配置中断的优先级和触发方式。
延时函数:用于产生一定的延时。
睡眠函数:用于使微控制器进入低功耗模式,降低功耗。
串口发送和接收函数:用于串口通信的发送和接收数据。
ADC 读取函数:用于读取ADC转换的结果。
GPIO 操作函数:用于控制GPIO引脚的电平高低或读取引脚的电平状态。
STM32+cubeMX+FreeRTOS学习(1)背景:最近项⽬要在STM32L152上移植FreeRTOS轻量级系统,本⽂将从FreeRTOS的⼊门知识讲起,记录FreeRTOS的⼀些基本知识点和学习⼼得。
硬件平台:STM32L152 ,备注:PA12连接LED1,PA11连接LED2;软件平台:keil v5和 cubeMx。
内容:1.FreeRTOS简介FreeRTOS是⼀种轻量级实时操作系统。
RTOS:Real Time OperatingSystem实时操作系统。
FreeRTOS可拆分为Free + RTOS,前⾯Free代表⼀种操作系统类型的名称,后⾯RTOS代表实时操作系统。
近⼏年,FreeRTOS的排名在嵌⼊式操作系统的排名中还是⽐较⾼的,且有不断上升趋势。
2. cubeMX中FreeRTOS的⽣成及任务创建⾸先,打开CUBEMX软件,点击NEW Project,选择芯⽚STM32L152RC;2,配置RCC时钟3,设置PA12和PA11为GPIO_OUTPUT;4,使能FREERTOS;5,设置时钟树,本例外部晶振8M,8倍频,2分频,得到32M;6,配置FREERTOS,创建两个任务;7,⽣成基于Keil V5的代码。
8,添加LED点亮和熄灭程序;编译运⾏,可以看到LED1和LED2 分别以不同的频率闪烁。
下⾯重点分析⽣成的代码:下⾯分析MX_FREERTOS_Init()函数;void MX_FREERTOS_Init(void){osThreadDef(Task_LED1, Func_LED1, osPriorityNormal, 0, 128);//宏定义,定义了⼀个名为os_thread_def_Task_LED1的osThreadDef_t类型结构体,并赋值给各个成员变量。
Task_LED0Handle = osThreadCreate(osThread(Task_LED1), NULL);//创建了LED1任务osThreadDef(Task_LED2, Func_LED2, osPriorityNormal, 0, 128);//宏定义,定义了⼀个名为os_thread_def_Task_LED2的osThreadDef_t类型结构体,并赋值给各个成员变量。
[FreeRTOS⼊门]1.CubeMX中FreeRTOS配置参数及理解1.有关优先级 1.1 Configuration --> FreeRTOSMAX_PRIORITIES 设置任务优先级的数量:配置应⽤程序有效的优先级数⽬。
任何数量的任务都可以共享⼀个优先级,使⽤协程可以单独的给与它们优先权。
见MAX_CO_ROUTINE_PRIORITIES。
在RTOS内核中,每个有效优先级都会消耗⼀定量的RAM,因此这个值不要超过你的应⽤实际需要的优先级数⽬。
每⼀个任务都会被分配⼀个优先级,优先级值从0~(MAX_PRIORITIES - 1)之间。
低优先级数表⽰低优先级任务。
空闲任务的优先级为0(PriorityIdle),因此它是最低优先级任务。
FreeRTOS调度器将确保处于就绪状态(Ready)或运⾏状态(Running)的⾼优先级任务⽐同样处于就绪状态的低优先级任务优先获取处理器时间。
换句话说,处于运⾏状态的任务永远是⾼优先级任务。
处于就绪状态的相同优先级任务使⽤时间⽚调度机制共享处理器时间。
Interrupt nesting behaviour configuration 断⾔配置LIBRARY_LOWEST_INTERRUPT_PRIORITY此宏定义是⽤来配置 FreeRTOS中⽤到的SysTick中断和PendSV中断的优先级reeRTOSreeRTOSreeRTOSreeRTOS ⽤到的 SysTSysT ick 中断和 PendSV中断的优先级。
在 NVIC分组设置为4的情况下,此宏定义的范围就是 0-15 ,即专门配置抢占优先级。
这⾥即专门配置抢占优先级。
这⾥配置为了 15,即 SysTick和 PendSV 都配配置为了最低优先级,实际项⽬中也建议配置为最低优先级。
LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY定义了受FreeRTOS管理的最⾼优先级中断。
FreeRTOS操作系统配置参数说明FreeRTOS操作系统配置参数说明⾦涛(上海致远绿⾊能源股份有限公司上海 201611 )本⽂仅针对FreeRTOS操作系统的配置参数进⾏说明,其他内容不在累述。
如有需要,请参考相关⽂档。
⼀、⽣成带FreeRTOS操作系统代码的步骤1.下载安装的过程就不在赘述,直接开始使⽤。
双击打开cube MX,点击新建⼯程;2.本⽂以STM32F407IGT6作为所选MCU,具体使⽤根据最终所选型号进⾏配置:选择STM32F407IGTx;3.使⽤STM32CubeMX来⽣成带MiddleWare的FreeRTOS的代码,可以在STM32CubeMX 中使能FreeRTOS:Configuration --> MiddleWare -- >FreeRTOS --> Enable;4.RCC时钟源配置为外部时钟:Configuration --> Peripherals --> RCC --> HSE --> CryStal/Ceramic Resonator;5.配置时钟系统,直接将HCLK设置为100MHz,其他的会根据此⾃动选择。
6.FreeRTOS配置:Configuration --> FreeRTOS1. 使能抢占式调度器。
2. 有创建与空闲任务同优先级的任务。
通过时间⽚共享同⼀个优先级的多个任务,如果共享的优先级⼤于空闲优先级,并假设没有更⾼优先级任务,这些任务应该获得相同的处理器时间。
但如果共享空闲优先级时,情况会稍微有些不同。
当IDLE_SHOULD_YIELD为Enabled时,其它共享空闲优先级的⽤户任务就绪时,空闲任务⽴刻让出CPU,⽤户任务运⾏,这样确保了能最快响应⽤户任务。
处于这种模式下也会有不良效果(取决于你的程序需要),描述如下:图中描述了四个处于空闲优先级的任务,任务A、B和C是⽤户任务,任务I是空闲任务。
freertos函数手册(原创实用版)目录1.FreeRTOS 简介2.FreeRTOS 函数手册内容3.FreeRTOS 任务应用函数介绍4.使用 FreeRTOS 的注意事项5.总结正文1.FreeRTOS 简介FreeRTOS 是一款开源实时操作系统,适用于嵌入式系统。
它的名字来源于“FreeRTOS”,意为“免费的实时操作系统”。
FreeRTOS 具有轻量级、可扩展性和高可靠性等特点,广泛应用于各类嵌入式设备。
2.FreeRTOS 函数手册内容FreeRTOS 函数手册包含了丰富的函数,这些函数可以用于完成各种任务。
例如,可以用于创建任务、删除任务、更改任务的优先级等。
此外,手册还包括了一些用于处理中断的函数,以及用于与外部设备进行通信的函数。
3.FreeRTOS 任务应用函数介绍在 FreeRTOS 中,任务是核心概念之一。
通过使用任务,可以实现多任务并发,提高系统的运行效率。
FreeRTOS 提供了许多用于处理任务的函数。
例如:- xTaskCreate() 函数:用于创建一个新任务。
- xTaskDelete() 函数:用于删除一个任务。
- xTaskChangePriority() 函数:用于更改任务的优先级。
4.使用 FreeRTOS 的注意事项在使用 FreeRTOS 时,需要注意以下几点:- 确保系统时钟频率足够高,以保证实时性能。
- 合理设置任务的优先级,避免任务饥饿。
- 避免使用太多的全局变量,以减少任务间的相互影响。
- 正确处理任务间的同步与通信,避免死锁。
5.总结总的来说,FreeRTOS 是一款功能强大、易于使用的实时操作系统。
通过学习 FreeRTOS 函数手册,可以掌握如何在嵌入式系统中实现多任务并发,提高系统的运行效率。
用了半天时间对FreeRTOS有了一个初步的认识,大概总结一下,其中混杂了系统实现和实际应用方面的问题。
现只是以应用为目的,实现方面待以后进一步研究。
1.FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理。
与平台有关的文件包含在portable文件夹中,主要是port.c, portmacro.h 两个文件。
平台无关的文件主要是:list.c(基本链表结构), queue.c(包括消息队列,信号量的实现), croutine.c,tasks.c(任务管理,时间管理)。
命名协定RTOS内核与范例程序源代码使用下面的协定:变量char类型的变量以c 为前缀short类型的变量以s 为前缀long类型的变量以l 为前缀float类型的变量以f 为前缀double类型的变量以d 为前缀枚举变量以e 为前缀其他类型(如结构体)以x 为前缀指针有一个额外的前缀p , 例如short类型的指针前缀为ps无符号类型的变量有一个额外的前缀u , 例如无符号short类型的变量前缀为us函数文件内部函数以prv为前缀API函数以其返回值类型为前缀,按照前面对变量的定义函数的名字以其所在的文件名开头。
如vTaskDelete函数在Task.c文件中定义数据类型数据类型并不直接在RTOS内核内部引用。
相反,每个平台都有其自身的定义方式。
例如,char类型定义为portCHAR,short类型定义为portSHORT等。
范例程序源代码使用的就是这种符号,但这并不是必须的,你可以在你的程序中使用任何你喜欢的符号。
此外,有两种额外的类型要为每种平台定义。
分别是:portTickType可配置为16位的无符号类型或32位的无符号类型。
参考API文档中的定制部分获取详细信息。
portBASE_TYPE为特定体系定义的最有效率的数据类型。
如果portBASE_TYPE定义为char则必须要特别小心的保证用来作为函数返回值的signed char可以为负数,用于指示错误。
AN0025应用笔记FreeRTOS on AT32 MCU前言本指导手册描述了如何在AT32F系列MCU上使用FreeRTOS。
FreeRTOS是一款开源的嵌入式实时操作系统,目前在各种嵌入式应用中应用广泛。
本指导手册包括FreeRTOS系统移植、FreeRTOS内核服务讲解、综合Demo三个方面展开,全方位的讲解了FreeRTOS的使用,并且各个章节配套有对应的例程源程序,极大的方便初学者对AT32F系列MCU和FreeRTOS配合使用的深入理解。
本指导手册也描述了怎样充分的利用FreeRTOS的功能,以及如何搭配AT32的外设实现想要的功能。
使用本指导手册时,需配合配套的例程和FreeRTOS的官方指导手册,以便更深入的理解FreeRTOS。
注:本例程对应的代码是基于雅特力提供的V2.x.x 板级支持包(BSP)而开发,对于其他版本BSP,需要注意使用上的区别。
支持型号列表:支持型号AT32F系列目录FreeRTOS简介 (10)在AT32上移植FreeRTOS (12)移植FreeRTOS (12)例程介绍 (14)FreeRTOS调试方法 (18)系统配置 (18)例程介绍 (19)FreeRTOS中断优先级管理 (21)AT32中断配置 (21)FreeRTOS中断配置 (22)中断优先级和任务优先级区别 (23)临界段保护 (23)例程介绍 (24)FreeRTOS任务管理 (29)裸机与带RTOS的区别 (29)FreeRTOS任务状态 (30)FreeRTOS空闲任务 (31)FreeRTOS任务相关函数 (31)例程介绍 (34)FreeRTOS任务调度 (39)合作式调度 (39)抢占式调度 (39)例程介绍 (41)FreeRTOS消息队列 (47)消息队列介绍 (47)消息队列相关API (48)例程介绍 (51)FreeRTOS信号量 (58)什么是信号量 (58)二值信号量 (58)二值信号量介绍 (58)二值信号量API (59)例程介绍 (61)计数型信号量 (66)计数型信号量介绍 (66)计数型信号量API (66)例程介绍 (68)互斥信号量 (72)优先级翻转 (72)互斥信号量介绍 (73)互斥信号量API (74)例程介绍 (76)递归互斥信号量 (82)递归互斥信号量介绍 (82)递归互斥信号量API (82)例程介绍 (84)FreeRTOS事件标志组 (89)事件标志组介绍 (89)事件标志组API (89)软件定时器组介绍 (98)软件定时器组API (100)例程介绍 (102)FreeRTOS低功耗模式 (108)Tickless机制介绍 (108)例程介绍 (110)FreeRTOS内存管理方式 (116)内存管理方式一 (116)内存管理方式二 (117)内存管理方式三 (121)内存管理方式四 (122)内存管理方式五 (127)FreeRTOS流缓存 (131)流缓存介绍 (131)流缓存API (131)例程介绍 (133)FreeRTOS消息缓存 (138)消息缓存介绍 (138)消息缓存API (138)例程介绍 (140)FreeRTOS任务通知 (146)任务通知介绍 (146)任务通知API (146)Demo功能简介 (153)例程演示 (153)版本历史 (155)表目录表1. 中断优先级分组 (21)表2. 临界区API (24)表3. 动态创建任务函数原型 (32)表4. 静态创建任务函数原型 (32)表5. 任务删除函数原型 (33)表6. 任务挂起函数原型 (33)表7. 任务解除挂起函数原型 (33)表8. 任务延时函数原型 (34)表9. 消息队列API (48)表10. 创建消息队列函数原型 (49)表11. 发送消息函数原型 (49)表12. 发送消息函数原型(中断级) (50)表13. 接受消息函数原型 (50)表14. 接受消息函数原型(中断级) (50)表15. 二值信号量API (59)表16. 创建互斥信号量函数原型 (60)表17. 删除信号量函数原型 (60)表18. 释放信号量函数原型 (60)表19. 获取信号量函数原型 (61)表20. 计数型信号量API (66)表21. 创建二值信号量函数原型 (67)表22. 删除信号量函数原型 (67)表23. 释放信号量函数原型 (67)表24. 获取信号量函数原型 (67)表25. 获取信号量值函数原型 (68)表26. 互斥信号量API (74)表27. 创建互斥信号量函数原型 (75)表28. 删除信号量函数原型 (75)表29. 释放信号量函数原型 (75)表31. 获取信号量值函数原型 (76)表32. 递归互斥信号量API (82)表33. 创建递归互斥信号量函数原型 (83)表34. 释放信号量函数原型 (83)表35. 获取信号量函数原型 (83)表36. 事件标志组API (90)表37. 创建事件标志组函数原型 (90)表38. 设置事件标志组函数原型 (90)表39. 等待事件标志组函数原型 (91)表40. 软件定时器组API (100)表41. 创建软件定时器函数原型 (100)表42. 启动定时器函数原型 (101)表43. 关闭定时器函数原型 (101)表44. 获取定时器名字函数原型 (102)表45. 获取定时器ID函数原型 (102)表46. 设置定时器ID函数原型 (102)表47. 流缓存API (131)表48. 创建流缓存函数原型 (132)表49. 从流缓存接收数据函数原型 (132)表50. 发送数据到流缓存函数原型 (132)表51. 计数型信号量API (138)表52. 创建消息缓存函数原型 (139)表53. 从消息缓存接收数据函数原型 (139)表54. 发送数据到消息缓存函数原型 (139)表55. 任务通知API (146)表56. 文档版本历史 (155)图目录图1. FreeRTOS官网界面 (12)图2. FreeRTOS源码目录 (12)图3. 工程目录 (13)图4. 头文件添加 (13)图5. 移植例程演示 (17)图6. 调试配置参数 (18)图7. 调试例程演示 (20)图8. AT32 NVIC配置 (22)图9. AT32 外设中断配置 (22)图10. FreeRTOS中断配置 (22)图11. FreeRTOS中断管理例程演示 (28)图12. 裸机运行流程 (29)图13. RTOS运行流程 (30)图14. 任务状态转换关系 (31)图15. 任务管理例程演示 (38)图16. FreeRTOS官网合作式调度描述 (39)图17. 时间片调度 (41)图18. 时间片例程演示 (46)图19. 消息队列工作流程 (47)图20. 消息队列例程演示 (56)图21. 消息队列例程演示 (57)图22. 二值信号量框图1 (59)图23. 二值信号量框图2 (59)图24. 二值信号量框图3 (59)图25. 二值信号量例程演示 (65)图26. 二值信号量例程演示 (65)图27. 计数型信号量例程演示 (72)图28. 优先级翻转 (73)图29. 互斥信号量解决优先级翻转 (74)图31. 递归互斥信号量例程演示 (88)图32. 事件标志组框图 (89)图33. 事件标志组例程演示 (97)图34. 单次模式VS周期性模式 (98)图35. 软件定时器Daemon Task (99)图36. 软件定时器例程演示 (107)图37. 低功耗模式例程演示 (115)图38. 流缓存例程演示 (137)图39. 消息缓存例程演示 (145)图40. 任务通知例程演示 (152)图41. 综合例程演示1 (153)图42. 综合例程演示2 (154)FreeRTOS简介简介在嵌入式领域,嵌入式实时操作系统正得到越来越广泛的应用。
FreeRTOS学习之三:计数信号量
前提:默认已经装好MDK V5和STM32CubeMX,并安装了STM32F1xx系列的支持包。
硬件平台:STM32F1xx系列。
目的:学习计数信号量的使用。
计数信号量的使用场景:一个二值信号量最多只可以锁存一个中断事件。
在锁存的事件还未被处理之前,如果还有中断事件发生,那么后续发生的中断事件将会丢失。
如果用计数信号量代替二值信号量,那么,这种丢中断的情形将可以避免。
本文例子使用STM32CubeMX配置创建两个任务,一个任务每秒钟发送多次信号量,另一个等待信号量并控制LED的闪烁。
Step1.打开STM32CubeMX,点击“New Project”,选择芯片型号,STM32F103RBTx。
Step2.配置时钟引脚。
Step3.配置PA8和PD2为Output,并把用户标签分别改为LED0,LED1。
Step4.将系统时基源改为TIM4。
Step5.使能FreeRTOS。
Step6.配置时钟树。
8M输入时,通过PLL得到72M内部时钟。
Step7.配置FreeRTOS。
在Tasks and Queues选项卡,默认配置了一个名为defaultTask的任务,其优先级为普通,任务堆栈大小为128字,任务函数名为StartDefaultTask。
双击蓝色的地方,弹出对话框,将任务名修改为SemGen,将任务函数名修改为SemGenTask。
点击Add按钮,增加一个任务Handle,优先级设置为Normal,函数名为HandleTask。
在Config parameters选项卡,使能计数信号量。
在Timers and Semaphores选项卡,点击Counting Semaphores项右边的“Add”按钮,添加一个信号量,名称改为cSem01,并把最大计数值改为10。
注:其他的都使用默认参数。
Step8.生成代码。
等完成后直接打开工程。
工程基本组织结构如下图,其中Application/User组中的文件是用户可以修改的,而其他组中的文件一般不进行修改。
Step9.分析程序结构。
在进入main函数之前,先定义了几个变量,声明了几个函数。
再看main函数。
将main函数整理,删除很多注释之后,得到下图所示内容。
其中第①部分,是硬件配置;第②部分,创建一个信号量和两个任务;第③部分,启动调度器。
Step10.添加代码。
在main.c文件中,找到前面配置添加的两个任务函数,并在其中分别添加代码。
SemGenTask的功能是,发送1次信号量,间隔一秒后发送2次,再间隔一秒发送3次,然后等待2秒。
HandleTask的功能的,等待信号量,然后控制LED0和LED1闪烁一次。
Step11.编译下载运行。
现象是,LED闪1次,一秒后闪2次,再过一秒闪3次,再等三秒,LED闪1次…如此循环。
程序分析:
在SemGenTask()任务中,连续调用osSemaphoreRelease(cSem01Handle);两次或者三次耗时是很短的,而HandleTask()任务执行一次LED闪烁耗时大约是200毫秒,会造成信号量值的累积。
如果把信号量的定义语句cSem01Handle = osSemaphoreCreate(osSemaphore(cSem01), 10);的最后一个参数改为1,即定义改为cSem01Handle = osSemaphoreCreate(osSemaphore(cSem01), 1);,这样就变成了二值信号量。
运行结果是,LED闪1次,一秒后闪1次,再过一秒闪1次,再等三秒,LED闪1次…如此循环。
由此可知,在连续释放二值信号时,如果处理信号量相关事件的函数来不及处理,就会造成事件的丢失。
S.D.Lu 于深圳
2016年8月
Welcome To Download
欢迎您的下载,资料仅供参考!。