This week will work on implementation reading of sensor data. And visualizing of received data using the some chart and data visualization library.
All files that I have demonstrated below are also available in this zip file
Let try from simple and let connect IR sensor using the Arduino UNO to get first prototype. Arduino IDE contain libraries that simplify work with Serial port. We loose in program size (and it may be critical in real realizations using the attiny controllers, but in case of arduino we have ~32K memory to use so it big enough and give a win on development speed)
Let connect the IR sensor to analog input port and let do simple C program that read data from sensor each 2 seconds (to avoid many noise) and send data to serial. Below you can see the arduino sketch and the output via seral.
#include <SharpIR.h>
#define ir A0
#define model 1080
SharpIR SharpIR(ir, model);
unsigned long starttime=millis();
void setup() {
Serial.begin(9600);
}
void loop() {
delay(2000);
unsigned long pepe1=millis();
int dis=SharpIR.distance();
Serial.print("Distance: ");
Serial.println(dis);
Serial.print("Runing since: ");
unsigned long r_since=millis()-starttime;
Serial.println(r_since);
}
Distance: 71
Runing since: 2003
Distance: 64
Runing since: 4007
Distance: 37
Runing since: 6011
Distance: 34
Runing since: 8015
Distance: 11
Runing since: 10019
Distance: 8
Runing since: 12024
Distance: 7
Runing since: 14028
Distance: 7
Runing since: 16032
Distance: 10
Runing since: 18037
Distance: 9
Runing since: 20041
Distance: 22
Runing since: 22045
Distance: 21
Runing since: 24049
Distance: 176
Runing since: 26054
Distance: 460
Runing since: 28058
Distance: 11
Now let use same program and change a little output so we can see the kind of "timestamp" of program running and it could be used to place values to timeline
unsigned long r_since=millis()-starttime;
if (r_since<10) Serial.print(B0);
if (r_since<100) Serial.print(B0);
if (r_since<1000) Serial.print(B0);
if (r_since<10000) Serial.print(B0);
if (r_since<100000) Serial.print(B0);
if (r_since<1000000) Serial.print(B0);
if (r_since<10000000) Serial.print(B0);
Serial.print(r_since);
Serial.print(" ");
Serial.println(dis);
0006011 38
0008015 37
0010019 26
0012023 21
0014028 855
0016032 39
0018036 30
0020040 13
Now we can use this data for visualization. Let see it a little later.
I took as example one of the provided code from the current week assignment. I tried to improve a little the Serial communication and integrated assembler library to same project. Goal was to use in same project the assembler code in parallel with the C (using the standard makefile and the XCode as IDE). So here what I have now.
#include <avr/io.h>
; correct for avr/io.h 0x20 port offset for io instructions
#define UART_Port (PORTB-0x20)
#define UART_Tx 0
#define bitcnt r18
#define delayArg 19
#if F_CPU == 8000000L
#warning Using 8Mhz CPU timing
#define TXDELAY 21
#elif F_CPU == 16000000L
#warning Using 16Mhz CPU timing
#define TXDELAY 44
#elif F_CPU == 1000000L
#warning Using 16Mhz CPU timing
#define TXDELAY 3
#else
#define TXDELAY 21
#endif
.global TxByte
; transmit byte in r24 - 12 instructions
; calling code must set Tx line to idle state (high) or 1st byte may be lost
; i.e. PORTB |= (1<
SRC = $(wildcard *.c)
OBJDIR = Builds
ASRC = $(wildcard *.S)
void TxByte(char);
//
// hello.load.45.c
//
// step response loading 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 <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include "BasicSerial.h"
#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 charge_delay_1() _delay_us(1) // charge delay 1
#define charge_delay_2() _delay_us(10) // charge delay 2
#define charge_delay_3() _delay_us(100) // charge delay 3
#define settle_delay() _delay_us(100) // settle delay
#define char_delay() _delay_ms(10) // char delay
#define serial_port PORTB
#define serial_direction DDRB
#define serial_pin_out (1 << PB2)
#define charge_port PORTB
#define charge_direction DDRB
#define charge_pin (1 << PB3)
void serOut(const char* str)
{
while (*str) TxByte (*str++);
}
void collect_step(unsigned char *up_lo_p, unsigned char *up_hi_p, unsigned char *down_lo_p, unsigned char *down_hi_p, char* snum) {
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
*up_lo_p = ADCL;
*up_hi_p = ADCH;
//
// settle, discharge, and wait 2
//
settle_delay();
clear(charge_port, charge_pin);
charge_delay_2();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
*down_lo_p = ADCL;
*down_hi_p = ADCH;
//
// send result
//
itoa(*up_lo_p,snum,10);
serOut(snum);
itoa (*up_hi_p,snum,10);
serOut(snum);
itoa (*down_lo_p,snum,10);
serOut(snum);
itoa (*down_hi_p,snum,10);
serOut(snum);
}
int main(void) {
//
// main
//
serOut("Starting\n");
static unsigned char up_lo,up_hi,down_lo,down_hi;
//
// 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);
clear(charge_port, charge_pin);
output(charge_direction, charge_pin);
//
// init A/D
//
ADMUX = (0 << REFS2) | (0 << REFS1) | (0 << REFS0) // Vcc ref
| (0 << ADLAR) // right adjust
| (0 << MUX3) | (0 << MUX2) | (1 << MUX1) | (0 << MUX0); // PB4
ADCSRA = (1 << ADEN) // enable
| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
//
// main loop
//
char snum[5];
while (1) {
//
// send framing
//
serOut("1");
serOut("2");
serOut("3");
serOut("4");
//
// settle, charge, and wait 1
//
settle_delay();
set(charge_port, charge_pin);
charge_delay_1();
collect_step(&up_lo, &up_hi, &down_lo, &down_hi, snum);
//
// settle, charge, and wait 2
//
settle_delay();
set(charge_port, charge_pin);
charge_delay_2();
collect_step(&up_lo, &up_hi, &down_lo, &down_hi, snum);
//
// settle, charge, and wait 3
//
settle_delay();
set(charge_port, charge_pin);
charge_delay_3();
collect_step(&up_lo, &up_hi, &down_lo, &down_hi, snum);
}
}
Using this method we can see that we won in app size and in some readability of code.
Now I have possibility to create a real card. My card will have 3 touch panels. It uses sensor based "step response" method. So touch is change the capacity assigned to the zone and it change the resistance that come with. So because of 1Mohm resistance - I can see the changes in voltage on pin. That I detect by checking values in high and in low state and comparing them.
Let make this card. First I did my visual check and I saw that in one location the trace was not cutted. So I need to fix it. And check it after again.
Let solder components on it.
Here is the result. BTW the additional change was applied later (I added one wire to fix missed path on the schema - the VCC was not related to capacitor that comes to RST pin. So each time RST produced it provoked RST as well on my programmer side. So fixed)
Now let program it. I use the code provided by Neil to step response slightly modified. Also I used the .py file to recive data from one of 3 touch pads to visualize them. Below is the result and used code (C code)
So we can see how it works.
//
// hello.load.45.c
//
// step response loading 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 <avr/io.h>
#include <util/delay.h>
#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 100 // 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 charge_delay_1() _delay_us(1) // charge delay 1
#define charge_delay_2() _delay_us(10) // charge delay 2
#define charge_delay_3() _delay_us(100) // charge delay 3
#define settle_delay() _delay_us(100) // settle delay
#define char_delay() _delay_ms(10) // char delay
#define ref (0 << REFS1) | (0 << REFS0) // reference voltage
#define serial_port PORTB
#define serial_direction DDRB
#define serial_pin_out (1 << PB1)
#define charge_port PORTA
#define charge_direction DDRA
#define charge_pin (1 << PA3)
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 unsigned char up_lo,up_hi,down_lo,down_hi;
//
// 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);
clear(charge_port, charge_pin);
output(charge_direction, charge_pin);
//
// init A/D
//
ADMUX = ref // Vcc ref
| (0 << ADLAR) // right adjust
| (0 << MUX2) | (0 << MUX1) | (0 << MUX0); // PB4
ADCSRA = (1 << ADEN) // enable
| (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // prescaler /128
//
// 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);
//
// settle, charge, and wait 1
//
settle_delay();
set(charge_port, charge_pin);
charge_delay_1();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
up_lo = ADCL;
up_hi = ADCH;
//
// settle, discharge, and wait 1
//
settle_delay();
clear(charge_port, charge_pin);
charge_delay_1();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
down_lo = ADCL;
down_hi = ADCH;
//
// send result
//
put_char(&serial_port, serial_pin_out, up_lo);
char_delay();
put_char(&serial_port, serial_pin_out, up_hi);
char_delay();
put_char(&serial_port, serial_pin_out, down_lo);
char_delay();
put_char(&serial_port, serial_pin_out, down_hi);
char_delay();
//
// settle, charge, and wait 2
//
settle_delay();
set(charge_port, charge_pin);
charge_delay_2();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
up_lo = ADCL;
up_hi = ADCH;
//
// settle, discharge, and wait 2
//
settle_delay();
clear(charge_port, charge_pin);
charge_delay_2();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
down_lo = ADCL;
down_hi = ADCH;
//
// send result
//
put_char(&serial_port, serial_pin_out, up_lo);
char_delay();
put_char(&serial_port, serial_pin_out, up_hi);
char_delay();
put_char(&serial_port, serial_pin_out, down_lo);
char_delay();
put_char(&serial_port, serial_pin_out, down_hi);
char_delay();
//
// settle, charge, and wait 3
//
settle_delay();
set(charge_port, charge_pin);
charge_delay_3();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
up_lo = ADCL;
up_hi = ADCH;
//
// settle, discharge, and wait 3
//
settle_delay();
clear(charge_port, charge_pin);
charge_delay_3();
//
// initiate conversion
//
ADCSRA |= (1 << ADSC);
//
// wait for completion
//
while (ADCSRA & (1 << ADSC))
;
//
// save result
//
down_lo = ADCL;
down_hi = ADCH;
//
// send result
//
put_char(&serial_port, serial_pin_out, up_lo);
char_delay();
put_char(&serial_port, serial_pin_out, up_hi);
char_delay();
put_char(&serial_port, serial_pin_out, down_lo);
char_delay();
put_char(&serial_port, serial_pin_out, down_hi);
char_delay();
}
}