找回密码
 立即注册
搜索
yeec近年来原创帖合集 本站基础知识下载汇总 yeec网站学习币充值链接 学习中心正式上线

[原创]一个51系统的设计过程(软件篇)

[复制链接]
顶风 发表于 2006-2-15 19:19 | 显示全部楼层 |阅读模式

注册登录才能更好的浏览或提问。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

让大家久等了。板子做好的2个月了,诸事缠身,没有写程序。没有程序的硬件如同人没有大脑,是没有任何用处的。春节放假,终于有了一段相对安静完整的时间,可以把程序写完了。

我的任务后来发生了一些小小的变动,就是说对系统完成的功能有了一些变化。由于硬件设计已经完成,这些变化只能通过软件来完成,所以对程序有了更高的要求,也更有趣了。

现在的任务如下:需要在Wave端口有选择地输出5组脉冲信号,脉冲宽度要求如下

1) 100uSH),200uSL;

2) 500uSH),500uSL

3) 1mSH),1mSL

4) 100mSH),100mSL

5) 200mSH),500mSL

我编制程序的时候增加了可以将上述脉冲宽度调整存储的功能。另外如果按Start键启动输出,输出方波脉冲信号的时长是60S,如果由Port端口启动输出,输出方波脉冲信号的时长是20S

我在编制程序的过程中遇到了3个比较大的困难。

1) 最短的脉冲宽度为100uS,这对时间中断服务程序的执行速度要求较高。也就是说必须在100uS的时间内执行完时间中断服务程序,否则上次的时间中断服务程序将会被下一次中断打断,发生难以预知的后果。

2) 我使用了89C2051做为主CPU,所以目标代码必须限制在2K以内。虽然现在有89C4051可以提供4K的代码空间,但我的共享版的C51编译程序仅仅支持2K的目标代码编译。所以,要对程序的长度进行严格的控制。

3) 由于汇编代码难以卒读,管理困难,我一直是用C语言来写所有的代码,包括中断服务程序。这对程序的时间效率和空间效率都会产生不利的影响。但值得庆幸的是KEIL C编译器是非常出色的,程序在效率方面的损失很小。

下面是本系统的全部C代码,其中的注释行是我对程序代码的详细解释。
[此贴子已经被作者于2006-2-15 20:17:49编辑过]
顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com

yeec维修网视频培训资料购买链接
BeckmanCoulter DXA系列培训资料
Ortho VITROS 系列培训资料
Ortho enGen_ThermoFisher TCA 实验室自动化系统培训资料
Roche Cobas 实验室自动化系统培训资料
Roche Cobas modular系列分析仪培训资料
Horiba-ABX Yumizen系列培训资料
DiaSorin Liaison系列培训资料
Advia2120培训资料
Inpeco-Aptio系列培训资料
Atellica Solution系列培训资料
Siemens Immunoassay系列培训资料 西门子化学发光系列
SIEMENS Advia系列培训资料 西门子生化系列
Toshiba/Abbott系列培训资料 东芝雅培生化系列
Abbott Architect 系列培训资料 雅培生化化学发光系列
ACL TOP 系列培训资料 沃芬TOP血凝系列
BeckmanCoulter Immunoassay系列培训资料 贝克曼化学发光系列
BeckmanCoulter DXH 系列培训资料 贝克曼DXH血球系列
BeckmanCoulter自动样品处理系统介绍性培训资料 贝克曼前后处理流水线系列
BeckmanCoulter AU系列培训资料 贝克曼AU生化系列
BeckmanCoulter DXC系列培训资料 贝克曼DXC生化系列
LaboSpect003/008/AS 7100/7180分析仪培训资料
Horiba-ABX系列培训资料 Horiba-ABX血球系列
Sysmex 血凝系列培训(CA/CS)
Sysmex 尿液分析系列培训(UF1000/5000/UC3500)
Sysmex 血球系列培训(KX21/POCH/XS/XT/XE)
Sysmex XN系列培训(XN-L/XN1000/XN2000/XN3000/XN9000)
Sysmex HISCL系列培训
可直接淘宝店铺购买https://yeec.taobao.com,或咨询手机/微信:13991827712,QQ:67708237
 

 楼主| 顶风 发表于 2006-2-15 19:20 | 显示全部楼层

