 |
 單片機埠定義: 
|
 |
注意:本程序按GPL協議發布。 程序如下: 【ports.h】 #define K1 (PINB&BIT(0)) //id減1 #define K2 (PINB&BIT(1)) //id加1 #define K3 (PINB&BIT(2)) //ctrl鍵,同時按下k1或k2可以加/減25 #define K4 (PINB&BIT(3)) //開始/停止
#define INPUT (PIND&BIT(2)) //輸入的信號 PD2 #define HC595_SHCK1 PORTC|=BIT(0) #define HC595_SHCK0 PORTC&=~BIT(0) #define HC595_STCK1 PORTC|=BIT(1) #define HC595_STCK0 PORTC&=~BIT(1) #define HC595_SD1 PORTC|=BIT(2) #define HC595_SD0 PORTC&=~BIT(2)
#define LED1_ON PORTB&=~BIT(4) //L1表示埠檢測器是否正在工作 #define LED1_OFF PORTB|=BIT(4) #define LED2_ON PORTB&=~BIT(5) //L2表示當前埠是否是高電平 #define LED2_OFF PORTB|=BIT(5)
|
 |
【eeprom.c】 #include <iom8v.h> #include <macros.h> #include "eeprom.h"
void EEPROM_Write(unsigned int address, unsigned char Data) { while (EECR&BIT(EEWE)) //等待上一次寫操作結束 ; /*seg8_scan();*/ //如果程序中有數碼管,請去掉該注釋,避免寫入時數碼管熄滅或閃爍 EEAR=address; //可以直接對地址寄存器賦int值 EEDR=Data; EECR|=BIT(EEMWE); //主機寫入允許 EECR|=BIT(EEWE); //允許EEPROM }
void EEPROM_Read(unsigned int address, unsigned char* Data) { while (EECR&BIT(EEWE)) //等待上一次寫操作結束 ; /*seg8_scan();*/ //如果程序中有數碼管,請去掉該注釋,避免寫入時數碼管熄滅或閃爍 EEAR=address; EECR|=BIT(EERE); //啟動讀操作 *Data=EEDR; }
|
 |
【eeprom.h】 void EEPROM_Write(unsigned int address, unsigned char Data); void EEPROM_Read(unsigned int address, unsigned char* Data);
|
 |
【HC595.c】 #include <iom8v.h> #include <macros.h> #include "HC595.h" #include "ports.h"
void HC595_SerIn(unsigned char Data) { unsigned char i; for (i=0;i<8;i++) { HC595_SHCK0; //CLOCK_MAX=100MHz if (Data&BIT(7-i)) HC595_SD1; else HC595_SD0; HC595_SHCK1; } }
void HC595_ParOut(void) { HC595_STCK0; HC595_STCK1; }
|
 |
【HC595.h】 void HC595_SerIn(unsigned char Data); void HC595_ParOut(void);
|
 |
【PortChecker.c】 #include <iom8v.h> #include <macros.h> #include "HC595.h" #include "eeprom.h" #include "ports.h"
flash unsigned char seg8[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; unsigned int time[256]={0}; unsigned char port_states[32]={0xff};
int id=0; unsigned int num=0; unsigned char cfg=0x00; unsigned int length=1; unsigned int interval=0;
void delay250us(void) { unsigned int i; for (i=0;i<285;i++); }
void delay(unsigned int n) { unsigned int i; while (n--) for (i=0;i<1140;i++); }
//數碼管動態掃描 //參數n為掃描次數 void seg8_scan(unsigned char n) { unsigned char i; unsigned int f; unsigned char tmp; while (n--) { f=1000; //每次循環時f必須初始化 for (i=0;i<=2;i++) { tmp=~seg8[id%f/(f/10)]; if (i==2) tmp|=BIT(7); //小數點 HC595_SerIn(BIT(i)); HC595_SerIn(tmp); HC595_ParOut(); delay250us(); f/=10; }
f=10000; for (i=3;i<=6;i++) { tmp=~seg8[num%f/(f/10)]; if ((cfg&0x03)+0x03==i) tmp|=BIT(7); HC595_SerIn(BIT(i)); HC595_SerIn(tmp); HC595_ParOut(); delay250us(); f/=10; } } }
//存儲數據到EEPROM中 void savedata(void) { unsigned char i; for (i=0;i<240;i++) //只存儲前240個數據,占用空間480位元組 { EEPROM_Write(i*2,time[i]/256); EEPROM_Write(i*2+1,time[i]%256); }
//寫入高低電平標識,占用30位元組 for (i=0;i<30;i++) EEPROM_Write(0x1e0+i,port_states[i]); //寫入長度 if (length>240) i=240; else { i=length%256; if (i<1) i=1; } EEPROM_Write(0x1fe,0x3d); //倒數第二位為是否有數據的標識 EEPROM_Write(0x1ff,i); //最後一位表示長度 }
//停止鍵的檢測 unsigned char stop_working(void) { if (!K4) { while (!K4); return 0x80; } else return 0x00; }
//禁用數碼管 void disable_seg8(void) { HC595_SerIn(0x7f); //七個數碼管全部顯示 HC595_SerIn(0x40); //字符「-」 HC595_ParOut(); }
//核心函數: //給輸入端的高低電平計時 void work(void) { unsigned int i; unsigned char low; disable_seg8(); TIMSK&=~BIT(TOIE0); //禁止定時器0中斷 LED1_ON; LED2_OFF; for (length=1;length<=256;length++) { TCNT1H=0x00; TCNT1L=0x00; if (INPUT) { cfg|=BIT(2); //倒數第3位表示當前檢測的是什麼電平 while (INPUT) { if (stop_working()==0x80) { cfg|=BIT(3); break; } } } else { cfg&=~BIT(2); while (!INPUT) { if (stop_working()==0x80) { cfg|=BIT(3); break; } } }
//記錄時間(us) low=TCNT1L; //先讀取一次低八位 time[length-1]=TCNT1H; time[length-1]*=256; time[length-1]+=low;
//記錄電平 if (cfg&BIT(2)) port_states[(length-1)/8]|=BIT((length-1)%8); else port_states[(length-1)/8]&=~BIT((length-1)%8);
if (stop_working()==0x80) break; if (cfg&BIT(3)) { cfg&=~BIT(3); break; } } LED1_OFF; length--; savedata(); TIMSK|=BIT(TOIE0); //允許定時器0中斷 }
//顯示時間和電平 void gettime(void) { num=time[id]; if (num>9999) { num/=10; cfg&=~BIT(1); //小數點位置 cfg|=BIT(0); //65.46ms } else { cfg&=~BIT(1); cfg&=~BIT(0); //7.000ms } if (port_states[id/8]&BIT(id%8)) LED2_ON; else LED2_OFF; interval=0; //防止再次自動跳變 }
//按鍵掃描 void key_scan(void) { //減1、25 if (!K1) { seg8_scan(5); //防止按下按鍵後數碼管熄滅 if (!K1) { if (!K3) { if (id>=25) id-=25; } else { id--; if (id<0) id=length-1; }
gettime(); while (!K1) seg8_scan(1); seg8_scan(3); } } //加1、25 if (!K2) { seg8_scan(5); if (!K2) { if (!K3) { if (id+25<=length-1) id+=25; } else { id++; if (id>=length) id=0; }
gettime(); while (!K2) seg8_scan(1); seg8_scan(3); } }
if (!K4) { while (!K4) seg8_scan(1); work(); id=1; //完畢後自動顯示第2個時間值,通常情況下採集到的第一個和最後一個時間值很不準確 if (length<=1 || length>300) { id=0; length=1; } gettime(); } }
//讀取數據 void readdata(void) { unsigned char i; unsigned char l,h; EEPROM_Read(0x1fe,&i); //讀標誌位 if (i==0x3d) { //如果已存儲了數據,則讀出來 EEPROM_Read(0x1ff,&l); //獲取數據長度 length=l; for (i=0;i<240;i++) { EEPROM_Read(i*2,&h); EEPROM_Read(i*2+1,&l); time[i]=h*256+l; } //讀高低電平標識 for (i=0;i<30;i++) EEPROM_Read(0x1e0+i,&port_states[i]); if (length>=2) id=1; gettime(); } }
void main(void) { DDRC=0xff; PORTC=0xff; DDRB=0xf0; //PB口低四位為按鍵 PORTB=0xff; DDRD=0xf3; //兩個外中斷口設為輸入 PORTD=0xff;
TCCR1A=0x00; TCCR1B=0x02; //定時器1設為8分頻,也就相當於51單片機接12M晶振 readdata();
TCNT0=0x06; //定時器0定時32ms TCCR0=0x05; //定時器0設為1024分頻 TIMSK|=BIT(TOIE0); //允許定時器0中斷 SEI();
while (1) { seg8_scan(1); key_scan(); } }
//自動跳變 #pragma interrupt_handler et0:iv_TIM0_OVF void et0(void) { if (length>1) { interval++; if (interval>=1000) //定時32s { id++; if (id>=length) id=0; gettime(); } } TCNT0=0x06; }

|
 |
10樓
巨大八爪鱼
2014-9-30 23:28
使用時按下K4鍵開始捕捉或停止捕捉, 完畢後用ISP口連接電路板和電腦,打開AVR Fighter,通過ISP口讀取EEPROM數據並保存為bin文件,再用php程序就能生成一張波形圖了!
|