Myth 发表于 2019-10-7 20:22:57

【开坑】【告别】在fx-9860系列上用C语言编程(翻译转载)

本帖最后由 Myth 于 2020-9-1 20:00 编辑

Written by Zezombye@planet-casio.
Original post

#此教程由法语翻译而来,并非本人成果。感谢原作者Zezombye!

好久没上cnCalc了。

遥想刚入坑时,cnCalc一日十几新帖,各种挖黑胶、爆机操作层出不穷,diameter、Mike等大神(大神过多,恕不一一列举)各显神通。再看如今,真是令人唏嘘。

入坑以来,未能给cnCalc做什么贡献,不过是写了几篇9750升级教程而已。今日退坑,决定再翻译一个planet-casio上的9860SDK教程,算是个留念,也算是致敬@diameter当年写的教程。

原教程法语,再加上我个人C语言水平过低,如有错误,还请包涵。

最后,感谢原作者@Zezombye,也感谢这个圈子内的所有人,这个圈子一直以来给我带来的快乐,我不会忘记。

原贴:https://www.planet-casio.com/Fr/forums/lecture_sujet.php?id=14992

fx-9860 SDK及官方文档:https://www.mythologyli.cn/    点击 DOWNLOAD -> 计算器 下载




Myth 发表于 2019-10-7 20:24:37

本帖最后由 Myth 于 2019-10-9 22:48 编辑

Written by Zezombye@planet-casio.
Original post

#此教程由法语翻译而来,并非本人成果。感谢原作者Zezombye!

为了更好地编写游戏,我们可以在fx-9860系列上使用C语言编程。用C语言编写的程序格式为*.g1a(与*.g1m不兼容),被称为Add-in。可以将这些程序传输到fx-9860中运行。

在本教程中,我假设您已经了解C语言,这意味着您熟悉结构、指针、变量等概念。
如果您对C语言没有足够了解,建议您查看Openclassroom教程。

Myth 发表于 2019-10-7 20:25:18

本帖最后由 Myth 于 2020-3-22 11:15 编辑

第一部分:安装SDK

如果您的操作系统是Linux,请查看Gint的有关内容。如果您的操作系统是Windows,您需要安装fx-9860 SDK(提取码:a4px)。如果您的电脑是Mac,请在Windows上使用fx-9860 SDK。

在Windows上安装时,请勿将安装在如Program Files(x86)等带括号的文件夹中!!!

Linux(使用Gint)无此限制。

Myth 发表于 2019-10-7 20:27:10

本帖最后由 Myth 于 2019-10-13 14:25 编辑

第二部分:使用SDK

安装SDK后,将其打开。我们首先来创建一个新的项目。

单击Project<<New,然后依次填写项目路径、文件夹名称、项目名称、版本号。



此后会弹出错误消息显示无项目文件,这是正常的。
您会发现,SDK为您自动预置了代码,您可以先编译一下。



要编译,请单击Project<<Rebuild all





如果您的路径不含括号的话,此时编译应该会顺利完成。若您的编译器报错,请检查路径是否含有括号。



然后单击Run<<Run开始在模拟器中运行程序。稍稍拉大Display窗口,使模拟器屏幕更大。然后在Menu内找到您的Add-in(图标为Debug),点击EXE打开。您会得到以下结果:

Myth 发表于 2019-10-7 20:29:29

本帖最后由 Myth 于 2020-3-22 11:16 编辑

第三部分:关于代码的基本介绍

首先,我们打开项目文件夹,您应该看到以下文件:



MainIcon.bmp是要在Menu中显示的图标(单色位图),更改此文件可更改程序的图标。

使用您喜欢的代码编辑器打开*.c文件(如Vscode)。您可以从SDK中直接编辑代码,但编辑体验极差,没有突出显示和代码缩进功能。

这里,主函数是此函数:

