Wie kann man einen Mikrocontroller verwenden, der nur 384 Bytes Programmspeicher hat?


67

Zum Beispiel ein PIC10F200T

Praktisch jeder Code, den Sie schreiben, ist größer, es sei denn, es handelt sich um einen Single-Purpose-Chip. Gibt es eine Möglichkeit, mehr Programmspeicher von einem externen Speicher oder etwas anderem zu laden? Ich bin nur neugierig, ich verstehe nicht, wie nützlich das sein könnte ... aber es muss sein.


6
Es gibt viele Anwendungen für winzige Mikrocontroller, von speziellen Signalgeneratoren über Protokollkonverter bis hin zu "Knoten" in einem größeren Steuerungssystem usw. usw.
Dave Tweed

13
Nun, ein Schachspielprogramm benötigt 672 Bytes, das ist also nicht gut. en.wikipedia.org/wiki/1K_ZX_Chess
John Burton

8
Hier sind einige Beispiele dafür, was mit winzigen Programmen (weniger als 256 Byte) gemacht werden kann.
Hammar

9
Was meinst du mit "es sei denn, es ist ein Single-Purpose-Chip"? Die Mehrzahl der eingebetteten Systeme dient nur einem Zweck.
Jeanne Pindar

6
Zurück am College habe ich ein voll funktionsfähiges Ampelprogramm für einen 8085/8155 Computer (max. 256 Byte) erstellt, den ich zusammengestellt habe. Es hatte Gehtasten und einige Sensoren, die die Anwesenheit eines Fahrzeugs simulieren würden.
Zoredache

Antworten:


133

Ihr Kinder, geht von meinem Rasen!

384 Bytes bieten ausreichend Platz, um in Assembler etwas ziemlich Komplexes zu erstellen.

Wenn Sie die Geschichte bis zu einem Zeitpunkt durchforsten, an dem Computer die Größe eines Raums hatten, werden Sie einige wirklich erstaunliche Meisterleistungen der Kunst in <1k finden.

Lesen Sie zum Beispiel die klassische Geschichte von Mel - A Real Programmer . Zugegeben, diese Typen hatten 4096 Erinnerungswörter, die dekadenten Ungläubigen.

Schauen Sie sich auch einige der alten Demoszenenwettbewerbe an, bei denen die Herausforderung darin bestand, ein "Intro" in den Bootblock einer Diskette einzubauen. Typische Ziele sind 4k oder 40k, und es gelingt normalerweise, Musik und Animation einzuschließen.

Bearbeiten zum Hinzufügen : Es hat sich herausgestellt, dass Sie den weltweit ersten wissenschaftlichen Taschenrechner für 100 US-Dollar in 320 Wörtern implementieren können .

Edit für die jungen 'uns:

  • Floppy = Diskette.
  • Bootblock = 1. Sektor der beim Booten gelesenen Diskette.
  • Demoscene = Programmierwettbewerbe zwischen Hackergruppen.
  • Assembler = ausgefallene Art, ein Gerät zu programmieren, wenn Sie zu weich sind, um 8 Kippschalter und einen "Store" -Knopf zu verwenden.

4
Die Atari 2600-Spielekonsole verfügte nur über 4 KB Speicherplatz in den ROM-Spielekassetten (obwohl einige Spiele diese Einschränkung umgehen konnten, indem sie beim Bankwechsel auf mehr als 4 KB zugegriffen haben).
Johnny

1
Vor Äonen habe ich ein ziemlich realistisches Vogelgezwitscher gemacht (genug, dass die Leute nach dem Vogel gesucht haben, anstatt den Computer zu ahnen), dessen Mut (aber nicht der zufällige Code, der ihn davon abgehalten hat, jedes Mal genau das gleiche Geräusch zu machen) hätte rasseln müssen herum in 384 Bytes und ich hatte die zusätzlichen Einschränkungen, keine beschreibbaren Adressen und ein Null-Byte in der Binärdatei nicht erlaubt.
Loren Pechtel

2
Ich muss mehr raus, erinnerte mich daran von damals - Bildschirmschoner in 368 Bytes: aminet.net/package/util/blank/368blanker
John U

