写在前面
树莓派pico,又称为RP2,其开发方式多种多样,有C语言和micropython语言,工具有cmake,vscode,arduino,thonny等,本版主要使用的工具链是VsCode结合cmake、官方提供的SDK——pico-sdk和移植的FreeRTOS。环境搭建见这四章:交叉编译踩坑指北
现在默认你已经完成了环境的搭建,让我们来概括性的认识一下我们所搭建的工具链。
1、PICO-SDK
首先是树莓派pico官方提供的pico-sdk。参考资料为github pico-example和pico-sdk的C开发手册。pico-sdk是树莓派官方给RP2提供的一个API,主要包含了GPIO,ADC,TIMER,INTERRUPT等函数封装,并且提供了丰富的例子,甚至包含了诸如DHT11,7段数码管的简单驱动。

1.1 PICO-SDK的CMake组织方式

如pico-sdk文档中的话所示, 其官方文件夹是用Cmake组织链接起来的。那么,pico-sdk是如何被使用的呢?我们可以在CMakeLists中一窥究竟。

在最外层的CMake文件中,我们可以看到它使用include指令,将pico_sdk_import.cmake文件加入进来(该文件是pico-sdk官方提供的)。这是cmake链接的一种方式,接下来就可以具体看到它是如何把我们的项目工程和pico-sdk链接起来的。

可以看到,在这里有一个变量PICO_SDK_PATH,指定的就是你存放官方提供的pico-sdk的位置。你在编译时指定或者在CMakeLists中指定该变量的值就可以了。这样就可以让CMake在顶层的CMakeLists的指引下找到pico-sdk这个文件夹。

而这个文件夹也是官方直接提供的,可以看到这个文件夹也有其顶层的CMakeLists,CMakeLists就像一个指引器,指引CMake进入到各种子文件夹中,而子文件夹中也有其各自的CMakeLists,向一棵树一样发散开去。但是因为这个pico-sdk文件夹是官方提供的,这个文件夹内部是怎么编写和放置CMakeLists来指引CMake的我们不关心,已经被官方的人做好了。我们要做的就是把我们工程的CMake指向这个文件夹就好了,之后的工作已经被封装好了。
1.2 PICO-SDK的使用方式
那么在代码中我们该如何调用pico-sdk呢?首先我们需要知道pico-sdk提供了许多库。包括了高层的库和底层的库,这些都在pico-sdk官方文档中说的很详细。当你需要使用哪个库时,只需要查询官方文档,将其名字以库的形式添加在指导main.c文件编译的CMakeLists中即可。具体而言如下所示,比方说要使用adc功能,在官方文档中查找到库名字的声明,这是第四节,在hardware分类下。

所以我们在直接编译main.c文件的CMakeLists中找到链接库的语句,加入hardware_adc即可

在main.c等文件中应用时,遵循其分类,因为再硬件库分类下,使用hardware/adc.h来表示,这一块可以参考文档中给出的示例就可以,如下所示。

因为pico-sdk提供的库已经内部链接了头文件,因此我们无需在CMake中声明include路径,直接在main.c文件里使用就行了。(下一节FreeRTOS编译的过程中将会看到这种为库内部链接头文件是怎么用CMake实现的)。
此外还有一个常用的主库pico/stdlib,这个库包含了许多常用子库如时间库,gpio库等等。

