Ever played with magic slates in your childhood? Well this project will show you how to make a digital magic slate using a PC, a touch screenand few other components.
Components Required
1. 4-wire resistive touch screen with connector
2. ATMega16 development board with 16MHz
3. 4 X 10kohms Resistor
4. Serial to USB converter or (Serial to RS-232 + RS-232 to USB converter)
5. PC/ Laptop
Software Required
2. Java Development Kit 7 or above
Description
Basically the project converts the analog voltage coming from the resistive touch screen into a two co-ordinate integer value and sends it to the PC through the microcontroller. The processing code takes these co-ordinates as inputs and draws a white dot for each co-ordinate, on the output screen.
Exclusive Digi-key Tools
So when you write continuously on the touch screen, the dots would be plotted close enough to make it look like a line or curve.
Code Explanation
ATMega16 Code Explanation
· Map the 4 pins of PORTA in the following way using “#define”
#define y1 PA1
#define x2 PA2
#define y2 PA3
#define x1 PA4
· Initialize the USART and ADC functions of the microcontroller.
· Enter into an infinite while loop
· Configure x1 (PA4) & x2 (PA2) as outputs. Set x1 (PA4) to high (+5V) state and x2 (PA2) to low (GND) state.
· Read the analog voltage at y2 (PA3) using ReadADC(3) command. Store the discrete value in the variable “x”
· Configure y1 (PA1) & y2 (PA3) as outputs. Set y1 (PA1) to high (+5V) state and y2 (PA3) to low (GND) state.
· Read the analog voltage at x1 (PA4) using ReadADC(4) command. Store the discrete value in the variable “y”
· Transmit the co-ordinates in “x, y” format to the PC using WrCoord(x,y) function.
Processing Code Explanation
1. First we define the output screen size and also fill the background with some color using size(width,height) and background(value) functions.
Note: I have taken width=690 and height=540. You can take any values but make sure it’s aspect ratio is same as that of the touch screen dimensions.
2. Next we need to create a serial connection, defining the COM port number where the board is connected and also the baud rate which is done by the following lines
Serial myport;
myport = new Serial(this,"COM9",57600);
COM9 is where my board is connected to and I have used baud rate=57600 bps since the program should keep up with my speed of writing.
3. Next we need to call a function whenever a data is available at the serial port. Then we need to read the data and store it in a string type variable.
void serialEvent(Serial p){
String stringData=myport.readStringUntil(10);
if(stringData!=null){
stringData=trim(stringData);
int data[]=int(split(stringData,','));
if(data.length==2){
x=data[0];
y=data[1];
}
Since our ATMega16 is programmed to continuously send the data (line after line), two set of co-ordinates may get into the “read” function same time causing errors. To avoid that we use “readStringUntil(10)” (where 10 is the ASCII value for a new line)instead of plain read. This is would help in setting a mark between two different co-ordinate by skipping every time after a new line occurs.
The trim() function is used to remove standard whitespace characters such as space, carriage return, and tab.
Example:”1009,1024/r/n” will be converted into “1009,1024”
4. Next we split the string to extract the x and y co-ordinate separately. For this we use the split(stringData,',') function and store the co-ordinates in two different address locations of a integer type array.
Example: “1009,1024” is split into and stored as x=1009 and y=1024
5. Now that we have the raw co-ordinate value, we need to convert them into a sensible range of values corresponding to the screen size we are going to plot our sketch onto. For this we use the map(value, start1, stop1, start2, stop2) function. Where “value” is the incoming value to be converted
“start1” is the lower bound of the value's current range
“stop1” is the upper bound of the value's current range
“start2” is the lower bound of the value's target range
“stop2”is the upper bound of the value's target range
Then the converted co-ordinates are stored in variables “xcord” and “ycord”.
6. Lastly we draw a solid circle (with small radius) at the co-ordinate given by xcord, ycord variables using ellipse() function.
7. At any point of time you can clear the drawing screen by pressing ‘c’ on the keyboard. This is achieved by using keyPressed() function.
Setup Instructions
Setup Instructions
1. You can either compile the code given using a suitable compiler like WINAVR with ATMEL STUDIO/AVR STUDIO or simply burn the “slate.hex” file given below.
2. Plug in the converter using an USB cable. If you are connecting it for the first time then get the drivers installed and note down the COM port to which the converter is connected. Go to System Properties> Device Manager and look out for the converter by its name to see the COM port number.
3. Open the processing software and copy paste the code given below. Remember to edit the COM port number.
4. Click on the following button and also turn ON the development board.
5. Now using your finger or a stylus, try drawing something onto the touch screen. If everything is done properly then you should see something on the output screen window of the processing.
Circuit:
Code:
************************C Code************************** /* * magicslate.c * * Created: 9/20/2013 8:50:01 PM * Author: Ganesh Selvaraj */ #define F_CPU 16000000UL #define y1 PA1 #define x2 PA2 #define y2 PA3 #define x1 PA4 #define USART_BAUDRATE 57600 #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) #include <avr/io.h> #include <util/delay.h> void BlueInit() { UCSRB |= (1 << RXEN) | (1 << TXEN); // Enable transmission and reception UCSRC |= (1 << URSEL) | (1<<USBS) | (1 << UCSZ0) | (1 << UCSZ1); // Use 8-bit character sizes UBRRL = BAUD_PRESCALE; UBRRH = (BAUD_PRESCALE >> 8); } unsigned int BlueRdChar() { while ((UCSRA & (1 << RXC)) == 0); // wait until data has been received return(UDR); // return the byte } void BlueWrChar(unsigned char d) { while ((UCSRA & (1 << UDRE)) == 0); // wait till UDR is ready UDR = d; // send data } void BlueWrString(const char *msg) { while(*msg!='\0') { BlueWrChar(*msg); msg++; } } void BlueWrInt(int val,unsigned int field_length) { char str[5]={0,0,0,0,0}; int i=4,j=0; while(val) { str[i]=val%10; val=val/10; i--; } if(field_length==-1) while(str[j]==0) j++; else j=5-field_length; if(val<0) BlueWrChar('-'); for(i=j;i<5;i++) { BlueWrChar(48+str[i]); } } void BlueWrCoord(uint16_t x,uint16_t y) { BlueWrInt(x,4); BlueWrChar(','); BlueWrInt(y,4); BlueWrChar('\r'); BlueWrChar('\n'); } void SetADC() { ADMUX|=(1<<REFS0); ADCSRA=(1<<ADEN)|(7<<ADPS0); } uint16_t ReadADC(uint8_t ch) { //Select ADC Channel ch must be 0-7 ch=ch&0b00000111; ADMUX&=0b11100000; ADMUX|=ch; //Start Single conversion ADCSRA|=(1<<ADSC); //Wait for conversion to complete while(!(ADCSRA & (1<<ADIF))); //Clear ADIF by writing one to it ADCSRA|=(1<<ADIF); return(ADC); } void Waiting(int j) // simple delay function { uint8_t i; for(i=0;i<j;i++) _delay_ms(200); } int main(void) { uint16_t x,y; BlueInit(); SetADC(); while(1) { DDRA=((1<<x1)|(1<<x2)); PORTA=((0<<x2)|(1<<x1)); _delay_ms(10); x=ReadADC(3); DDRA=((1<<y1)|(1<<y2)); PORTA=((1<<y1)|(0<<y2)); _delay_ms(10); y=ReadADC(4); if(x!=0 && y!=0) BlueWrCoord(x,y); } } ***********************Processing Code************************ import processing.serial.*; Serial myport; int x,y; float xcord,ycord; void setup(){ size(690,540); background(0); myport = new Serial(this,"COM9",57600); myport.bufferUntil(10); } void draw(){ stroke(255); if(x>10 && y>10){ xcord=map(x,70,860,0,width); ycord=map(y,700,120,0,height); println(x+","+y+"->"+xcord+","+ycord); } //draw a dot ellipse(xcord,ycord ,10 ,10 ); } //serial communication void serialEvent(Serial p){ String stringData=myport.readStringUntil(10); if(stringData!=null){ stringData=trim(stringData); int data[]=int(split(stringData,',')); if(data.length==2){ x=data[0]; y=data[1]; } } } void keyPressed(){ if(key=='c'){ background(0); } }
Không có nhận xét nào:
Đăng nhận xét