7
+1 für "Die Geschichte von Mel". Eines der besten Dinge, die ich die ganze Woche gelesen habe.
Justin ᚅᚔᚈᚄᚒᚔ

1
@ JohnU: Die ersten Spiele auf dem Atari 2600 waren alle 2K. Viele Entwickler haben niemals Spiele entwickelt, die über 4K hinausgehen, denn obwohl 8K-Chips erschwinglich waren (und die Karren einiger Unternehmen nur die Hälfte eines 4K-Chips verwendeten), fügten sie einer Karte Bank-Switching mit einem Standard (Active-Low-Chip-Select) hinzu. Chip erhöhte die Anzahl der Support-Chips von eins auf drei.
Supercat

59

Mikrocontroller sind so billig, dass sie häufig für wirklich einfache Aufgaben verwendet werden, die in der Vergangenheit eher mit diskreter Logik erledigt worden wären. Wirklich einfache Dinge. Beispielsweise möchte man, dass ein Gerät alle fünf Sekunden einen Ausgang für eine Sekunde einschaltet, genauer gesagt, als dies mit einem 555-Timer möglich wäre.

  movwf OSCCON
mainLp:
  ; Set output low
  clrf  GPIO
  movlw 0xFE
  movwf TRIS
  clrwdt
  call  Wait1Sec
  clrwdt
  call  Wait1Sec
  clrwdt
  call  Wait1Sec
  clrwdt
  call  Wait1Sec
  ; Set output high
  bsf   GPIO,0
  clrwdt
  call  Wait1Sec
  goto  mainLp
Wait1Sec:
  movlw 6
  movwf count2
  movlw 23
  movwf count1
  movlw 17
  movwf count0
waitLp:
  decfsz count0
   goto   waitLp
  decfsz count1
   goto   waitLp
  decfsz count2
   goto   waitLp
  retlw  0

Das wäre eine echte, brauchbare Anwendung mit weniger als 32 Wörtern (48 Bytes) Code-Speicherplatz. Man könnte leicht ein paar Optionen hinzufügen, damit einige I / O-Pins die Timing-Optionen steuern und immer noch viel Platz übrig haben, aber selbst wenn der Chip genau das ist, was oben gezeigt wurde, ist er möglicherweise immer noch billiger und einfacher als jede Alternative, die diskrete Technik verwendet Logik. Übrigens clrwdtkönnten die Anweisungen in das Unterprogramm verschoben werden, aber dies würde die Dinge weniger robust machen. Wie beschrieben, wird der Watchdog erst dann gespeist, wenn die Ausführung zur Hauptschleife zurückkehrt, wenn ein Fehler den Rücksendeadressenstapel beschädigt. Geschieht dies nie, setzt der Watchdog den Chip nach einigen Sekunden zurück.


9
Ehrlich gesagt, könnten Sie Ihren Code ein wenig optimieren und den Kindern ein schlechtes Beispiel geben - 5 separate Aufrufe für wait1sec ??? Wastrel! ;)
John U

9
@JohnU: Zu Ihrer Information, der Code verwendet separate Aufrufe, da die Schleife bei Verwendung eines Count-to-Zero-Zählers und fehlerhafter Zählung möglicherweise 255 statt vier Mal ausgeführt wird, während der Watchdog einmal pro Sekunde gespeist wird. Während es möglich wäre, sich davor zu schützen, indem bei jeder Schleife geprüft würde, ob der Zählerstand im Bereich liegt, ist der Code dafür am Ende komplizierter als fünf Aufrufe und fünf clrwdtAnweisungen. Dies ist nicht die absolut ausfallsichere Zähleranordnung, die möglich ist. Es werden jedoch einige Sicherheitsaspekte berücksichtigt (z. B. das Vermeiden clrwdtinnerhalb eines Unterprogramms).
Supercat

10
@ coder543: In Abwesenheit von Dingen wie Netzteilrauschen nicht sehr. Andererseits können in Teilen ohne Brown-out-Detektor alle möglichen verrückten Dinge passieren, wenn VDD auf einen Pegel zwischen der minimalen Betriebsspannung und Masse abfällt und dann wieder auf den Normalwert ansteigt. Im Allgemeinen sollte versucht werden, sicherzustellen, dass jeder Zustand, in dem sich das Gerät möglicherweise befindet, innerhalb eines angemessenen Zeitraums wieder normalisiert wird. Die ungefähr zwei Sekunden, die der Watchdog benötigt, sind möglicherweise unvermeidlich, aber vier Minuten, bis ein fehlerhafter Zähler Null erreicht, können ein bisschen viel sein.
Supercat

