#define SKIPNEXT1W (PC + 2) #define DS(var) Y + var - _dataStart
inc R16 cpi R16, 5 brne SKIPNEXT1W dec R16 ...
ldd R16, Y + 6
.dseg _dataStart: ... testVar: .byte 1
ldd R16, DS (testVar)
ldd R16, Y + testVar - _dataStart
ldi R16, 32 mov R0, R16
.def R_TS = R0
// ********************************************* // *** Simple digital thermometer/hygrometer *** // ********************************************* // *** (c) SD, 14.03.2016 *** // ********************************************* // Based on ATtiny13, AM2303 and MAX7219 // ************** // *** Clocks *** // ************** // MCU clock frequency is 9.6MHz (internal oscillator) // Timer frequency is 75KHz = 9.6MHz/128 // (13.3 us between interrupts) #define SKIPNEXT1W (PC + 2) #define DS(var) Y + var - _dataStart // ************ // *** Pins *** // ************ // MAX7219 output pins .equ MAX_DIN = 0 .equ MAX_CS = 1 .equ MAX_CLK = 4 // AM2302 input pin .equ AM2302_PIN = 3 // MAX7219 registers .equ MAX_DECODE = 0x09 .equ MAX_INTENSITY = 0x0A .equ MAX_SCANLIMIT = 0x0B .equ MAX_SHUTDOWN = 0x0C .equ MAX_DISPTEST = 0x0F // Temperature measurement state register // Bits 0 - 2 define the byte number being received // Bit 3 is set when there are valid data received // Bits 4 - 7 define the current receiver state .def R_TS = R0 // Temperature measurement tick .def R_TT = R1 // Temperature data register .def R_TD = R2 // Temperature measurement states .equ TMS_NONE = 0x00 // TMS_NONE - do nothing an wait until // somebody changes the state .equ TMS_START = 0x10 // Start of the measurement cycle .equ TMS_ST_LOW = 0x20 // Initial low signal is being sent // (1 ms = 75 timer ticks) .equ TMS_WRSP_LOW = 0x30 // Initial low signal has been sent, // waiting for the response low signal .equ TMS_WRSP_HIGH = 0x40 // Response low signal has been received, // waiting for the response high signal .equ TMS_W1ST_BIT_LOW = 0x50 // Waiting for the first bit low signal .equ TMS_WBIT_HIGH = 0x60 // Waiting for the bit high signal .equ TMS_WBIT_LOW = 0x70 // Waiting for the bit low signal .equ TMS_WHIGH = 0x80 // Waiting for the final high signal // Timer 100Hz tick counter // (counts upwards from 0 to 255) .def R_TICK100 = R3 // Timer 16bit 75KHz tick counter // (counts downwords from 749 to 0) .def R_TICKL = R4 .def R_TICKH = R5 // ************ // *** Data *** // ************ .dseg _dataStart: // Data start label tempData: .byte 5 // Data, received from the AM2302 sensor displayData: .byte 4 // Decimal printing result .equ DATA_BUF_SIZE = 8 // AM2302 data buffer size in samples // (each sample is 4 bytes) dataBuffer: .byte DATA_BUF_SIZE*4 .cseg .org 0 // *** Interrupts *** // Reset Handler rjmp start // IRQ0 Handler reti // PCINT0 Handler reti // Timer0 Overflow Handler rjmp timerOvfl // EEPROM Ready Handler reti // Analog Comparator Handler reti // Timer0 CompareA Handler rjmp timerCompA // Timer0 CompareB Handler reti // Watchdog Interrupt Handler reti // ADC Conversion Handler reti // Table to convert decimal digit into 7-segment code hexTable: .db 0b01111110, 0b00110000, 0b01101101, 0b01111001 .db 0b00110011, 0b01011011, 0b01011111, 0b01110010 .db 0b01111111, 0b01111011 start: cli ldi R16, RAMEND out (SPL), R16 // Init watchdog (4s interval) wdr ldi R16, (1 << WDCE) | (1 << WDE) out (WDTCR), R16 ldi R16, (1 << WDE) | (1 << WDP3) out (WDTCR), R16 // Init registers ldi YL, low (_dataStart) ldi YH, high (_dataStart) clr R_TS clr R_TT clr R_TICKL clr R_TICKH clr R_TICK100 // Init ports out (PORTB), R_TS ldi R16, (1 << MAX_DIN) | (1 << MAX_CS) | (1 << MAX_CLK) out (DDRB), R16 // Init LED driver // Set all digits to "-" ldi XL, 0b00000001 ldi XH, 1 init1: rcall maxWriteWord cpi XH, 9 brne init1 // Set control registers ldi XL, 0 // Decode rcall maxWriteWord ldi XL, 4 // Intensity rcall maxWriteWord ldi XL, 7 // Scan limit rcall maxWriteWord ldi XL, 1 // Shutdown rcall maxWriteWord ldi XH, 0x0F ldi XL, 0 // Display test rcall maxWriteWord // Init timer for 1 interrupt each 128 CPU cycles ldi R16, 127 out (OCR0A), R16 ldi R16, 0b00000110 out (TIMSK0), R16 ldi R16, 0b00000001 out (TCCR0B), R16 // First part of the initialization is done. // Enable interrupts sei // Wait 2 sec (while AM2302 initialize itself) // with little animation ldi XH, 1 ldi XL, 0 init2: ldi R16, 25 rcall wait100Hz rcall maxWriteWord cpi XH, 9 brne init2 // R6 will contain the number of // measurement values received clr R6 // R7 will contain the number of // continious errors clr R7 loop: // Reset watchdog timer wdr // Initiate measurement ldi R16, TMS_START mov R_TS, R16 loop1: // Wait for the TMS_NONE state // which indicates that the measurement // is done sleep mov R16, R_TS andi R16, 0xF0 brne loop1 // Do we have the valid data? sbrs R_TS, 3 loop_error1: rjmp loop_error // Check control sum of the received data ldd R16, DS (tempData) ldd ZL, DS (tempData + 1) add R16, ZL ldd ZL, DS (tempData + 2) add R16, ZL ldd ZL, DS (tempData + 3) add R16, ZL ldd ZL, DS (tempData + 4) cp R16, ZL brne loop_error1 // We have valid new measurement data, // reset error count clr R7 // Move up data in the buffer // and count the sum at the same time. // R12:R13 will contain the humidity value and // R14:R15 the temperature value clr R12 clr R13 clr R14 clr R15 ldi ZL, low (dataBuffer + (DATA_BUF_SIZE - 2)*4) ldi ZH, 0 buf1: ldd R16, Z + 0 ldd R17, Z + 1 std Z + 4, R16 std Z + 5, R17 add R12, R16 adc R13, R17 ldd R16, Z + 2 ldd R17, Z + 3 std Z + 6, R16 std Z + 7, R17 add R14, R16 adc R15, R17 subi ZL, 4 cpi ZL, low (dataBuffer - 4) brne buf1 // Add new humidity value to the buffer // and to the sum ldd R16, DS (tempData + 1) ldd R17, DS (tempData) std DS (dataBuffer + 0), R16 std DS (dataBuffer + 1), R17 add R12, R16 adc R13, R17 // Add new temperature value to the buffer // and to the sum ldd R16, DS (tempData + 3) ldd R17, DS (tempData + 2) // Check for a negative value and R17, R17 brpl buf2 // Convert negative temperature to the 2's // complement form clr ZL andi R17, 0x7F neg R16 sbc ZL, R17 mov R17, ZL buf2: std DS (dataBuffer + 2), R16 std DS (dataBuffer + 3), R17 add R14, R16 adc R15, R17 // Divide the humidity and temperature // sum values by 8 (by shifting them right // three times) ldi R16, 3 buf3: asr R15 ror R14 asr R13 ror R12 dec R16 brne buf3 // Do we have 8 full measurements? mov R16, R6 cpi R16, 7 // If so, use the average values from // the buffer breq buf4 // Otherwise use the latest measurement ldd R12, DS (dataBuffer + 0) ldd R13, DS (dataBuffer + 1) ldd R14, DS (dataBuffer + 2) ldd R15, DS (dataBuffer + 3) inc R6 buf4: // Print out values // *** Humidity *** movw X, R12 rcall printDecX ldi XH, 1 ldd XL, DS (displayData + 3) rcall maxWriteWord ldd XL, DS (displayData + 2) ori XL, 0x80 rcall maxWriteWord ldd XL, DS (displayData + 1) rcall maxWriteWord ldd XL, DS (displayData) rcall maxWriteWord // *** Temperature *** movw X, R14 // Check for a negative value and XH, XH brpl buf5 // Calculate the absolute value clr ZL neg XL sbc ZL, XH mov XH, ZL buf5: rcall printDecX ldi XH, 5 ldd XL, DS (displayData + 3) rcall maxWriteWord ldd XL, DS (displayData + 2) ori XL, 0x80 rcall maxWriteWord ldd XL, DS (displayData + 1) rcall maxWriteWord // If temperature is negative // write the minus sign to the first digit // (temperatures of -100.0 and below // are not supported anyway) ldd XL, DS (displayData) and R15, R15 brpl SKIPNEXT1W ldi XL, 1 rcall maxWriteWord loop2: // Wait for 1 sec ldi R16, 100 rcall wait100Hz // And repeat rjmp loop loop_error: // An error had occured. // Increment error count inc R7 // Do we have 3 or more errors in a row? mov R16, R7 cpi R16, 3 // No? Just do nothing brne loop2 // Prevent error count from growing dec R7 // Display error ldi ZL, low (errText*2) ldi ZH, high (errText*2) rcall maxWrite8Bytes rjmp loop2 errText: // "Sn Error" .db 0b00000101, 0b00011101, 0b00000101, 0b00000101 .db 0b01001111, 0b00000000, 0b00010101, 0b01011011 // ********** // Waits given number (R16) of 100Hz ticks // Uses: Z wait100Hz: // Enable sleep ldi ZL, 0b00100000 out (MCUCR), ZL mov ZL, R_TICK100 w100: sleep mov ZH, R_TICK100 sub ZH, ZL cp ZH, R16 brcs w100 ret // Timer interrupt timerOvfl: timerCompA: push R16 in R16, (SREG) push R16 push ZL push ZH // Receive AM2303 data rcall am2302proc // Decrement current 75KHz tick ldi R16, 1 sub R_TICKL, R16 brcc timerRet sub R_TICKH, R16 brcc timerRet // Initialize 75KHz tick value ldi ZL, low (750 - 1) ldi ZH, high (750 - 1) movw R_TICKL, Z // Increment current 100Hz tick inc R_TICK100 timerRet: pop ZH pop ZL pop R16 out (SREG), R16 pop R16 reti // ************** // *** AM2302 *** // ************** amStart: // Send the start low signal. // Switch corresponding PORTB pin to output // (there is already 0 in the PORTB register) sbi (DDRB), AM2302_PIN ldi R16, TMS_ST_LOW rjmp amSetState amStartLow: // Initial start low signal is being sent. // Wait for 75 ticks cpi R16, 75 brne amNone // Switch PORTB pin back to input cbi (DDRB), AM2302_PIN ldi R16, TMS_WRSP_LOW // Do not check AM2303 input pin at this tick // since it's possible that it has not recovered // from the low state yet. rjmp amSetState amWRespLow: // Waiting for the response low signal sbrc ZH, AM2302_PIN ret ldi R16, TMS_WRSP_HIGH rjmp amSetState amWRespHigh: // Waiting for the response high signal sbrs ZH, AM2302_PIN ret ldi R16, TMS_W1ST_BIT_LOW rjmp amSetState amW1StBitLow: // Waiting for the first bit low signal sbrc ZH, AM2302_PIN ret // Get ready to receive the first bit ldi R16, 1 mov R_TD, R16 // Set new state and reset the byte counter ldi ZL, TMS_WBIT_HIGH rjmp amSetState2 amBitHigh: sbrs ZH, AM2302_PIN ret // If the bit low signal was there too long // (longer than 5 ticks (5*13.3 = 66.5us) // something went wrong) cpi R16, 6 brcc amResetState ldi R16, TMS_WBIT_LOW rjmp amSetState am2302proc: // First, check for the TMS_NONE state. // In this case just do nothing to // not waste MCU cycles. mov ZL, R_TS andi ZL, 0xF0 cpi ZL, TMS_NONE breq amNone // Increment receiver tick inc R_TT // If we are waiting for too long, // something went wrong, reset the state breq amResetState // Save the current tick into a more // convenient register mov R16, R_TT // Get input signal in ZH, (PINB) // Branch depending on the current state. // Check for TMS_WBIT_LOW first since it // has the longest service routine cpi ZL, TMS_WBIT_LOW breq amBitLow cpi ZL, TMS_START breq amStart cpi ZL, TMS_ST_LOW breq amStartLow cpi ZL, TMS_WRSP_LOW breq amWRespLow cpi ZL, TMS_WRSP_HIGH breq amWRespHigh cpi ZL, TMS_W1ST_BIT_LOW breq amW1StBitLow cpi ZL, TMS_WBIT_HIGH breq amBitHigh cpi ZL, TMS_WHIGH breq amWHigh amResetState: // In case of an error, reset state to // the default TMS_NONE ldi R16, TMS_NONE amSetState: // Preserve the current byte number mov ZL, R_TS andi ZL, 0x07 or ZL, R16 amSetState2: mov R_TS, ZL // Clear receiver tick counter clr R_TT amNone: ret amBitLow: sbrc ZH, AM2302_PIN ret // The high bit signal was too long? cpi R16, 8 brcc amResetState // Store input bit (inverted, since cpi produces // inverted result in the carry flag) cpi R16, 4 rol R_TD // Initally we set R_TD to 1, so when all 8 // bits are received, the carry flag will be set // indicating that a full byte has been received. // Otherwise, receive the next bit ldi R16, TMS_WBIT_HIGH brcc amSetState // We have the full byte. Invert it com R_TD // Save it mov ZL, R_TS andi ZL, 0x07 subi ZL, low (-tempData) ldi ZH, high (tempData) st Z+, R_TD // Did we receive all 5 bytes? cpi ZL, low (tempData + 5) ldi R16, TMS_WHIGH breq amSetState // OK, receive the next byte. // Increment the byte counter inc R_TS // Initialize R_TD ldi R16, 1 mov R_TD, R16 ldi R16, TMS_WBIT_HIGH rjmp amSetState amWHigh: sbrs ZH, AM2302_PIN ret cpi R16, 6 brcc amResetState // We received everything. Set // the state to TMS_NONE and set // the data validity bit ldi R16, 0x08 mov R_TS, R16 ret // ********* /* // Write data from Z // Uses R16 - R19, X, Z maxWriteData: lpm XH, Z+ tst XH brne SKIPNEXT1W ret lpm XL, Z+ rcall maxWriteWord rjmp maxWriteData maxInit: .db MAX_DECODE, 0 .db MAX_INTENSITY, 4 .db MAX_SCANLIMIT, 7 .db MAX_SHUTDOWN, 1 .db MAX_DISPTEST, 0 .db 0, 0 maxTest: .db 0, 0b00011101, 0b00010101, 0b00010000, 0b00011100, 0b00111101, 0b00000101, 0b01110111 */ // Writes 8 bytes from (Z) (program memory) // to MAX7219 // Uses R16 - R19, X, Z maxWrite8Bytes: ldi XH, 0x01 mw8b1: lpm XL, Z+ rcall maxWriteWord cpi XH, 9 brne mw8b1 ret // Write word X (XL = data, XH = address) to MAX2719 // Uses R16 - R19, X maxWriteWord: // Set all pins to zero in R17, (PORTB) andi R17, ~((1 << MAX_DIN) | (1 << MAX_CS) | (1 << MAX_CLK)) out (PORTB), R17 ldi R19, (1 << MAX_CLK) mov R16, XH rcall mww1 mov R16, XL rcall mww1 // Set LOAD(CS) to high thus writing all 16 bits into // MAX register sbi (PORTB), MAX_CS // Increment MAX register number inc XH ret mww1: ldi R18, 8 mww2: bst R16, 7 bld R17, MAX_DIN out (PORTB), R17 lsl R16 dec R18 // Create clock impulse by toggling clock output twice out (PINB), R19 out (PINB), R19 brne mww2 ret // ********* printDecX: ldi ZH, low (1000) ldi R16, high (1000) rcall pdx // Change zero digit to empty space cpi ZL, 0b01111110 brne SKIPNEXT1W ldi ZL, 0 std DS (displayData), ZL ldi ZH, 100 ldi R16, 0 rcall pdx // If this digit is zero and the first // digit is empty (ie it was zero too) // change this digit to empty space ldi R16, 0b01111110 eor R16, ZL ldd ZH, DS (displayData) or R16, ZH brne SKIPNEXT1W ldi ZL, 0 std DS (displayData + 1), ZL ldi ZH, 10 ldi R16, 0 rcall pdx std DS (displayData + 2), ZL mov ZL, XL rcall pdx3 std DS (displayData + 3), ZL // Clear carry flag to indicate that // no error occurred clc ret pdx: ldi ZL, 0 pdx1: sub XL, ZH sbc XH, R16 brcs pdx2 cpi ZL, 9 breq pdxOverflow inc ZL rjmp pdx1 pdx2: add XL, ZH adc XH, R16 pdx3: subi ZL, -low (hexTable << 1) ldi ZH, high (hexTable << 1) lpm ZL, Z ret pdxOverflow: // Set carry flag to indicate error sec // Pop return address out of the stack // so we can return to the caller of printDecX pop R16 pop R16 ret
:020000020000FC
:100000000EC018951895C2C018951895BFC01895C0
:10001000189518957E306D79335B5F727F7BF8940D
:100020000FE90DBFA89508E101BD08E201BDC0E6DA
:10003000D0E00024112444245524332408BA03E1D9
:1000400007BBA1E0B1E015D1B930E9F7A0E011D1CB
:10005000A4E00FD1A7E00DD1A1E00BD1BFE0A0E05B
:1000600008D10FE706BF06E009BF01E003BF78949F
:10007000B1E0A0E009E181D0FCD0B930D9F7662425
:100080007724A89500E1002E8895002D007FE1F7E8
:1000900003FE66C00881E9810E0FEA810E0FEB8135
:1000A0000E0FEC810E17A9F77724CC24DD24EE2463
:1000B000FF24E1E8F0E00081118104831583C00E84
:1000C000D11E0281138106831783E00EF11EE450D6
:1000D000E53689F70981188109871A87C00ED11E74
:1000E0000B811A8111232AF4EE271F770195E10B6A
:1000F0001E2F0B871C87E00EF11E03E0F594E7949A
:10010000D594C7940A95D1F7062D073029F0C984F4
:10011000DA84EB84FC846394D601C0D0B1E0A88576
:10012000A8D0AF81A068A5D0AE81A3D0AD81A1D069
:10013000D701BB2322F4EE27A195EB0BBE2FAED047
:10014000B5E0A88596D0AF81A06893D0AE8191D05C
:10015000AD81FF200AF4A1E08CD004E60ED091CF4F
:100160007394072D0330C9F77A94E2E7F1E07BD06E
:10017000F4CF051D05054F00155BE0E2E5BFE32D5B
:100180008895F32DFE1BF017D8F308950F930FB742
:100190000F93EF93FF932BD001E0401A30F4501AE5
:1001A00020F4EDEEF2E02F013394FF91EF910F91E7
:1001B0000FBF0F911895BB9A00E232C00B34A9F51E
:1001C000BB9800E32DC0F3FD089500E429C0F3FFC0
:1001D000089500E525C0F3FD089501E0202EE0E636
:1001E00022C0F3FF08950630D0F400E719C0E02DD7
:1001F000E07FE030D1F0139491F0012DF6B3E037B9
:10020000A9F0E031C1F2E032C9F2E033E1F2E034CA
:10021000F1F2E03501F3E03621F3E038E9F000E0F7
:10022000E02DE770E02B0E2E11240895F3FD0895C4
:100230000830A8F70430221C00E690F72094E02D47
:10024000E770E05AF0E02192E53600E849F30394C4
:1002500001E0202E00E6E4CFF3FF08950630F8F623
:1002600008E0002E0895B1E0A59103D0B930E1F780
:10027000089518B31C7E18BB30E10B2F05D00A2F50
:1002800003D0C19AB395089528E007FB10F918BB75
:10029000000F2A9536BB36BBC1F70895F8EE03E090
:1002A00017D0EE3709F4E0E0ED83F4E600E010D07B
:1002B0000EE70E27FD810F2B09F4E0E0EE83FAE054
:1002C00000E006D0EF83EA2F0DD0E88788940895E8
:1002D000E0E0AF1BB00B20F0E93041F0E395F9CF3F
:1002E000AF0FB01FEC5EF0E0E491089508940F9119
:0402F0000F910895CD
:00000001FF
Source: https://habr.com/ru/post/371973/
All Articles