Measure something: add a sensor to a microcontroller board that you have designed and read it.
*Demonstrate workflows used in circuit board design and fabrication.
*Implement and interpret programming protocols.
*Described your design and fabrication process using words/images/screenshots.
*Explained the programming process/es you used and how the microcontroller datasheet helped you.
*Explained problems and how you fixed them.
*Included original design files and code.
For this assignment I decided to test alternatives that can be useful for my final project so I chose to work with the temperature sensor. Then I started designing with the "Eagle" software, then I performed all the procedure for its construction, first milling the board using the Roland Modela 20X machine and then soldering the components that are needed.
To program the board, I downloaded from the Fab Academy classes, "hello.temp.45.py".
Using Ubuntu, I proceeded to program the microcontroller with the previously downloaded files. First I had to install python and then run it.
The programming was successful, there are the commands: - python hello.temp.45.py /dev/ttyUSB0
I chose to work with the NTC temperature sensor
I opened Eagle software and after selected all the components that I needed from the fab library :
Here you have the list:
4 R 10k ohm
1 NTC sensor
1 cap 1 uF
1 Jumper *6
1 Attiny45
1 pin ISP *6
I ordered them and made a board file.
Then exported in .png format
And start milling:
I used 0.010" milling tool to mill and 1/32" milling tool to cut,
First using the 0.010" milling tool, I change it on the top. Load .png,
Parameters:
diameter (mm): 0.254
overlap: 0.5
offsets (-1 to fill): -1
error: 0.1 pixels
intensity: 0.5
z: -0.1 mm
And make .path
Set xero, moving "x", "y" and "z", click on make .rml and Send it !
Then, change the 0.010" milling tool for 1/32" milling tool to cut,
Additionally you create a silhouette of the board, you can do it with the same Eagle or with paint, I did it with paint and loaded the image with the same dimensions and set it at the same point of origin.
This is the first time that I did it!, I learned that it is an easier way to get the boards, more accurately, but in Fab Lab Tecsup anyway, they told me to do not do it, because it will damage the base of work.
Soldering:
Then I selected the electronic components and started soldering:
I really enjoy it
As you can see there is the result:
I did it! I redrew it!
Testing with AVR
Visit my week 8 to find the attiny45 datasheet
Using this I made the connections correctly in the eagle software.
In case of some correction needed, using datasheet you are able to verify.
In order to program this board is vitally important to use the datasheet that gives you the exact location and name of each pin in a ATtiny 45 microcontroller. Then you are able to make the connections to the input device. In this case a NTC sensor.
It convert an analog signal into a digital one. In this case, the analog input gets a sign from 0 to 5 volts and transform it into a digital sign of 8 bits. (From 0 to 255).
The analog-digital converter (ADC) that equips many micro controllers converts an analog external volt in a number, that we can operate with.
Features:
• 10-bit Resolution
• 1 LSB Integral Non-linearity
• ± 2 LSB Absolute Accuracy
• 65 - 260 µs Conversion Time
• Up to 15 kSPS at Maximum Resolution
• Four Multiplexed Single Ended Input Channels
• Two differential input channels with selectable gain
• Temperature sensor input channel
• Optional Left Adjustment for ADC Result Readout
• 0 - VCC ADC Input Voltage Range
• Selectable 1.1V / 2.56V ADC Voltage Reference
• Free Running or Single Conversion Mode
• ADC Start Conversion by Auto Triggering on Interrupt Sources
• Interrupt on ADC Conversion Complete
• Sleep Mode Noise Cancele
• Unipolar / Bibilar Input Mode
• Input Polarity Reversal Mode
The ATtiny25/45/85 features a 10-bit successive approximation Analog to digital Converter (ADC). The ADC is connected to a 4-channel Analog Multiplexer which allows one differential voltage input and four single-ended voltage inputs constructed from the pins of Port B. The differential input (PB3, PB4 or PB2, PB5) is equipped with a programmable gain stage, providing amplification step of 26 dB (20x) on the differential input voltage before the A/D conversion. The single-ended voltage inputs refer to 0V (GND).
The ADC contains a Sample and Hold circuit which ensures that the input voltage to the ADC is held at a constant level during conversion.
Internal reference voltages of nominally 1.1V / 2.56V are provided on-chip. Alternatively, VCC can be used as reference voltage for single ended channels. There is also an option to use an external voltage reference and turn-off the internal voltage reference.The ADC converts an analog input voltage to a 10-bit digital value through successive approximation. The minimum value represents GND and the maximum value represents the voltage on VCC, the voltage on the AREF pin or an internal 1.1V / 2.56V voltage reference.
The voltage reference for the ADC may be selected by writing to the REFS[2:0] bits in ADMUX. The VCC supply, the AREF pin or an internal 1.1V / 2.56V voltage reference may be selected as the ADC voltage reference.
Optionallythe internal 2.56V voltage reference may be decoupled by an external capacitor at the AREF pin to improve noise immunity.
The analog input channel and differential gain are selected by writing to the MUX[3:0] bits in ADMUX. Any of the four ADC input pins ADC[3:0] can be selected as single ended inputs to the ADC. ADC2 or ADC0 can be selected as positive input and ADC0, ADC1, ADC2 or ADC3 can be selected as negative input to the differential gain amplifier.
If differential channels are selected, the differential gain stage amplifies the voltage difference between the selected input pair by the selected gain factor, 1x or 20x, according to the setting of the MUX[3:0] bits in ADMUX.
This amplified value then becomes the analog input to the ADC. If single ended channels are used, the gain amplifier is bypassed altogether.
If ADC0 or ADC2 is selected as both the positive and negative input to the differential gain amplifier (ADC0-ADC0 or ADC2-ADC2), the remaining offset in the gain stage and conversion circuitry can be measured directly as the result of the conversion. This figure can be subtracted from subsequent conversions with the same gain setting to reduce offset error to below 1 LSW.
The on-chip temperature sensor is selected by writing the code “1111” to the MUX[3:0] bits in ADMUX register when the ADC4 channel is used as an ADC input.
The ADC is enabled by setting the ADC Enable bit, ADEN in ADCSRA. Voltage reference and input channel selections will not go into effect until ADEN is set. The ADC does not consume power when ADEN is cleared, so it is recommended to switch off the ADC before entering power saving sleep modes. The ADC generates a 10-bit result which is presented in the ADC Data Registers, ADCH and ADCL. By default, the result is presented right adjusted, but can optionally be presented left adjusted by setting the ADLAR bit in ADMUX.
If the result is left adjusted and no more than 8-bit precision is required, it is sufficient to read ADCH. Otherwise, ADCL must be read first, then ADCH, to ensure that the content of the data registers belongs to the same conversion.
Once ADCL is read, ADC access to data registers is blocked. This means that if ADCL has been read, and a conversion completes before ADCH is read, neither register is updated and the result from the conversion is lost.
When ADCH is read, ADC access to the ADCH and ADCL Registers is e-enabled.
The ADC has its own interrupt which can be triggered when a conversion completes. When ADC access to the data registers is prohibited between reading of ADCH and ADCL, the interrupt will trigger even if the result is lost.
A single conversion is started by writing a logical one to the ADC Start Conversion bit, ADSC. This bit stays high as long as the conversion is in progress and will be cleared by hardware when the conversion is completed. If a different data channel is selected while a conversion is in progress, the ADC will finish the current conversion before performing the channel change.
Alternatively, a conversion can be triggered automatically by various sources. Auto Triggering is enabled by setting the ADC Auto Trigger Enable bit, ADATE in ADCSRA. The trigger source is selected by setting the ADC Trigger Select bits, ADTS in ADCSRB (see description of the ADTS bits for a list of the trigger sources). When a positive edge occurs on the selected trigger signal, the ADC prescaler is reset and a conversion is started. This provides a method of starting conversions at fixed intervals. If the trigger signal still is set when the conversion completes, a new conversion will not be started. If another positive edge occurs on the trigger signal during conversion, the edge will be ignored. Note that an Interrupt Flag will be set even if the specific interrupt is disabled or the Global Interrupt Enable bit in SREG is cleared. A conversion can thus be triggered without causing an interrupt. However, the Interrupt Flag must be cleared in order to trigger a new conversion at the next interrupt event.
Using the ADC Interrupt Flag as a trigger source makes the ADC start a new conversion as soon as the ongoing conversion has finished. The ADC then operates in Free Running mode, constantly sampling and updating the ADC Data Register. The first conversion must be started by writing a logical one to the ADSC bit in ADCSRA. In this mode the ADC will perform successive conversions independently of whether the ADC Interrupt Flag, ADIF is cleared or not.
You need to download: .make file,.c file and .py file. Save all those in a single file.
Now you have to open "Terminal" in Ubuntu.
>Enter to the file where those were downloaded
I will use my ISP board to achieve this challenge
Write:
sudo make -f hello.temp.45.make program-usbtiny
Good, done!
Now, open .py file to interact with the temperature sensor.
python hello.light.45.py /dev/ttyUSB1
Using the heat gun you can see how I tested it:
//
//
// hello.temp.45.c
//
// thermistor hello-world
// 9600 baud FTDI interface
//
// Neil Gershenfeld
// 10/27/10
//
// (c) Massachusetts Institute of Technology 2010
// This work may be reproduced, modified, distributed,
// performed, and displayed for any purpose. Copyright is
// retained and must be preserved. The work is provided
// as is; no warranty is provided, and users accept all
// liability.
//
#include
#include
#define output(directions,pin) (directions |= pin) // set port direction for output
#define set(port,pin) (port |= pin) // set port pin
#define clear(port,pin) (port &= (~pin)) // clear port pin
#define pin_test(pins,pin) (pins & pin) // test for port pin
#define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set
#define bit_delay_time 102 // bit delay for 9600 with overhead
#define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay
#define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay
#define char_delay() _delay_ms(10) // char delay
#define serial_port PORTB
#define serial_direction DDRB
#define serial_pin_out (1 << PB2)
void put_char(volatile unsigned char *port, unsigned char pin, char txchar) {
//
// send character in txchar on port pin
// assumes line driver (inverts bits)
//
// start bit
//
clear(*port,pin);
bit_delay();
//
// unrolled loop to write data bits
//
if bit_test(txchar,0)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,1)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,2)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,3)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,4)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,5)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,6)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
if bit_test(txchar,7)
set(*port,pin);
else
clear(*port,pin);
bit_delay();
//
// stop bit
//
set(*port,pin);
bit_delay();
//
// char delay
//
bit_delay();
}
int main(void) {
//
// main
//
static char chr;
//
// set clock divider to /1
//
CLKPR = (1 << CLKPCE);
CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0);
//
// initialize output pins
//
set(serial_port, serial_pin_out);
output(serial_direction, serial_pin_out);
//
// init A/D
//
ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) // VCC ref
| (0 << ADLAR) // right adjust
| (0 << MUX3) | (1 << MUX2) | (1 << MUX1) | (1 << MUX0); // 20(PB4-PB3)
ADCSRA = (1 << ADEN) // enable
| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
ADCSRB = (1 << BIN); // bipolar mode
//
// main loop
//
while (1) {
//
// send framing
//
put_char(&serial_port, serial_pin_out, 1);
char_delay();
put_char(&serial_port, serial_pin_out, 2);
char_delay();
put_char(&serial_port, serial_pin_out, 3);
char_delay();
put_char(&serial_port, serial_pin_out, 4);
char_delay();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// send result
//
chr = ADCL;
put_char(&serial_port, serial_pin_out, chr);
char_delay();
chr = ADCH;
put_char(&serial_port, serial_pin_out, chr);
char_delay();
}
}
By this code I can understand that here is the formula that measures the temperature and how the logic is done to be able to register as increase and reduce. But I have not risked changing anything. In this code .py is the interface that interacts with us to visualize this data, in this part if I made a change, look here and then try it.
#
# hello.temp.45.py
#
# receive and display temperature
# hello.temp.45.py serial_port
#
# Neil Gershenfeld
# CBA MIT 3/27/12
#
# (c) Massachusetts Institute of Technology 2012
# Permission granted for experimental and personal use;
# license for commercial sale available from MIT
#
from Tkinter import *
from numpy import log
import serial
WINDOW = 600 # window size
eps = 0.5 # filter time constant
filter = 0.0 # filtered value
def idle(parent,canvas):
global filter, eps
#
# idle routine
#
byte2 = 0
byte3 = 0
byte4 = 0
ser.flush()
while 1:
#
# find framing
#
byte1 = byte2
byte2 = byte3
byte3 = byte4
byte4 = ord(ser.read())
if ((byte1 == 1) & (byte2 == 2) & (byte3 == 3) & (byte4 == 4)):
break
low = ord(ser.read())
high = ord(ser.read())
value = 256*high + low
if (value > 511):
value -= 1024
V = 2.5 - value*5.0/(20.0*512.0)
R = 10000.0/(5.0/V-1.0)
# NHQ103B375R5
# R25 10000 (O)
# B (25/85) 3750 (K)
# R(T(C)) = R(25)*exp(B*(1/(T(C)+273.15)-(1/(25+273.15))))
B = 3750.0
R25 = 10000.0
T = 1.0/(log(R/R25)/B+(1/(25.0+273.15))) - 273.15
filter = (1-eps)*filter + eps*T
x = int(.2*WINDOW + (.9-.2)*WINDOW*(filter-20.0)/10.0)
canvas.itemconfigure("text",text="%.2f"%filter)
canvas.coords('rect1',.2*WINDOW,.05*WINDOW,x,.2*WINDOW)
canvas.coords('rect2',x,.05*WINDOW,.9*WINDOW,.2*WINDOW)
canvas.update()
parent.after_idle(idle,parent,canvas)
#
# check command line arguments
#
if (len(sys.argv) != 2):
print "command line: hello.temp.45.py serial_port"
sys.exit()
port = sys.argv[1]
#
# open serial port
#
ser = serial.Serial(port,9600)
ser.setDTR()
#
# start plotting
#
root = Tk()
root.title('hello.temp.45.py (q to exit)')
root.bind('q','exit')
canvas = Canvas(root, width=WINDOW, height=.25*WINDOW, background='white')
canvas.create_text(.1*WINDOW,.125*WINDOW,text=".33",font=("Helvetica", 24),tags="text",fill="#0000b0")
canvas.create_rectangle(.2*WINDOW,.05*WINDOW,.3*WINDOW,.2*WINDOW, tags='rect1', fill='#b00000')
canvas.create_rectangle(.3*WINDOW,.05*WINDOW,.9*WINDOW,.2*WINDOW, tags='rect2', fill='#0000b0')
canvas.pack()
root.after(100,idle,root,canvas)
root.mainloop()
Here is the code that I change, I'm not a specialist of this topic, but I tried my best, this part is about how the interface of temperature sensor looks, I change it with differente name, color and dimension
# start plotting
#
root = Tk()
root.title('Temperature Sensor (q to exit)')
root.bind('q','exit')
canvas = Canvas(root, width=WINDOW, height=.3*WINDOW, background='white')
canvas.create_text(.1*WINDOW,.125*WINDOW,text=".33",font=("Helvetica", 24),tags="text",fill="#0000b0")
canvas.create_rectangle(.2*WINDOW,.05*WINDOW,.3*WINDOW,.2*WINDOW, tags='rect1', fill='#8100b0')
canvas.create_rectangle(.3*WINDOW,.05*WINDOW,.9*WINDOW,.2*WINDOW, tags='rect2', fill='#1db000')
canvas.pack()
root.after(100,idle,root,canvas)
root.mainloop()
Read to purple and blue to green, using this codes (Color represented in hexagesimal): Click here
As you can see in the video, I managed to program an input device. This is evidenced when data increases and decreases.
I achieved to add a temperature sensor to ATtiny45 board.
I learned about the code and make some changes to the code creating my own code and programming the temperature sensor board