10
@ coder543, sie kommen öfter bei einer wichtigen Demo vor, als Sie glauben wollen. Diese Art des Denkens ist auch erforderlich, wenn tief eingebettete Dinge erstellt werden, die keine Mittel haben, um Hilfe zu rufen oder einen Fehler zu melden. Oder sind unzugänglich (denken Sie an die Tiefsee oder den Weltraum), auch wenn ein Fehler bemerkt wurde.
RBerteig

6
@ JohnU: Ich habe es bemerkt, aber es könnte hilfreich sein, zu erklären, warum ich den Code so geschrieben habe, wie ich es getan habe. Im Übrigen wollte ich auch zeigen, dass kleine Aufgaben in einen kleinen Prozessor passen, auch wenn sie nicht absolut perfekt optimiert sind.
Supercat

26

"NUR" 384 Bytes?

Vor langer Zeit hatte ich die Aufgabe, ein gesamtes Betriebssystem (für mich) für einen Spezialcomputer zu schreiben, der die Schiffs-, Pipeline- und Raffineriemanagementbranche bediente. Das erste derartige Produkt des Unternehmens war 6800-basiert und wurde auf 6809 aktualisiert. Sie wollten ein neues Betriebssystem, das mit dem 6809 kompatibel ist, um die Lizenzkosten des ursprünglichen Betriebssystems zu senken. Sie haben auch die Größe des Boot-Roms von 32 auf 64 Bytes erhöht. Wenn ich mich recht entsinne, war es ungefähr 33 Jahre her! - Ich habe die Ingenieure überzeugt, mir 128 Bytes zu geben, damit ich die Gerätetreiber des gesamten Betriebssystems auf die ROM schreiben und so das gesamte Gerät zuverlässiger und vielseitiger machen kann. Dies beinhaltete:

  • Tastaturtreiber mit Tastenentprellung
  • Videotreiber
  • Festplattentreiber und rudimentäres Dateisystem (Motorola "abloader format", IIRC) mit integrierter Fähigkeit, "banked" Speicher so zu behandeln, als wäre es wirklich schneller Speicherplatz.
  • Modemtreiber (sie haben das FSK rückwärts bekommen, so dass diese Modems nur miteinander gesprochen haben)

Ja, all dies war so einfach wie es nur geht und handoptimiert, um jeden überflüssigen Zyklus zu beseitigen, aber perfekt wartbar und zuverlässig. Ja, all das habe ich in die verfügbaren Bytes geschustert - oh, es hat AUCH die Interrupt-Behandlung und die verschiedenen Stapel eingerichtet und das Echtzeit- / Multitasking-Betriebssystem initialisiert, den Benutzer zu Startoptionen aufgefordert und das System gebootet.

Ein Freund von mir, der immer noch mit dem Unternehmen (seinem Nachfolger) verbunden ist, hat mir vor einigen Jahren erzählt, dass mein Code immer noch in Betrieb ist!

Sie können eine Menge mit 384 Bytes tun ...


2
Sie sagen Boot-ROM und Sie erwähnen, dass Treiber auf das Boot-ROM verschoben werden. Dies zeigt mir, dass ein sekundäres Speichermedium verfügbar war. In dieser Diskussion haben wir bereits festgestellt, dass Sie auf diesem PIC keinen Code von einem externen Speicher laden können.
coder543

5
@ coder543 Das geht daneben: 384 Bytes reichen aus, um ziemlich viel zu tun! Die ursprüngliche Frage lautete wie eine Beschwerde, dass 384 nicht ausreichte, um etwas Nützliches zu tun - es war mehr als ich brauchte - VIEL mehr -, um alle grundlegenden Komponenten eines Echtzeit-Multitasking-Betriebssystems bereitzustellen ...
Richard T


17

