Sei sulla pagina 1di 16

TACTILE BRAILLE E-BOOK/E-TEXT READER

Rajarshi Roy (roy18@illinois.edu)


Angky William (willia84@illinois.edu)

December 15th, 2010

ECE 395: Advanced Digital Projects Laboratory


University of Illinois at Urbana Champaign

Page 1 of 16

Abstract:
This report details the design concept and prototype implementation of a tactile Braille e-book/etext reader. The text is stored in the .txt file format inside a micro-SD card. An Arduino
Duemilanove micro-controller then reads this information to control a six-dot Braille cell using six
servos. A mouse scroll-wheel encoder is used at the bottom of the device so that the user can scroll
forward or backward through the textual information by sliding the device on a flat surface to the
right or left respectively. This device opens up a much cheaper and complete platform for
education and knowledge transfer for the blind as compared to current technologies.

Introduction:
Technology has revolutionized the daily life of people but it has particularly benefited visually
impaired individuals. Until recently, most print information such as newspapers, magazines, books
and such were of very limited accessibility due to the lack of widespread Braille publications. Only
recently have assistive technologies such as audio books and tactile Braille refreshable displays
allowed the access of information to the blind through the digital medium. However, current
technologies still have major drawbacks. For example, audio books only cover certain publications
and any piece of text cannot be accessed through them. Furthermore, this technology inaccessible
to the deaf-blind and does not provide intuitive control over the information flow. Tactile
refreshable Braille displays on the other hand overcome this problem by using refreshable tactile
Braille cells that are accessible to all due the use of touch. Furthermore, tactile Braille cells can be
refreshed at the user's own pace allowing full control. However, most tactile Braille technologies
are extremely expensive, ranging from 5000 to 10000 dollars [1]. This cost factor makes this
technology impact-less in the blind community.
Our motivation for this project was to have a low-cost tactile Braille reader that can make digital
information widely accessible to the blind. The main cost factor of tactile Braille displays is the cost
of the actuators that raise or lower each Braille dot. In all current tactile Braille devices,
piezoelectric actuators are used which are very expensive [2]. Thus we based our design on using
servo motors which provide a precise actuation for a very cheap price. Also we used the Arduino
Duemilanove micro-controller to carry out all controls. This allows the device to be easily modified
from our current portable e-text reader design to a Braille output interface from software.

Page 2 of 16

Design:
The main design consists of four parts: the micro-controller (Arduino Duemilanove) [3], the
encoder (a cheap old mouse scroll wheel), the Braille cell (six servos and some piano wire) and the
SD card reader (micro-SD/prototyping shield PCB from SparkFun.com) [4]. All circuitry was
soldered on the prototyping portion of the micro-SD/prototyping shield.

Figure 1: Top-right-back corner view of device

Figure 2: Top-left-front corner view of device


Page 3 of 16

The concept of the device is simple. Since there is only one Braille cell of 6 dots, the device can
only show one character in the text at a time. Thus, the user will not use the traditional method of
reading a Braille text by moving his fingers from left to right over a row of Braille characters. In
this design, the user will keep his finger on the Braille cell and move the device from left to right
on a flat surface to read the text. As the device is moved, the encoder wheel rotates, signaling the
micro-controller. After a certain threshold amount of movement, the Arduino refreshes the Braille
cell to the configuration of the next character in the text that is stored in the micro-SD card.
Similarly, the user can move the device from right to left to read the previous character, thus
allowing a bidirectional control over the reading of the text (Figure 3).

Figure 3: Reading text using the Braille e-book reader (left) as compared to reading traditional
Braille (right)
Thus, the overall data flow is as such:
the movement data from the encoder

Encoder

and the text file from the micro-SD card

Arduino

Servos in Braille cell

is processed by the Arduino to control


the six servos in the Braille cell.

Micro-SD card

Braille Cell
The most important component of the device that distinguishes it from current tactile Braille
technology is the cheap Braille cell. The Braille cell is constructed using six servos (T-Pro SG90 at
$2.77 each) (Appendix C), some piano wire (0.040 at negligible cost) and a section of a perfboard.
Since the standard Braille specifications require that the spacing between two Braille dots to be
0.090 to 0.100 [5], it was a challenge to create a Braille cell that compact with servos that are
Page 4 of 16