1.3 PICO-SDK常见函数的简单介绍
因为文档比较长,秉承着用到哪学哪的理念,我使用较多的为gpio、time还有adc功能。
| 函数 | 功能 |
|---|---|
| gpio_init(PIN) | 初始化管脚 |
| gpio_set_dir(PIN,GPIO_OUT/GPIO_IN) | 设置gpio方向 |
| gpio_put(PIN,1/0) | 输出高/低电平 |
| x=gpio_get(PIN) | 获取引脚电平 |
| adc_init() | 初始化ADC |
| adc_set_temp_sensor_enabled(true) | 开启内置温度计 |
| adc_select_input(channel) | 选择ADC通道,4通道是温度计 |
| gpio_set_mask(mask) | gpio数据掩码赋值 |
| gpio_clr_mask(mask) | gpio清除掩码 |
2、 FreeRTOS
前面介绍了Pico-SDK,实际上它就相当于一个库的集合,一个包,被链接到我们的工程文件中来。这里的FreeRTOS其实也是一样的,也是通过CMake链接进来。只不过我们下载的是FreeRTOS的源代码,需要先用CMake把它转换成库,然后链接进来。
2.1 FreeRTOS的CMake组织方式
如前所述,既然pico-sdk已经是CMake所组织连接的,因此我们在已知FreeRTOS时也要使用CMake。
首先去FreeRTOS官网下载V9.0.0版本,虽然不是up-to-dated,但是是比较主流的。我们主要用到的文件在FreeRTOSv9.0.0\FreeRTOS\Source文件夹下,当然,官方也给出了很多移植的demo,在FreeRTOSv9.0.0\FreeRTOS\Demo下有许多芯片型号的移植实例。
我们先新建一个文件夹freertos,其中包括了FreeRTOSKernel,CMakeLists和FreeRTOSConfig.h这几个文件,如下图所示。

其中,FreeRTOS-Kernel文件夹中主要存放的是之前所说的FreeRTOS Source文件夹提供的源文件。

我们可以在此基础上对不需要的功能进行剪裁,或者可以在FreeRTOS Plus文件中加入额外的功能比如UDP通讯等等。总之就是根据需要对源代码进行相应的取舍。但是在这里不删减也没关系,因为后面讲到的配置文件会利用条件编译的方法来决定是否加入某种功能。
CMakeLists的内容如下,

#提取文件夹中的源文件生成静态库freertos.a在build/freertos下
#将头文件添加到目标头文件路径中,可能是为了辅助生成freertos库
set(PICO_SDK_FREERTOS_SOURCE FreeRTOS-Kernel)#添加文件夹位置变量
add_library(freertos#生成库
${
PICO_SDK_FREERTOS_SOURCE}/event_groups.c#事件功能
${
PICO_SDK_FREERTOS_SOURCE}/list.c
${
PICO_SDK_FREERTOS_SOURCE}/queue.c#队列功能(队列消息,信号量,互斥量)
${
PICO_SDK_FREERTOS_SOURCE}/stream_buffer.c
${
PICO_SDK_FREERTOS_SOURCE}/tasks.c#任务功能
${
PICO_SDK_FREERTOS_SOURCE}/timers.c#定时器功能
${
PICO_SDK_FREERTOS_SOURCE}/portable/MemMang/heap_3.c#内存管理模块
${
PICO_SDK_FREERTOS_SOURCE}/portable/GCC/ARM_CM0/port.c
)
target_include_directories(freertos PUBLIC#为库连接头文件
.
${
PICO_SDK_FREERTOS_SOURCE}/include
${
PICO_SDK_FREERTOS_SOURCE}/portable/GCC/ARM_CM0
)
add_library()是CMake中生成库的指令.默认是静态库(.a),生成库 add_library(libname [SHARED| STATIC] source1 …sourceN) 指令用于将一系列源文件指定身成为静态库或者动态库。例如本例中为静态库,就会在指定的libname前面添加lib作为生成库文件的名字,后缀为.a

将头文件位置加入了freertos的include搜索路径,使用指令**target_include_directories**,cmake引入头文件有2条指令分别是 include_directories() 和 target_include_directories() 区别是,前者是当前CMakeLists.txt中所有目标的搜索路径及其之后子目录目标的搜索路径后者是指定目标所包含的头文件路径(一般是先生成文件,才能指定,因此是出现在后面的)后者的好处是,具体化,对于不同文件夹下相同名称的文件也具有区分性
target_include_directories( [SYSTEM] [AFTER|BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1…])
其中指定的参数代表含义如下
INTERFACE:target对应的对头文件使用
PRIVATE:target对应的源文件使用
PUBLIC:target对应的头文件/源文件都可以用
以源文件构建库文件之一的源文件list.c为例,其中就有include