Ich habe einen Feuchtigkeitssensor für Pflanzen entwickelt, der die Wassermenge der Pflanze misst und eine LED blinkt, wenn die Pflanze Wasser benötigt. Sie können den Sensor veranlassen, den Anlagentyp zu lernen und somit seine Einstellungen während des Betriebs zu ändern. Es erkennt niedrige Spannung an der Batterie. Ich hatte keinen Flash- und RAM-Speicher mehr, konnte aber alles in C-Code schreiben, damit dieses Produkt einwandfrei funktioniert.

Ich habe das von Ihnen erwähnte Bild 10f verwendet.


Hier ist der Code, den ich für meinen Pflanzenwassersensor erstellt habe. Ich habe das pic10f220 benutzt, da es ein ADC-Modul hat, es hat den gleichen Speicher wie das pic10f200, ich werde morgen versuchen, das Schema zu finden.

Der Code ist in Spanisch, aber es ist sehr einfach und sollte leicht zu verstehen sein. Wenn der Pic10F aus dem Ruhemodus aufwacht, wird er zurückgesetzt, sodass Sie prüfen müssen, ob es sich um ein PowerUp oder einen Reset handelt, und entsprechend vorgehen. Die Anlageneinstellung bleibt im RAM, da sie sich nie wirklich ausschaltet.

HAUPT C

/*
Author: woziX (AML)

Feel free to use the code as you wish. 
*/

#include "main.h"

void main(void) 
{  
    unsigned char Humedad_Ref;
    unsigned char Ciclos;
    unsigned char Bateria_Baja;
    unsigned char Humedad_Ref_Bkp;

    OSCCAL &= 0xfe;             //Solo borramos el primer bit
    WDT_POST64();                   //1s
    ADCON0 = 0b01000000;
    LEDOFF();
    TRIS_LEDOFF(); 

    for(;;) 
    {  
        //Se checa si es la primera vez que arranca
        if(FIRST_RUN())
        {
            Ciclos = 0;
            Humedad_Ref = 0;
            Bateria_Baja = 0;
        }

        //Checamos el nivel de la bateria cuando arranca por primera vez y cada 255 ciclos.
        if(Ciclos == 0)
        {
            if(Bateria_Baja)
            {
                Bateria_Baja--;
                Blink(2);
                WDT_POST128();
                SLEEP();
            }       

            if(BateriaBaja())
            {
                Bateria_Baja = 100;     //Vamos a parpadear doble por 100 ciclos de 2 segundos
                SLEEP();
            }
            Ciclos = 255;
        }   

        //Checamos si el boton esta picado
        if(Boton_Picado)
        {
            WDT_POST128();
            CLRWDT();
            TRIS_LEDON(); 
            LEDON();
            __delay_ms(1000);   
            TRIS_ADOFF();
            Humedad_Ref = Humedad();
            Humedad_Ref_Bkp = Humedad_Ref;
        }   

        //Checamos si esta calibrado. Esta calibrado si Humedad_Ref es mayor a cero
        if( (!Humedad_Ref) || (Humedad_Ref != Humedad_Ref_Bkp) )
        {
            //No esta calibrado, hacer blink y dormir
            Blink(3);
            SLEEP();
        }   

        //Checamos que Humedad_Ref sea mayor o igual a 4 antes de restarle 
        if(Humedad_Ref <= (255 - Offset_Muy_Seca))
        {
            if(Humedad() > (Humedad_Ref + Offset_Muy_Seca)) //planta casi seca
            {
                Blink(1);
                WDT_POST32();
                SLEEP();    
            }       
        }

        if(Humedad() >= (Humedad_Ref))  //planta seca
        {
            Blink(1);
            WDT_POST64();
            SLEEP();    
        }   

        if(Humedad_Ref >= Offset_Casi_Seca )
        {
            //Si Humedad_Ref es menor a Humedad, entonces la tierra esta seca. 
            if(Humedad() > (Humedad_Ref - Offset_Casi_Seca))  //Planta muy seca
            {
                Blink(1);
                WDT_POST128();
                SLEEP();    
            }
        }

        SLEEP();
    }  
} 

