me  

How to Build Almost Anything

MAS 863 @ MIT

MicroControl Devices!

 
 
   
 

PROJECTS!

1. CAD design

2. Press Fit

3. Circuits

4. Programming Cables

5. MicroControl.

6. The Future.

         
(ATiny13)
 
(Board Pre-Stuffing)
 
(MiniMill)
   
(Components Needed)
(Board Stuffed)
(Cables for Programming)
     
(Everything Hooked Up)
(Code!)
(Outpot Graph)
   
 

The story in text:

The objective of this project is to resize the average workbench. David mentioned that it is interesting to make something of greater simplicity from to objects of higher order, equivalent complexity. I agree! We are building an oscilliscope, with each of the fifteen of us working on a particular aspect of the design. Organization is reasonably free-form, which seems to me to add a third degree of equivalent complexity (our degree of understanding) to the puzzle. I like it a lot! I am developing a device to determine capacitance, because the ability to collect charge is highly interesting to me, so something I would like to measure. (Super capacitors, here we come?) Of all of the units so far, this is the one that is farthest from my base of knowledge, but should our individual efforts come together also something that I will rebuild on my own and put in our student shop. I ordered a copy of the Roland Mill yesterday, and am exceedingly excited to get going.

The Thought Process :

1. Of course, every project begins with ideas, but this one more than usual because I know less than is common. I began by milling and stuffing the Hello3 board, and just looking down on it believe that the new device denoted by a 1$ on the schematic looks like an ideal input / output location. Perhaps I will add leads here that can attach to whatever it might be that I am trying to measure (me?)!

 
         
The Potential Input Point
 
Some Text from the Manual

2. Next step here involved looking at the base code adn reading through it:

;
; hello3.step.asm
; step response measurement
; Neil Gershenfeld CBA MIT 10/29/05
;
; definitions
;
.include "tn13def.inc"
.equ chargepin  = PB1 ; charging pin
.equ txpin = PB4 ; serial transmit pin
.def bitcnt = R16 ; bit counter
.def temp = R17            ; temporary storage
.def txbyte = R18 ; data byte
.def delaycnt = R19 ; delay counter
.def uplo = R20 ; up low byte
.def uphi = R21 ; up hi byte
;
; start of code
;
.cseg
.org 0
rjmp reset ; jump to reset routine
;
; putchar routine
; assumes no line driver (doesn't invert bits)
;
.equ sb = 1 ;  number of stop bits
putchar:
   ldi bitcnt, 9+sb ; 1+8+sb
   com txbyte ; invert everything
   sec ; set start bit
   putchar0:
      brcc putchar1 ; if carry set
      sbi PORTB, txpin ; send a '0'
      rjmp  putchar2 ; else           
   putchar1:
      cbi PORTB, txpin ; send a '1'
      nop
   putchar2:
      rcall bitdelay ; one bit delay
      rcall  bitdelay
      lsr txbyte ; get next bit
      dec bitcnt ; if not all bits sent
      brne putchar0 ; send next
   ret ; else return
;
; serial bit delay routine
;
.equ b = 17 ; 9600 bps
bitdelay:
   ldi temp, b
   bitloop:
      dec temp
      brne bitloop
   ret
;
; routine to wait for sample to settle
;
.equ delay = 255
settle:
   ldi temp, delay
   settleloop:
      dec temp
      brne settleloop
   ret
;
; main program
;
reset:
   ldi temp, low(RAMEND) ; set stack pointer to top of RAM
   out SPL, temp ;
   ;
   ; init output pins
   ;
   sbi PORTB, txpin ; comm
   sbi DDRB, txpin ; "
   sbi PORTB, chargepin ; charging
   sbi DDRB, chargepin ; "
   ;
   ; init A/D
   ;
   cbi ADMUX, REFS0 ; use Vcc as reference
   cbi ADMUX, ADLAR ; right-adjust result
   sbi ADCSRA, ADEN ; enable A/D
   cbi ADCSRA, ADATE ; disable auto-trigger
   cbi ADCSRA, ADPS2 ; set prescaler for /2
   cbi ADCSRA, ADPS1 ; "
   cbi ADCSRA, ADPS0 ; "
   cbi ADMUX, MUX1 ; input on ADC1
   sbi ADMUX, MUX0 ; "
   ;
   ; infinite main loop
   ;
   loop:
      ;
      ; loop over delays
      ;
      ldi delaycnt, 254
      delayloop:
         ;
             ; settle sample and start upward step response
             ;
         cbi PORTB, chargepin
         rcall settle
             mov temp, delaycnt
         sbi PORTB, chargepin
             ;
         ; wait for delay
             ;
             addelayup:
                dec temp
                brne addelayup
         ;
             ; read response
             ;
         sbi ADCSRA, ADSC ; start conversion
         adloopup:
            sbic ADCSRA, ADSC ; loop until complete
            rjmp adloopup
             ;
             ; save conversion
             ;
         in uplo, ADCL ; get low byte
         in uphi, ADCH ; get high byte
         ;
             ; settle sample and start downward step response
             ;
         rcall settle
             mov temp, delaycnt
         cbi PORTB, chargepin
             ;
         ; wait for delay
             ;
             addelaydown:
                dec temp
                brne addelaydown
         ;
             ; read response
             ;
         sbi ADCSRA, ADSC ; start conversion
         adloopdown:
            sbic ADCSRA, ADSC ; loop until complete
            rjmp adloopdown
             ;
             ; send conversions
             ;
         in txbyte, ADCL ; low down byte
         rcall putchar
         in txbyte, ADCH ; hi down byte
         rcall putchar
         mov txbyte, uplo ; low up byte
         rcall putchar
         mov txbyte, uphi ; hi up byte
         rcall putchar
             dec delaycnt
             dec delaycnt
             brne delayloop
      ;
      ; send 1 2 3 4 for framing
      ;
      ldi txbyte, 1
      rcall putchar
      ldi txbyte, 2
      rcall putchar
      ldi txbyte, 3
      rcall putchar
      ldi txbyte, 4
      rcall putchar
      rjmp loop

This will become a link, but for now everything is here so I can scroll through it easily while reading over the manual for ATiny13 to determine what exactly needs to be changed to allow for capacitance to be read. Notes from reading over the manual include:

Perhaps most importantly, what the pins do!

• Bit 7 – I: Global Interrupt Enable
The Global Interrupt Enable bit must be set for the interrupts to be enabled. The individ-
ual interrupt enable control is then performed in separate control registers. If the Global
Interrupt Enable Register is cleared, none of the interrupts are enabled independent of
the individual interrupt enable settings. The I-bit is cleared by hardware after an interrupt
has occurred, and is set by the RETI instruction to enable subsequent interrupts. The I-
bit can also be set and cleared by the application with the SEI and CLI instructions, as
described in the instruction set reference.
• Bit 6 – T: Bit Copy Storage
The Bit Copy instructions BLD (Bit LoaD) and BST (Bit STore) use the T-bit as source or destination for the operated bit. A bit from a register in the Register File can be copied
into T by the BST instruction, and a bit in T can be copied into a bit in a register in the
Register File by the BLD instruction.
• Bit 5 – H: Half Carry Flag
The Half Carry Flag H indicates a Half Carry in some arithmetic operations. Half Carry is useful in BCD arithmetic. See the “Instruction Set Description” for detailed information.
• Bit 4 – S: Sign Bit, S = N ⊕ V
The S-bit is always an exclusive or between the Negative Flag N and the Two’s Comple- ment Overflow Flag V. See the “Instruction Set Description” for detailed information.
• Bit 3 – V: Two’s Complement Overflow Flag
The Two’s Complement Overflow Flag V supports two’s complement arithmetics. See
the “Instruction Set Description” for detailed information.
• Bit 2 – N: Negative Flag
The Negative Flag N indicates a negative result in an arithmetic or logic operation. See
the “Instruction Set Description” for detailed information.
• Bit 1 – Z: Zero Flag
The Zero Flag Z indicates a zero result in an arithmetic or logic operation. See the
“Instruction Set Description” for detailed information.
• Bit 0 – C: Carry Flag
The Carry Flag C indicates a carry in an arithmetic or logic operation. See the “Instruc-
tion Set Description” for detailed information.

The stack pointer stores temporary data. In reading over the code, I have yet to assimilate what is being measured, or where exactly I want to process the data I gather. But I do know how to find capacitance! I need to determine the dv/dt and current, which means I have a device to measure all three! if I so choose. Or maybe there is an easier way to go about it, though in searching through all manuals capacitance as a word only appears twice!, so this path seems unlikely to result in success.

 

 

 

 

 

 
         

 

 

Computer Used for Programming
Command Line Prompt .
 

Now that the code is written to get capacitance, we are interested in how this is displayed to the world, and so want to develop a GUI. As a beginning point, I read over the tkinter and looked at the following code in python:

#
# hello3.step.py
# receive and plot step response
# Neil Gershenfeld CBA MIT
# 10/29/05
#
from Tkinter import *
import serial

WINDOW = 600
NSAMPLES = 254
MAX = 1040
eps = .9
saveflag = 0
index = 0
path = []
step = []
path_filt = []
step_filt = []
baseline = []

def idle(parent,canvas):
   global index, channel, baseline, path, path_filt, step, step_filt, saveflag
   #
   # idle routine
   #
   eps = float(sfilter.get())
   lo_dn = ord(ser.read())
   hi_dn = ord(ser.read())
   lo_up = ord(ser.read())
   hi_up = ord(ser.read())
   if ((lo_dn == 1) & (hi_dn == 2) & (lo_up == 3) & (hi_up == 4)):
      if (path_filt == []):
         path_filt = path
             step_filt = step
      else:
         for i in range(len(path_filt)):
                path_filt[i] = (1-eps)*path_filt[i] + eps*path[i]
         for i in range(len(step_filt)):
                step_filt[i] = (1-eps)*step_filt[i] + eps*step[i]
      canvas.delete("path")
      canvas.create_line(path_filt,tag="path",width=3,fill="#00b000")
      if (baseline != []):
         canvas.delete("baseline_path")
         canvas.create_line(baseline,tag="baseline_path",width=3,fill="#b00000")
      canvas.itemconfigure("y0",text="y[0]: %.2f"%step_filt[0])
      canvas.itemconfigure("y1",text="y[1]: %.2f"%step_filt[1])
      canvas.itemconfigure("y-1",text="y[-1]: %.2f"%step_filt[-1])
      canvas.coords('x0',0,.95*WINDOW,step_filt[0],WINDOW)
      if (saveflag == 1):
         file = open(soutfile.get(),"w")
             for i in range(len(step_filt)):
                file.write("%f\n"%(step_filt[i]))
             file.close()
             print 'saved to '+soutfile.get()
         saveflag = 0
      index = 0
      path = []
      step = []
   else:
      value_up = 256*hi_up + lo_up
      value_dn = 256*hi_dn + lo_dn
      value = (value_up + (1023-value_dn))/2.0
      index += 2
      step.insert(0,value)
      path.insert(0,WINDOW-value*WINDOW/float(MAX))
      path.insert(0,WINDOW-index*WINDOW/float(NSAMPLES))
   parent.after_idle(idle,parent,canvas)

def save_data(parent):
   global saveflag
   saveflag = 1

def store_baseline(parent):
   global path_filt, baseline
   baseline = []
   for i in range(len(path_filt)):
      baseline.append(path_filt[i])

#
# open serial port
#
#ser = serial.Serial('/dev/ttyUSB0',9600)
ser = serial.Serial('/dev/ttyS0',9600)
#ser = serial.Serial('COM6',9600)
ser.setDTR()
#
# find framing
#
print "finding framing ..."
byte2 = 0
byte3 = 0
byte4 = 0
while 1:
   byte1 = byte2
   byte2 = byte3
   byte3 = byte4
   byte4 = ord(ser.read())
   if ((byte1 == 1) & (byte2 == 2) & (byte3 == 3) & (byte4 == 4)):
      print "start plotting"
      break
#
# start plotting
#
root = Tk()
root.title('hello3.step.py')
root.bind('q','exit')

canvas = Canvas(root, width=WINDOW, height=WINDOW, background='white')
canvas.create_text(.2*WINDOW,.9*WINDOW,font=("Helvetica", 24),tags="y0",fill="#0000b0")
canvas.create_text(.5*WINDOW,.9*WINDOW,font=("Helvetica", 24),tags="y1",fill="#0000b0")
canvas.create_text(.8*WINDOW,.9*WINDOW,font=("Helvetica", 24),tags="y-1",fill="#0000b0")
canvas.create_rectangle(0,.95*WINDOW,0,WINDOW, tags='x0', fill='#b00000')
canvas.pack()

ioframe = Frame(root)
Label(ioframe, text=" filter (0-1):").pack(side="left")
sfilter = StringVar()
sfilter.set(str(eps))
Entry(ioframe, width=5, textvariable=sfilter).pack(side="left")
Label(ioframe, text=" ").pack(side="left")
basebtn = Button(ioframe, text="store baseline")
basebtn.bind('<Button-1>',store_baseline)
basebtn.pack(side="left")
Label(ioframe, text=" ").pack(side="left")
savebtn = Button(ioframe, text="save data")
savebtn.bind('<Button-1>',save_data)
savebtn.pack(side="left")
Label(ioframe, text=" output file:").pack(side="left")
soutfile = StringVar()
soutfile.set("out.dat")
Entry(ioframe, width=10, textvariable=soutfile).pack(side="left")
Label(ioframe, text=" ").pack(side="left")
quitbtn = Button(ioframe, text="quit")
quitbtn.bind('<Button-1>','exit')
quitbtn.pack(side="left")
ioframe.pack()

root.after(100,idle,root,canvas)
root.mainloop()