cnCalc计算器论坛

 找回密码
 注册
搜索
查看: 5476|回复: 17

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

[复制链接]
发表于 2019-10-7 20:22:57 | 显示全部楼层 |阅读模式
本帖最后由 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 -> 计算器 下载




评分

参与人数 1金钱 +10 专家 +1 贡献 +2 收起 理由
lch + 10 + 1 + 2

查看全部评分

 楼主| 发表于 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教程

 楼主| 发表于 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)无此限制。
 楼主| 发表于 2019-10-7 20:27:10 | 显示全部楼层
本帖最后由 Myth 于 2019-10-13 14:25 编辑

第二部分:使用SDK

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

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

批注 2019-10-07 165644.jpg

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

批注 2019-10-07 165825.jpg

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

批注 2019-10-07 170314.jpg

批注 2019-10-07 170344.jpg

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

批注 2019-10-07 170431.jpg

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

批注 2019-10-07 170637.jpg
 楼主| 发表于 2019-10-7 20:29:29 | 显示全部楼层
本帖最后由 Myth 于 2020-3-22 11:16 编辑

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

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

批注 2019-10-07 172616.jpg

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

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

这里,主函数是此函数:

  1. int AddIn_main(int isAppli, unsigned short OptionNum)
  2. {
  3.     unsigned int key;

  4.     Bdisp_AllClr_DDVRAM();

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

  9.     while(1){
  10.         GetKey(&key);
  11.     }

  12.     return 1;
  13. }
复制代码

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

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

  1. locate(int x, int y); //将光标放在x,y处
  2. Print(char* str); //显示字符串
复制代码

没有scanf()函数令人恼火,但其实您不太需要它。毕竟大多数人想要制作游戏,而大多数游戏不要求输入文本。

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

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

要么使用sprintf()函数,例如:
  1. int a = 30, u = 40;
  2. char* str = malloc(u);
  3. sprintf(str, " %d", a);
  4. locate(1,1);
  5. Print(str);
复制代码

您也可以使用不在C标准库中的itoa函数:

  1. void itoa(int n, char s[])
  2. {
  3.      int i, j, sign;
  4.      char c;

  5.      if ((sign = n) < 0)
  6.          n = -n;
  7.      i = 0;
  8.      do {
  9.          s[i++] = n % 10 + '0';
  10.      } while ((n /= 10) > 0);
  11.      if (sign < 0)
  12.          s[i++] = '-';
  13.      s[i] = '\0';
  14.      for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
  15.          c = s[i];
  16.          s[i] = s[j];
  17.          s[j] = c;
  18.      }
  19. }
复制代码

考虑到使用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。
 楼主| 发表于 2019-10-7 20:30:09 | 显示全部楼层
(未完待续)
发表于 2019-10-9 22:31:15 来自手机 | 显示全部楼层
支持你,感谢分享和翻译
 楼主| 发表于 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文件选中。

批注 2019-10-11 080342.jpg

批注 2019-10-11 080956.jpg

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

ss (2017-11-29 at 05.29.19).png


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

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

在以后的编程中,尽可能使用MonochromeLib中的绘图功能,而非fxlib中的函数。
发表于 2019-10-12 19:12:30 | 显示全部楼层
感谢!
发表于 2019-10-13 16:41:53 | 显示全部楼层
希望继续更新!
 楼主| 发表于 2019-10-13 16:56:49 | 显示全部楼层
cctvgm 发表于 2019-10-13 16:41
希望继续更新!

这个教程很短的,剩的也不多了
其实真说要编程的话,看到这儿再结合diameter的帖子,我觉得已经够了
这两天比较忙,不过以后应该会更完的
 楼主| 发表于 2019-12-28 16:22:50 | 显示全部楼层
竟然咕到了现在。。。考试周结束再说吧
发表于 2020-1-5 19:35:01 | 显示全部楼层
十分感谢楼主的入门帖子,11月份的时候参加了学校组织的一个小型的设计比赛,脑洞大开想在casio上写个小游戏(2048小游戏),然而网上相关资料特别少,还好看到了楼主的入门帖,结合着diameter的教程,总算是成功了,十分感谢!!!
现在又把当时做的小游戏想传到真正的计算器上,不太知道咋搞
 楼主| 发表于 2020-1-8 22:46:59 | 显示全部楼层
1282708293 发表于 2020-1-5 19:35
十分感谢楼主的入门帖子,11月份的时候参加了学校组织的一个小型的设计比赛,脑洞大开想在casio上写个小游 ...

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





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


 楼主| 发表于 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)。

例如,这里是一个游戏中的循环,可以用来移动一个方块(伪代码)。

  1. while (1)
  2. {
  3.         ML_clear_vram();
  4.         ML_pixel(x, y);
  5.         ML_display_vram();
  6.    
  7.         if (IsKeyDown(KEY_CTRL_UP))
  8.         {
  9.                 y--;
  10.         }
  11.         else if (isKeyDown(KEY_CTRL_DOWN))
  12.         {
  13.                 y++;
  14.         } ...
  15. }
复制代码

至于显示功能方面,有以下语句:

- 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"),你会注意到它显示的是这个:
1.png


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

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

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

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

2.png

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

Print("agr\xE6\x0A""able")
 楼主| 发表于 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的方法相同)。

把下面的代码放在里面。
  1. syscall_table:
  2.         .data.l    H'80010070

  3.         .end
复制代码

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

  2. _monSyscall:
  3.         mov.l    syscall_table, r2
  4.         mov.l    monSyscall_code, r0
  5.         jmp    @r2
  6.         nop
  7. monSyscall_code:
  8.         .data.l    H'123
复制代码

在你的.c文件中,你只需要执行mySyscall()就可以了(当然要有必要的参数)。
 楼主| 发表于 2020-4-29 12:58:59 | 显示全部楼层
本帖最后由 Myth 于 2020-4-29 15:59 编辑

第七部分:SDK 的其它功能

我从来没有用过这些功能(其实,在casio上编程的时候,这些功能会很好用),但它们可能对你有用。

首先,SDK有断点,用来停止程序的执行,以便更好地调试程序。也可以在 "globalvariables "和"localvariables"窗口中查看变量的值。

当错误发生时,有一个"trace "功能,它将指向导致错误的代码行。

也可以执行"Run"→" Trace Into",这样就可以得到:

3.png

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

在 " View"选项卡中可以访问一个反汇编器,但由于不了解SH3汇编器,我不能说什么(这只是个入门教程)。

它还允许:

- 查看闪存(如果你想用syscalls来接触系统的话,非常有用)。
- 获得堆区、栈区和调用堆栈的视图。
- 查看寄存器。

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

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

 楼主| 发表于 2020-4-29 13:04:27 | 显示全部楼层
本帖最后由 Myth 于 2020-4-29 13:05 编辑

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

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|cnCalc计算器论坛

GMT+8, 2020-10-22 15:03 , Processed in 0.033624 second(s), 22 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表