0.88x 0.86x0.45. In our design, we made two stacks of three servos (Figure 4). Each stack
controls either the left or right vertical column of Braille dots. The Braille dots are basically the
rounded tips of the piano wire that is attached on the other end to the servo arm. The piano wire
passes through the holes of the perfboard and can thus move in or out through the holes. This
system converts the rotational motion of the servo arm into the translational motion of the Braille
dots (similar to the piston system of an internal combustion engine). The slight angle change of the
servo arm controlled by the Arduino determines the raised or lowered position of the Braille dot.
4.1

4.2

4.3

Figure 4: The left stack of three servos (4.1) control the left vertical column of Braille dots. The
Braille dots are the rounded tips of the three .040 piano wires (a), (b), (c) which are 3.3mm,
2.2mm, and 1.1 mm long respectively. A slight change in the angle of the lowest servos arm (d)
produces the translational displacement (e) to raise the bottom-left Braille dot (f). Image 4.2 shows
the actual implementation of the design and the corresponding dot pattern (4.3).

We were very lucky that the standard perfboard has holes which are 0.100 spaced apart [6] which
met the Braille specification exactly. The Braille cell was constructed by using glue-gun to attach
the parts together and a Dremel tool to cut the perfboard and round the tips of the piano wire. This
was the most time-consuming portion of our project.
The six servos are controlled by the digital pins 4(top left), 5(middle left), 6(bottom left), 7(top
right), 9(middle right), 10(bottom right). The servo library <SoftwareServo.h> [7] provided online
in the Arduino playground was used. In the code (Appendix A), function braille() takes in a char
variable and controls the servos based on the Braille code. We decided to use the # symbol to be
the special character that number follows.

Page 5 of 16

The circuit for the servo system (Figure 5) is very simple as all the servos power (red) and ground
(brown) are connected to the Arduinos 5V and GND pin respectively. The signal wires (yellow) of
each servo are connected to their respective digital pins (10, 9, 7, 6, 5, 4).

5V

Power

GND
D10

GND
Signal

5V

Power

GND
D9

GND
Signal

5V

Power

GND
D7

GND
Signal

5V

Power

Servo: bot. left

GND
D6

GND
Signal

5V

Power

Servo: mid left

GND
D5

GND
Signal

5V

Power

GND
D4

GND
Signal

Servo: top left

Servo: bot. left

Servo: mid left

Servo: top left

Figure 5: Servo connections schematic

Encoder
We attempted to use an optical mouses sensor to
sense the movement of the device. We managed
to interface a mouses optical chip to the Arduino.
However, it was difficult to integrate it into the
device due the precise height the chip and its lens
system needs to be above a surface. Thus, we
simplified things by using a mouses scroll wheel
mechanical encoder. The mechanical encoder has
three pins A, B and C with C being in the middle
while A and B being at the sides. In the circuit, C
is connected to 5V from the Arduino while A and
B are pulled down to GND through 300 ohm
resistors (Figure 6).

Figure 6: Encoder circuit

Page 6 of 16

When the encoder wheel is rotated, each A and B pins


produce pulse patterns which are at slight offsets [8]. This
pattern is actually etched into copper inside the
mechanical encoder. One interesting property of this
pattern is that when pin A has a rising or falling edge, pin
B will either be zero or one. Depending on which way the
encoder is rotated, the transition from zero to one (rising
edge) of pin A will correspond to a low or high value of
pin B. The Arduino code (Appendix A) uses polling to detect this. In the void loop() portion of the
Arduino code that always loops, the outermost if structure checks for a rising edge by comparing
the current value of A with the previous value of A. Then when a rising edge triggers the
conditional, the code checks the value of B and accordingly increments or decrements the
encoderPos variable. After certain threshold conditions that decide how much the device should be
moved before a change in the character, the next or previous character is fetched from the SD card
code nested inside the encoder code.

