用 Arduino Uno 制作功能计算机

电器工程 Arduino
2022-01-25 05:09:05

那里有任何 Arduino 爱好者吗?

嘿,我一直在想这个,我想得越多,我就越觉得我可以做到这一点。我的想法基本上是这样的:用 Arduino Uno 微控制器制作一台功能正常的计算机。

我对这台计算机的唯一目标是能够编辑和执行 BASIC 程序。就这样。我只希望它用于编程,因为这几乎是我现在唯一感兴趣的东西:)

所以在我看来,我需要三个主要的硬件组件:

  1. 某种形式的显示器(VGA屏幕或其他东西)
  2. 某种注册键盘输入的方法,以及
  3. 某种方式将数据存储到外部存储器。

有谁知道有什么方法可以做到这一点?我知道在屏幕上显示的方法,但我不知道一个好的 API/硬件组件来注册键盘输入或存储外部存储器。

在这方面我需要很多帮助。任何人都可以帮助我并为好的硬件/好的开源库提供想法和有用的提示和建议,或者两个、三个或十个?

添加:

博客为任何感兴趣的人制作 Arduino Uno 计算机。

4个回答

键盘可以简单地使用 PS/2 键盘完成 - 它只是串行的,并且有很多教程可供使用。

存储数据可以简单地在 SD 卡上完成 - 已经有一个屏蔽可以做到这一点。

至于视频 - 这要困难得多。例如,如果您希望 Arduino 生成 PAL 视频信号,那么您的工作已经完成。是的,这是可能的,有人创建了一个 Arduino“乒乓”游戏,但它的图形非常厚实,而且只有黑白。

对于 VGA,您将需要某种形式的接口来为您完成工作。Sparkfun 曾经出售可以与 Arduino 配合使用的 Picaso视频卡,但可惜已经停产,目前还没有更换的计划。

TBH,您最好的选择是使用Wyse 终端之类的东西,并完全使用串行与 Arduino 进行通信。比弄乱视频信号等简单得多。

我在这里看到 Olin 的观点 - 如果您只想编辑/运行/学习 BASIC,只需使用 PC。

但是,如果目标是创建一台可以运行 BASIC 并同时了解硬件和较低级别实现的计算机的挑战,那么这有点不同。我完全赞成这样的东西,这是提高知识的好方法,我相信你会从中得到很多。正如 Steven 提到的,Windows 等所有令人困惑和(大部分)不相关的层都可以被剥离,留下基本的(不是双关语的)概念。

不管怎样,你可能想看看像PIC32这样更强大的东西,因为它应该能够自己处理所有功能(例如基本VGA)。
这是一个 Arduino 兼容板,UNO32
The Maximite是一台带有基于 PIC32 的 BASIC 解释器的计算机,您可能想查看设计和构造以获得一些想法。

有点走运,因为我现在正在使用 arduino PC!虽然不多,只是第一个模型。固件也很简单,并且有一个小的 API 集。但是,这件事奏效了!不足以编辑 BASIC(或除它自己之外的任何语言),但这只是第一个模型。主板很简单,我用了这个这是我使用的固件:

        #include <LCD4884.h>
#include <SD.h>
#include <SPI.h>
#include <SoftwareSerial.h>

void setup() {   
    lcd.LCD_init();             
    lcd.LCD_clear();
    lcd.LCD_write_string_big(0, 0, "Gilbert", MENU_NORMAL);
    pinMode(10, OUTPUT);
    delay(3000);
}

byte line = 10;
SoftwareSerial FC(8,9);
byte RAM[501];
byte Error = 0;
char tempString[15];

