|
注:ouravr.com 内部独家资料,不允许转载,不允许应用于商业用途。
我写软件,习惯先规划好流程图,然后才动手的 :)
我们的拆机AVR芯片,均是经过以下的IO端口扫描程序,检查至少2000次后,才出货,以确保我们的拆机AVR芯片能有100%的合格率。
检查的思路,是将JTAG的熔丝位取消,将PB6作为检查正常的输出(绿灯),PB7作为出错的红灯及蜂鸣器长响输出。
将两个两个IO组成一组。并且以270K电阻接地。 然后两只IO连接在一起(中间各用1K的电阻隔离)。
开始均作为输入,使用上拉电阻编程与接地电阻,产生0、1状态,自己读自己的输入是否正常。
然后一个作为输入,另一个作为输出,以上拉电阻编程与接地电阻,分别读取0,1。
然后换成一个作为输出,另一个作为输入,以上拉电阻编程与接地电阻,分别读取0,1。
以上的过程重复2000次。
如果全部执行通过,绿灯闪两下后就长亮。
如果执行过程中有任何出错,立即停止运行,红灯亮并且发出声音报警。
本程序经过了长时间及超过10K芯片的检测,证实性能可靠稳定。
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红灯
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);
(原文件名:1.JPG)
(原文件名:2.jpg)
(原文件名:SNAG-0031.jpg)
/******* *********************************************************************
*
* This file is used to test IO.
*
* - Compiler: GNU GCC
* - Supported devices: M16,M32
* - author Armok / www.OurAvr.com / 鸣谢kingofkings网友帮忙做了函数封装的工作
*
* - 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是红灯,先将灯熄灭
//PORTB|=0B11000000;
//delay_ms(100);
PORTB&=0b00111111;
int reply_times = 2000; //检测次数
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红灯
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 --;
}
//全部执行完成,绿灯,指示正常。
green_led();
delay_ms(500);
PORTB&=~(1<<6);
delay_ms(500);
green_led();
delay_ms(500);
PORTB&=~(1<<6);
delay_ms(500);
//green_led();
//delay_ms(500);
//PORTB&=~(1<<6);
//delay_ms(500);
}
void green_led(void)
{
PORTB|=(1<<6);
}
void red_led(void)
{
PORTB|=(1<<7);
check_end:;
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检测流程图
clrDDRX(IOtestID0);
clrDDRX(IOtestID1);
clrPORTX(IOtestID0);
clrPORTX(IOtestID1);
delay_nop();
if ((ReadIO(IOtestID0) != 0)&&(ReadIO(IOtestID1) != 0)) red_led();
else if((ReadIO(IOtestID0) == 0)&&(ReadIO(IOtestID1) != 0)) red_led();
else if((ReadIO(IOtestID0) != 0)&&(ReadIO(IOtestID1) == 0)) red_led();
clrDDRX(IOtestID0);
clrDDRX(IOtestID1);
setPORTX(IOtestID0);
setPORTX(IOtestID1);
delay_nop();
if ((ReadIO(IOtestID0) != 1)&&(ReadIO(IOtestID1) != 1)) red_led();
else if ((ReadIO(IOtestID0) == 1)&&(ReadIO(IOtestID1) != 1)) red_led();
else if ((ReadIO(IOtestID0) != 1)&&(ReadIO(IOtestID1) == 1)) red_led();
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();
//green_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");
} |
|