#include <reg51.h> /*这个不用多说了,51系统的头文件,定义了51单片机的内部寄存器及端口的信息。可以打开reg51.h的文件看到详细的内容*/

typedef unsigned char BYTE;

typedef unsigned int WORD;

typedef unsigned long DWORD;

/* 以上定义数据类型,我的个人习惯,程序中如果用unsigned charunsigned intunsigned long也未尝不可 */

#define ON 0

#define OFF 1

/* 以上定义开关状态字,用ONOFF在程序中表示开和关比较清晰一些 */

sbit KEY_START=P3^7;

sbit KEY_SET =P3^5;

sbit KEY_UP =P3^4;

sbit KEY_DOWN =P3^3;

sbit PORT =P1^0;

/* 以上定义了按键使用的的IO口,外部启动端口PORT作用与键盘近似,在此定义为按键 */

sbit DSP_CS = P1^6;

sbit DSP_CLK =P3^1;

sbit DSP_DATA =P3^0;

/* 以上定义了显示驱动芯片MC14489使用的IO */

sbit WAVE =P1^1;

/* 这个是方波信号输出使用的IO口的定义 */

sbit SETLAMP =P1^3;

/* 设置状态指示灯使用的IO的口定义 */

sbit SPEAKER =P1^2;

/* 蜂鸣器使用的IO口的定义 */

sbit MEM_SO =P1^4;

sbit MEM_SI =P1^7;

sbit MEM_SCK =P1^5;

sbit MEM_CS =P3^2;

/* X25045使用的IO口的定义 */

顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com
 楼主| 顶风 发表于 2006-2-15 19:21 | 显示全部楼层

#define kpNoKey 0X00

#define kpSet 0X01

#define kpUp 0X02

#define kpDown 0X03

#define kpStart 0X04

#define kpPort 0X05

/* 定义各个键的键值,Port启动信号当作按键处理 */

BYTE cKeyCode=kpNoKey;

/* 用一个全局变量存储键值,不建议采用全局变量,这样使程序不易读懂而且调试困难,但为了效率,只好如此了。 */

#define KEYDELAY 80

#define KEYFASTDELAY 9000

WORD wKeyDelay=KEYDELAY;

WORD wKeyFastDelay=KEYFASTDELAY;

/* 以上定义键盘延时和键盘加速延时参数,并使用两个全局变量存储这两个参数。由于设定的脉冲宽度由19999可调,为了大范围的调整参数,我做了如下处理,如果按一下UP键,就加一。如果按住UP键不放,就不断做加一处理,而且速度越来越快。按DOWN键同理。时间参数的大小通过试验确定 */

#define mdReady 0

#define mdSet 1

#define mdWave 2

BYTE cCurrMode=mdReady;

/* 以上定义程序工作模式字,我将系统的工作模式分为3个:1,准备模式,此时按UP/DOWN键可以查看各组脉冲的宽度。2,设定模式,用于改变并存储各组脉冲的宽度。3,波形输出模式,输出一组脉冲波形。 */

顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com
 楼主| 顶风 发表于 2006-2-15 19:22 | 显示全部楼层

void PutChar(BYTE cData); /* MC14489传送一个字节的数据的子程序 */

void Display(DWORD dwData);

/* 数码管显示子程序,此程序需要调用PutChar()子程序,这段程序涉及到MC14489的特性及其灭零处理,需要对照手册才能读懂。 */

void ReadKey(void); /* 读键值并存于全局变量cKeyCode */

#define WRSR_INST 0X01 /* Write Status Register Instruction */

#define WRITE_INST 0X02 /* Write Memory Instruction */

#define READ_INST 0X03 /* Read Memory Instruction */

#define RDSR_INST 0X05 /* Read Status Register Instruction */

#define WREN_INST 0X06 /* Write Enable Latch Instruction */

#define STATUS_REG 0X30 /* Status Register */

#define MAX_POLL 0x99 /* Maximum Number of Polls */

void wren_cmd(void); /* Set the Write Enable Latch */

void wrsr_cmd(void); /* Write the Status Register */

BYTE rdsr_cmd(void); /* Read the Status Register */

void byte_write(BYTE cData,BYTE cAddress); /* Write a Byte to the EEPROM Memory Array */

BYTE byte_read(BYTE cAddress); /* Read a Byte to the EEPROM Memory Array */

