构建一个轻量级的嵌入式虚拟平台,开发工程用板stm32 picoc解释器,大量自定义函数,sarm拓

2019-07-13 02:41发布



让嵌入式想java一样一处编写到处运行

第一次写博客,其实接触嵌入式已经快两年了,从开始学51单片机的时候,怀着满腔的热情。写出了点亮第一个流水灯代码的时候那个无比的激动,到后面自己做许多有趣的东西(比如光立方,电子时钟,无线通讯等等),刚开始连单片机知识一点也不了解,c语言写的很烂的时候,到后面开始慢慢的学着别人写代码,经过了两年的时光,,, 现在我觉得我应该证明我自己。于是我决定写一篇做了快一个月的东西,分享给大家,同时大家相互的学习,互相的进步。 在学习stm32的时候,当时是犹如大海找针一样的学习,完全不知道重哪儿开始,后面找到了刘凯的视频,发现视频讲的很全面,于是就花了15天的时间,专心的学习,晚上专研到2,3点,当时很穷,买的开发板也是淘宝上最便宜的那种,所以资料少的可怜。自己在写程序的时候也总是想自己把所有的代码全部都写出来,这期间走了不少的弯路,造了不少的轮子,这里就不细说了,后面在谈,下面我来介绍一下这个平台把:
起初想到这个想法的时候,完全是起源与mtk手机上的一个冒泡开发实验系统,在这套系统上移植一个一个picoc的嵌入式c语言解释器,我就在想能不能在嵌入式上也跑上这个解释器,在嵌入式上运行许多的应用程序,其他的嵌入式芯片只需要移植我这个平台就可以了,到目前为止,项目的函数的构建已经完成了一大半,只有网络与对话框等没有完成,还存在一定的bug 这个轻量级的嵌入式虚拟平台,开发工程用板stm32 picoc解释器,大量自定义函数,sarm拓展,lwip移植,nes模拟器移植,系统优化,等等技术的融合 在这个虚拟平台上,不仅完成了按键事件的结构,还支持触屏接口,支持page页面,button的创建等等
下面列出完成的功能: 完成了字库的驱动,可以加载任意的字库,一个字库的简单管理。、 完成了字库读取优化,字库第一次从sd卡读取到ram时会保存,第二次就会自动的去ram读取,不会在读写sd卡了 完成了unciode 码到gb2312码的转换,能够在内部自动的转换 完成了菜单的创建,菜单的创建采用链表管理,不受长度的限制, 完成了button的创建,button做的比较简单,能狗进行事件的回调(回调函数),颜 {MOD}设置,内容设置等(只支持触屏) 完成了page页面的管理,能够创建任意多的页面,可以将button等加入到页面中,button就收到了page的管理,page的释放,将释放掉button 完成了软定时器,用户可以创建任意多个软定时器,定时器由回调函数返回结果。、 完成了sram的拓展,实现动态内存的管理 完成了lwip的移植,运行链接网络,测试服务器成功(socket为实现) 完成了file文件的扫描,能够直接运行应用程序。 完成了bmp图片解码,自己花了几天时间写的bmp图片解码,支持8bit 16bit 24bit图片解码(1,2,4,想做的还没来的急) 完成了bmp565纯数据格式的显示(速度很快),做界面最爱 完成了txt文字的显示,可以字节写一个小说阅读器啥的。 完成了nes模拟器的移植,能够运行40kb一下的游戏(本来想移植一个支持全部游戏的,觉得麻烦) 完成了屏幕缓冲区的设置,能够通过宏开关打开或关闭屏幕缓存(这个玩意可是暂用150kb的ram) 完成了gpio口到picoc的添加,能够在应用程序中直接控制gpio

今天就将这么多了,都说没图没真相,今天太晚了,明天上图。


下面我一一的讲解:、 picoc解释器: Picoc C语言解释器的STM32平台移植
Picoc是google开源代码项目中看到的一个项目,其初衷貌似是要做一个在小的嵌入设备上的C解释器。它的核心代码只有3500行左右,可读性不错,虽然没有实现完整的ISO C标准,基本的C运行库还是具备了。
picoc代码上看,基本有如下几块:lex词法解析,table一个基本数据结构(用于存放变量),是个字符串hash表,heap管理内存分配(包括了stack frame的实现), type做类型管理(基本型别和程序自定义的struct,typedef等),expression做表达式解析,variable变量管理分配释放栈帧。
picoc的定位是一个解释器,它的解析和代码运行是在同一块代码块里做

  • PicoC是一个非常小的C解释器的脚本。它最初是作为一个无人机的飞行系统板上的脚本语言。它也非常适合于其他机器人,嵌入式和非嵌入式应用。
  • 核心的C源代码是大约4500行代码。它并不打算成为一个完整的ISO C实现的,但它拥有所有的必需品。在编译时,只需要几K的代码空间也很不遗余力的数据空间。这意味着,在小型嵌入式设备,它可以很好地工作。这也是一个有趣的例子,如何创建一个非常小的语言实现,同时仍保持代码的可读性。
  • picoc已经过测试的x86-32,x86-64的的PowerPC,ARM,以UltraSPARC,HP-PA和Blackfin处理器上,并很容易地移植到新的目标。