int AddIn_main(int isAppli, unsigned short OptionNum)
{
    unsigned int key;

    Bdisp_AllClr_DDVRAM();

    locate(1,4);
    Print((unsigned char*)"This application is");
    locate(1,5);
    Print((unsigned char*)" sample Add-In.");

    while(1){
      GetKey(&key);
    }

    return 1;
}
程序将从这里的主函数开始。当然,您不用考虑int AddIn_main()中的参数。事实上,Add-in可以在Menu或E-act中被启动,但由于在绝大多数情况下程序是从Menu启动的,您可以忽略这些参数。

首先要注意的是,尽管fx9860 SDK有C标准库,但它却不支持printf()函数和scanf()函数。事实上,计算器没有PC那样输入流和输出流的概念。像在CASIO BASIC中一样,有必要在输出时进行定位。例如:

locate(int x, int y); //将光标放在x,y处
Print(char* str); //显示字符串
没有scanf()函数令人恼火,但其实您不太需要它。毕竟大多数人想要制作游戏,而大多数游戏不要求输入文本。

如果确实有输入文本的需要,请自己编写函数或使用EasyInput库。

如果要在屏幕上输出数字,则有两种选择:

要么使用sprintf()函数,例如:
int a = 30, u = 40;
char* str = malloc(u);
sprintf(str, " %d", a);
locate(1,1);
Print(str);
您也可以使用不在C标准库中的itoa函数:

void itoa(int n, char s[])
{
   int i, j, sign;
   char c;

   if ((sign = n) < 0)
         n = -n;
   i = 0;
   do {
         s = n % 10 + '0';
   } while ((n /= 10) > 0);
   if (sign < 0)
         s = '-';
   s = '\0';
   for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s;
         s = s;
         s = c;
   }
}
考虑到使用sprintf()会使加载项增加30 KB,建议使用第二种方式。若要使用sprintf(),请务必记得#include<stdio.h>。

另外,请注意该编译器不支持C99标准,因此,请注意变量声明的位置与for循环的使用。



[*]函数Bdisp_AllClr_DDVRAM()用于清空DD和VRAM。

要了解DD与VRAM的区别,请设想现在要绘制一个图案。首先,图案在VRAM上绘制,然后发送给DD,后者将其显示出来。

由VRAM向DD的发送并不是自动的,需要通过Bdisp_PutDisp_DD()函数来实现。需要注意的是,某些函数会自动进行此操作,例如GetKey()函数。



[*]函数GetKey(int *key)用于按键检测。

请注意,若没有按下任何键,该函数将暂停程序的执行,直到一个键按下为止。我们稍后将介绍一些不会使程序暂停的函数。要特别注意的是,GetKey()将刷新DD。

Myth 发表于 2019-10-7 20:30:09

(未完待续)

etkane 发表于 2019-10-9 22:31:15

支持你,感谢分享和翻译

Myth 发表于 2019-10-11 08:34:05

本帖最后由 Myth 于 2019-10-11 08:39 编辑

第四部分:使用MonochromeLib

MonochromeLib是使用fx-9860 SDK时必不可少的库:它极大地提高了绘图速度(帧率)。

您可以从这里下载.

您将得到MonochromeLib.c和MonochromeLib.h两个文件,请将它们移动到您的项目文件夹中,并添加到您的项目中。

在SDK的左侧,右键单击Source Files,然后点击Add,把您项目文件夹中的MonochromeLib.c文件选中;同样地,右键单击Header Files,然后点击Add,把您项目文件夹中的MonochromeLib.h文件选中。





注意:打开MonochromeLib.h文件,您会注意到一些#define被注释掉了,这是为了避免占用太多空间。您可以根据需要进行更改。




最后,在原先创建的*.c文件中,添加#include “MonochromeLib.h”,最后用ML_clear_vram()函数代替Bdisp_AllClr_DDVRAM()函数。

在SDK中,单击Project<<Rebuild all(如为灰色,先单击Run<<Stop)。程序应该可以正常编译,并且运行结果与之前相同——但要快一点。