void rst_wdog(void); /* Reset the WatchDog Timer without Sending a Command */

void outbyte(BYTE cData); /* Shifes Out a Byte,Starting with the MSB,to the EEPROM */

BYTE inbyte(void); /* Recieves a Byte,MSB first, from the EEPROM */

void wip_poll(void); /* Poll for completion of a nonvolatile write cycle by examining the WIP bit of the status register */

/* 以上是25045的命令字及驱动程序,同显示程序一样,设计到太多的芯片参数和时序,慢慢看吧,看不懂也没事,知道怎么用就行了。这些子程序是厂方提供的,我做了一些小修改,以提高效率。 */

void ReadPara(BYTE cPara); /* 通过调用上述子程序从25404中读出各参数值 */

void WritePara(BYTE cPara); /* 通过调用上述子程序将参数值写入25045 */

#define MaxStatus 10 /* 5组信号每组有高低两个电平共10个状态 */

const WORD code wMaxValue[MaxStatus]= {9999,9999,9999,9999,9999,9999,9999,9999,9999,9999};

const WORD code wParaConst[MaxStatus]={ 1, 2, 5, 5, 10, 10,1000,1000,2000,5000};

const WORD code wMinValue[MaxStatus]= { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};

/* 以上定义每个状态持续时间的值域范围和默认数值,每个单位100uS */

WORD wParaValue[MaxStatus]; /* 存储状态持续时间的全局变量数组 */

BYTE cCurrStatus=0X00; /* 存储当前状态的全局变量 */

#define KeyWave 600000 /* 通过Start键启动波形输出,持续60 */

#define PortWave 200000 /* 通过Port端口启动波形输出,20 */

WORD wClick; /* 存储系统时钟数的全局变量 */

DWORD dwWaveTime; /* 存储输出时间的全局变量 */

顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com
 楼主| 顶风 发表于 2006-2-15 19:23 | 显示全部楼层

/* 以下是时间中断服务程序,没100uS中断一次,这段程序可以用循环来完成,这样会清晰明确,但时间成本太高,无法在100uS内完成,只好用空间换时间,写成如下的样子,比较丑陋 */

void timer0() interrupt 1 using 1

{

if(cCurrMode==mdWave) /* 在波形输出模式下启动输出 */

{

wClick--;

if(wClick==0)

{

switch(cCurrStatus)

{

case 0:

wClick=wParaValue[1];

cCurrStatus=1;

WAVE=0;

break;

case 1:

wClick=wParaValue[0];

cCurrStatus=0;

WAVE=1;

break;

/* 状态0和状态1为一组,每发生一次时间中断,wClick1。当wClick减到0,将wClick赋值为状态1的持续时长,并将当前状态改为1,将WAVE端口变为低电平。当wClick减到0,将wClick赋值为状态0的持续时长,并将当前状态改为0,将WAVE端口变为高电平。如此循环往复。其他组的信号同理。*/

case 2:

wClick=wParaValue[3];

cCurrStatus=3;

WAVE=0;

break;

case 3:

wClick=wParaValue[2];

cCurrStatus=2;

WAVE=1;

break;

case 4:

wClick=wParaValue[5];

cCurrStatus=5;

WAVE=0;

break;

case 5:

wClick=wParaValue[4];

cCurrStatus=4;

WAVE=1;

break;

case 6:

wClick=wParaValue[7];

cCurrStatus=7;

WAVE=0;

break;

case 7:

wClick=wParaValue[6];

cCurrStatus=6;

WAVE=1;

break;

case 8:

wClick=wParaValue[9];

cCurrStatus=9;

WAVE=0;

break;

case 9:

wClick=wParaValue[8];

cCurrStatus=8;

WAVE=1;

break;

}

}

dwWaveTime--;

if(dwWaveTime==0) cCurrMode=mdReady;

/* 每发生一次中断,输出时间变量减1,当此变量为0时,将当前模式改为准备模式 */

}

}

顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com
 楼主| 顶风 发表于 2006-2-15 19:28 | 显示全部楼层

/* 以下主程序 */

void main()

