|
这套测试器的软件、硬件全部是我一个人独力完成的。甚至电路图也是我画的。估计让不少人掉眼镜。
先声明一下: 目前邮购部的拆机件,均是使用这个测试器测试的。 我保证本资料100%的准确性。 这是第三个版本,修正了前面两个版本的一些缺陷,将我能想像到的IO检测都做在上面了。 它经过了近30K次的测试检验。
这台测试器,我原本是交给我们邮购部的两位技术人员制作的。但出来的样品让我失望+绝望。慢慢我意识到:我们要在AVR拆机件上走得更远,我需要投入更多的时间与精力去研究它。
呵呵,这个检测器,看来简单,但有些细节比较折磨人的耐性。就像电路图中的100K的电阻,没有做过的人,可能会就卡死在上面。如果你选择10K或大于470K,是做不出这个测试器的。 HC4066上的30只1K电阻,也是同样道理。使用其它的数值,就会导致高压编程接口不能正常工作。
这个电路的硬件设计,我花了大量的时间在兼容高压编程、ISP,JTAG 接口的测试与试验上。 它能兼容这三种接口,对我们的拆机件检测工作带来便利性。
(原文件名:01 全图.jpg)
(原文件名:02 侧面图.jpg)
(原文件名:03 底面全图.jpg)
(原文件名:04 HC4066部分.jpg)
(原文件名:05 IO引脚接地部分.jpg)
(原文件名:06 高压编程部分.jpg)
(原文件名:07 HC4066.jpg)
(原文件名:08 弹性测试座.jpg)
(原文件名:09 高压编程接口、复位开关、结果显示LED.jpg)
(原文件名:10 JTAG、ISP接口、电源.jpg)
(原文件名:11 局部放大图.jpg)
先用流程图表明我要做的检测思路:
(原文件名:流程图.jpg)
它使用我编写的DOS批处理,自动运行测试。每测试一片芯片约需要4-5秒时间:
(原文件名:SNAG-0001.jpg)
适用于网站生产的STK500下载器的自动检测批处理文件:
@echo off
rem Atmega-16的ID是0x-1e 0x-94 0x-03.ATemga-32的ID是0x-1e 0x-95 0x-02。缺省熔丝位均是-f0x99e1。
rem 测试IO扫描时的熔丝位均是:-f0xd9d4
rem 改成ATmega-32时,需要做以下的替换:
rem ATmega.16 -> ATmega.32
rem 0x.94 -> 0x.95
rem 0x.03 -> 0x.02
rem 16K -> 32K
rem M.16 -> M.32
@echo ****************** 本软件由阿莫编写 2008.06.17 ************
:start
@echo 请放入新的芯片(ATmega16 0x1e 0x94 0x03),即将进行第①个检查。
@echo 本检查包括:本检查包括:IO扫描,内核检查 (网站自制STK500下载器USB转串口)
pause
set second_1=%time:~6,2%
@echo 检查芯片的ID是否正确....
STK500 -dATmega16 -s -cCOM4 |findstr/i "0x1e.0x94.0x03" & if errorlevel 1 (goto error_s)
set second_2=%time:~6,2%
if second_2 GTR second_1 (set /a seconds=%second_2% - %second_1% ) else (set /a seconds=60+ %second_2% - %second_1% )
@echo 累计时间消耗:%seconds%秒
@echo --------------------------
@echo 设置成8M的工作频率 ...
STK500 -dATmega16 -cCOM4 -f0xd9d4 |findstr/i "failed" && goto error_f
set second_2=%time:~6,2%
if second_2 GTR second_1 (set /a seconds=%second_2% - %second_1% ) else (set /a seconds=60+ %second_2% - %second_1% )
@echo 累计时间消耗:%seconds%秒
@echo --------------------------
@echo 擦除芯片.....
STK500 -dATmega16 -cCOM4 -e | findstr/i "failed" && goto error_e
set second_2=%time:~6,2%
if second_2 GTR second_1 (set /a seconds=%second_2% - %second_1% ) else (set /a seconds=60+ %second_2% - %second_1% )
@echo 累计时间消耗:%seconds%秒
@echo --------------------------
@echo 正在写入IO扫描、内核检查程序......
STK500 -dATmega16 -cCOM4 -ifD:\AVR_test\M-16_M-32\default\M-16_M-32.hex -vf -pf | findstr/i "failed" && goto error_if
set second_2=%time:~6,2%
if second_2 GTR second_1 (set /a seconds=%second_2% - %second_1% ) else (set /a seconds=60+ %second_2% - %second_1% )
@echo 累计时间消耗:%seconds%秒
@echo --------------------------
@echo --------------------------------
@echo 写入IO扫描程序、内核检查程序成功。请观察约2秒后绿灯亮。
@echo 看到绿灯长亮,表示芯片合格。
@echo 绿灯闪,表示芯片不合格。
@echo 可按测试板上的蓝色圆形钮让测试程序重新运行 ---
@echo -----------------------------------------------------------------
@echo -----------------------------------------------------------------
goto start
:error_s
@echo ***********************************************************
@echo ***********************************************************
@echo *** 警告!!不正确的ATmega16 ID (Signature) 芯片不合格 ***
@echo *** 请留意测试板上的电源灯是否亮? ***
@echo ***********************************************************
goto start
:error_f
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!设置8M频率有错误,芯片不合格! *******
@echo ***********************************************************
goto start
:error_I
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!设置ISP 921.6KHz速度有错误,芯片不合格! ****
@echo ***********************************************************
goto start
:error_e
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!擦除芯片有错误,芯片不合格! ****
@echo ***********************************************************
goto start
:error_if
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!FLASH写入校验有错误,芯片不合格! ****
@echo ***********************************************************
goto start
:error_ie
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!eeprom 写入校验有错误,芯片不合格! ****
@echo ***********************************************************
goto start
:error_I_2
@echo ***********************************************************
@echo ***********************************************************
@echo ****** 警告!!设置ISP 230.4KHz速度有错误,芯片不合格! ****
@echo ***********************************************************
goto start
由于这台测试器,是根据我们的检测情况随时更改的,所以,使用手焊板的形式(参见上面的实物图)。
电路图的零件封装是自己根据实物做的。这个我们在焊接手工板时,不用查找数据手册,根据电路图就能直接焊出来。
(原文件名:mcu部分.jpg.jpg)
(原文件名:电源、复位、显示部分.jpg)
(原文件名:IO引脚、接地电阻部分.jpg)
(原文件名:HC4066部分.jpg)
点击此处下载完整版的PDF格式线路图 ourdev_322863.pdf(文件大小:40K) (原文件名:IO_SCAN.pdf)
完整的代码:
/******* *********************************************************************
*
* This file is used to test IO.
*
* - Compiler: GNU GCC
* - Supported devices: M16,M32
* - author Armok / www.OurAvr.com
*
* - Last updated 2008-06-05,14:11
*****************************************************************************/
#include <avr/io.h>
//宏定义管脚ID号
//进行如下分配:PA0~PA7:00~07,其中十位上是组号,个位上是管脚号
#define AVRPA0 00
#define AVRPA1 01
#define AVRPA2 02
#define AVRPA3 03
#define AVRPA4 04
#define AVRPA5 05
#define AVRPA6 06
#define AVRPA7 07
#define AVRPB0 10
#define AVRPB1 11
#define AVRPB2 12
#define AVRPB3 13
#define AVRPB4 14
#define AVRPB5 15
#define AVRPB6 16
#define AVRPB7 17
#define AVRPC0 20
#define AVRPC1 21
#define AVRPC2 22
#define AVRPC3 23
#define AVRPC4 24
#define AVRPC5 25
#define AVRPC6 26
#define AVRPC7 27
#define AVRPD0 30
#define AVRPD1 31
#define AVRPD2 32
#define AVRPD3 33
#define AVRPD4 34
#define AVRPD5 35
#define AVRPD6 36
#define AVRPD7 37
void delay_us(int time)
{
for(;time>1;time--);
}
void delay_ms(unsigned int time)
{
while(time!=0)
{
delay_us(884);
time--;
}
}
void green_led(void);
void red_led(void);
void delay_nop(void);
void IOSearch(unsigned char IOID[2],unsigned char IOresult[3]);//IO定位程序
void IOdetect(unsigned char IOaddr[3],unsigned char IOtestID0,unsigned char IOtestID1);//IO检测程序
void checkIO(unsigned char IO0,unsigned char IO1);//IO检测主函数
void CoreTest();
int main()
{
SFIOR&=~(1<<2); //SFIOR的PUD是0时,上拉电阻才有效。缺省是0。所以这句话可以不要的。
//PA,PB,PC,PD设置成输入,上拉电阻启用
DDRA=0x00;
PORTA=0xff;
DDRB=0x00;
PORTB=0xff;
DDRC=0x00;
PORTC=0xff;
DDRD=0x00;
PORTD=0xff;
DDRB|=0b11000000; //PB6是绿灯,长亮时表示正常,闪烁表示出错。PB7控制HC4066
PORTB&=0b00111111;
int reply_times = 3000;
while (reply_times>1)
{
checkIO(AVRPA0,AVRPA1);
checkIO(AVRPA2,AVRPA3);
checkIO(AVRPA4,AVRPA5);
checkIO(AVRPA6,AVRPA7);
checkIO(AVRPB0,AVRPB1);
checkIO(AVRPB2,AVRPB3);
checkIO(AVRPB4,AVRPB5);
//-----checkIO(AVRPB6,AVRPB7); //用于输出,6绿灯长亮时正常,闪时出错,7控制HC4066
checkIO(AVRPC0,AVRPC1);
checkIO(AVRPC2,AVRPC3); //jtag
checkIO(AVRPC4,AVRPC5); //jtag
checkIO(AVRPC6,AVRPC7);
checkIO(AVRPD0,AVRPD1);
checkIO(AVRPD2,AVRPD3);
checkIO(AVRPD4,AVRPD5);
checkIO(AVRPD6,AVRPD7);
reply_times --;
}
reply_times = 500;
while (reply_times>1)
{
reply_times --;
}
green_led();
}
void setHC4066(void)
{
PORTB|=(1<<7);
}
void clrHC4066(void)
{
PORTB&=~(1<<7);
}
void green_led(void)
{
PORTB|=(1<<6);
}
void red_led(void)
{
check_end:;
//PORTB|=(1<<7);
PORTB|=(1<<6);
delay_ms(20);
PORTB&=~(1<<6);
delay_ms(20);
PORTB|=(1<<6);
delay_ms(20);
PORTB&=~(1<<6);
delay_ms(20);
goto check_end;
}
//IO定位程序
/*
为了便于封装程序,操作IO采用地址传递的方式,但是首先需要对IO的组别(ABCD) 和管脚号(0~7)进行分类
在文件的宏定义中,我对M16的IO进行如下分配:PA0~PA7:00~07,其中十位上是组号,个位上是管脚号,通过
IOSearch函数来进行分类处理,输入为需要测试的两个IO号(这个值通过checkIO检测主函数传入) 并通过操作
IOresult数组将数据传出
*/
/*
传入:IOID[2]测试IO号
交换:IOresult[3]处理结果,IOresult[0]放组号,IOresult[1]放测试IO管脚号,IOresult[2]放另一个测试IO管脚号
*/
void IOSearch(unsigned char IOID[2],unsigned char IOresult[3])
{
IOresult[0] = IOID[0]/10; //取十位数,为组号
IOresult[1] = IOID[0]-(10*IOresult[0]);//取个位数,为测试IO管脚号
IOresult[2] = IOID[1]-(10*IOresult[0]);//取个位数,为另一个测试IO管脚号
}
/*
举例:
define AVRPD2 32
define AVRPD3 33
IOID[2]={32,33};
IOresult[0]=32/10=3
IOresult[1]=32-10*3 = 2;
IOresult[0]=33-10*3 = 3;
*/
//IO检测程序
/*
这个程序是实际操作检测的过程函数
检测过程请参考IO检测流程图
*/
/*
传入:unsigned char IOaddr[3] 测试IO组别的操作变量地址(DDRX PINX PORTX)
unsigned char IOtestID0,unsigned char IOtestID1 传入的两个测试管脚号
*/
void IOdetect(unsigned char IOaddr[3],unsigned char IOtestID0,unsigned char IOtestID1)
{
unsigned char *IODDRX = IOaddr[0];//通过指针将DDRX地址取出
unsigned char *IOPINX = IOaddr[1];//通过指针将PINX地址取出
unsigned char *IOPORTX = IOaddr[2];//通过指针将PORTX地址取出
void setDDRX(unsigned char IOtestID)//置位DDRX某一位,传入:unsigned char IOtestID 需要操作的管脚号
{
*IODDRX |= (1<<IOtestID);
}
void clrDDRX(unsigned char IOtestID)//清0 DDRX某一位,传入:unsigned char IOtestID 需要操作的管脚号
{
*IODDRX &= ~(1<<IOtestID);
}
void setPORTX(unsigned char IOtestID)//置位PORTX某一位,传入:unsigned char IOtestID 需要操作的管脚号
{
*IOPORTX |= (1<<IOtestID);
}
void clrPORTX(unsigned char IOtestID)//清0 PORTX某一位,传入:unsigned char IOtestID 需要操作的管脚号
{
*IOPORTX &= ~(1<<IOtestID);
}
//读测试IO某一位上的电平值
//传入:unsigned char IOtestID 需要操作的管脚号
//传出:测试IO的电平值
unsigned char ReadIO(unsigned char IOtestID)
{
return ((*IOPINX >> IOtestID)&0x01);
}
//检测过程请参考IO检测流程图
clrHC4066();
// PA0,PA1输入 PA0上拉电阻 PA1无上拉电阻. PA0=1, PA1=0
clrDDRX(IOtestID0);
clrDDRX(IOtestID1);
setPORTX(IOtestID0);
clrPORTX(IOtestID1);
delay_nop();
if ((ReadIO(IOtestID0) != 1) || (ReadIO(IOtestID1) != 0 )) red_led();
// PA0,PA1输入 PA0无上拉电阻 PA1上拉电阻. PA0=0, PA1=1
clrDDRX(IOtestID0);
clrDDRX(IOtestID1);
clrPORTX(IOtestID0);
setPORTX(IOtestID1);
delay_nop();
if ((ReadIO(IOtestID0) != 0)||(ReadIO(IOtestID1) != 1)) red_led();
setHC4066();
setDDRX(IOtestID0);
clrDDRX(IOtestID1);
setPORTX(IOtestID0);
clrPORTX(IOtestID1);
delay_nop();
if (ReadIO(IOtestID1) != 1) red_led();
setDDRX(IOtestID0);
clrDDRX(IOtestID1);
clrPORTX(IOtestID0);
setPORTX(IOtestID1);
delay_nop();
if (ReadIO(IOtestID1) != 0) red_led();
setDDRX(IOtestID1);
clrDDRX(IOtestID0);
setPORTX(IOtestID1);
clrPORTX(IOtestID0);
delay_nop();
if (ReadIO(IOtestID0) != 1) red_led();
setDDRX(IOtestID1);
clrDDRX(IOtestID0);
clrPORTX(IOtestID1);
setPORTX(IOtestID0);
delay_nop();
if (ReadIO(IOtestID0) != 0) red_led();
}
//IO检测主函数
/*
IO检测主函数,这个函数将完成所有的检测工作。
传入两个测试IO号,IO号在宏定义中命名,命名方式为:AVRPXY其中X为组号,Y为管脚号
*/
/*
传入unsigned char IO0,unsigned char IO1 两个测试管脚号
*/
void checkIO(unsigned char IO0,unsigned char IO1)
{
unsigned char IOaddr[4][3] = {{&DDRA,&PINA,&PORTA},{&DDRB,&PINB,&PORTB},{&DDRC,&PINC,&PORTC},{&DDRD,&PIND,&PORTD}};
//为了便于封装,使用了操作IO地址的方式,实际上DDRX之类的变量在头文件中也是操作地址,这个数组就是把所有的
//IO地址取出来便于传递和调用。
unsigned char IOID[2] = {IO0,IO1};//对传递进来的测试IO管脚号赋值给一个一维数组,便于操作
unsigned char IOtestID[3];//传递IO管脚参数的数组
IOSearch(IOID,IOtestID);//调用IO管脚定位程序
IOdetect(IOaddr[IOtestID[0]],IOtestID[1],IOtestID[2]);//IO检测程序
}
void delay_nop(void)
{
asm("nop");
asm("nop");
asm("nop");
}
void IOdetect2(int NO,unsigned int testimony[8])
{
unsigned int clew[2] = {0,0};
//showdata = NO;
delay_ms(1);
clew[0] = 1;
delay_ms(1);
clew[1] = 0;
testimony[NO] = ((clew[0]&0xff)&(~(clew[1]|0x00)));
testimony[NO] = testimony[NO];//showdata = 0x00;
}
unsigned int inquestOUTPUT(unsigned int testimony)
{
unsigned int confession = 0;
unsigned int result = 0;
confession = testimony;
for(int i = 0;i < 8;)
{
result = result + (confession&0b00000001);
confession = (confession >> 1);
i++;
}
return result;
}
unsigned int inquestINPUT(int NO,unsigned int testimony[8])
{
unsigned int confession[8] = {0,0,0,0,0,0,0,0};
unsigned int result = 0;
for(int i = 0;i < 8;)
{
confession = testimony;
confession = ((confession>> NO)&0b00000001);
result = result + confession;
i++;
}
return result;
}
unsigned int IOArbitrate(unsigned int testimony[8])
{
unsigned int judgement[8][2] = {{0,0,0,0,0,0,0,0},{0,0,0,0,0,0,0,0}};
unsigned int adjudgement = 0;
for(int i = 0;i < 8;)
{
judgement[0] = inquestOUTPUT(testimony);
judgement[1] = inquestINPUT(i,testimony);
i++;
}
for(int i = 8;i >= 0;i--)
{
adjudgement |=(1<<i);
}
return adjudgement;
}
void CoreTest()
{
unsigned int testimony[8];
unsigned int adjudgement;
while(1)
{
for(int j = 0;j < 8;)
{
IOdetect2((j),testimony);
j++;
}
adjudgement = IOArbitrate(testimony);
if(adjudgement == 0b111111111) green_led();
else red_led();
}
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)
|