项目地址,有文档和源码:
GOOGLE https://code.google.com/p/picoc/
GitHub  https://github.com/larryhe/tiny-c-interpreter
SVN 地址,貌似还有人在开发当中,但是只有 win32版本可以编译过去,变化比较大...
# Non-members may check out a read-only working copy anonymously over HTTP.
svn checkout http://picoc.googlecode.com/svn/trunk/ picoc-read-only
以及我已经完成的函数列表: #ifndef MRC_BASE_H
#define MRC_BASE_H


/*
本文件只相当于帮助文件,没有任何实际意义,也就是说在这里增加或修改定义不会有任何效果
如果你需要增加定义,请定义在其他文件中,要使用以下所有接口请在你的代码中增加“#include "base.h"”


请不要将此文件改名为其他文件名后包含在你的代码中!否则可能会导致系统异常!!!
*/






//系统版本,由于软件的更新,可能会造成有些函数、宏、类型等不一致而导致运行出错
//建议在源码中判断系统版本是否相同
#define _VERSION 1001


/*
此文件为系统内部简单封装的MRP函数实现了MRPAPI库的部分功能
*/
typedef  unsigned short     uint16;      //有符号16bit整型
typedef  unsigned long int  uint32;      //无符号32bit整型
typedef  long int           int32;       //有符号32bit整型
typedef  unsigned char      uint8;       //无符号8bit整型
typedef  signed char        int8;        //有符号8bit整型
typedef  signed short       int16;       //有符号16bit整型


//下面四项为大部分系统函数的返回值,没有在系统内定义,如果需要这些宏定义请在其他头文件中定义
#define MR_SUCCESS  0    //成功
#define MR_FAILED   -1    //失败
#define MR_IGNORE   1     //不关心
#define MR_WAITING  2     //异步(非阻塞)模式


#define NULL (void*)0
#define TRUE 1
#define FALSE 0
#define SCRW  //系统内部宏,值为屏幕宽
#define SCRH  //系统内部宏,值为屏幕高




//基本按键值(未定义的其他按键也可以使用,但需知道其键值)
enum {  
   _0,           //按键 0
   _1,           //按键 1
   _2,           //按键 2
   _3,           //按键 3
   _4,           //按键 4
   _5,           //按键 5
   _6,           //按键 6
   _7,           //按键 7
   _8,           //按键 8
   _9,           //按键 9
   _STAR,        //按键 * 10
   _POUND,       //按键 # 11
   _UP,          //按键 上 12
   _DOWN,        //按键 下  13
   _LEFT,        //按键 左 14
   _RIGHT,       //按键 右  15
   _SLEFT=17,    //按键 左软键
   _SRIGHT,      //按键 右软键
   _SEND,        //按键 接听键
   _SELECT       //按键 确认/选择(若方向键中间有确认键,建议设为该键)
};


//基本事件(其他事件需自己定义)
enum {
    KY_DOWN, //按键按下
    KY_UP,       //按键释放
    MS_DOWN, //鼠标按下
    MS_UP,     //鼠标释放
    MN_SLT, //菜单选择
    MN_RET, //菜单返回
    MR_DIALOG, //对话框
    MS_MOVE=12   //鼠标移动
};


enum {
    DLG_OK,         //对话框/文本框等的"确定"键被点击(选择)
    DLG_CANCEL  //对话框/文本框等的"取消"("返回")键被点击(选择)
};


enum
{
    SEEK_SET,             //从文件起始开始
    SEEK_CUR,             //从当前位置开始
    SEEK_END             //从文件末尾开始
};
enum
{
    IS_FILE=1,      //文件
    IS_DIR=2,      //目录
    IS_INVALID=8,  //无效(非文件、非目录)
};


typedef struct {
    uint16            x;
    uint16            y;
    uint16            w;
    uint16            h;
}rectst;


typedef struct {
    uint8            r;
    uint8            g;
    uint8            b;
}colorst;




/********************************C库函数********************************/


/*该函数功能与printf函数相似,区别是本函数的输出
信息将打印在print.txt文件中(与mrpapi有点区别)*/
void printf(const char *format,...);


//申请内存接口,注意!必须严格管理申请的内存,以防内存泄漏!系统不会为你检查申请的内存的使用情况
void* malloc(int size);


//释放由malloc申请的内存
void free(void *address);


//由src所指内存区域复制count个字节到dest所指内存区域。src和dest所指内存区域不能重叠,函数返回指向dest的指针。
void *memcpy(void *dest, void *src, unsigned int count)


//由src所指内存区域复制count个字节到dest所指内存区域。src和dest所指内存区域可以重叠,但复制后dest内容会被更改。
void *memmove(void *dest, const void *src, unsigned int count);


//把src所指由NULL结束的字符串复制到dest所指的数组中。src和dest所指内存区域不可以重叠,且dest必须有足够的空间来容纳src的字符串。
char *strcpy(char *dest,char *src);


//将字符串src中最多n个字符复制到字符数组dest中,它并不像strcpy一样遇到NULL就开始复制,而是等凑够n个字符才开始复制。
char *strncpy(char *dest, char *src, int32 n);


//把src所指字符串添加到dest结尾处(覆盖dest结尾处的'