unsigned char Humedad (void)
{
    LEDOFF();
    TRIS_ADON();
    ADON();
    ADCON0_CH0_ADON();
    __delay_us(12); 
    GO_nDONE = 1;
    while(GO_nDONE);
    TRIS_ADOFF();
    ADCON0_CH0_ADOFF();
    return ADRES;
}   

//Regresa 1 si la bateria esta baja (fijado por el define LOWBAT)
//Regresa 0 si la bateria no esta baja
unsigned char BateriaBaja (void)
{
    LEDON();                
    TRIS_ADLEDON();
    ADON();
    ADCON0_ABSREF_ADON();
    __delay_us(150);        //Delay largo para que se baje el voltaje de la bateria 
    GO_nDONE = 1;
    while(GO_nDONE);
    TRIS_ADOFF();
    LEDOFF();
    ADCON0_ABSREF_ADOFF();  
    return (ADRES > LOWBAT ? 1 : 0);
}   

void Blink(unsigned char veces)
{
    while(veces)
    {
        veces--;
        WDT_POST64();
        TRIS_LEDON(); 
        CLRWDT();
        LEDON();
        __delay_ms(18); 
        LEDOFF();
        TRIS_ADOFF();
        if(veces)__delay_ms(320);   
    }   
}   

MAIN.H

/*
Author: woziX (AML)

Feel free to use the code as you wish. 
*/

#ifndef MAIN_H
#define MAIN_H

#include <htc.h>
#include <pic.h>

 __CONFIG (MCPU_OFF  & WDTE_ON & CP_OFF & MCLRE_OFF & IOSCFS_4MHZ ); 

#define _XTAL_FREQ              4000000
#define TRIS_ADON()             TRIS = 0b1101
#define TRIS_ADOFF()            TRIS = 0b1111
#define TRIS_LEDON()            TRIS = 0b1011
#define TRIS_LEDOFF()           TRIS = 0b1111
#define TRIS_ADLEDON()          TRIS = 0b1001


#define ADCON0_CH0_ADON()          ADCON0 = 0b01000001;     // Canal 0 sin ADON
#define ADCON0_CH0_ADOFF()       ADCON0 = 0b01000000;       // Canal 0 con adON
#define ADCON0_ABSREF_ADOFF()    ADCON0 = 0b01001100;       //Referencia interna absoluta sin ADON
#define ADCON0_ABSREF_ADON()     ADCON0 = 0b01001101;       //referencia interna absoluta con ADON

//Llamar a WDT_POST() tambien cambia las otras configuracion de OPTION
#define WDT_POST1()   OPTION = 0b11001000
#define WDT_POST2()   OPTION = 0b11001001
#define WDT_POST4()   OPTION = 0b11001010
#define WDT_POST8()   OPTION = 0b11001011
#define WDT_POST16()  OPTION = 0b11001100
#define WDT_POST32()  OPTION = 0b11001101
#define WDT_POST64()  OPTION = 0b11001110
#define WDT_POST128() OPTION = 0b11001111

#define Boton_Picado    !GP3
#define FIRST_RUN()     (STATUS & 0x10) //Solo tomamos el bit TO

//Offsets
#define Offset_Casi_Seca  5
#define Offset_Muy_Seca   5

 //Low Bat Threshold
#define LOWBAT                    73
/*
Los siguientes valores son aproximados
LOWBAT  VDD
50      3.07
51      3.01
52      2.95
53      2.90
54      2.84
55      2.79
56      2.74
57      2.69
58      2.65
59      2.60
60      2.56
61      2.52
62      2.48
63      2.44
64      2.40
65      2.36
66      2.33
67      2.29
68      2.26
69      2.23
70      2.19
71      2.16
72      2.13
73      2.10
74      2.08
75      2.05
76      2.02
77      1.99
78      1.97
*/


#define LEDON()                 GP2 = 0; //GPIO = GPIO & 0b1011
#define LEDOFF()                GP2 = 1; //GPIO = GPIO | 0b0100
#define ADON()                  GP1 = 0; //GPIO = GPIO & 0b1101
#define ADOFF()                 GP1 = 1; //GPIO = GPIO | 0b0010

unsigned char Humedad (void);
unsigned char BateriaBaja (void);
void Delay_Parpadeo(void);
void Blink(unsigned char veces);