SD card interface
The SD card circuitry was entirely provided on the Sparkfun micro-SD shield that was bought
online [4]. The code uses the <SdFat.h> and <SdFatUtil.h> libraries provided online [9] by Sparkfun
to access a byte in the SD card. We decided to use a .txt format to store our text in because each
character in the text has a one-to-one correspondence with each byte in the file system. Thus,
reading a byte and then reading the next byte would directly mean reading a character and then
reading the next character.
The documentation of the library only had the .read() function that reads a byte and sets the
pointer to the next byte. Thus, initially we read a certain point in the file by reading through every
point until that point. However, this caused a lot of problem with large files like books because the
code was not fast enough. Thus, after searching through the code of the library we found a variable
CurrentPos in the SDFat library that determined which byte was being read. Luckily the library
even has an internal function .seekSet() which sets this value. Thus, using this function we could
directly jump to a point in the text based on the variable position that incremented or decremented
based on the movement of the ebook reader.
The data transfer between the SD card and Arduino uses the Arduinos built-in SPI protocol pins
8(CS), 11(MOSI), 12(MISO), 13(SCK). The micro-SD shield was designed by sparkfun.com and its
schematic is provided in Figure 7.
Page 7 of 16

Figure 7: micro-SD shield schematic [10]

Future work:
The size of the device can be made much smaller by using smaller servos and using custom PCB
with the ATMega328 chip and SD card integrated. We started working on this but could not finish
due to the lack of time. Also, an optical mouse chip can be used instead of the mouse encoder. This
would enable another mode of use whereby the mouse chips image is accessed and the Arduino
runs a simple optical character recognition program on it. The character recognized would
determine the Braille cell content, allowing the user to read printed text such as medicine expiry
labels. Finally, a feature that we could have added that we realized lately is a character number
storing system whereby the character number is continuously stored at the end of the file. Thus,
when the device is turned off and on again, the user can choose to continue reading from where he
last left off.

Conclusion and Acknowledgements:


Acknowledgements:
This project was very enjoyable and we would like to thank Professor Lippold Haken and Zuofu
Cheng (big-time!) for their supervision and insights. We are grateful to the University of Illinois at
Urbana Champaign Department of Electrical and Computer Engineering for providing us with
every resource we needed including funding for parts, access to the ECE machine shop and ECE
service store.

Page 8 of 16

Refere
References
[1] Accessibility: Refreshable Braille Displays
<http://www.apple.com/accessibility/voiceover/devicesupport.html>
[2] Refreshable Braille Now and in the Years Ahead
<http://nfb.org/legacy/bm/bm00/bm0001/bm000110.htm>
[3] Arduino Duemilanove
<http://www.arduino.cc/en/Main/ArduinoBoardDuemilanove>
[4] SparkFun electronics: microSD Shield
<http://www.sparkfun.com/products/9802>
[5] Size and Spacing of Braille Characters
<http://www.brailleauthority.org/sizespacingofbraille/sizespacingofbraille.pdf>
[6] Pre-Punched IC-Spacing Perfboard
<http://www.radioshack.com/product/index.jsp?productId=2102862#>
[7] Arduino Playground-Servo
<http://www.arduino.cc/playground/ComponentLib/Servo>
[8] Using Encoders
<http://abrobotics.tripod.com/Ebot/using_encoder.htm>
[9] SparkFun electronics: microSD Shield SdFat library
<http://www.sparkfun.com/tutorial/microSD_Shield/SdFat.zip>
[10] SparkFun electronics: microSD Shield Schematic
<http://www.sparkfun.com/datasheets/DevTools/Arduino/microSD_Shield-v13%20Schematic.pdf>

Page 9 of 16

Appendix A
//
//
//
//
//

OVERALL DEVICE CONTROL


crystallized into a big crystal with the
help of seed crystals (example codes):
http://www.sparkfun.com/tutorial/microSD_Shield/SD_SimpleExample.pde
http://www.arduino.cc/playground/ComponentLib/Servo

// ECE395 - Braille e-book/e-text reader


//
//
//
//
//

Developers
Rajarshi Roy: servo control, sd card reading, quadrature encoder
Angky William: the idea to structure the function braille()
based on each pin rather than each character, shortening the code greatly

//add servo library


#include <SoftwareServo.h>
//add sd
#include
#include
#include

card library
<SdFat.h>
<SdFatUtil.h>
<ctype.h>

//////sd card variables and objects


Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
char name[] = "Test.txt";

// Create an array that contains the name of our file.

//////servo variables and objects


