; ; ; definitions ; .include "tn13def.inc" .equ txpin = PB1 ; serial transmit pin .equ ledpin = PB4 ; serial transmit pin .def sentByte = R12 .def lastByte = R13 .def debugCounter = R14 .def doublecount = R15 .def count = R16 .def temp = R17 ; temporary storage .def temp1 = R18 ; temporary storage .def lowByte = R19 .def highByte = R20 .def byte = R21 .def clickdelay = R22 .def tripledelay = R23 .def bitcount = R24 .def sum1Low = R25 .def sum1High = R26 .def sum2Low = R27 .def sum2High = R28 .def waveCounter = R29 .def wavesCounter = R30 .def bitStatus = R31 ;bits in bitStatus ;store lots of data that is true/false as bits in this one register .equ normalWaveBit = 0 .equ normalWaveBitEOR = 0b01 .equ offsetWaveBit = 1 .equ offsetWaveBitEOR = 0b10 .equ captureDoneBit = 2 .equ captureDoneBitEOR = 0b100 .equ isAudioBit = 3 .equ isAudioBitEOR = 0b1000 .equ audioNotedBit = 4 .equ audioNotedBitEOR = 0b10000 .equ waveLength = 4 .equ wavesCount = 20 .equ offsetWaveToggleAt = 2 .equ zeroHighByteForSum = 0b00100000 .equ thresholdHigh = 0b00000000 .equ thresholdLow = 0b00100000 .equ MAX_BYTE = 32 ; ; start of code ; .cseg .org 0 rjmp reset ; jump to reset routine ; ; process new AD data in lowByte, highByte ; processing means maintaining information about where in the square wave we are, then multiplying the new audio by that. ; and adding it to a sum. ; when enough audio is received, we set the captureDoneBit to notify other functions to process the sum ; processNewAD: cpi waveCounter, offsetWaveToggleAt brne DontToggleOffsetWave ;done with offset wave, toggle ldi temp, offsetWaveBitEOR eor bitStatus, temp DontToggleOffsetWave: cpi waveCounter, waveLength brne DontResetWaveCounter ;done with normalwave, toggle cpi wavesCounter, wavesCount brne DontOutputYet ;done with all waves, output sbr bitStatus, captureDoneBitEOR ldi wavesCounter, 0 DontOutputYet: inc wavesCounter ldi temp, normalWaveBitEOR eor bitStatus, temp ldi waveCounter, 0 DontResetWaveCounter: inc waveCounter sbrs bitStatus, normalWaveBit ;skip if square top rjmp NormalSub ;not set, we are in square bottom rjmp NormalAdd ;square top DoneNormalWave: sbrs bitStatus, offsetWaveBit ;skip if square top rjmp OffsetSub ;not set, we are in square bottom rjmp OffsetAdd ;square top DoneOffsetWave: ret NormalAdd: add sum1Low, lowByte adc sum1High, highByte rjmp DoneNormalWave NormalSub: sub sum1Low, lowByte sbc sum1High, highByte rjmp DoneNormalWave OffsetAdd: add sum2Low, lowByte adc sum2High, highByte rjmp DoneOffsetWave OffsetSub: sub sum2Low, lowByte sbc sum2High, highByte rjmp DoneOffsetWave ; ; getclick ; input an I0 byte following first click ; modified from the dc-power example, calls to read from the input pin are replaced with calls to updateClickStatus, ; and a check on whether the "isAudioBit" is set - this is set if there is new audio, ie a click ; getclick: clr clickdelay ;sbi PORTB, ledpin start1: rcall updateClickStatus sbrs bitStatus, isAudioBit rjmp start1 ;reset isAudio cbr bitStatus, isAudioBitEOR ;sbi PORTB, ledpin ; ; find click delay from arrival of second start click ; start2: inc clickdelay breq getclicktimeout ; time-out if count overflows rcall updateClickStatus sbrs bitStatus, isAudioBit rjmp start2 cbr bitStatus, isAudioBitEOR mov tripledelay, clickdelay add tripledelay, clickdelay add tripledelay, clickdelay ; ; decode data clicks ; clr byte ldi bitcount, 8 bitloop: ;sbi PORTB, ledpin ; ; time arrival of next click ; clr count cbr bitStatus, isAudioBitEOR bitclickloop: inc count breq getclicktimeout ; time-out if count overflows rcall updateClickStatus sbrs bitStatus, isAudioBit rjmp bitclickloop ; ; determine bit delay ; mov doublecount, count add doublecount, count cp doublecount, tripledelay brsh zero ; ; one bit ; ;cbi PORTB, ledpin sec ; set carry ror byte ; shift in carry ; ; even out timing with click delay ; mov count, clickdelay onedelay: nop ; time for breq nop ; time for sbis rcall updateClickStatus dec count brne onedelay dec bitcount brne bitloop ; output if byte received rjmp getclickend zero: ; ; zero bit ; ;sbi PORTB, ledpin clc ; clear carry ror byte ; shift in carry dec bitcount brne bitloop ; output if byte received getclickend: mov lastByte, byte ret getclicktimeout: ;cbi PORTB, ledpin mov byte, lastByte ;rcall lightPinOn ret ; ; misnamed - this is called when we have accumulated enough audio data to determine if our signal ; frequency is present. ; ; if it is, and it is the first we have seen of it, set the isAudio bit. ; if it is, but we have already set the isAudioBit and there has been no silence since then, don't need to do anything ; - is is just he same burst continuing. ; ; if there is silence, reset our state so we are ready to set isAudio on the next signal ; outputNow: cbr bitStatus, captureDoneBitEOR ;reset output bit cpi sum1High, zeroHighByteForSum brsh NormalPositive ;Normal Negative ldi temp1, zeroHighByteForSum ldi temp, 0 sub temp, sum1Low sbc temp1, sum1High mov sum1Low, temp mov sum1High, temp1 rjmp DoneNormalSub NormalPositive: subi sum1High, zeroHighByteForSum rjmp DoneNormalSub DoneNormalSub: cpi sum2High, zeroHighByteForSum brsh OffsetPositive ;Offset Negative ldi temp1, zeroHighByteForSum ldi temp, 0 sub temp, sum2Low sbc temp1, sum2High mov sum2Low, temp mov sum2High, temp1 rjmp DoneOffsetSub OffsetPositive: subi sum2High, zeroHighByteForSum rjmp DoneOffsetSub DoneOffsetSub: cp sum2High, sum1High brlo CheckThreshold ; sum2 is same or higher breq CheckLoS ; sum2 higher mov sum1Low, sum2Low mov sum1High, sum2High rjmp CheckThreshold CheckLoS: ;high is equal cp sum2Low, sum1Low brlo CheckThreshold ;2 is lower, done mov sum1Low, sum2Low ;2 is not lower, copy then done. rjmp CheckThreshold CheckThreshold: ;sum1 has max cpi sum1High, thresholdHigh brlo ThreshFail ;same or higher breq CheckLoT rjmp ThreshSucceeded ;not same, not lower, we're good CheckLoT: ;highs are equal, its down to lows cpi sum1Low, thresholdLow brsh ThreshSucceeded rjmp ThreshFail ThreshFail: ;sbi PORTB, ledpin cbr bitStatus, isAudioBitEOR cbr bitStatus, audioNotedBitEOR rjmp OutputDone ThreshSucceeded: ;sbi PORTB, ledpin ;sbrs bitStatus, audioNotedBit ;cbi PORTB, ledpin sbrs bitStatus, audioNotedBit sbr bitStatus, isAudioBitEOR ;do not set this if audio already noted. sbr bitStatus, audioNotedBitEOR rjmp OutputDone OutputDone: ;reset: ldi sum1High, zeroHighByteForSum ldi sum2High, zeroHighByteForSum ldi sum1Low, 0 ldi sum2Low, 0 ret ; ; get enough audio to determine if a frequency is present, determine if it is present, then return. ; this is kindof an atomic "is frequency present" function, when it first is, isAudio Bit will be set. ; updateClickStatus: ; wait for AD to finish before we re-loop ; ADWait: sbic ADCSRA, ADSC ; loop until complete rjmp ADWait ;---- cache the output of conversion ---- ; in lowByte, ADCL ; send low byte in highByte, ADCH ; send high byte ;---- start a new conversion before we process ---- ; sbi ADCSRA, ADSC ; start conversion ;---- process conversion while getting next sample ---- ; rcall processNewAD ; ; only output if we have something to output. ; sbrs bitStatus, captureDoneBit rjmp ADWait rcall outputNow ret ; ; putchar ; assumes no line driver (doesn't invert bits) ; .equ sb = 1; number of stop bits putchar: ldi bitcount, 9+sb; 1+8+sb com byte; invert everything sec; set start bit putchar0: brcc putchar1; if carry set sbi PORTB, txpin; send a '0' rjmp putchar2; else putchar1: cbi PORTB, txpin ; send a '1' nop ; even out timing putchar2: rcall bitdelay; one bit delay rcall bitdelay lsr byte; get next bit dec bitcount; if not all bits sent brne putchar0; send next bit ret; ; ; bit delay .equ b = 38 bitdelay: ldi temp, b bdloop: dec temp brne bdloop ret ; ; for deguging - light the pin ON the nth call to this function (n set by debugCounter) ; lightPinOn: dec debugCounter brne debugEnd cbi PORTB, ledpin debugEnd: ret ; ; for deguging - toggle light on or off ; toggleLED: ldi temp, 0 cp debugCounter, temp breq TON ;off sbi PORTB, ledpin inc debugCounter ret TON: cbi PORTB, ledpin clr debugCounter ret ; ; main program ; reset: ; ; set stack pointer ; ldi temp, low(RAMEND) ; set stack pointer to top of RAM out SPL, temp ; ; ; setup clock ; ;ldi temp, 0x7f ; maximum RC clock ;out OSCCAL, temp ldi temp, (1 << CLKPCE) ; set clock divider ldi temp1, (0<