#endif

Lassen Sie mich wissen, wenn Sie Fragen haben, ich werde versuchen, auf der Grundlage dessen, woran ich mich erinnere, zu antworten. Ich habe das vor einigen Jahren codiert, also überprüfe nicht meine Codierfähigkeiten, sie haben sich verbessert :).

Schlussbemerkung. Ich habe den Hi-Tech C-Compiler verwendet.


3
Es würde mich wirklich interessieren zu lesen, wie Sie das gemacht haben. Haben Sie sich dabei überhaupt Notizen gemacht, die Sie gerne im Internet teilen würden?
RhysW

1
Hallo RhysW, ich glaube ich habe noch den Code. Es war eigentlich ganz einfach. Ich könnte Ihnen meinen Code schicken, wenn Sie interessiert sind. Gib mir Bescheid. Die Schaltung, die ich entworfen habe, ist sehr einfach und cool, nur 3 Widerstände, ein p-Kanal-Mosfet (für den Verpolungsschutz der Batterie), eine 100-nF-Kappe und eine LED. Ich verwende eine interne Diode im Bild 10f als Referenz für die Batteriemessung und um die ADC-Werte konstant zu halten.
Scrafy

1
Das klingt nach einem ordentlichen Projekt. Gibt es eine Möglichkeit, die Details hier zu posten (oder sie zumindest irgendwo zu posten und mit ihnen zu verlinken)?
Ilmari Karonen

1
Hallo scrafy! Wenn Sie einer Antwort etwas hinzufügen möchten, verwenden Sie bitte den Link "Bearbeiten", anstatt eine neue Antwort zu veröffentlichen, da diese Seite Abstimmungen verwendet und nicht wie ein Forum funktioniert.
Clabacchio

16

Eine Sache, die ich nicht erwähnt habe: Der von Ihnen erwähnte Mikrocontroller kostet nur 0,34 US-Dollar pro Stück in Mengen von 100. Für billige Massenprodukte kann es also sinnvoll sein, sich mit den zusätzlichen Codierungsproblemen zu befassen, die durch eine derart begrenzte Einheit verursacht werden. Gleiches gilt möglicherweise für die Größe oder den Stromverbrauch.


2
Das war genau mein erster Gedanke. Außerdem: Wenn ich ein Start-up mit einer guten Idee wäre, aber nur ein paar hundert Dollar frei hätten, kann so etwas den Unterschied zwischen der Rückkehr zum Tagesgeschäft und der Beendigung des Tagesgeschäfts bedeuten.
Phresnel

14

Als ich in der Highschool war, hatte ich einen Lehrer, der darauf bestand, dass es für einen Schüler wie mich zu schwierig sei, das Licht zu dimmen.

So herausgefordert verbrachte ich eine ganze Menge Zeit damit, das phasenbasierte Dimmen mit Triacs zu lernen und zu verstehen und den 16C84 aus einem Mikrochip zu programmieren, um dieses Kunststück auszuführen. Ich endete mit diesem Assembler-Code:

'Timing info:
'There are 120 half-cycles in a 60Hz AC waveform
'We want to be able to trigger a triac at any of 256 
'points inside each half-cycle.  So:
'1 Half cycle takes 8 1/3 mS
'1/256 of one half cycle takes about 32.6uS
'The Pause function here waits (34 * 0xD)uS, plus 3uS overhead
'Overhead includes CALL PAUSE.
'This was originally assembled using Parallax's "8051 style" 
'assembler, and was not optimized any further.  I suppose
'it could be modified to be closer to 32 or 33uS, but it is
'sufficient for my testing purposes.

list 16c84

    movlw   0xFD     '11111101
    tris    0x5      'Port A
    movlw   0xFF     '11111111
    tris    0x6      'Port B
WaitLow:             'Wait for zero-crossing start
    btfss   0x5,0x0  'Port A, Bit 1
    goto    WaitLow  'If high, goto WaitLow
