几乎所有您编写的代码都将比该代码大,除非它是单用途芯片。有什么办法可以从外部存储器中加载更多程序存储器吗?我只是很好奇,我不知道这怎么可能非常有用……但一定如此。
几乎所有您编写的代码都将比该代码大,除非它是单用途芯片。有什么办法可以从外部存储器中加载更多程序存储器吗?我只是很好奇,我不知道这怎么可能非常有用……但一定如此。
Answers:
你们孩子们,滚下我的草坪!
384字节的空间足以在汇编程序中创建相当复杂的内容。
如果您回顾历史,直到计算机像一间房间那么大,您会发现在<1k的时间内完成了一些令人惊叹的艺术技艺。
例如,阅读经典的《梅尔-一个真正的程序员的故事》。诚然,这些家伙有4096个单词可玩,,废异教徒。
还要看看一些古老的模拟竞赛,其中的挑战是将“介绍”放入软盘的启动块中,典型的目标是4k或40k,并且通常设法包含音乐和动画。
编辑添加:事实证明,您可以用320个单词实现世界上第一个100美元的科学计算器。
编辑年轻的联合国:
微控制器足够便宜,以至于它们经常被用来做一些非常简单的事情,而在过去几年中,它们很可能是用离散逻辑来完成的。真的很简单。例如,人们可能希望设备每五秒钟打开一个输出一秒钟,这比555计时器能够做到的更精确。
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
用不到32个字(48个字节)的代码空间,这将是一个真实,可用的应用程序。一个人可以轻松添加一些选项,使一些I / O引脚控制时序选项,并且仍有很大的余地,但是,即使所有的芯片正是上面显示的内容,它仍然比使用分立器件的任何替代方案更便宜,更容易。逻辑。顺便说一句,clrwdt
指令可以移入子例程,但是这样做会使事情变得不那么健壮。按照书面规定,即使故障导致返回地址堆栈损坏,在执行返回主循环之前也不会监视看门狗。如果这从未发生,看门狗将在几秒钟后重置芯片。
clrwdt
指令更为复杂。这不是最绝对的故障安全计数器安排,但会考虑安全问题(例如,避免clrwdt
在子例程中使用)。
“仅” 384个字节?
追溯到今天,我负责为服务于船舶,管道和炼油厂管理行业的专用计算机编写整个操作系统(由我自己)。该公司的首个此类产品基于6800,并已升级到6809,他们希望将新操作系统与6809搭配使用,以便消除原始操作系统的许可成本。他们还把引导ROM的大小从32个增加到了64个字节。如果我没记错的话-它大约在33年前!-我说服工程师给了我128个字节,这样我就可以将整个操作系统的设备驱动程序放到rom上,从而使整个设备更加可靠和通用。这包括:
是的,所有这些都一无所获,并且经过手动优化以消除每个不必要的循环,但是却非常易于维护和可靠。是的,我把所有这些都弄成可用字节了-哦,它还设置了中断处理,各种堆栈,并初始化了实时/多任务操作系统,提示用户启动选项,并启动了系统。
我的一个仍然与该公司有关系的朋友(其继承人)几年前告诉我,我的代码仍在使用中!
您可以做很多384字节...
您可以将其用于非常小的应用(例如,延迟的PSU启动,555定时器更换,基于双向可控硅的控制,LED闪烁等),其占用空间比逻辑门或555定时器所需的占用空间小。
我为植物设计了一个湿度传感器,该传感器可跟踪植物的水量,并在植物需要水时使LED闪烁。您可以使传感器了解植物的类型,从而在运行时更改其设置。它检测电池上的低电压。我用光了闪存和ram,但能够用C代码编写所有内容,以使该产品完美运行。
我用了你提到的pic10f。
这是我为植物水分传感器编写的代码。我使用pic10f220是因为它具有ADC模块,它的内存与pic10f200相同,我将在明天尝试查找原理图。
该代码是西班牙语,但它非常简单,应易于理解。当Pic10F从睡眠模式唤醒时,它将重置,因此您必须检查它是上电还是重置,并采取相应的措施。工厂设置被保存在ram中,因为它从未真正关闭。
MAIN.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);
}
}
主站
/*
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
如果您有任何问题,请告诉我,我将根据我记得的内容进行回答。我几年前编写了这个代码,所以不要检查我的编码技能,他们已经提高了:)。
最后说明。我使用了高科技C编译器。
高中时,我有一位老师坚持说,调光对于像我这样的学生来说太难了。
因此,面对挑战,我花了很多时间使用双向可控硅来学习和理解基于相位的调光,并通过微芯片对16C84进行编程以实现这一壮举。我最终得到了以下汇编代码:
'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
当然,您需要针对您提到的芯片进行修改,并可能添加一个廉价的串行例程进行输入,因为您的芯片没有8位宽的端口可以监听,但是这样做的目的是,看似复杂的工作可以只需很少的代码即可完成-您可以将上述程序的十个副本放入10F200中。
您可以在我的调光页面上找到更多项目信息。顺便说一句,我从来没有向老师展示过这个,但是最终却为我的DJ朋友做了许多照明设备。
您可以为闪烁的LED写入384字节的程序存储器,甚至更多。
据我所知,不可能用外部芯片来扩展程序存储器(除非您要在384个字节中构建完整的ASM解释器,这会很慢)。不过,可以使用外部芯片(EEPROM,SRAM)扩展数据存储器。
实际上比你想的还要糟。当链接的Mouser页指定此处理器具有384字节的程序存储器时,令人感到困惑。PIC10F200实际上具有256个12位字的程序存储器。
那么,您该怎么办?PIC10F20 x器件使用的12位PIC指令集都是单字指令,因此,在减去一些用于处理器设置的指令后,剩下的空间足以容纳约250个步骤的程序。这对于许多应用程序来说已经足够了。例如,我可能可以在这种空间中编写洗衣机控制器。
我只是查看了可用的PIC C编译器,似乎其中大约有一半甚至不会尝试为PIC10F200发出代码。那些确实写出了很多样板代码的人可能只能在剩余的空间中编写一个LED闪光灯。您真的想在这样的处理器上使用汇编语言。
在我挥舞着拐杖的日子里,我们不得不用沙子蚀刻自己的碎片!
1976年(或其前后),Atari 2600 VCS系统是当时最受欢迎的“视频游戏平台”之一。其中,微处理器(MOSTEK 6507)的运行频率高达1 MHz,并具有**** 128字节的RAM **。
我回想起具有极其有限的RAM (〜128 字节)的微控制器的第二个例子是在DC-DC转换器上使用的PIC12F。该微型计算机还必须使用汇编语言才能运行。