{

BYTE i; /* 为以后的循环程序定义一个临时变量 */

TMOD=0X02;

TH0=156;

TL0=156;

ET0=1;

TR0=1;

EA=1;

/* 以上定义时间中断的参数,每100uS产生一次时间中断 */

ReadKey(); /*读键值*/

if(cKeyCode==kpSet)

{

for(i=0;i<MaxStatus;i++)

{

wParaValue=wParaConst;

WritePara(i);

}

}

/* 如果上电的时候按住SET键,将各个状态的时间参数置为系统默认值并存于X25045 */

for(i=0;i<MaxStatus;i++) ReadPara(i); /* X25045读出各个状态的时间参数 */

wClick=wParaValue[cCurrStatus]; /* 将系统时钟数设为当前状态的时间参数 */

for(;;)

{

ReadKey();

switch(cKeyCode)

{

case kpSet:

if(cCurrMode==mdReady)

{

cCurrMode=mdSet;

SETLAMP=ON;

break;

}

/* 如果当前工作模式是准备模式,按下SET键进入设置模式,并点亮设置指示灯 */

if(cCurrMode==mdSet)

{

cCurrMode=mdReady;

SETLAMP=OFF;

WritePara(cCurrStatus);

wClick=wParaValue[cCurrStatus];

}

break;

/* 如果当前模式是设置模式,按下SET键进入准备模式,熄灭指示灯,将设置号的时间参数存入X25045并赋值给系统时钟变量 */

case kpUp:

if(cCurrMode==mdReady)

{

if (cCurrStatus==MaxStatus-1) cCurrStatus=0;

else cCurrStatus++;

ReadPara(cCurrStatus);

}

/* 在准备模式下按UP键,从小到大循环查看各个状态的时间参数,对kpDown键的解释同理,不再赘述 */

if(cCurrMode==mdSet)

{

if(wParaValue[cCurrStatus]==wMaxValue[cCurrStatus]) wParaValue[cCurrStatus]=wMinValue[cCurrStatus];

else wParaValue[cCurrStatus]++;

}

wClick=wParaValue[cCurrStatus];

break;

/* 在设定模式下按UP键,增加当先状态的时间参数,并将当前状态的时间参数赋值给系统时钟变量 */

case kpDown:

if(cCurrMode==mdReady)

{

if(cCurrStatus==0) cCurrStatus=MaxStatus-1;

else cCurrStatus--;

ReadPara(cCurrStatus);

}

if(cCurrMode==mdSet)

{

if(wParaValue[cCurrStatus]==wMinValue[cCurrStatus]) wParaValue[cCurrStatus]=wMaxValue[cCurrStatus];

else wParaValue[cCurrStatus]--;

}

wClick=wParaValue[cCurrStatus];

break;

case kpStart:

if(cCurrMode|=mdWave)

{

wClick=wParaValue[cCurrStatus];

cCurrMode=mdWave;

dwWaveTime=KeyWave;

}

break;

/* 在非输出模式下按Start键,程序进入输出模式,将当前状态的时间参数赋值给系统时钟变量,将输出时长设定为60秒。下面的通过Port启动输出同理 */

case kpPort:

if(cCurrMode|=mdWave)

{

wClick=wParaValue[cCurrStatus];

cCurrMode=mdWave;

dwWaveTime=PortWave;

}

break;

default:

wKeyDelay=wKeyFastDelay;

wKeyFastDelay=KEYFASTDELAY;

break;

/* 无按键按下的时候,将键盘延时和键盘加速延时赋值 */

}

Display(wClick+(DWORD)cCurrStatus*10000);

/* 显示程序,左起第一位显示当前状态,后4位显示当前状态的脉冲宽度,WAVE灯显示电平的高低 */

for(;;)

{

rst_wdog (); /*喂狗程序*/

if(wKeyDelay==0)

{

if(wKeyFastDelay<100) wKeyFastDelay=100;

wKeyFastDelay-=100;

wKeyDelay=wKeyFastDelay;

break;

}

wKeyDelay--;

}

/* 以上程序完成键盘延时和键盘加速延时及喂狗等功能 */

}

}

/* 以上是主程序的全部内容,下面是本系统的子程序的全部代码,里面涉及了芯片的工作时序,特征字等内容,比较繁琐,编制和调试的时候要有很大的耐心,得拿着芯片的DATASHEET慢慢看慢慢写慢慢调,偷不得懒。一旦成型以后直接调用就可以了。有兴趣的可以看一下,不看也无所谓。 */

顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com
 楼主| 顶风 发表于 2006-2-15 19:29 | 显示全部楼层

void PutChar(BYTE cData)

{

BYTE i;

for(i=8;i>=1;i--)

{

DSP_DATA=cData&0x80;

cData<<=1;

DSP_CLK=0;

DSP_CLK=1;

}

}

void DIsplay(DWORD dwData)

{

WORD a;

BYTE i,j,k,b=0xD9; /* BLANK3,BLANK4灭零 */

a=dwData%10000;

if(a>99) b=0XD1; /* BLANK4灭零 */

if(a>999) b=0XC1; /* 不灭零 */

i=dwData%100;

i=i/10*16+i%10;

dwData/=100;

j=dwData%100;

j=j/10*16+j%10;

k=dwData/100; /* 10进制数转换成显示码 */

k+=0xA0; /* 小数点在BLANK2点亮 */

DSP_CS=ON;

PutChar(b);

DSP_CS=OFF;

DSP_CS=ON;

PutChar(k);

PutChar(j);

PutChar(i);

DSP_CS=OFF; /* 将显示码及小数点、灭零等数据传输至MC14489显示 */

if(cCurrStatus==1||cCurrStatus==3||cCurrStatus==5||cCurrStatus==7||cCurrStatus==9) WAVE=0;

else WAVE=1; /* LED指示灯显示 */

}

void ReadKey(void)

{

KEY_START=1;

KEY_SET =1;

KEY_UP =1;

KEY_DOWN =1;

PORT =1;

cKeyCode=kpNoKey;

if(KEY_SET==ON && KEY_UP==OFF && KEY_DOWN==OFF && KEY_START==OFF) cKeyCode=kpSet;

if(KEY_SET==OFF && KEY_UP==ON && KEY_DOWN==OFF && KEY_START==OFF) cKeyCode=kpUp;

if(KEY_SET==OFF && KEY_UP==OFF && KEY_DOWN==ON && KEY_START==OFF) cKeyCode=kpDown;

if(KEY_SET==OFF && KEY_UP==OFF && KEY_DOWN==OFF && KEY_START==ON) cKeyCode=kpStart;

if(PORT==ON) cKeyCode=kpPort;

}

void wren_cmd(void)

{

MEM_SCK=0;

MEM_CS=ON;

outbyte(WREN_INST);

MEM_SCK=0;

MEM_CS=OFF;

}

void wrsr_cmd(void)

{

MEM_SCK=0;

MEM_CS=ON;

outbyte(WRSR_INST);

outbyte(STATUS_REG);

MEM_SCK=0;

MEM_CS=OFF;

wip_poll();

}

BYTE rdsr_cmd (void)

{

BYTE cData;

MEM_SCK=0;

MEM_CS=ON;

outbyte(RDSR_INST);

cData=inbyte();

MEM_SCK=0;

MEM_CS=OFF;

return(cData);

}

void byte_write(BYTE cData,BYTE cAddress)

{

MEM_SCK=0;

MEM_CS=ON;

SPEAKER=ON;

outbyte(WRITE_INST);

outbyte(cAddress);

outbyte(cData);

MEM_SCK=0;

MEM_CS=OFF;

wip_poll();

SPEAKER=OFF;

}

BYTE byte_read(BYTE cAddress)

{

BYTE cData;

MEM_SCK=0;

MEM_CS=ON;

outbyte(READ_INST);

outbyte(cAddress);

cData=inbyte();

MEM_SCK=0;

MEM_CS=OFF;

return(cData);

}

void rst_wdog (void)

{

MEM_CS=ON;

MEM_CS=OFF;

}

void wip_poll(void)

{

BYTE i,cData;

for (i=0;i<MAX_POLL;i++)

{

cData=rdsr_cmd();

if ((cData&&0x01)==1) continue;

}

}

void outbyte(BYTE cData)

{

BYTE i;

for (i=8;i>=1;i--)

{

MEM_SCK=0;

MEM_SI=cData&0x80;

cData<<=1;

MEM_SCK=1;

}

MEM_SI=0;

}

BYTE inbyte(void)

{

BYTE cData,cTemp,i;

for (i=8;i>=1;i--)

{

cData<<=1;

MEM_SCK=1;

MEM_SCK=0;

cTemp=MEM_SO;

cData|=cTemp;

}

return (cData);

}