WaitHigh:            'Wait for end of Zero Crossing
    btfsc   0x5,0x0  'Port A, Bit 1
    goto    WaitHigh 'If low, goto waitHigh
    call    Pause    'Wait for 0xD * 34 + 3 uS
    bcf     0x5,0x1  'Put Low on port A, Bit 1
    movlw   0x3      'Put 3 into W
    movwf   0xD      'Put W into 0xD
    call    Pause    'Call Pause, 105 uS
    bsf     0x5,0x1  'Put High on Port A, Bit 1
    decf    0xE      'Decrement E
    movf    0x6,W    'Copy Port B to W
    movwf   0xD      'Copy W to 0xD
    goto    Start    'Wait for zero Crossing
Pause:               'This pauses for 0xD * 34 + 3 Micro Seconds
                     'Our goal is approx. 32 uS per 0xD
                     'But this is close enough for testing
    movlw   0xA      'Move 10 to W
    movwf   0xC      'Move W to 0xC
Label1:
    decfsz  0xC      'Decrement C
    goto    Label1   'If C is not zero, goto Label1
    decfsz  0xD      'Decrement D
    goto    Pause    'If D is not zero, goto Pause
    return           'Return

Natürlich müssten Sie dies für den von Ihnen erwähnten Chip ändern und möglicherweise eine billige serielle Routine für die Eingabe hinzufügen, da Ihr Chip keinen 8-Bit-breiten Port zum Abhören hat, aber die Idee ist, dass ein scheinbar komplexer Job dies kann in sehr wenig Code erledigt werden - Sie können zehn Kopien des obigen Programms in den 10F200 einpassen.

Weitere Projektinformationen finden Sie auf meiner Seite zum Dimmen von Licht . Übrigens habe ich das meinem Lehrer nie gezeigt, aber am Ende habe ich eine Reihe von Lichtanlagen für meinen DJ-Freund gemacht.


12

Nun, vor Jahren habe ich einen Temperaturregler mit serieller E / A (Bit-Banging der seriellen E / A, da die MCU keinen UART hatte) und einen einfachen Befehlsinterpreter geschrieben, um mit dem Regler zu sprechen. Die MCU war eine Motorola (jetzt Freescale) MC68HC705K1 mit satten 504 Bytes Programmspeicher (OTPROM) und etwa 32 Bytes RAM. Nicht so wenig wie das PIC, auf das Sie verweisen, aber ich erinnere mich, dass noch ein ROM übrig war. Ich habe noch ein paar zusammengebaute Einheiten, 17 Jahre später; willst du einen kaufen?

Also ja, es kann zumindest in der Montage gemacht werden.

Auf jeden Fall habe ich kürzlich sehr einfache C-Programme geschrieben, die bei einer Optimierung wahrscheinlich in 384 Byte passen würden. Nicht alles erfordert große, komplexe Software.


5

Sie können eine LED mit 384 Bytes Programmspeicher und noch mehr schreiben.

Soweit ich weiß, ist es nicht möglich, den Programmspeicher mit einem externen Chip zu erweitern (es sei denn, Sie erstellen einen vollständigen ASM-Interpreter in den 384 Bytes , was langsam wäre). Es ist jedoch möglich, den Datenspeicher mit einem externen Chip (EEPROM, SRAM) zu erweitern.


1
Es wäre nicht schwer, einen Turing-Maschinensimulator in 384 Bytes zu bauen ...
Chris Stratton

@ChrisStratton Ich meinte einen Vollinterpreter, damit der 'erweiterte Programmspeicher' die gleichen Funktionen wie normal hat.

Ja, das ist es, was ich vorgeschlagen habe, um es eng umzusetzen. Der Rest ist nur Compiler-Design ...
Chris Stratton

7
Wenn eine Programmlogik in einem externen EEPROM gespeichert werden soll, ist der Versuch, den PIC-Befehlssatz zu emulieren, nicht der richtige Weg. Ein besserer Ansatz wäre, einen Befehlssatz zu entwerfen, der für die Verwendung mit der virtuellen Maschine optimiert wurde. In der Tat ist dies der Ansatz, den Parallax in den 90er Jahren mit seinem "Basic STAMP" verfolgte. Es war ein PIC mit 3072 Byte Code-Speicherplatz, der mit einem seriellen EEPROM-Chip gepaart war.
Supercat

