目前共有45篇帖子。
【單片機程序】AVRMega8製作的簡易示波器(只能檢測高低電平)
1樓 巨大八爪鱼 2014-9-30 23:17


單片機埠定義:


2樓 巨大八爪鱼 2014-9-30 23:19






3樓 巨大八爪鱼 2014-9-30 23:20



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程序就能生成一張波形圖了!

回復帖子

內容:
用戶名: 您目前是匿名發表
驗證碼:
 
 
©2010-2024 Arslanbar [手機版] [桌面版]
除非另有聲明,本站採用創用CC姓名標示-相同方式分享 3.0 Unported許可協議進行許可。