void loop() {
    // <editor-fold defaultstate="collapsed" desc="Initilization">
    FC.begin(4800);
    if (!FC.available()) {
        lcd.LCD_clear();
        lcd.LCD_write_string(0, 0, "FC Failed!", MENU_NORMAL);
        delay(1000);
    }
    int address = 1;
    lcd.LCD_clear();
    lcd.LCD_write_string(0, 0, "SD Init...", MENU_NORMAL);
    if (!SD.begin(10)) {
        lcd.LCD_clear();
        lcd.LCD_write_string(0, 0, "SD Failed!", MENU_NORMAL);
        while (true) {
            ;
        }
    }
    lcd.LCD_clear();
    lcd.LCD_write_string(0, 0, "Loading...", MENU_NORMAL);
    File file;
    file = SD.open("BIOS.mk8", FILE_READ);
    RAM[0] = 53;
    RAM[file.read()] = 8;
    while (file.available()) {
        RAM[address] = file.read();
        address++;
    }
    address++;
    RAM[address] = 55;
    long loops = 0;
    long time1 = 0;
    long time2 = 0;
    address = 0;
    byte instruction = 0;
    int exeaddress;
    byte tempbyte;
    lcd.LCD_clear();
    lcd.LCD_write_string(0, 0, "EMU. Started", MENU_NORMAL);// </editor-fold>
    //emulation loop
    while(true){
        switch(RAM[address]){
            // <editor-fold defaultstate="collapsed" desc="Codes 1-10">
            case 1:
            {//getCycleCount[intvar i]
                tempbyte = (loops) / ((time2 - time1) / 1000);
                convert(address + 1);
                writeInt(exeaddress, tempbyte);
                break;
            }
            case 2:
            {//getTemp[intvar i]
                tempbyte = (((analogRead(A1) / 1024.0) * 5.0) - .5) * 100;
                convert(address + 1);
                writeInt(exeaddress, tempbyte);
                break;
            }
            case 3:
            {//getKey[intvar i]
                //Up 745
                //Down 332
                //Left 0
                //Right 509
                //Center 145
                switch (analogRead(A0)) {
                    case 745:
                    {
                        tempbyte = 1;
                        break;
                    }
                    case 332:
                    {
                        tempbyte = 2;
                        break;
                    }
                    case 0:
                    {
                        tempbyte = 3;
                        break;
                    }
                    case 509:
                    {
                        tempbyte = 4;
                        break;
                    }
                    case 145:
                    {
                        tempbyte = 5;
                        break;
                    }
                }
                convert(address + 1);
                writeInt(exeaddress, tempbyte);
                break;
            }
            case 4:
            {//printLine[variable v]
                if (line > 70) {
                    lcd.LCD_clear();
                    line = 0;
                }
                switch(RAM[address + 1]){
                    case 9:{
                        tempbyte = RAM[address + 1];
                        tempString[0] = char(tempbyte);
                        break;
                    }
                    case 15:{
                        convert(address + 1);
                        break;
                    }
                }
                lcd.LCD_write_string(0, line, tempString, MENU_NORMAL);
                line += 10;
                break;
            }
            case 5:
            {//exe detector
                exeaddress = address;
                break;
            }
            case 7:
            {//lcdClear
                lcd.LCD_clear();
                line = 0;
                break;
            }
            case 10:
            {//declareInteger[string name]
                convert(address + 1);
                tempbyte = 0;
                while (tempbyte != 15) {
                    RAM[address + tempbyte + 1] = tempString[tempbyte];
                }
                break;
            }// </editor-fold>
            case 11:{//getError[intvar i]
                tempbyte = Error;
                Error = 0;
                convert(address + 1);
                writeInt(exeaddress, tempbyte);
                break;
            }
            case 12:{//deadlock
                while(true){;}
                break;
            }
            case 13:{//assignInteger[int value, intvar i]
                tempbyte = RAM[address + 1];
                convert(address + 2);
                writeInt(exeaddress, tempbyte);
                break;
            }
            case 14:{//transferInteger[intvar i1, intvar i2]
                convert(address + 1);
                writeInt(exeaddress, RAM[getIntAddr(exeaddress)]);
                break;
            }
        }
        // <editor-fold defaultstate="collapsed" desc="post loop process">
        address++;
        time2 = millis();
        loops++;
        if (loops < 0) {
            loops = 0;
        }// </editor-fold>
    }
}

void convert(int startAddress){
    byte charadd = 0;
    while(RAM[startAddress] != 6){
        tempString[charadd] = RAM[startAddress];
        charadd++;
        startAddress++;
    }
}

void writeInt(int exeStart, byte value){
    byte count = 0;
    char compare[15];
    while(true){
        if (RAM[exeStart] == 9) {
            exeStart++;
            while (count != 15) {
                compare[count] = RAM[exeStart];
                exeStart++;
                count++;
            }
            if(compare == tempString){
                RAM[exeStart + 2] = value;
                break;
            }else{
                exeStart += 3;
            }
            if(RAM[exeStart] == 8){
                Error = 1;
            }
        }
    }
}

int getIntAddr(int exeStart){
    byte count = 0;
    char compare[15];
    while(true){
        if (RAM[exeStart] == 9) {
            exeStart++;
            while (count != 15) {
                compare[count] = RAM[exeStart];
                exeStart++;
                count++;
            }
            if(compare == tempString){
                return RAM[exeStart + 2];
                break;
            }else{
                exeStart += 3;
            }
            if(RAM[exeStart] == 8){
                Error = 1;
            }
        }
    }
}

方法描述很难解释,但代码存储为原始字节。我应该很快就会有开发软件......希望这会有所帮助!如果您想将它用于任何项目,您必须在 SD 的根目录中有一个 BIOS.mk8 文件,否则系统将无法工作。

尽管对 David Brin(我碰巧非常喜欢他的书;我没有资格判断他作为天体物理学家有多好)表示应有的尊重,但他既不是程序员也不是教育家。

我在 PC 的早期就在附近并进行编码,并且我编写了相当多的 BASIC 代码。从那时起,我一直在专业地编写代码。

我们当时使用 BASIC 的原因是您的两个选择是使用 BASIC 或用汇编编写,而汇编既难以理解,使用起来也麻烦得多。如此基础。

从那时起的 30 多年里,编程教学有了显着的改进。我的妻子教了一门使用 Alice (www.alice.org) 的初级编程课程,它在概念上比旧方法要好得多。

我认为布林的解决方案非常优雅。您可以在 Raspberry PI 上构建一些非常简单的东西。在 arduino 上,我认为将你需要的所有东西都塞进 2K 的 RAM 是很有挑战性的。它必须包含您最终编写的任何操作系统/监视器、命令解释器、进行显示的代码以及基本程序本身的存储。

更不用说您将不得不进行大量困难的自定义编程,以便您可以在简单的环境中编写代码。