3
Übrigens ein zusätzlicher Hinweis zum BASIC-Stempel: Er wurde zu einer Zeit eingeführt, als Flash- oder EEPROM-basierte Mikrocontroller vergleichsweise selten waren, aber serielle EEPROM-Chips relativ billig. Für Anwendungen, die nicht viel Geschwindigkeit benötigen, ist ein Festcode-Mikro mit einem seriellen EEPROM-Teil billiger als ein vergleichbares EEPROM- oder Flash-basiertes Mikro. Das Design der BASIC Stamp würde heute keinen Sinn ergeben, war aber bei der Einführung recht praktisch.
Supercat

4

Es ist tatsächlich schlimmer als du denkst. Ihre verknüpfte Mouser-Seite ist verwirrend, wenn angegeben wird, dass dieser Prozessor 384 Byte Programmspeicher hat. Der PIC10F200 verfügt tatsächlich über 256 12-Bit- Wörter im Programmspeicher.

Also, was kannst du damit machen? Der 12-Bit-PIC-Befehlssatz, der von den PIC10F20 x- Geräten verwendet wird, besteht aus nur einem Wort. Nachdem Sie also einige Anweisungen für die Prozessoreinrichtung abgezogen haben, bleibt genügend Platz für ein Programm mit etwa 250 Schritten. Das reicht für viele Anwendungen. Ich könnte wahrscheinlich eine Waschmaschinensteuerung in dieser Art von Raum schreiben, zum Beispiel.

Ich habe mir gerade die verfügbaren PIC C-Compiler angesehen, und es sieht so aus, als würde etwa die Hälfte von ihnen nicht einmal versuchen, Code für einen PIC10F200 zu emittieren. Diejenigen, die wahrscheinlich so viel Kesselcode ausgeben, dass Sie möglicherweise nur einen LED-Blinker in den verbleibenden Bereich schreiben können. Sie möchten mit einem solchen Prozessor wirklich Assemblersprache verwenden.


Sie haben Recht mit den 256 Anweisungswörtern. Tatsächlich wird eine davon mit der Oszillatorkalibrierungskonstante belegt, sodass Sie 255 verwendbare Anweisungen erhalten. Außerdem verwendet der 10F200 nicht den üblichen 14-Bit-Befehlssatz von PIC 16. Es wird der 12-Bit-Befehlssatz von PIC 12 verwendet. Ich stimme jedoch Ihren Grundvoraussetzungen zu. Ich habe viele nützliche Dinge mit einem PIC 10F200 gemacht. +1
Olin Lathrop

@OlinLathrop: Ich habe die Antwort geklärt. Ich habe den Begriff PIC16 von Seite 51 des Datensatzes erhalten , aber ich habe beschlossen, dass es klarer ist, nur auf den 12-Bit-Befehlssatz zu verweisen. Das Teilepräfix ist kein verlässlicher Hinweis auf den verwendeten Befehlssatz.
Warren Young

0

Zu meiner Zeit winkten wir mit meinem Stock und mussten unsere eigenen Stücke aus dem Sand ätzen!

1976 (oder so ungefähr) war das Atari 2600 VCS-System eine der beliebtesten "Videospielplattformen" der damaligen Zeit. Darin lief der Mikroprozessor (MOSTEK 6507) mit einer hohen Frequenz von ~ 1 MHz und hatte **** 128 Bytes RAM **.

Ein zweites Beispiel, das ich an einen Mikrocontroller mit extrem begrenztem RAM (~ 128 Byte) erinnere, war ein PIC12F, der in einem DC-DC-Wandler verwendet wurde. Dieses Mikro musste auch Assembler-Sprache verwenden, um überhaupt ausgeführt werden zu können.


4
Das OP spricht nicht über RAM, er spricht über Programmraum. Der Programmplatz im Atari 2600 befindet sich in der Kassette, nicht im RIOT-Chip . Der 2600 unterstützt Programm-ROMs bis zu 4 kB ohne Bankwechsel. (Und einige handelsübliche Kassetten haben die Bank gewechselt!) Was Ihr PIC12F-Beispiel betrifft, so haben Sie es mit den OPs zu tun: Die Geräte der PIC10F20x-Serie haben entweder 16 oder 24 Byte SRAM.
Warren Young
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.