本帖最后由 妖猊 于 2023-9-5 09:45 编辑
第十篇 正文:
接着一篇,
5、添加源码链接把pikascript的源码添加到可编译路径,因为单纯的添加源码到工程目录下,但是编译的时候不一定会参与编译 打开之前说的CMakeLists.txt文件,并添加如下内容
- # 递归搜索C源文件,将源添加到target
- file(GLOB_RECURSE sources "${CMAKE_CURRENT_SOURCE_DIR}/pikapython/*.c")
- file(GLOB_RECURSE sources_user "${CMAKE_CURRENT_SOURCE_DIR}/*user.c")
- target_sources(app PRIVATE ${sources} ${sources_user})
- # 添加头文件路径
- sdk_add_include_directories(.)
- sdk_add_include_directories(pikapython/pikascript-core)
- sdk_add_include_directories(pikapython/pikascript-api)
- # 添加宏定义
- sdk_add_compile_definitions(
- PIKA_CONFIG_ENABLE=1
- # LWIP_DNS=1
- LV_LVGL_H_INCLUDE_SIMPLE=1
- PIKASCRIPT=1,
- )
复制代码 宏定义是起到一些配置的使能,详细可以搜索看下是使能哪些配置的,这里我不注释了
添加在sdk_set_main_file之前
除此之外,因为pikascript还依赖了一些组件,我们得在proj.conf文件里配置些依赖组件,那些组件基本都在sdk里有。配置如下 - set(CONFIG_FREERTOS 1)
- set(CONFIG_CHERRYUSB 1)
- set(CONFIG_CHERRYUSB_DEVICE 1)
- set(CONFIG_CHERRYUSB_DEVICE_CDC 1)
- set(CONFIG_CHERRYUSB_DEVICE_HID 1)
- set(CONFIG_CHERRYUSB_DEVICE_MSC 1)
- set(CONFIG_CHERRYUSB_DEVICE_AUDIO 1)
- set(CONFIG_CHERRYUSB_DEVICE_VIDEO 1)
- set(CONFIG_LVGL 1)
- set(CONFIG_BSP_LCD 1)
- set(CONFIG_BSP_TOUCH 1)
复制代码分别是FREERTOS和usb 设备及lvgl和LCD、触摸的 主要是FREERTOS和usb 设备,lvgl和LCD、触摸的是因为我添加相应的python模块所以需要添加 6、调整堆栈
pikascript建议分配 4K 的栈空间和 16K 的堆空间,最少也需要分配 1K 的栈空间和 4K 的堆空间 4K 栈空间对应 0x1000, 16K 堆空间对应 0x4000
至于堆栈的是什么,一会讲 7、启动 PikaPython 在 main.c 的初始化代码中添加 PikaPython 的启动代码。 添加头文件 在头文件中加入 初始化 pikaScript 并得到 pikapython 主对象的指针 pikaMain 在 main 函数中加入一句启动代码 - PikaObj* pikaMain = pikaScriptInit();
复制代码结束了?对,结束了,就这么简单,是不是很神奇。 这是因为预编译器在背后做了很多辅助工作,包括自动生成 pikaScriptInit() 函数。 8、编译 然后bat文件了在添加 - cd pikapython && rust-msc-latest-win10.exe && cd ..
复制代码然后直接双击bat编译即可,一般来说是可以直接通过的。 补充知识点:堆栈,(C语言简单数据结构) 首先:我们程序都是运行在内存里的,一个由C/C++ 编译的程序占用的内存分为以下几个部分:栈区(stack)、堆区(heap)、全局区(静态区)(static)、文字常量区、程序代码区 栈区(stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式类似于链表。 全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。 文字常量区:常量字符串就是放在这里的,程序结束后由系统释放。 程序代码区:存放函数体的二进制代码。
1、什么是堆栈?在嵌入式的世界里,堆栈通常指的是栈,严格来说,堆栈分为堆(Heap)和栈(Stack)。 - 栈(Stack): 一种顺序数据结构,满足后进先出(Last-In / First-Out)的原则,由编译器自动分配和释放。使用一级缓存,调用完立即释放。
- 堆(Heap):类似于链表结构,可对任意位置进行操作,通常由程序员手动分配,使用完需及时释放(free),不然容易造成内存泄漏。使用二级缓存
2、堆栈的作用
- 函数调用时,如果函数参数和局部变量很多,寄存器放不下,需要开辟栈空间存储。
- 中断发生时,栈空间用于存放当前执行程序的现场数据(下一条指令地址、各种缓存数据),以便中断结束后恢复现场。
3、经典例子程序
- int a = 0; //全局初始化区
- char *p1; //全局未初始化区
- main()
- {
- int b; //栈
- char s[] = "abc"; //栈
- char *p2; //栈
- char *p3 = "123456"; //123456\0在常量区,p3在栈上。
- static int c =0;//全局(静态)初始化区
- p1 = (char *)malloc(10);
- p2 = (char *)malloc(20); //分配得来得10和20字节的区域就在堆区。
- strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
- }
复制代码 从上面的描述可以看得出来,在代码中是如何占用堆和栈的。
4、栈(Stack)
- 先进后出
- 编译器自动分配和释放的,主要存储的是函数的参数值,局部变量等值。相对较高的地址,地址值从高往低分配 例如:声明 int test 变量就是自动分配的空间
- 由于是自动分配,速度比堆快
- 次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址
函数体内局部变量:
- void Fun(void)
- {
- char i;
- int Tmp[256];
- //...
- }
复制代码局部变量总共占用了256*4 + 1字节的栈空间。 所以,在函数内有较多局部变量时,就需要注意是否超过我们配置的堆栈大小。 函数参数: - void bflb_gpio_init(struct bflb_device_s *dev, uint8_t pin, uint32_t cfgset);
复制代码这里要强调一点:传递指针只占4字节,如果传递的是结构体,就会占用结构大小空间。 提示:在函数嵌套,递归时,系统仍会占用栈空间。 5、堆(Heap)- 顺序随意
- 由程序员编写代码去控制分配和释放,一般放的是指针。从低往高分配。 例如:test = (int*)malloc(1),要记得free,不然容易内存泄漏
- 速度比较慢,而且容易产生内存碎片
- 堆得具体行为,整个生命周期由程序员控制释放free
我们大部分人应该很少使用malloc来分配堆空间。 虽然堆上的数据只要程序员不释放空间就可以一直访问,但是,如果忘记了释放堆内存,那么将会造成内存泄漏,甚至致命的潜在错误。
关于堆栈知识就这样简单复习一下
|