SoftwareServo servoltop;
// create
SoftwareServo servolmiddle;
// create
SoftwareServo servolbottom;
// create
SoftwareServo servortop;
// create
SoftwareServo servormiddle;
// create
SoftwareServo servorbottom;
// create
//note that all servo.write() values were
//may not work for other builds
//////encoder variables
int encoderPinA = A0;
int encoderPinB = A1;
int encoderPos = 0;
quadrature data*/
int encoderPinALast = LOW;
int n = LOW;
int position = -1;
void setup() {
servoltop.attach(4);
servoltop.write(92);
prevent damage to device*/
servolmiddle.attach(5);
servolmiddle.write(95);
servolbottom.attach(6);
servolbottom.write(93);
servortop.attach(7);

servo object to
servo object to
servo object to
servo object to
servo object to
servo object to
caliberated for

control left-top servo


control left-middle servo
control left-bottom servo
control right-top servo
control right-middle servo
control right-bottom servo
our device. the same values

// pin A of encoder hooked up to analog0


// pin B of encoder hooked up to analog1
/* variable that increments or decrements based on
/* last value of pin A (used to detect rising edges)*/
/* current value of pin A (used to detect rising edges)*/
// position in the text. we noticed initially position=0
// makes it skip the first character
// digital pin 4 now controls left-top servo
/* quickly stabilize servo (default lowered position) to
//
//
//
//
//

digital pin 5 now controls left-middle servo


to stabilize servo
digital pin 6 now controls left-bottom servo
to stabilize servo
digital pin 7 now controls right-top servo

Page 10 of 16

servortop.write(90);
servormiddle.attach(9);
servormiddle.write(96);
servorbottom.attach(10);
servorbottom.write(91);

//
//
//
//
//

to stabilize servo
digital pin 9 now controls right-middle servo
to stabilize servo
digital pin 10 now controls right-bottom servo
to stabilize servo

pinMode (encoderPinA,INPUT); // use encoder pin A as digital input


pinMode (encoderPinB,INPUT); // use encoder pin B as digital input
pinMode(10, OUTPUT);
to work.*/
card.init();
volume.init(card);
root.openRoot(volume);

/* Pin 10 must be set as an output for the SD communication


// Initialize the SD card and configure the I/O pins.
// Initialize a volume on the SD card.
// Open the root directory in the volume.

}
void loop() {
// Quadrature encoding from encoder code works using polling
// SD card code is nested withing this code
n = digitalRead(encoderPinA);
if ((encoderPinALast == LOW) && (n == HIGH)) {
transition)
if (digitalRead(encoderPinB) == LOW) {
encoderPos--;
} else {
encoderPos++;
}
if(encoderPos == 2) {position++; encoderPos=0;}
//before refreshing
if(encoderPos == -2) {position--; encoderPos=0;}
//before refreshing

// make n to be current value of A


// if rising edge (1 to 0
// decrement if B is low
// increment if B is high
// determines how much to move
// determines how much to move

// SD card code begins here


char alphabet;

// To store the current character

file.open(root, name, O_READ);


file.seekSet(position);
alphabet=file.read();
file.close();

//
//
//
//

Open the file in read mode.


Position seek in file.
Get the byte in the file at seek location.
Close the file

// SD card code ends here


braille(alphabet);
//character

// Actuate braille pins based on current

}
encoder0PinALast = n;

//Now last value of pin A must be set to n

void braille(char letter){


on that
servoltop.write(92);
servolmiddle.write(95);
servolbottom.write(93);
servortop.write(90);
servormiddle.write(96);
servorbottom.write(91);

//takes in a character (char letter) and initializes pins based


//
//
//
//
//
//

initializes
initializes
initializes
initializes
initializes
initializes

pin
pin
pin
pin
pin
pin

Page 11 of 16

to
to
to
to
to
to

default
default
default
default
default
default

lowered
lowered
lowered
lowered
lowered
lowered

position
position
position
position
position
position

for (d=0; d<=1; d++){


//(d=1)

// loop that sets left side (d=0) first then right side

if(
((letter=='a'||letter=='A'||letter=='1') && (d==0)) ||
((letter=='b'||letter=='B'||letter=='2') && (d==0)) ||
((letter=='c'||letter=='C'||letter=='3') && (d==0)) ||
((letter=='c'||letter=='C'||letter=='3') && (d==1)) ||
((letter=='d'||letter=='D'||letter=='4') && (d==0)) ||
((letter=='d'||letter=='D'||letter=='4') && (d==1)) ||
((letter=='e'||letter=='E'||letter=='5') && (d==0)) ||
((letter=='f'||letter=='F'||letter=='6') && (d==0)) ||
((letter=='f'||letter=='F'||letter=='6') && (d==1)) ||
((letter=='g'||letter=='G'||letter=='7') && (d==0)) ||
((letter=='g'||letter=='G'||letter=='7') && (d==1)) ||
((letter=='h'||letter=='H'||letter=='8') && (d==0)) ||
((letter=='i'||letter=='I'||letter=='9') && (d==1)) ||
((letter=='j'||letter=='J'||letter=='0') && (d==1)) ||
((letter=='k'||letter=='K') && (d==0)) ||
((letter=='l'||letter=='L') && (d==0)) ||
((letter=='m'||letter=='M') && (d==0)) ||
((letter=='m'||letter=='M') && (d==1)) ||
((letter=='n'||letter=='N') && (d==0)) ||
((letter=='n'||letter=='N') && (d==1)) ||
((letter=='o'||letter=='O') && (d==0)) ||
((letter=='p'||letter=='P') && (d==0)) ||
((letter=='p'||letter=='P') && (d==1)) ||
((letter=='q'||letter=='Q') && (d==0)) ||
((letter=='q'||letter=='Q') && (d==1)) ||
((letter=='r'||letter=='R') && (d==0)) ||
((letter=='s'||letter=='S') && (d==1)) ||
((letter=='t'||letter=='T') && (d==1)) ||
((letter=='u'||letter=='U') && (d==0)) ||
((letter=='v'||letter=='V') && (d==0)) ||
((letter=='w'||letter=='W') && (d==1)) ||
((letter=='x'||letter=='X') && (d==0)) ||
((letter=='x'||letter=='X') && (d==1)) ||
((letter=='y'||letter=='Y') && (d==0)) ||
((letter=='y'||letter=='Y') && (d==1)) ||
((letter=='z'||letter=='Z') && (d==0)) ||
(letter=='#' && (d==1))
){if(d==0){servoltop.write(82);} if(d==1){servortop.write(100);}}
if(
((letter=='b'||letter=='B'||letter=='2') && (d==0)) ||
((letter=='d'||letter=='D'||letter=='4') && (d==1)) ||
((letter=='e'||letter=='E'||letter=='5') && (d==1)) ||
((letter=='f'||letter=='F'||letter=='6') && (d==0)) ||
((letter=='g'||letter=='G'||letter=='7') && (d==0)) ||
((letter=='g'||letter=='G'||letter=='7') && (d==1)) ||
((letter=='h'||letter=='H'||letter=='8') && (d==0)) ||
((letter=='h'||letter=='H'||letter=='8') && (d==1)) ||
((letter=='i'||letter=='I'||letter=='9') && (d==0)) ||
((letter=='j'||letter=='J'||letter=='0') && (d==0)) ||
((letter=='j'||letter=='J'||letter=='0') && (d==1)) ||
((letter=='l'||letter=='L') && (d==0)) ||
((letter=='n'||letter=='N') && (d==1)) ||
((letter=='o'||letter=='O') && (d==1)) ||
((letter=='p'||letter=='P') && (d==0)) ||
((letter=='q'||letter=='Q') && (d==0)) ||
((letter=='q'||letter=='Q') && (d==1)) ||
((letter=='r'||letter=='R') && (d==0)) ||
((letter=='r'||letter=='R') && (d==1)) ||
((letter=='s'||letter=='S') && (d==0)) ||
((letter=='t'||letter=='T') && (d==0)) ||
((letter=='t'||letter=='T') && (d==1)) ||
((letter=='v'||letter=='V') && (d==0)) ||

Page 12 of 16

//set top pins

((letter=='w'||letter=='W') && (d==0)) ||


((letter=='w'||letter=='W') && (d==1)) ||
((letter=='y'||letter=='Y') && (d==1)) ||
((letter=='z'||letter=='Z') && (d==1)) ||
(letter==',' && (d==0))
||
(letter=='.' && (d==0))
||
(letter=='.' && (d==1))
||
(letter==';' && (d==0))
||
(letter=='!' && (d==0))
||
(letter=='!' && (d==1))
||
((letter=='(' || letter==')')
&& (d==0)) ||
((letter=='(' || letter==')') && (d==1)) ||
(letter=='?' && (d==0)) ||
(letter=='"' && (d==1)) ||
(letter=='#' && (d==1))
){if(d==0){servolmiddle.write(85);} if(d==1){servormiddle.write(106);}} //set middle
//pins
if(
((letter=='k'||letter=='K') && (d==0))||
((letter=='l'||letter=='L') && (d==0))||
((letter=='m'||letter=='M') && (d==0))||
((letter=='n'||letter=='N') && (d==0))||
((letter=='o'||letter=='O') && (d==0))||
((letter=='p'||letter=='P') && (d==0))||
((letter=='q'||letter=='Q') && (d==0))||
((letter=='r'||letter=='R') && (d==0))||
((letter=='s'||letter=='S') && (d==0))||
((letter=='t'||letter=='T') && (d==0))||
((letter=='u'||letter=='U') && (d==0))||
((letter=='u'||letter=='U') && (d==1))||
((letter=='v'||letter=='V') && (d==0))||
((letter=='v'||letter=='V') && (d==1))||
((letter=='w'||letter=='W') && (d==1))||
((letter=='x'||letter=='X') && (d==0))||
((letter=='x'||letter=='X') && (d==1))||
((letter=='y'||letter=='Y') && (d==0))||
((letter=='y'||letter=='Y') && (d==1))||
((letter=='z'||letter=='Z') && (d==0))||
((letter=='z'||letter=='Z') && (d==1))||
(letter== '\''&& (d==0))
||
(letter=='.' && (d==1))
||
(letter==';' && (d==0))
||
(letter=='!' && (d==0))
||
((letter=='('|| letter==')') && (d==0)) ||
((letter=='('|| letter==')') && (d==1)) ||
(letter=='-' && (d==0))
||
(letter=='-' && (d==1))
||
(letter=='?' && (d==0))
||
(letter=='?' && (d==1))
||
(letter=='"' && (d==0))
||
(letter=='"' && (d==1))
||
(letter=='#' && (d==0))
||
(letter=='#' && (d==1))
){if(d==0){servolbottom.write(83);} if(d==1){servorbottom.write(101);}} //set bottom
//pins
}
}

// end of for loop


// end of function braille

Page 13 of 16

Appendix B
Since Braille uses the same symbol for 1 and A, 2 and B and so on till 0 and J, it adds a special
character before a number. This code modifies a text file in the computer to add the # symbols in
front of numbers prior to transferring the text into the device.
// ADDING # CHARACTER BEFORE NUMBERS
// ECE395 - Braille e-book/e-text reader
//

Developer: Angky William

#include <stdio.h>
int main ()
{
FILE * pFile;
int c='a';
int n = 0;
int a;
int b;
int d;
int e=0;
int f=0;
pFile=fopen ("test.txt","r+");
//file name to be edited
if (pFile==NULL) perror ("Error opening file");
else
{
for(n=0;c!=EOF;n++)
{
c=getc(pFile);
if('0' <=c && c<= '9')
{e++;}
}
while(f<e)
{ fputs(" ",pFile);
f++;
}
fseek(pFile,0,SEEK_SET);
c='a';
for(n=0;c!=EOF;n++)
{
c=getc(pFile);
if('0'<= c && c <='9')
{
fseek(pFile,-1,SEEK_CUR);
a=getc(pFile);
b=getc(pFile);
fseek(pFile,-2,SEEK_CUR);
fputs(" ",pFile);
while (b!=EOF && a!=EOF)
{
fputc((int)a,pFile);
a=getc(pFile);
fseek(pFile,-1,SEEK_CUR);
//printf(" a is %d b is %d",a,b);

Page 14 of 16

fputc((int)b,pFile);
b=getc(pFile);
fseek(pFile,-1,SEEK_CUR);
//printf(" a is %d b is %d",a,b);
}
fseek(pFile,n+2,SEEK_SET);
n++;
}
}
//adding special code start here
fseek(pFile,0,SEEK_SET);
c='a';
for(n=0;c!=EOF;n++)
{
c=getc(pFile);
if(('0'<= c && c <= '9' ) && (a < '0' || a > '9') )
{
fseek ( pFile, -2 , SEEK_CUR);
fputs ("#", pFile);
fseek ( pFile, 1 ,SEEK_CUR);
}
}
fclose (pFile);
// printf ("The file contains %d dollar sign characters ($).\n",n);
}
return 0;
}

Page 15 of 16

Appendix C

Page 16 of 16

Potrebbero piacerti anche