這是發(fā)布在Hackster.io上的一個(gè)項(xiàng)目,作者為John Bradnam,一個(gè)很小的分析儀能分析CMOS和TTL電路,能夠測(cè)量5種狀態(tài),檢測(cè)脈沖并針對(duì)不同的狀態(tài)播放不同的聲音。
國(guó)外的玩家沒(méi)有我們方便,做個(gè)PCB是件很折騰的事情,因此簡(jiǎn)單的電路都要想辦法手工打造。
下面就是這個(gè)項(xiàng)目的簡(jiǎn)單介紹:
在此之前,作者嘗試做過(guò)多種不同的邏輯分析探針,看下圖是作者多年來(lái)設(shè)計(jì)的一些作品:
作者認(rèn)為應(yīng)該設(shè)計(jì)一款終極的邏輯探針,具有如下的一些特點(diǎn):
它必須足夠小以方便拿在手中
能夠顯示低、高和不關(guān)心的狀態(tài)
一個(gè)顯示系統(tǒng),在使用時(shí)易于閱讀
對(duì)“低”和“高”狀態(tài)有聲音反饋
處理不同邏輯系列的器件,例如:TTL 和 CMOS
能夠檢測(cè)探頭是否正在測(cè)量快速變化的信號(hào)
具有針對(duì)意外過(guò)電壓的輸入保護(hù)
硬件的設(shè)計(jì)
采用了ATtiny1614位微處理器,通過(guò)一個(gè)7段數(shù)碼管進(jìn)行顯示測(cè)量的電壓,并驅(qū)動(dòng)一個(gè)揚(yáng)聲器發(fā)出聲音,輕觸開(kāi)關(guān)切換不同的邏輯系列,一個(gè)3.3V的穩(wěn)壓器給微處理器提供電源,原理圖見(jiàn)下(使用Eagle繪制)
這個(gè)設(shè)計(jì)中用到的器件主要有:
微芯科技 ATtiny1614 | x1 |
TSS-307EWA 7-Seg 0.36in CC 顯示器 | x1 |
LM1117-33 3.3V 穩(wěn)壓器(SOT-223封裝) | x1 |
C&K 開(kāi)關(guān) PTS 645 系列開(kāi)關(guān)(6mm軸) | x1 |
SMT-916喇叭 | x1 |
3.6V 400mW 齊納二極管(SOD80C 封裝) | x2 |
1N4007 – 高電壓、高額定電流二極管(SOD-123 包裝) | x2 |
無(wú)源元件:5 個(gè) 180R 0805、1 個(gè) 91R 0805、2 個(gè) 1K 0805、2 個(gè) 3K 0805、1 個(gè) 15K 0805 電阻器;2 x 0.1uF 0805, 1 x 10uF 0805, 1 x 100uF/10V 7343 電容器 |
作者制作了一個(gè)PCB,單面板,主要器件都是表面貼裝的。7段數(shù)碼管和電路板成直角安裝。
該探針是高度可以配置的,允許添加其它的邏輯系列器件,見(jiàn)下面程序中的截圖部分:
下面是制作的PCB,在國(guó)外制作PCB還是很不方便的。
將縫衣針綁上做探針:
焊上7段數(shù)碼管:
裝上開(kāi)關(guān)和電源連線:
作者用一個(gè)Arduino Nano來(lái)對(duì)其進(jìn)行編程:
使用Arduino的IDE:
下面是這個(gè)邏輯分析探針的代碼:
/************************************************************************** ATtiny1614 Logic Probe Schematic & PCB at https://www.hackster.io/john-bradnam/contact-digital-thermometer-ed18d2 2021-08-10 John Bradnam (jbrad2089@gmail.com) Create program for ATtiny1614 -------------------------------------------------------------------------- Arduino IDE: -------------------------------------------------------------------------- BOARD: ATtiny1614/1604/814/804/414/404/214/204 Chip: ATtiny1614 Clock Speed: 20MHz millis()/micros(): "Enabled (default timer)" Programmer: jtag2updi (megaTinyCore) ATTiny1614 Pins mapped to Ardunio Pins +--------+ VCC + 1 14 + GND (SS) 0 PA4 + 2 13 + PA3 10 (SCK) 1 PA5 + 3 12 + PA2 9 (MISO) (DAC) 2 PA6 + 4 11 + PA1 8 (MOSI) 3 PA7 + 5 10 + PA0 11 (UPDI) (RXD) 4 PB3 + 6 9 + PB0 7 (SCL) (TXD) 5 PB2 + 7 8 + PB1 6 (SDA) +--------+ **************************************************************************/ //Debug mode will use the TX pin to send serial messages. As this is also used//for Segment A, the display is disabled when DEBUG mode is enabled//#define DEBUG //Display Pins#define A_PIN 5 //PB2#define B_PIN 4 //PB3#define C_PIN 3 //PA7#define D_PIN 0 //PA4#define EF_PIN 1 //PA5#define G_PIN 2 //PA6 //Inputs#define VIN_PIN 9 //PA2#define PROBE_PIN 8 //PA1#define MODE_PIN 10 //PA3 #define ADC_PROBE ADC_MUXPOS_AIN1_gc#define ADC_VIN ADC_MUXPOS_AIN2_gc //Outputs#define SPKR_PIN 6 //PB1 //Frequency for different states#define VDD_TONE 1760#define HIGH_TONE 880#define LOW_TONE 220#define GND_TONE 110#define BTN_TONE 440 //Pin and mask mapping tabletypedef struct { int8_t pin; int8_t mask;} SEG; #define SEG_COUNT 6SEG segments[] = { {A_PIN, B00000001}, {B_PIN, B00000010}, {C_PIN, B00000100}, {D_PIN, B00001000}, {EF_PIN, B00010000}, {G_PIN, B00100000}}; //Character set#define CHAR_COUNT 10#define CHAR_SPACE 0#define CHAR_VDD 1#define CHAR_HIGH 2#define CHAR_FLOAT 3#define CHAR_LOW 4#define CHAR_GND 5#define CHAR_PULSE 6#define CHAR_CMOS 7#define CHAR_TTL 8#define CHAR_LS 9 uint8_t charset[] = { B00000000, //CHAR_SPACE B00000001, //CHAR_VDD B00000110, //CHAR_HIGH B00100000, //CHAR_FLOAT B00011111, //CHAR_LOW B00001000, //CHAR_GND B00110011, //CHAR_PULSE B00011001, //CHAR_CMOS B00111000, //CHAR_TTL B00011000 //CHAR_LS}; char debugset[] = { ' ', //CHAR_SPACE '+', //CHAR_VDD '1', //CHAR_HIGH '?', //CHAR_FLOAT '0', //CHAR_LOW '-', //CHAR_GND 'P', //CHAR_PULSE 'C', //CHAR_CMOS 'T', //CHAR_TTL 'L' //CHAR_LS}; typedef struct { float low; //Maximum voltage a LOW state can be (fixed voltage) float high; //Minumum voltage a HIGH state can be as a percentage of VDD uint8_t chr; //Character to display for this family} FAMILY; //This table defines the voltage levels for each family that the probe can measure#define NUMBER_OF_FAMILIES 3FAMILY families[NUMBER_OF_FAMILIES] = { {0.8,80,CHAR_CMOS}, //CMOS family with tones {0.4,48,CHAR_TTL}, //0.4, 2.4 (1987 - National LS S TTL Logic Databook) {0.5,54,CHAR_LS} //0.5, 2.7 (1987 - National LS S TTL Logic Databook)}; enum STATES { STATE_UNKNOWN, STATE_VDD, STATE_HIGH, STATE_FLOAT, STATE_LOW, STATE_GND, STATE_PULSE }; #define PULSE_PERIOD 100 //Maximum time between state changes to be detected as a pulse (1/2 the period => 5Hz) uint8_t activeFamily = 0; //Current chip family being testedSTATES lastState = STATE_UNKNOWN; //Last state measuredSTATES activeState = STATE_UNKNOWN; //Current state at probefloat supplyVoltage = 0; //VDD from 3V3 regulatorfloat probeVoltage = 0; //Last reading from probefloat vinVoltage = 0; //Last reading from VINlong pulseTimeout = 0; //Timer used to measure pulsesbool waitingOnChange = false; //Enabled when waiting on pulseTimeoutbool soundEnabled = false; //Whether tones are played for the states //-------------------------------------------------------------------------// Initialise Hardwarevoid setup(void){ for (int i = 0; i < SEG_COUNT; i++) { pinMode(segments[i].pin, OUTPUT); digitalWrite(segments[i].pin, LOW); } #ifdef DEBUG Serial.begin(115200); #endif pinMode(VIN_PIN, INPUT); pinMode(PROBE_PIN, INPUT); pinMode(MODE_PIN, INPUT_PULLUP); pinMode(SPKR_PIN, OUTPUT); //Setup ADC VREF.CTRLA = VREF_ADC0REFSEL_1V1_gc; ADC0.CTRLC = ADC_REFSEL_VDDREF_gc | ADC_PRESC_DIV256_gc; // 78kHz clock ADC0.CTRLA = ADC_ENABLE_bm; // Single, 10-bit measureSupplyVoltage();} //--------------------------------------------------------------------// Main program loopvoid loop(void){ if (buttonPressed()) { activeFamily++; if (activeFamily == NUMBER_OF_FAMILIES) { activeFamily = 0; soundEnabled = !soundEnabled; //Turn/off audio } showChar(families[activeFamily].chr); noTone(SPKR_PIN); if (soundEnabled) { tone(SPKR_PIN, BTN_TONE); } waitForButtonRelease(); noTone(SPKR_PIN); //Force an update waitingOnChange = false; lastState = STATE_UNKNOWN; } testProbe();} //--------------------------------------------------------------------// Test if button pressedbool buttonPressed(){ bool result = false; if (digitalRead(MODE_PIN) == LOW) { delay(10); //Debounce return (digitalRead(MODE_PIN) == LOW); } return result;} //--------------------------------------------------------------------// Wait until the button is releasedvoid waitForButtonRelease(){ while (digitalRead(MODE_PIN) == LOW) ;} //--------------------------------------------------------------------// Measure the voltages and dislay the results if changedvoid testProbe(){ //Voltages are feed through divide by 4 resistor voltage converter //so they need to multiplied by 4. probeVoltage = measureVoltage(ADC_PROBE) * 4; vinVoltage = measureVoltage(ADC_VIN) * 4; //Calculate HIGH and VDD thresholds from VIN voltage float vdd = vinVoltage - 0.1; float high = families[activeFamily].high * vinVoltage / 100; bool pulse = false; //Workout state if (probeVoltage < 0.1) { activeState = STATE_GND; } else if (probeVoltage <= families[activeFamily].low) { activeState = STATE_LOW; } else if (probeVoltage < high) { activeState = STATE_FLOAT; } else if (probeVoltage <= vdd) { activeState = STATE_HIGH; } else { activeState = STATE_VDD; } if (activeState != lastState) //Only do something if state changes { #ifdef DEBUG Serial.println("p=" + String(probeVoltage) + ", vin=" + String(vinVoltage) + ", vdd=" + String(supplyVoltage)); delay(200); #endif if ((activeState == STATE_HIGH) ^ (lastState == STATE_HIGH)) //Change in state from either LOW to HIGH or HIGH to LOW { pulse = (waitingOnChange && millis() < pulseTimeout); //If state change within PULSE_PERIOD signal it as a pulse pulseTimeout = millis() + PULSE_PERIOD; //Set next timeout waitingOnChange = true; //and signal we are waiting on a state change } else { //This isn't a pulse waitingOnChange = false; pulse = false; } //Turn off any sound from the last state noTone(SPKR_PIN); //Show the result int chr = (pulse) ? CHAR_PULSE : (uint8_t)activeState; showChar(chr); if (soundEnabled) //Play sound if enabled { switch(chr) { case CHAR_VDD: tone(SPKR_PIN, VDD_TONE); break; case CHAR_HIGH: tone(SPKR_PIN, HIGH_TONE); break; case CHAR_LOW: tone(SPKR_PIN, LOW_TONE); break; case CHAR_GND: tone(SPKR_PIN, GND_TONE); break; } } //Record last state lastState = activeState; }} //--------------------------------------------------------------------// Display character on 7 segment display// chr - character to show (0 <= chr < CHAR_COUNT)void showChar(uint8_t chr){ if (chr < CHAR_COUNT) { #ifdef DEBUG Serial.println(debugset[chr]); #else uint8_t mask = charset[chr]; for (int i = 0; i < SEG_COUNT; i++) { digitalWrite(segments[i].pin, (mask & segments[i].mask) ? HIGH : LOW); } #endif } } //--------------------------------------------------------------------------// Measure supply voltage// Source: David Johnson-Davies - www.technoblogy.com - 13th April 2021void measureSupplyVoltage() { ADC0.MUXPOS = ADC_MUXPOS_INTREF_gc; // Measure INTREF ADC0.COMMAND = ADC_STCONV_bm; // Start conversion while (ADC0.COMMAND & ADC_STCONV_bm); // Wait for completion uint16_t adc_reading = ADC0.RES; // ADC conversion result supplyVoltage = 1126.4 / adc_reading;} //--------------------------------------------------------------------------// Measure voltage of a given pin// adcMux - ADC_Ax constant for the pin to measurefloat measureVoltage(uint8_t adcMux) { ADC0.MUXPOS = adcMux; // Measure Analog pin ADC0.COMMAND = ADC_STCONV_bm; // Start conversion while (ADC0.COMMAND & ADC_STCONV_bm); // Wait for completion uint16_t adc_reading = ADC0.RES; // ADC conversion result return supplyVoltage * adc_reading / 1024;}
編輯:jq
-
CMOS
+關(guān)注
關(guān)注
58文章
5731瀏覽量
235826 -
pcb
+關(guān)注
關(guān)注
4324文章
23147瀏覽量
399038 -
穩(wěn)壓器
+關(guān)注
關(guān)注
24文章
4254瀏覽量
94002 -
TTL
+關(guān)注
關(guān)注
7文章
504瀏覽量
70339
原文標(biāo)題:手工打造的邏輯分析探頭
文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開(kāi)發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論