User:Frosti/Sensors, Actuators, and Displays: Difference between revisions
Jump to navigation
Jump to search


Schematic layout

Board layout
No edit summary |
code second version |
||
| Line 238: | Line 238: | ||
rjmp main_loop | rjmp main_loop | ||
==Code second 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. | |||
; 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== | ==Using AVR Studio== | ||
* Build and Run | * Build and Run | ||
Revision as of 12:48, 31 March 2010
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
- Add

Making the 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.
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.
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 second 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. ; 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;