void ReadPara(BYTE cPara)

{

wParaValue[cPara]=byte_read(cPara*2)*128+byte_read(cPara*2+1);

}

void WritePara(BYTE cPara)

{

BYTE cData1,cData2;

cData1=wParaValue[cPara]/128;

cData2=wParaValue[cPara]%128;

wren_cmd();

byte_write(cData1,cPara*2);

wren_cmd();

byte_write(cData2,cPara*2+1);

}

最后编译完成了,目标代码0X7FC,距离0X7FF仅一步之遥,好险!!!

顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com
 楼主| 顶风 发表于 2006-2-15 19:30 | 显示全部楼层

终于把它完成了,多少有点成就感,但不大。下面想说说我对这个小东西的制作过程的一点点体会。

1. 编制程序是年轻人的事情,我现在已经36岁,思想保守,心态懒散,难以写出漂亮的代码。上面的程序中还有很多需要进行改进和值得商榷的地方,但由于懒惰,我放弃了。留待有兴趣的同仁来修改吧。

2. 但我认为我的程序还是有一些优点的:对整个程序的状态模式等划分得比较清晰合理;变量名起得让人望文生义,使用匈牙利标记法,使程序容易阅读和调试。有一些子程序无论是从时间效率还是空间效率上都是很不错的。

3. 单片机系统的程序需要和硬件打交道,所以在设计的过程中最好软硬兼施。硬件难以解决的地方用软件解决,软件不好完成的由硬件解决,这样系统比较匀称。看程序的时候最好对照着电路图看,否则很多地方会不知所云的。

4. 我想通过这个小系统让做维修的同行们对电子设备的软硬件开发过程有个粗略的了解,或许能在日后的工作中开阔视野启发思路。

5. 值得一题的是目前的单片机系统的开发过程已经发生了根本性的改变:32位单片机+RTOS逐渐成为主流,开发模式和方法特别是软件的开发方法完全不同了。这些我都未曾涉猎,时间精力金钱等方面的原因都有,从这方面讲,我已经落伍了。

虽然我没有说调试的问题,但调试对于电子产品的开发是一个非常重要的过程。

1. 也许是因为我画电路图和电路板的习惯比较好吧,这个小东西的电路没有出现任何问题,焊接好了就能用了,省却了我很多麻烦。这也是我本人所追求的目标之一:第一次就要做对。

2. 尽管我有仿真器,但我没有使用。一来程序很小,调试起来相对容易,二来我的仿真器的仿真软件不能脱机运行,使用不方便。我在网上下载了一个51的仿真环境。在这里面完成了调试的过程。然后将目标代码写入89C2051中,加电试验。发现问题再修改程序,再编译――烧录――加电试验。如此反复,直到程序运行正常。

3. 调试中有很多小技巧,需要在实践中不断的摸索积累。比如说:我没有示波器,难以验证100uS的脉冲时间是否正确。我就编制了一个测试程序,产生1000000个脉冲,这些脉冲开始发出和结束的时候用SPEAKER提示,我用秒表计算时间,以测试程序的时间精确性。这方面没有捷径可循。从这个方面来讲,程序一次写正确,没有任何错误,不需要调试未必就是一件好事了。

[此贴子已经被作者于2006-2-15 20:25:53编辑过]
顶风作品 QQ:50443527 TEL:13701010924 E-Mail:leehp@sohu.com http://www.yeec.com
郑振寰 发表于 2006-2-15 19:37 | 显示全部楼层

李工辛苦了,接下来就是如何应用这个设计进行血液分析仪的调试了,这个好像就是我的工作了,过几个月把使用方法和调试步骤以及图形发送上来大家分享一下。

 楼主| 顶风 发表于 2006-2-15 20:00 | 显示全部楼层

Protel99格式的文件,里面包括原理图、网络表、板图、源程序、目标代码(Intel HEX格式)
一个本科生可以拿去做个毕业设计了。


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
 楼主| 顶风 发表于 2006-2-22 22:30 | 显示全部楼层

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

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

本版积分规则

QQ|申请友链|手机版|小黑屋|加入QQ群|注销账号|yeec维修网

GMT+8, 2024-11-22 02:57 , Processed in 0.855621 second(s), 36 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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