因此使用target_include_directories可以为库中的每个文件引入头文件的路径进行具体化,使其可以找到特定的头文件而不会出错。
FreeRTOSConig.h头文件在FreeRTOS.h中被引用,如下图所示

当我们在主程序中调用FreeRTOS核心库FreeRTOS.h时,会自动调用配置文件FreeRTOSConfig.h文件。下面简单讲一下该文件中的一些常用功能与配置。

其实在这本书中除了对FreeRTOS有详细讲解外,也穿插着对其配置文件有阐述。
例如

#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
/* Use Pico SDK ISR handlers */
#define vPortSVCHandler isr_svcall
#define xPortPendSVHandler isr_pendsv
#define xPortSysTickHandler isr_systick
#define configUSE_PREEMPTION 1
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 0//使能它时任务优先级可以支持32级
#define configUSE_TICKLESS_IDLE 0//低功耗使能,置0系统节拍中断一直运行
#define configCPU_CLOCK_HZ 133000000//设置CPU频率133M,用于在port.c文件中进行时钟配置
#define configTICK_RATE_HZ 1000//设置FREERTOS系统时钟节拍频率HZ,系统滴答定时器的中断频率,设为1000则系统时钟节拍周期1ms,软件定时器的值必须是该周期的整数倍;pdMS_TO_TICKS()可以将毫秒转换为tick,前提是该宏小于1000
#define configMAX_PRIORITIES 5//设置任务优先级数量从0-该数-1,就绪列表数组大小,最大支持255,数值越大优先级越高
#define configMINIMAL_STACK_SIZE 128//设置空闲任务的最小任务堆栈大小(字)
#define configMAX_TASK_NAME_LEN 16//设置任务名最大长度
#define configUSE_16_BIT_TICKS 0//1:8位存储事件组 0:24位存储事件组,*推荐:0
#define configIDLE_SHOULD_YIELD 1//空闲任务与处于同等优先级的其他用户任务的行为.为1时空闲任务会为同等优先级的用户任务让出cpu使用权
#define configUSE_TASK_NOTIFICATIONS 1
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 3
#define configUSE_MUTEXES 1//使用互斥量
#define configUSE_RECURSIVE_MUTEXES 1//使用递归互斥量
#define configUSE_COUNTING_SEMAPHORES 1//使用计数信号量
#define configQUEUE_REGISTRY_SIZE 10//设置可以注册的信号量和消息队列个数
#define configUSE_QUEUE_SETS 0//启用队列集
#define configUSE_TIME_SLICING 1//使能时,处于就绪态的多个相同优先级任务会以时间分片方式共享CPU
#define configUSE_NEWLIB_REENTRANT 0
#define configENABLE_BACKWARD_COMPATIBILITY 0//支持RTOS8.0之前的数据类型
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS 5
#define configSTACK_DEPTH_TYPE uint16_t
#define configMESSAGE_BUFFER_LENGTH_TYPE size_t
/* Memory allocation related definitions. */
#define configSUPPORT_STATIC_ALLOCATION 0//SRAM静态分配任务栈和任务控制块的内存,需要用户自定义两个函数设定空任务和定时器任务的堆栈大小,建议使用动态
#define configSUPPORT_DYNAMIC_ALLOCATION 1//SRAM动态分配任务栈和任务控制块的内存,分配到堆。堆在heap_x.c文件中定义.支持动态分配任务、队列、信号等
#define configAPPLICATION_ALLOCATED_HEAP 1

】CC++&FreeRTOS版&spm=1001.2101.3001.5002&articleId=127708853&d=1&t=3&u=b37b30dd6518412e9838d442634542f8)
2573

被折叠的 条评论
为什么被折叠?



