; Copyright 2021 KoroLion (https://github.com/KoroLion) #define __SFR_OFFSET 0 #define LED_PORT 7 // led port #include "avr/io.h" // #include "avr/iom328p.h" .section .bss lm35_port: .byte 0 .section .text .global lm35_init .global lm35_read .global led_init .global led_enable .global led_disable led_init: sbi DDRD, LED_PORT ret led_enable: sbi PORTD, LED_PORT ret led_disable: cbi PORTD, LED_PORT ret .macro pin_mode_input port ; sets analog port as input ldi r31, 1 ; means port 0 cpi \port, 0 breq end_convert ; = 0 => no need to convert (already set mask to port 0) mov r30, \port convert: lsl r31 ; logic shift left ~ r31 * 2 dec r30 cpi r30, 0 brne convert end_convert: com r31 ; inverting mask (00001000 -> 11110111) ; setting correct DDRC using mask in r30, DDRC and r30, r31 ; applying mask (11111111 and 11110111 = 11110111) out DDRC, r30 .endm .macro adc_read port, res_high, res_low ldi r30, 0b00000000 sts PRR, r30 ; first two bits are for the ref voltage ; 11 means using internal 1.1v atmega voltage for adc ; last three bits are for the analog port number ldi r30, 0b11000000 or r30, \port sts ADMUX, r30 ; last 3 bits (111 means 128) ; ADC Prescaler Select Bits (ADPS): ADPS2, ADPS1 and ADPS0 bits are used to set circuit clock frequency. ; For ADC circuitry to work at its maximum resolution needs to be supplied with 50 kHz to 200 kHz frequency as per the datasheet; ; but the system clock will be generally higher (8 MHz, 10 MHz, 16 MHz etc). ; To reduce it to required frequency we use ADC prescaler bits. Suppose we have system clock with frequency 10Mhz (10000000 Hz) and set division factor to 64, ; then ADC clock frequency is 10000000/64 = 156250Hz = 156.25 KHz, which is between 50 to 200 KHz as mentioned in the datasheet. ; (http://www.robotplatform.com/knowledge/ADC/adc_tutorial_2.html) ; ; 16 MHz / 128 = 16000000 Hz / 128 = 125000 Hz = 125 KHz => OK! ldi r30, 0b11000111 sts ADCSRA, r30 wait_adc: lds r30, ADCSRA ldi r31, 0b01000000 and r31, r30 cpi r31, 0 brne wait_adc lds \res_low, ADCL lds \res_high, ADCH ; clearing unused bits to be sure they're zero ldi r31, 0b00000011 and \res_high, r31 .endm .macro divw10 divident_high, divident_low ; r30 - res ; divident_low - quotient ldi r30, 0 division: cpi \divident_low, 10 brlo division_low_end ; < continue_division: sbiw \divident_low, 10 inc r30 rjmp division division_low_end: cpi \divident_high, 0 brne continue_division cpi \divident_low, 5 brlo not_inc ; < inc r30 not_inc: .endm lm35_init: ; r25:r24 is the first arg subi r24, 14 ; because A0 is D14 pin_mode_input r24 sts lm35_port, r24 ret lm35_read: cli ; forbids interruptions lds r24, lm35_port adc_read r24, r25, r24 divw10 r25, r24 mov r24, r30 ; uint8_t return value adiw r24, 2 ; due to LM35 formula (2C to 150C) clr r1 ; docs requirement sei ; allow interruptions ret