在以后的编程中,尽可能使用MonochromeLib中的绘图功能,而非fxlib中的函数。

zyf722 发表于 2019-10-12 19:12:30

感谢!

cctvgm 发表于 2019-10-13 16:41:53

希望继续更新!

Myth 发表于 2019-10-13 16:56:49

cctvgm 发表于 2019-10-13 16:41
希望继续更新!

这个教程很短的,剩的也不多了
其实真说要编程的话,看到这儿再结合diameter的帖子,我觉得已经够了
这两天比较忙,不过以后应该会更完的

Myth 发表于 2019-12-28 16:22:50

竟然咕到了现在。。。考试周结束再说吧

1282708293 发表于 2020-1-5 19:35:01

十分感谢楼主的入门帖子,11月份的时候参加了学校组织的一个小型的设计比赛,脑洞大开想在casio上写个小游戏(2048小游戏),然而网上相关资料特别少,还好看到了楼主的入门帖,结合着diameter的教程,总算是成功了,十分感谢!!!
现在又把当时做的小游戏想传到真正的计算器上,不太知道咋搞

Myth 发表于 2020-1-8 22:46:59

1282708293 发表于 2020-1-5 19:35
十分感谢楼主的入门帖子,11月份的时候参加了学校组织的一个小型的设计比赛,脑洞大开想在casio上写个小游 ...

很高兴能帮助到你!
编译生成的*.g1a文件,需要通过FA-124软件传入fx9860运行。如果是fx9750的话,需要先刷机刷成9860的系统。


https://www.cncalc.org/data/attachment/forum/201912/27/192901e11i4a1jkaejaiir.jpg


如图,当计算器连上电脑后,计算器调至连接模式,在FA-124左边点击connect连接计算器。点击圈出的部分,这时候就可以传g1a了。(右边copy,左边paste)


Myth 发表于 2020-4-29 12:18:58

本帖最后由 Myth 于 2020-4-29 15:57 编辑

# 感谢 @wan帮忙翻译了以下所有内容

第五部分:按键和显示管理
有2个功能用来管理按键。
- GetKey()会暂停程序,并自动在屏幕上显示VRAM。- IsKeyDown()不暂停程序,不在屏幕上显示VRAM。
用哪一种?这一切都取决于你的游戏是否是实时的。如果不是实时的(如选择菜单),使用GetKey()。如果是实时的,使用IsKeyDown()。
按键值可以在SDK安装文件夹中的PDF文件中找到("KeyCode List.pdf "文件)。
注意上档键(shift和alpha)可能会返回不同的值(所以如果用户按shift+down,会返回KEY_CTRL_PAGEDOWN而不是KEY_CTRL_DOWN)。
例如,这里是一个游戏中的循环,可以用来移动一个方块(伪代码)。
while (1)
{
      ML_clear_vram();
      ML_pixel(x, y);
      ML_display_vram();
   
      if (IsKeyDown(KEY_CTRL_UP))
      {
                y--;
      }
      else if (isKeyDown(KEY_CTRL_DOWN))
      {
                y++;
      } ...
}
至于显示功能方面,有以下语句:
- ML_pixel() 显示一个像素点- ML_line() 显示一行- ML_rectangle()来显示一个矩形等。
所有的函数参见MonochromeLib.h,名字很明确。
要显示文字,有以下语句:
- Print(char *str),在Locate(intx, int y)函数之后使用,以类似于basic中的Locate函数的方式显示。- PrintRev,其工作原理与Print类似,但颜色反转(黑底白字)。- PrintXY(int x, int y, char* str, int type),在坐标x, y处显示str,如果type = 0,则以黑色显示,如果type = 1,则以白色显示- PrintMini,其工作原理与PrintXY类似,但使用小字体显示(类似basic中的Text功能)。- BetterFont,一个可以显示带有自定义字符的字体库
请注意,这些功能使用卡西欧编码,部分兼容ASCII编码。
例如,我们要显示"agréable "。如果你使用Print("agréable"),你会注意到它显示的是这个:


如果你将文件保存为ANSI而不是UTF-8,则 "agr able"。

所以必须要符合卡西欧的编码。要知道怎么做,请到SDK安装文件夹里去看,里面有5个pdf文件。我们感兴趣的是 "字符集"。

在PDF的第6页,我们看到"é"的编码是0xE60A。

要在字符串中插入这些字节,不需要使用十六进制编辑器来修改.c文件(可能会导致编译错误):你必须使用十六进制转义符\x,通常只需要2位数作为参数。因此我们的代码行将是Print("agr\xE6\x0Aable")。如果我们执行它,它是这样显示的:



问题出在哪里?显然,编译器考虑到\x最多需要3位数,因此翻译成0xE6和0x0Aa→0xAA,而0xE6AA在卡西欧编码中就是中间那个点。并排的字符串是自动关联的。为了避免这种情况,加2个引号就足以让编译器知道应该停止在0A处:

Print("agr\xE6\x0A""able")

Myth 发表于 2020-4-29 12:56:19

本帖最后由 Myth 于 2020-4-29 15:58 编辑

第六部分:Syscalls
Syscalls(系统调用)是操作系统固有的功能。卡西欧没有做任何关于这个问题的文档,但由于Simon Lothar的工作,大多数系统调用都是已知的:https://bible.planet-casio.com/simlo/chm/v20/
这些系统调用可能不会有什么用处,但它们允许你在主/副存储器中创建一个自定义文件夹,改变对比度等。
要使用syscall,有不同的方法。这里是其中之一。
创建一个syscalls.src文件,将把它添加到项目中(与添加MonochromeLib的方法相同)。
把下面的代码放在里面。syscall_table:
      .data.l    H'80010070

      .end
然后,当你想添加你要调用mySyscall的syscall 0x123时,添加下面的代码(在代码的顶部):
    .export _monSyscall

_monSyscall:
      mov.l    syscall_table, r2
      mov.l    monSyscall_code, r0
      jmp    @r2
      nop
monSyscall_code:
      .data.l    H'123
在你的.c文件中,你只需要执行mySyscall()就可以了(当然要有必要的参数)。

Myth 发表于 2020-4-29 12:58:59

本帖最后由 Myth 于 2020-4-29 15:59 编辑

第七部分:SDK 的其它功能
我从来没有用过这些功能(其实,在casio上编程的时候,这些功能会很好用),但它们可能对你有用。
首先,SDK有断点,用来停止程序的执行,以便更好地调试程序。也可以在 "globalvariables "和"localvariables"窗口中查看变量的值。
当错误发生时,有一个"trace "功能,它将指向导致错误的代码行。
也可以执行"Run"→" Trace Into",这样就可以得到:


因为不能使用printf,这个功能非常便于调试。

在 " View"选项卡中可以访问一个反汇编器,但由于不了解SH3汇编器,我不能说什么(这只是个入门教程)。
它还允许:
- 查看闪存(如果你想用syscalls来接触系统的话,非常有用)。- 获得堆区、栈区和调用堆栈的视图。- 查看寄存器。

注意,你有8kb的静态RAM(全局变量存储在这里),32 kb的栈区(静态RAM占用了这32kb),64 kb的堆区(SH4上还有额外的256kb,但要通过显式指针访问)。

重要:SDK默认会生成SH3插件,对于新的计算器(>2012年),必须将其转换为SH4。可以使用此网页进行转换:https://tools.planet-casio.com/SH4compatibility/

Myth 发表于 2020-4-29 13:04:27

本帖最后由 Myth 于 2020-4-29 13:05 编辑

教程翻译结束,感谢原作者@Zezombye,也感谢帮忙翻译最后三部分的@wan!

页: [1]
查看完整版本: 【开坑】【告别】在fx-9860系列上用C语言编程(翻译转载)