; mic_serial ; ; microphone input with RGB LED Output .include "tn44def.inc" ; ; definitions ; .equ tx_pin = PA3; transmit pin .equ nloop = 200 ; number of samples between framing .equ red = PA6; red pin .equ green = PA7; green pin .equ blue = PB2; blue pin ; ; registers ; .def count = R30; loop counter .def pwm = R31; PWM counter .def bit_count = R16; bit counter .def temp = R17; temporary storage .def temp1 = R18; temporary storage .def txbyte = R19; data byte .def loop_count = R20 ; loop counter .def min_lo = R21 .def min_hi = R22 .def max_lo = R23 .def max_hi = R24 .def zero_lo = R25 .def zero_hi = R26 .def zero_crossings = R27 .def prev_lo = R28 .def prev_hi = R29 ; ; code segment ; .cseg .org 0 rjmp reset ; ; print ; .macro print ldi zl,low(@0*2) ldi zh,high(@0*2) rcall print_db .endmacro ; ; print_db ; prints a null-terminated .db string ; print_db: print_loop: lpm mov txbyte,R0 cpi txbyte,0 breq return rcall putchar adiw zl, 1 rjmp print_loop return: ret ; ; half_bit_delay ; serial half bit delay ; half_bit_delay: ldi temp, 25; 115200 baud (20 MHz clock /1) half_bit_delay_loop: dec temp brne half_bit_delay_loop ret ;do_pwm do_pwm: ; ; init LED pins for output ; sbi PORTA, red sbi DDRA, red sbi PORTA, green sbi DDRA, green sbi PORTB, blue sbi DDRB, blue ldi count, 255 off_red_loop: mov pwm, count sbi PORTA, red off_red_loop_off: dec pwm brne off_red_loop_off mov pwm, count cbi PORTA, red off_red_loop_on: inc pwm brne off_red_loop_on dec count brne off_red_loop ldi count, 255 red_green_loop: mov pwm, count cbi PORTA, red sbi PORTA, green red_green_loop_off: dec pwm brne red_green_loop_off mov pwm, count sbi PORTA, red cbi PORTA, green red_green_loop_on: inc pwm brne red_green_loop_on dec count brne red_green_loop green_blue_loop: mov pwm, count cbi PORTA, green sbi PORTB, blue green_blue_loop_off: dec pwm brne green_blue_loop_off mov pwm, count sbi PORTA, green cbi PORTB, blue green_blue_loop_on: inc pwm brne green_blue_loop_on dec count brne green_blue_loop blue_on_loop: mov pwm, count sbi PORTA, red sbi PORTA, green blue_on_loop_off: dec pwm brne blue_on_loop_off mov pwm, count cbi PORTA, red cbi PORTA, green blue_on_loop_on: inc pwm brne blue_on_loop_on dec count brne blue_on_loop on_off_loop: mov pwm, count cbi PORTA, red cbi PORTA, green cbi PORTB, blue on_off_loop_off: dec pwm brne on_off_loop_off mov pwm, count sbi PORTA, red sbi PORTA, green sbi PORTB, blue on_off_loop_on: inc pwm brne on_off_loop_on dec count brne on_off_loop ret ;pwm off ledoff: cbi PORTA, red cbi DDRA, red cbi PORTA, green cbi DDRA, green cbi PORTB, blue cbi DDRB, blue ret ; ; putchar ; assumes no line driver (doesn't invert bits) ; .equ sb = 1; number of stop bits putchar: ldi bit_count, 9+sb; 1+8+sb com txbyte; invert everything sec; set start bit putchar0: brcc putchar1; if carry set sbi PORTA, tx_pin; send a '0' ;cpi txbyte, 0x0 ;brne doit ;doit: ;rcall do_pwm rjmp putchar2; else putchar1: ;rcall do_pwm cbi PORTA, tx_pin ; send a '1' ;rcall ledoff nop ; even out timing putchar2: rcall half_bit_delay; one bit delay rcall half_bit_delay lsr txbyte; get next bit dec bit_count; if not all bits sent ;rcall do_pwm brne putchar0; send next bit ret; ; ; char_delay ; delay between characters ; char_delay: ldi temp, 255 char_delay_loop: ldi temp1, 10 char_delay_loop1: dec temp1 brne char_delay_loop1 dec temp brne char_delay_loop ret ; ; main program ; reset: ; ; set clock divider to /1 ; ldi temp, (1 << CLKPCE) ldi temp1, (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0) out CLKPR, temp out CLKPR, temp1 ; ; set stack pointer to top of RAM ; ldi temp, high(RAMEND) out SPH, temp ldi temp, low(RAMEND) out SPL, temp ; ; init comm pin for output ; sbi PORTA, tx_pin sbi DDRA, tx_pin ; ; set up A/D ; sbi ADMUX, REFS1 ; use 1.1V reference cbi ADMUX, REFS0 ; " sbi ADMUX, MUX5 ; differential, 20x gain, PA2-PA1 cbi ADMUX, MUX4 ; sbi ADMUX, MUX3 ; sbi ADMUX, MUX2 ; cbi ADMUX, MUX1 ; sbi ADMUX, MUX0 ; cbi ADMUX, ADLAR ; right-adjust result sbi ADCSRA, ADEN ; enable A/D cbi ADCSRA, ADATE ; disable auto-trigger sbi ADCSRA, ADPS2 ; set prescaler for /32 cbi ADCSRA, ADPS1 ; " sbi ADCSRA, ADPS0 ; " ; ; main loop ; main_loop: ; ; init ; ldi min_lo, 255 ldi min_hi, 255 ldi max_lo, 0 ldi max_hi, 0 ldi zero_crossings, 0 ldi prev_lo, 0 ldi prev_hi, 0 ; ; sample loop ; ldi loop_count, nloop sample_loop: ; ; read A/D ; sbi ADCSRA, ADSC ; start conversion adloopup: sbic ADCSRA, ADSC ; loop until complete rjmp adloopup ; ; send conversion ; in txbyte, ADCL ; low byte in txbyte, ADCH ; hi byte ; ; set min and max ; only if we're beyond the first few samples ; in temp, ADCL in temp1, ADCH cpi loop_count, 170 brsh donotsetmax cp temp, min_lo cpc temp1, min_hi brsh donotsetmin in min_lo, ADCL in min_hi, ADCH donotsetmin: cp temp, max_lo cpc temp1, max_hi brlo donotsetmax in max_lo, ADCL in max_hi, ADCH donotsetmax: ; ; count zero crossings ; using zero calculated in prev frame ; ; if current sample >= zero ; if prev sample < zero ; inc zero_crossings ; in temp, ADCL in temp1, ADCH cp temp, zero_lo cpc temp1, zero_hi brlo donotcount cp prev_lo, zero_lo cpc prev_hi, zero_hi brsh donotcount inc zero_crossings donotcount: ; ; prev sample = current sample ; in prev_lo, ADCL in prev_hi, ADCH ; ; loop ; dec loop_count brne sample_loop ; ; calculate zero = max + min / 2 ; to use as a 'zero' for counting zero-crossings ; mov zero_lo, min_lo mov zero_hi, min_hi add zero_lo, max_lo adc zero_hi, max_hi lsr zero_hi ror zero_lo ; ; multiply zero crossings by 8 ; lsl zero_crossings lsl zero_crossings lsl zero_crossings ; ; if max - min > threshold ; send zero crossings ; else ; send a 0 sub max_lo, min_lo sbc max_hi, min_hi ldi temp, 100 ldi temp1, 0 cp max_lo, temp cpc max_hi, temp1 brlo send_zero mov txbyte, zero_crossings rcall do_pwm rcall putchar rcall char_delay rjmp main_loop send_zero: rcall ledoff ldi txbyte, 0 rcall putchar rcall char_delay rjmp main_loop