Week 8
Input Devices

Step Response

I started this week by trying to make a step response input. My goal is to make a few different types of buttons (that will eventually fit in my alarm clock) using the step response input and different vinyl cutter shapes.

Here is a schematic of how the step response input works. The microcontroller outputs a pulse through the charge pin. The contact and the resistor form an RC network that causes a charging delay at the ADC pin. The microcontroller runs ADC conversions to measure the charging delay, which is related to the size of the parasitic capacitance. The charge signal is also sent out with the ADC signal and GND as a shield.



I made the hello.step.45.cad board with the modela and had no issues stuffing the parts. After installing gavrasm on my PC, I was able to compile and program hello.step.45.asm on the tiny45.



It took me a while to figure out how to use the Python script on my Windows PC. First, I had to install the latest version of Python. Then I needed to download and install two extra modules for python: pyserial and pywin32. After installing these modules, the hello.45.step.py program ran successfully.

Note: It is useful to update your Windows path to include the Python (and Gavrasm) directory. You do this by right clicking My Computer -> Properties -> Advanced -> Environment Variables.

So the single input version seemed to work ok. When I touched the wire going to the ADC input the response changed. My next goal was to make a slider switch. I figured I would need an input for two triangular contacts, so I made a board with two step inputs. Unfortunately, I didn't connect the second input to an ADC pin, as pointed out by Charlie. I re-made the two input board using pins 6 and 7 as the charge and ADC inputs, respectively.



When I first tested this board, I just programmed Neil's hello.step.45.asm code to check that the first input was working. It wasn't. After a while of debugging and not finding anything, I decided to replace the tiny45. This did the trick and the first input worked as expected.

Next, I tried to test the second input by changing the assembly code so that the charging pin was PB1 and the ADC input was ADC1. When I loaded up the python script I only got a flat line. I realized that the ADC input pin I was using was the same pin that I was using to transmit data back to the serial port.

I did some board surgery to move my ADC input from ADC1 to ADC2 for the second input. This means that I also had to move the charging pin for the first input from PB4/ADC2 to PB0.



I tested this board in a similar fashion and each input functioned separately, so I knew the hardware was ok.

The next major step was figuring out the assembly and python code. Siggi helped me a lot during this, especially in explaining the assembly code and how framing worked with serial transmission. The code was adapted from hello.step.45.asm; the major changes included adding another charge bit, changing the ADCMUX, and adding a second ADC conversion for the second input. After quite a bit of debugging and timing issues we came up with the following code:

Assembly:
; loop for 1st input
   loop1:
      cbi ADMUX, MUX3 ; set MUX to ADC3
      cbi ADMUX, MUX2 ; "
      sbi ADMUX, MUX1 ; "
      sbi ADMUX, MUX0 ; "

      ldi delay_count, 254
         ;
	 ; settle sample and start upward step response (1st input)
	 ;
         cbi PORTB, charge_pin1
         rcall settle
	 mov temp, delay_count
         sbi PORTB, charge_pin1
	 ;
         ; wait for delay
	 ;
	 addelayup1:
	    dec temp
	    brne addelayup1
         ;
	 ; read response
	 ;
         sbi ADCSRA, ADSC ; start conversion
         adloopup1:
            sbic ADCSRA, ADSC ; loop until complete
            rjmp adloopup1
	 ;
	 ; save conversion
	 ;
         in uplo1, ADCL ; get low byte
         in uphi1, ADCH ; get high byte
         ;
	 ; settle sample and start downward step response (1st input)
	 ;
         rcall settle
	 mov temp, delay_count
         cbi PORTB, charge_pin1
	 ;
         ; wait for delay
	 ;
	 addelaydown1:
	    dec temp
	    brne addelaydown1
         ;
	 ; read response
	 ;
         sbi ADCSRA, ADSC ; start conversion
         adloopdown1:
            sbic ADCSRA, ADSC ; loop until complete
            rjmp adloopdown1
	 ;
	 ; send conversions
	 ;
         in txbyte, ADCL ; low down byte
         rcall putchar
         in txbyte, ADCH ; hi down byte
         rcall putchar
         mov txbyte, uplo1 ; low up byte
         rcall putchar
         mov txbyte, uphi1 ; hi up byte
         rcall putchar
         rcall char_delay

