User:Frosti/Sensors, Actuators, and Displays

From Fab Lab Wiki - by NMÍ Kvikan
Revision as of 12:59, 31 March 2010 by Frosti (talk | contribs)
Jump to navigation Jump to search

Goal

The goal is to make theremin with our Fab Lab equipment and inventory.

Steps

Desired function of the circuit board

First I have to decide the function of the board.

  • The function should be:
    • It should be musical instrument, in the way that the board develops sounds on the speaker when I move copper foils towards one another.


The schematic and board layout

I tried to use Inkscape to sketch what I wanted it to do. Then I decided to try to start to draw the board in Eagle.

  • I downloaded and installed the Eagle Free version from Cad Soft USA
  • I downloaded and copied Neils library from http://fab.cba.mit.edu/about/fab/dist/ng.lbr to the folder where other libraries are.
  • First I drew hello.speaker.45.MTA.
  • Before starting to draw, remember to change the grid to 0.025 inches. That will help a lot later on.
  • We have two views
    • Schematic
    • Board
  • I added some new components
    • Add
      • Resistor 1 Mega Ohm
      • MTA connector 3 pin
Schematic layout

Making the Board layout

Board layout

At first I had some troubles making the routes.

  • Then I used Route button and connected from one component to another.
  • When the routes are ready you can go to View -> Display/hide layers and select what layers you want to see.
  • Turn off all layers except the routes, go to File-> Export, .png, 500 dpi.
  • Now turn off all layers except the frame, and go to File-> Export, .png, 500 dpi.

Physical Fabrication

We make the board on Modela.

  • Mistakes that we made originally, we changed X min and Y min like we should do, but we also changed X width and Height. But we shouldn't have to change X width and Height.

Programming the board

  • Then I have to make program for the board.
  • I downloaded [AVR Data sheet for Attiny45] from Atmel

I take a look at codes from Fab Hello World page specially at hello.speaker.45.pwm.asm and hello.step.45.asm


Some AVR Instructions

  • SBI -> Set Bit in I/O Register
  • CBI -> Clear Bit in I/O Register
  • LDI -> Load Immediate
  • BRNE-> Branch if Not Equal

First we made some experiments

  • Open AVR studio
  • File New Project
  • Write .asm code
  • Build and Run
  • Step into

First we look at our board

  • We look at our hello.speaker.45.cad board and check if we have some available pins to use.
  • We see that we have PB3 and PB4 available.
  • We can now start to check the code.

Lets use hello.speaker.45.pwm.asm

We download hello.speaker.45.pwm.asm and change the code.

We use also a little bit of hello.step.45.asm program.

Alternate the code

Define variablbe. .equ sensor_pin = PB3 ; we call pin PB3 a sensor pin .equ charge_pin = PB4 ; PB4 is our charge pin

.def sensor_value_high = R23	; temporary storage for sensor value  (here we store our sensor values (because   we have 10 bit value, here we have the higher value)
.def sensor_value_low = R24	; temporary storage for sensor value (here we store our sensor values (because  we have 10 bit value, here we have the lower value)


; set Chargepin to output
   ;
   cbi PORTB, charge_pin (the charge_pin is set to low)
   sbi DDRB, charge_pin ( charge pin is output

Next we define measuring method.

   ; init A/D
   ;
   cbi ADMUX, REFS2 ; use Vcc as reference
   cbi ADMUX, REFS1 ; "
   cbi ADMUX, REFS0 ; "
   cbi ADMUX, ADLAR ; right-adjust result
   cbi ADMUX, MUX3 ; set MUX to ADC2 (PB4) here we decide what pin we use for measurement
   cbi ADMUX, MUX2 ; "
   sbi ADMUX, MUX1 ; "
   cbi ADMUX, MUX0 ; "
   sbi ADCSRA, ADEN ; enable A/D
   cbi ADCSRA, ADPS2 ; set prescaler to /2 (here we define at what speed we measure)
   cbi ADCSRA, ADPS1 ; "
   cbi ADCSRA, ADPS0 ; "


Mistakes that we made:

  • First we defined PB4 as a sensor pin and a charge pin, we fixed that by defining PB3 as a charge pin and PB4 as a sensor pin.
  • Then we started to get some response from the sensor.
  • At first we only used lower value.
;==First version==
;
; hello.speaker.45.pwm.asm
;
; software PWM speaker hello-world program
;
; Neil Gershenfeld MIT CBA 8/2/07
;
; (c) Massachusetts Institute of Technology 2007
; Permission granted for experimental and personal use;
; license for commercial sale available from MIT.
;

 .include "tn45def.inc"

 .equ mosfet_pin = PB1 ; MOSFET pin
.equ max_pwm = 20 ; maximum PWM on value
.equ pwm_length = 40 ; PWM loop length
.equ sensor_pin = PB4	; we call pin PB4 a sensor pin
.equ charge_pin = PB3	; PB3 is our charge pin


.def temp = R16	; temporary storage
.def temp1 = R17 ; temporary storage
.def pwm = R18 ; PWM value
.def pwm_count = R19 ; PWM counter
.def pwm_cycle = R20 ; PWM cycle count
.def pwm_cycle_count = R21 ; number of PWM cycles per audio cycle
.def cycle_count = R22 ; audio cycle count 
.def sensor_value_high = R23	; temporary storage for sensor value
.def sensor_value_low = R24	; temporary storage for sensor value

.cseg
.org 0
rjmp reset

;
; main program
;
reset:	   
   ;
   ; initialization
   ;
   ; 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
   ;
   ; set MOSFET to output
   ;
   cbi PORTB, mosfet_pin
   sbi DDRB, mosfet_pin
   ;

 ; set Chargepin to output
   ;
   cbi PORTB, charge_pin
   sbi DDRB, charge_pin

;
   ; init A/D
  ;
   cbi ADMUX, REFS2 ; use Vcc as reference
   cbi ADMUX, REFS1 ; "
   cbi ADMUX, REFS0 ; "
   cbi ADMUX, ADLAR ; right-adjust result
   cbi ADMUX, MUX3 ; set MUX to ADC2 (PB4) here we decide what pin we use for measurement
   cbi ADMUX, MUX2 ; "
   sbi ADMUX, MUX1 ; "
   cbi ADMUX, MUX0 ; "
   sbi ADCSRA, ADEN ; enable A/D
   cbi ADCSRA, ADPS2 ; set prescaler to /2 (here we define at what speed we measure)
   cbi ADCSRA, ADPS1 ; "
   cbi ADCSRA, ADPS0 ; "

 

   ; infinite main loop
   ;
   main_loop:

	;first we fetch one measurement

	 ; read response
         ;
         sbi ADCSRA, ADSC ; start conversion
         adloopup:
            sbic ADCSRA, ADSC ; loop until complete
            rjmp adloopup
         ;
         ; save conversion
         ;
         in sensor_value_low, ADCL ; get low byte from sensor
         in sensor_value_high, ADCH ; get high byte from sensor


      ldi pwm_cycle_count, 5
      frequency_loop:
         ; we will not use this line ldi cycle_count, sensor_value_low 
		 mov cycle_count, sensor_value_low
         cycle_count_loop:
            ldi pwm, max_pwm
           cycle_loop:
                mov pwm_cycle, pwm_cycle_count
               pwm_loop:
                  mov pwm_count, pwm
                  sbi PORTB, mosfet_pin
                  pwm_on_loop:
                     dec pwm_count
                     brne pwm_on_loop
                  ldi pwm_count, pwm_length
                  sub pwm_count, pwm
                  cbi PORTB, mosfet_pin
                  pwm_off_loop:
                     dec pwm_count
                     brne pwm_off_loop
                  dec pwm_cycle
                  brne pwm_loop
               dec pwm
               brne cycle_loop
             dec cycle_count
             brne cycle_count_loop
          dec pwm_cycle_count
          brne frequency_loop
       rjmp main_loop 

Code of second version

This is second version of our program and now it changes the speed of the music depending on how we turn the variable resistor.

	;
	; hello.speaker.45.pwm.asm
	;
	; software PWM speaker hello-world program
	;
	; Neil Gershenfeld MIT CBA 8/2/07
	;
	; (c) Massachusetts Institute of Technology 2007
	; Permission granted for experimental and personal use;
	; license for commercial sale available from MIT.
	; changed by Fab Academy students in Vestmannaeyjar
	
	.include "tn45def.inc"
	
	.equ mosfet_pin = PB1 ; MOSFET pin
	.equ max_pwm = 20 ; maximum PWM on value
	.equ pwm_length = 40 ; PWM loop length
	.equ sensor_pin = PB4    ; we call pin PB4 a sensor pin
	.equ charge_pin = PB3    ; PB3 is our charge pin
	
	
	.def temp = R16    ; temporary storage
	.def temp1 = R17 ; temporary storage
	.def pwm = R18 ; PWM value
	.def pwm_count = R19 ; PWM counter
	.def pwm_cycle = R20 ; PWM cycle count
	.def pwm_cycle_count = R21 ; number of PWM cycles per audio cycle
	.def cycle_count = R22 ; audio cycle count
	.def sensor_value_high = R23    ; temporary storage for sensor value
	.def sensor_value_low = R24    ; temporary storage for sensor value
	.DEF rd1l = R0 ; LSB 16-bit-number to be divided
	.DEF rd1h = R1 ; MSB 16-bit-number to be divided
	.DEF rd1u = R2 ; interim register
	.DEF rd2 = R3 ; 8-bit-number to divide with
	.DEF rel = R4 ; LSB result
	.DEF reh = R5 ; MSB result
	.DEF rmp = R25; multipurpose register for loading
	
	
	.cseg
	.org 0
	rjmp reset
	
	;
	; main program
	;
	reset:      
	   ;
	   ; initialization
	   ;
	   ; 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
	   ;
	   ; set MOSFET to output
	   ;
	   cbi PORTB, mosfet_pin
	   sbi DDRB, mosfet_pin
	   ;
	
	 ; set Chargepin to output
	   ;
	   cbi PORTB, charge_pin
	   sbi DDRB, charge_pin
	
	;
	   ; init A/D
	   ;
	   cbi ADMUX, REFS2 ; use Vcc as reference
	   cbi ADMUX, REFS1 ; "
	   cbi ADMUX, REFS0 ; "
	   cbi ADMUX, ADLAR ; right-adjust result
	   cbi ADMUX, MUX3 ; set MUX to ADC2 (PB4) here we decide what pin we use for measurement
	   cbi ADMUX, MUX2 ; "
	   sbi ADMUX, MUX1 ; "
	   cbi ADMUX, MUX0 ; "
	   sbi ADCSRA, ADEN ; enable A/D
	   cbi ADCSRA, ADPS2 ; set prescaler to /2 (here we define at what speed we measure)
	   cbi ADCSRA, ADPS1 ; "
	   cbi ADCSRA, ADPS0 ; "
	
	
	
	   ; infinite main loop
	   ;
	   main_loop:
	
	    ;first we fetch one measurement
	
	     ; read response
	         ;
	         sbi ADCSRA, ADSC ; start conversion
	         adloopup:
	            sbic ADCSRA, ADSC ; loop until complete
	            rjmp adloopup
	         ;
	         ; save conversion
	       
	         
	         ;
	         in sensor_value_low, ADCL ; get low byte from sensor
	         in sensor_value_high, ADCH ; get high byte from sensor
	
	            ;Here we divide the results from the sensor Devision starts
	        ; Load the test numbers to the appropriate registers
	        ;
	           
	            mov rd1h,sensor_value_high ; use the high sensor value
	            mov rd1l,sensor_value_low ; use the low sensor value
	            ldi rmp,0x4 ; 0x4 to be divided with
	            mov rd2,rmp
	        ;
	        ; Divide rd1h:rd1l by rd2
	        ;
	        div8:
	            clr rd1u ; clear interim register
	            clr reh ; clear result (the result registers
	            clr rel ; are also used to count to 16 for the
	            inc rel ; division steps, is set to 1 at start)
	        ;
	        ; Here the division loop starts
	        ;
	        div8a:
	            clc ; clear carry-bit
	            rol rd1l ; rotate the next-upper bit of the number
	            rol rd1h ; to the interim register (multiply by 2)
	            rol rd1u
	            brcs div8b ; a one has rolled left, so subtract
	            cp rd1u,rd2 ; Division result 1 or 0?
	            brcs div8c ; jump over subtraction, if smaller
	        div8b:
	            sub rd1u,rd2; subtract number to divide with
	            sec ; set carry-bit, result is a 1
	            rjmp div8d ; jump to shift of the result bit
	        div8c:
	            clc ; clear carry-bit, resulting bit is a 0
	        div8d:
	            rol rel ; rotate carry-bit into result registers
	            rol reh
	            brcc div8a ; as long as zero rotate out of the result
	             ; registers: go on with the division loop
	        ; End of the division reached
	
	      ldi pwm_cycle_count, 5
	      frequency_loop:
	         ; we will not use this line ldi cycle_count, sensor_value_low
	         mov cycle_count, rel ; we use the result from the devision, lower value
	         cycle_count_loop:
	            ldi pwm, max_pwm
	            cycle_loop:
	               mov pwm_cycle, pwm_cycle_count
	               pwm_loop:
	                  mov pwm_count, pwm
	                  sbi PORTB, mosfet_pin
	                  pwm_on_loop:
	                     dec pwm_count
	                     brne pwm_on_loop
	                  ldi pwm_count, pwm_length
	                  sub pwm_count, pwm
	                  cbi PORTB, mosfet_pin
	                  pwm_off_loop:
	                     dec pwm_count
	                     brne pwm_off_loop
	                  dec pwm_cycle
	                  brne pwm_loop
	               dec pwm
	               brne cycle_loop
	            dec cycle_count
	            brne cycle_count_loop
	         dec pwm_cycle_count
	         brne frequency_loop
	      rjmp main_loop

Using AVR Studio

  • Build and Run
  • Create .hex file
  • Attention -> Remember to unplug the speaker before you program the micro controler.
  • Load program to circuit board.
  • avrdude -p t45 -c bsd -U flash:w:file.hex

Links


Simple test program=

include "tn44def.inc";
sbi DDRA, 0;
ldi R18, 10;
LoopA:
	sbi PORTA, 0;
	ldi R19, 15; 
	Loop2:
		dec R19;
		brne Loop2;
		cbi PORTA, 0;
		ldi R19, 20;
		Loop3:
			dec R19;
			brne Loop3
  	dec R18;
  	brne LoopA;