|  | 
          1楼
          巨大八爪鱼
          2014-9-30 23:17
          
          
             单片机端口定义:   | 
    
      |  | 
          4楼
          巨大八爪鱼
          2014-9-30 23:21
          
          
            注意:本程序按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)
 
   | 
    
      |  | 
          5楼
          巨大八爪鱼
          2014-9-30 23:22
          
          
            【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;
 }
 
   | 
    
      |  | 
          6楼
          巨大八爪鱼
          2014-9-30 23:24
          
          
            【eeprom.h】void EEPROM_Write(unsigned int address, unsigned char Data);
 void EEPROM_Read(unsigned int address, unsigned char* Data);
 
   | 
    
      |  | 
          7楼
          巨大八爪鱼
          2014-9-30 23:25
          
          
            【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;
 }
 
   | 
    
      |  | 
          8楼
          巨大八爪鱼
          2014-9-30 23:25
          
          
            【HC595.h】void HC595_SerIn(unsigned char Data);
 void HC595_ParOut(void);
 
   | 
    
      |  | 
          9楼
          巨大八爪鱼
          2014-9-30 23:26
          
          
            【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程序就能生成一张波形图了!
 
   |