; loop for 2nd input
   loop2:	
      cbi ADMUX, MUX3 ; set MUX to ADC2
      cbi ADMUX, MUX2 ; "
      sbi ADMUX, MUX1 ; "
      cbi ADMUX, MUX0 ; "

      ldi delay_count, 254
         ;
	 ; settle sample and start upward step response (2nd input)
	 ;
         cbi PORTB, charge_pin2
         rcall settle
	 mov temp, delay_count
         sbi PORTB, charge_pin2
	 ;
         ; wait for delay
	 ;
	 addelayup2:
	    dec temp
	    brne addelayup2
         ;
	 ; read response
	 ;
         sbi ADCSRA, ADSC ; start conversion
         adloopup2:
            sbic ADCSRA, ADSC ; loop until complete
            rjmp adloopup2
	 ;
	 ; save conversion
	 ;
         in uplo2, ADCL ; get low byte
         in uphi2, ADCH ; get high byte
         ;
	 ; settle sample and start downward step response (2nd input)
	 ;
         rcall settle
	 mov temp, delay_count
         cbi PORTB, charge_pin2
	 ;
         ; wait for delay
	 ;
	 addelaydown2:
	    dec temp
	    brne addelaydown2
         ;
	 ; read response
	 ;
         sbi ADCSRA, ADSC ; start conversion
         adloopdown2:
            sbic ADCSRA, ADSC ; loop until complete
            rjmp adloopdown2
	 ;
	 ; send conversions
	 ;
         in txbyte, ADCL ; low down byte
         rcall putchar
         in txbyte, ADCH ; hi down byte
         rcall putchar
         mov txbyte, uplo2 ; low up byte
         rcall putchar
         mov txbyte, uphi2 ; hi up byte
         rcall putchar
         rcall char_delay
      ;
      ; 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 loop1



Python:
import serial
#
# open serial port
#
ser = serial.Serial('com2',9600)
ser.setDTR()
ser.flush()

#
# find framing
#
byte2 = 0
byte3 = 0
byte4 = 0

value1 = 0
value2 = 0


while 1:
	while 1:
		byte1 = byte2
		byte2 = byte3
		byte3 = byte4
		byte4 = ord(ser.read())
		if ((byte1 == 1) & (byte2 == 2) & (byte3 == 3) & (byte4 == 4)):
			break
	downlo = ord( ser.read() )	
	downhi = ord( ser.read() )	
	uplo = ord( ser.read() )	
	uphi = ord( ser.read() )	
	value_up = uphi*256+uplo
	value_down = downhi*256+downlo

	value1 = (value_up + (1023-value_down))/2.0

	downlo = ord( ser.read() )	
	downhi = ord( ser.read() )	
	uplo = ord( ser.read() )	
	uphi = ord( ser.read() )	
	value_up = uphi*256+uplo
	value_down = downhi*256+downlo
		
	value2 = (value_up + (1023-value_down))/2.0

	print "Value1=%f\tValue2=%f"%(value1, value2)

	slider_value = 100*(value1 - value2) / (value1 + value2)

	print "Slider value = %f"%slider_value



This code outputs the end values of each step response input (the ADC conversion after a delay of 254). When I touched either of the wires, these numbers changed, so everything was looking good. Next I cut two triangular pieces of copper to try out the slider. Once I hooked everything up, changing the position of the ground plate (or my finger) didn't really have any effect on the values for each of the step inputs. I am not sure how to fix this, and I don't understand why I didn't see a difference as I moved the plate across the triangles. Here is the entire test setup: