Subversion Repositories svnkaklik

Compare Revisions

No changes between revisions

Ignore whitespace Rev 359 → Rev 409

/programy/avr/SFR08/Readme.txt
0,0 → 1,28
/****************************************************************************
Title : SRF08 RANGING MODULE FUNCTIONS library
Author: Chris Efstathiou hendrix@otenet.gr
Date: 13/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Info: This code is FREE. There are no copyright issues with this code.
 
*****************************************************************************/
 
I use it to drive the SRF08 ultrasonic ranging module
for use with Free Fall night parachute landing
where i MUST know the distance from ground in order to land safely.
Infrared goggles gives you an idea about the drop zone
but you cannot judje the precise distance from the ground due to
optics distortion.
For programming example see the SRF08 module code.
 
CAUTION: THIS IS A TEST PROGRAM. DO NOT USE IT FOR PARACHUTE LANDING!!!
There are too many thing missing from the code like
audio and visual alerts, height averaging, variable gain,
variable range settings and many other safety features
needed to make it suitable for this task!
I can experiment because it is my life!
Its only purpose is to give an idea of how to use the driver code.
 
I hope it can help someone.
Chris.
/programy/avr/SFR08/SRF08 Ultra sonic range finder.htm
0,0 → 1,595
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0054)http://www.robot-electronics.co.uk/htm/srf08tech.shtml -->
<HTML><HEAD><TITLE>SRF08 Ultra sonic range finder</TITLE>
<META http-equiv=Content-Type content="text/html; charset=windows-1253">
<META content="MSHTML 6.00.2600.0" name=GENERATOR></HEAD>
<BODY>
<P align=center><B><FONT size=5>SRF08 Ultra sonic range finder </FONT><FONT
size=3><BR>Technical Specification</FONT></B></P>
<P align=left>Communication with the SRF08 ultrasonic rangefinder is via the I2C
bus. This is available on popular controllers such as the OOPic and Stamp BS2p,
as well as a wide variety of micro-controllers. To the programmer the SRF08
behaves in the same way as the ubiquitous 24xx series eeprom's, except that the
I2C address is different. The default shipped address of the SRF08 is 0xE0. It
can be changed by the user to any of 16 addresses E0, E2, E4, E6, E8, EA, EC,
EE, F0, F2, F4, F6, F8, FA, FC or FE, therefore up to 16 sonar's can be used. In
addition to the above addresses, all sonar's on the I2C bus will respond to
address 0 - the General Broadcast address. This means that writing a ranging
command to I2C address 0 (0x00) will start all sonar's ranging at the same time.
This should be useful in ANN Mode (See below). The results must be read
individually from each sonar's real address. We have <A
href="http://www.robot-electronics.co.uk/htm/examples.shtml">examples</A> of
using the SRF08 module with a wide range of popular controllers.</P>
<P align=left><B>Connections<BR></B>The "Do Not Connect" pin should be left
unconnected. It is actually the CPU MCLR line and is used once only in our
workshop to program the PIC16F872 on-board after assembly, and has an internal
pull-up resistor. The SCL and SDA lines should each have a pull-up resistor to
+5v somewhere on the I2C bus. You only need one pair of resistors, not a pair
for every module. They are normally located with the bus master rather than the
slaves. The SRF08 is always a slave - never a bus master. If you need them, I
recommend 1.8k resistors. Some modules such as the OOPic already have pull-up
resistors and you do not need to add any more. &nbsp;</P>
<P align=center><IMG height=232
src="SRF08 Ultra sonic range finder_files/srf08con.jpg" width=302 border=0></P>
<P align=left><B>Registers</B><BR>&nbsp;The SRF08 appears as a set of 36
registers.</P>
<DIV align=center>
<CENTER>
<TABLE cellSpacing=0 cellPadding=0 width="53%" bgColor=#ffffcc border=1>
<TBODY>
<TR>
<TD width="24%">
<P align=center>Location</P></TD>
<TD width="32%">
<P align=center>Read</P></TD>
<TD width="44%">
<P align=center>Write</P></TD></TR>
<TR>
<TD width="24%">
<P align=center>0</P></TD>
<TD width="32%">
<P align=center>Software Revision</P></TD>
<TD width="44%">
<P align=center>Command Register</P></TD></TR>
<TR>
<TD width="24%">
<P align=center>1</P></TD>
<TD width="32%">
<P align=center>Light Sensor</P></TD>
<TD width="44%">
<P align=center>Max Gain Register (default 31)&nbsp;</P></TD></TR>
<TR>
<TD width="24%">
<P align=center>2</P></TD>
<TD width="32%">
<P align=center>1st Echo High Byte</P></TD>
<TD width="44%">
<P align=center>Range Register (default 255)</P></TD></TR>
<TR>
<TD width="24%">
<P align=center>3</P></TD>
<TD width="32%">
<P align=center>1st Echo Low Byte</P></TD>
<TD width="44%">
<P align=center>N/A</P></TD></TR>
<TR>
<TD width="24%">
<P align=center>~~~~</P></TD>
<TD width="32%">
<P align=center>~~~~</P></TD>
<TD width="44%">
<P align=center>~~~~</P></TD></TR>
<TR>
<TD width="24%">
<P align=center>34</P></TD>
<TD width="32%">
<P align=center>17th Echo High Byte</P></TD>
<TD width="44%">
<P align=center>N/A</P></TD></TR>
<TR>
<TD width="24%">
<P align=center>35</P></TD>
<TD width="32%">
<P align=center>17th Echo Low Byte</P></TD>
<TD width="44%">
<P align=center>N/A</P></TD></TR></TBODY></TABLE></CENTER></DIV>
<P align=left>Only locations 0, 1 and 2 can be written to. Location 0 is the
command register and is used to start a ranging session. It cannot be read.
Reading from location 0 returns the SRF08 software revision.&nbsp; By default,
the ranging lasts for 65mS, but can be changed by writing to the range register
at location 2. If you do so, then you will likely need to change the analogue
gain by writing to location 1. See the <B>Changing Range</B> and <B>Analogue
Gain</B> sections below.</P>
<P align=left>Location 1 is the onboard light sensor. This data is updated every
time a new ranging command has completed and can be read when range data is
read. The next two locations, 2 and 3, are the 16bit unsigned result from the
latest ranging - high byte first. The meaning of this value depends on the
command used, and is either the range in inches, or the range in cm or the
flight time in uS. A value of zero indicates that no objects were detected.
There are up to a further 16 results indicating echo's from more distant
objects.&nbsp;</P>
<P align=left><B>Commands</B><BR>The are three commands to initiate a ranging
(80 to 82), to return the result in inches, centimeters or microseconds. There
is also an ANN mode (Artificial Neural Network) mode which is described later
and a set of commands to change the I2C address.</P>
<DIV align=center>
<CENTER>
<TABLE cellSpacing=0 cellPadding=0 width="77%" bgColor=#ffffcc border=1>
<TBODY>
<TR>
<TD align=middle width="34%" colSpan=2>Command</TD>
<TD align=middle width="94%" rowSpan=2>Action</TD></TR>
<TR>
<TD align=middle width="16%">Decimal</TD>
<TD align=middle width="18%">Hex</TD></TR>
<TR>
<TD align=middle width="16%">80</TD>
<TD align=middle width="18%">0x50</TD>
<TD align=left width="94%">Ranging Mode - Result in inches</TD></TR>
<TR>
<TD align=middle width="16%">81</TD>
<TD align=middle width="18%">0x51</TD>
<TD align=left width="94%">Ranging Mode - Result in centimeters</TD></TR>
<TR>
<TD align=middle width="16%">82</TD>
<TD align=middle width="18%">0x52</TD>
<TD align=left width="94%">Ranging Mode - Result in micro-seconds</TD></TR>
<TR>
<TD align=middle width="16%">&nbsp;</TD>
<TD align=middle width="18%">&nbsp;</TD>
<TD align=left width="94%">&nbsp;</TD></TR>
<TR>
<TD align=middle width="16%">83</TD>
<TD align=middle width="18%">0x53</TD>
<TD align=left width="94%">ANN Mode - Result in inches</TD></TR>
<TR>
<TD align=middle width="16%">84</TD>
<TD align=middle width="18%">0x54</TD>
<TD align=left width="94%">ANN Mode - Result in centimeters</TD></TR>
<TR>
<TD align=middle width="16%">85</TD>
<TD align=middle width="18%">0x55</TD>
<TD align=left width="94%">ANN Mode - Result in micro-seconds</TD></TR>
<TR>
<TD align=middle width="16%">&nbsp;</TD>
<TD align=middle width="18%">&nbsp;</TD>
<TD align=left width="94%">&nbsp;</TD></TR>
<TR>
<TD align=middle width="16%">160</TD>
<TD align=middle width="18%">0xA0</TD>
<TD align=left width="94%">1st in sequence to change I2C address</TD></TR>
<TR>
<TD align=middle width="16%">165</TD>
<TD align=middle width="18%">0xA5</TD>
<TD align=left width="94%">3rd in sequence to change I2C address</TD></TR>
<TR>
<TD align=middle width="16%">170</TD>
<TD align=middle width="18%">0xAA</TD>
<TD align=left width="94%">2nd in sequence to change I2C
address</TD></TR></TBODY></TABLE></CENTER></DIV>
<P align=left><B>Ranging Mode</B><BR>To initiate a ranging, write one of the
above commands to the command register and wait the required amount of time for
completion and read as many results as you wish. The echo buffer is cleared at
the start of each ranging. The first echo range is placed in locations 2,3. the
second in 4,5, etc. If a location (high and low bytes) is 0, then there will be
no further reading in the rest of the registers. The default and recommended
time for completion of ranging is 65mS, however you can shorten this by writing
to the range register before issuing a ranging command. Light sensor data at
location 1 will also have been updated after a ranging command.&nbsp;</P>
<P align=left><B>ANN Mode<BR></B>ANN mode (Artificial Neural Network) is
designed to provide the multi echo data in a way that is easier to input to a
neural network, at least I hope it is - I've not actually done it yet. ANN mode
provides a 32 byte buffer (locations 4 to 35 inclusive) where each byte
represents the 65536uS maximum flight time divided into 32 chunks of 2048uS each
- equivalent to about 352mm of range. If an echo is received within a bytes time
slot then it will be set to no-zero, otherwise it will be zero. So if an echo is
received from within the first 352mm, location 4 will be non-zero. If an object
is detected 3m away the location 12 will be non-zero (3000/352 = 8) (8+4=12).
Arranging the data like this should be better for a neural net than the other
formats. The input to your network should be 0 if the byte is zero and 1 if its
non-zero. I have a SOFM (Self Organizing Feature Map) in mind for the neural
net, but will hopefully be useful for any type. </P>
<DIV align=center>
<CENTER>
<TABLE cellSpacing=0 cellPadding=0 width="71%" bgColor=#ffffcc border=1>
<TBODY>
<TR>
<TD align=middle width="20%">Location 4</TD>
<TD align=middle width="20%">Location 5</TD>
<TD align=middle width="20%">Location 6</TD>
<TD align=middle width="20%">Location 7</TD>
<TD align=middle width="20%">Locations 8 - 35</TD></TR>
<TR>
<TD align=middle width="20%">0 - 352mm</TD>
<TD align=middle width="20%">353 - 705mm</TD>
<TD align=middle width="20%">706 - 1057mm</TD>
<TD align=middle width="20%">1058 - 1410mm</TD>
<TD align=middle width="20%">and so on</TD></TR></TBODY></TABLE></CENTER></DIV>
<P align=left>Locations 2,3 contain the range of the nearest object converted to
inches, cm or uS and is the same as for Ranging Mode.</P>
<P align=left><B>Checking for Completion of Ranging</B><BR>You do not have to
use a timer on your own controller to wait for ranging to finish. You can take
advantage of the fact that the SRF08 will not respond to any I2C activity whilst
ranging. Therefore, if you try to read from the SRF08 (we use the software
revision number a location 0) then you will get 255 (0xFF) whilst ranging. This
is because the I2C data line (SDA) is pulled high if nothing is driving it. As
soon as the ranging is complete the SRF08 will again respond to the I2C bus, so
just keep reading the register until its not 255 (0xFF) anymore. You can then
read the sonar data. Your controller can take advantage of this to perform other
tasks while the SRF08 is ranging.&nbsp;</P>
<P align=left><B>Changing the Range</B><BR>The maximum range of the SRF08 is set
by an internal timer. By default, this is 65mS or the equivalent of 11 metres of
range. This is much further than the 6 metres the SRF08&nbsp; is actually
capable of. It is possible to reduce the time the SRF08 listens for an echo, and
hence the range, by writing to the range register at location 2. The range can
be set in steps of about 43mm (0.043m or 1.68 inches) up to 11
metres.&nbsp;<BR>The range is ((Range Register x 43mm) + 43mm) so setting the
Range Register to 0 (0x00) gives a maximum range of 43mm. Setting the Range
Register to 1 (0x01) gives a maximum range of 86mm. More usefully, 24 (0x18)
gives a range of 1 metre and 140 (0x8C) is 6 metres. Setting 255 (0xFF) gives
the original 11 metres (255 x 43 + 43 is 11008mm). There are two reasons you may
wish to reduce the range.<BR>1. To get at the range information quicker<BR>2. To
be able to fire the SRF08 at a faster rate.<BR>If you only wish to get at the
range information a bit sooner and will continue to fire the SRF08 at 65ms of
slower, then all will be well. However if you wish to fire the SRF08 at a faster
rate than 65mS, you will definitely need to reduce the gain - see next
section.<BR>The range is set to maximum every time the SRF08 is powered-up. If
you need a different range, change it once as part of your system initialization
code.<BR></P>
<P align=left><B>Analogue Gain</B><BR>The analogue gain register sets the
<I>Maximum</I> gain of the analogue stages. To set the maximum gain, just write
one of these values to the gain register at location 1. During a ranging, the
analogue gain starts off at its minimum value of 94. This is increased at
approx. 70uS intervals up to the maximum gain setting, set by register
1.&nbsp;Maximum possible gain is reached after about 390mm of range. The purpose
of providing a limit to the maximum gain is to allow you to fire the sonar more
rapidly than 65mS. Since the ranging can be very short, a new ranging can be
initiated as soon as the previous range data has been read. A potential hazard
with this is that the second ranging may pick up a distant echo returning from
the previous "ping", give a false result of a close by object when there is
none. To reduce this possibility, the maximum gain can be reduced to limit the
modules sensitivity to the weaker distant echo, whilst still able to detect
close by objects. The maximum gain setting is stored only in the CPU's RAM and
is initialized to maximum on power-up, so if you only want do a ranging every
65mS, or longer, you can ignore the Range and Gain Registers.<BR><I><B><FONT
color=#ff00ff>Note</FONT></B></I> - Effective in Ranging Mode only, in ANN mode,
gain is controlled automatically.&nbsp;</P>
<DIV align=center>
<CENTER>
<TABLE height=714 cellSpacing=0 cellPadding=0 width=428 bgColor=#ffffcc
border=1>
<TBODY>
<TR>
<TD align=middle width=157 colSpan=2 height=19>Gain Register</TD>
<TD align=middle width=265 height=40 rowSpan=2>Maximum Analogue Gain</TD></TR>
<TR>
<TD align=middle width=77 height=19>Decimal</TD>
<TD align=middle width=80 height=19>Hex</TD></TR>
<TR>
<TD align=middle width=74 height=19>0</TD>
<TD align=middle width=81 height=19>0x00</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to 94</TD></TR>
<TR>
<TD align=middle width=74 height=19>1</TD>
<TD align=middle width=81 height=19>0x01</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to 97</TD></TR>
<TR>
<TD align=middle width=74 height=19>2</TD>
<TD align=middle width=81 height=19>0x02</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
100</TD></TR>
<TR>
<TD align=middle width=74 height=19>3</TD>
<TD align=middle width=81 height=19>0x03</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
103</TD></TR>
<TR>
<TD align=middle width=74 height=19>4</TD>
<TD align=middle width=81 height=19>0x04</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
107</TD></TR>
<TR>
<TD align=middle width=74 height=19>5</TD>
<TD align=middle width=81 height=19>0x05</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
110</TD></TR>
<TR>
<TD align=middle width=74 height=19>6</TD>
<TD align=middle width=81 height=19>0x06</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
114</TD></TR>
<TR>
<TD align=middle width=74 height=19>7</TD>
<TD align=middle width=81 height=19>0x07</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
118</TD></TR>
<TR>
<TD align=middle width=74 height=19>8</TD>
<TD align=middle width=81 height=19>0x08</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
123</TD></TR>
<TR>
<TD align=middle width=74 height=19>9</TD>
<TD align=middle width=81 height=19>0x09</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
128</TD></TR>
<TR>
<TD align=middle width=74 height=19>10</TD>
<TD align=middle width=81 height=19>0x0A</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
133</TD></TR>
<TR>
<TD align=middle width=74 height=19>11</TD>
<TD align=middle width=81 height=19>0x0B</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
139</TD></TR>
<TR>
<TD align=middle width=74 height=19>12</TD>
<TD align=middle width=81 height=19>0x0C</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
145</TD></TR>
<TR>
<TD align=middle width=74 height=19>13</TD>
<TD align=middle width=81 height=19>0x0D</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
152</TD></TR>
<TR>
<TD align=middle width=74 height=19>14</TD>
<TD align=middle width=81 height=19>0x0E</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
159</TD></TR>
<TR>
<TD align=middle width=74 height=19>15</TD>
<TD align=middle width=81 height=19>0x0F</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
168</TD></TR>
<TR>
<TD align=middle width=74 height=19>16</TD>
<TD align=middle width=81 height=19>0x10</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
177</TD></TR>
<TR>
<TD align=middle width=74 height=19>17</TD>
<TD align=middle width=81 height=19>0x11</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
187</TD></TR>
<TR>
<TD align=middle width=74 height=19>18</TD>
<TD align=middle width=81 height=19>0x12</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
199</TD></TR>
<TR>
<TD align=middle width=74 height=19>19</TD>
<TD align=middle width=81 height=19>0x13</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
212</TD></TR>
<TR>
<TD align=middle width=74 height=19>20</TD>
<TD align=middle width=81 height=19>0x14</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
227</TD></TR>
<TR>
<TD align=middle width=74 height=19>21</TD>
<TD align=middle width=81 height=19>0x15</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
245</TD></TR>
<TR>
<TD align=middle width=74 height=19>22</TD>
<TD align=middle width=81 height=19>0x16</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
265</TD></TR>
<TR>
<TD align=middle width=74 height=19>23</TD>
<TD align=middle width=81 height=19>0x17</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
288</TD></TR>
<TR>
<TD align=middle width=74 height=19>24</TD>
<TD align=middle width=81 height=19>0x18</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
317</TD></TR>
<TR>
<TD align=middle width=74 height=19>25</TD>
<TD align=middle width=81 height=19>0x18</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
352</TD></TR>
<TR>
<TD align=middle width=74 height=19>26</TD>
<TD align=middle width=81 height=19>0x20</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
395</TD></TR>
<TR>
<TD align=middle width=74 height=19>27</TD>
<TD align=middle width=81 height=19>0x21</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
450</TD></TR>
<TR>
<TD align=middle width=74 height=19>28</TD>
<TD align=middle width=81 height=19>0x22</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
524</TD></TR>
<TR>
<TD align=middle width=74 height=19>29</TD>
<TD align=middle width=81 height=19>0x23</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
626</TD></TR>
<TR>
<TD align=middle width=74 height=19>30</TD>
<TD align=middle width=81 height=19>0x24</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
777</TD></TR>
<TR>
<TD align=middle width=74 height=19>31</TD>
<TD align=middle width=81 height=19>0x25</TD>
<TD align=middle width=265 height=19>Set Maximum Analogue Gain to
1025</TD></TR></TBODY></TABLE></CENTER></DIV>
<P align=left>Note that the relationship between the Gain Register setting and
the actual gain is not a linear one. Also there is no magic formula to say "use
this gain setting with that range setting". It depends on the size, shape and
material of the object and what else is around in the room. Try playing with
different settings until you get the result you want. If you appear to get false
readings, it may be echo's from previous "pings", try going back to firing the
SRF08 every 65mS or longer (slower).&nbsp;<BR>If you are in any doubt about the
Range and Gain Registers, remember they are automatically set by the SRF08 to
their default values when it is powered-up. You can ignore and forget about them
and the SRF08 will work fine, detecting objects up to 6 metres away every 65mS
or slower.</P>
<P align=left><B>Light Sensor</B><BR>The SRF08 has a light sensor on-board. A
reading of the light intensity is made by the SRF08 each time a ranging takes
place in either Ranging or ANN Modes ( The A/D conversion is actually done just
before the "ping" whilst the +/- 10v generator is stabilizing). The reading
increases as the brightness increases, so you will get a maximum value in bright
light and minimum value in darkness. It should get close to 2-3 in complete
darkness and up to about 248 (0xF8) in bright light. The light intensity can be
read from the Light Sensor Register at&nbsp; location 1 at the same time that
you are reading the range data.</P>
<P align=left><B>LED</B><BR>The red LED is used to flash out a code for the I2C
address on power-up (see below). It also gives a brief flash during the "ping"
whilst ranging.</P>
<P align=left><B>Changing the I2C Bus Address</B><BR>To change the I2C address
of the SRF08 you must have only one sonar on the bus. Write the 3 sequence
commands in the correct order followed by the address. Example; to change the
address of a sonar currently at 0xE0 (the default shipped address) to 0xF2,
write the following to address 0xE0; (0xA0, 0xAA, 0xA5, 0xF2 ). These commands
must be sent in the correct sequence to change the I2C address, additionally, No
other command may be issued in the middle of the sequence. The sequence must be
sent to the command register at location 0, which means 4 separate write
transactions on the I2C bus. When done, you should label the sonar with its
address, however if you do forget, just power it up without sending any
commands. The SRF08 will flash its address out on the LED. One long flash
followed by a number of shorter flashes indicating its address. The flashing is
terminated immediately on sending a command the SRF08.</P>
<DIV align=center>
<CENTER>
<TABLE cellSpacing=0 cellPadding=0 width="45%" bgColor=#ffffcc border=1>
<TBODY>
<TR>
<TD align=middle width="45%" colSpan=2>Address</TD>
<TD align=middle width="25%" rowSpan=2>Long Flash</TD>
<TD align=middle width="30%" rowSpan=2>Short flashes</TD></TR>
<TR>
<TD align=middle width="23%">Decimal</TD>
<TD align=middle width="22%">Hex</TD></TR>
<TR>
<TD align=middle width="23%">224</TD>
<TD align=middle width="22%">E0</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">0</TD></TR>
<TR>
<TD align=middle width="23%">226</TD>
<TD align=middle width="22%">E2</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">1</TD></TR>
<TR>
<TD align=middle width="23%">228</TD>
<TD align=middle width="22%">E4</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">2</TD></TR>
<TR>
<TD align=middle width="23%">230</TD>
<TD align=middle width="22%">E6</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">3</TD></TR>
<TR>
<TD align=middle width="23%">232</TD>
<TD align=middle width="22%">E8</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">4</TD></TR>
<TR>
<TD align=middle width="23%">234</TD>
<TD align=middle width="22%">EA</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">5</TD></TR>
<TR>
<TD align=middle width="23%">236</TD>
<TD align=middle width="22%">EC</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">6</TD></TR>
<TR>
<TD align=middle width="23%">238</TD>
<TD align=middle width="22%">EE</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">7</TD></TR>
<TR>
<TD align=middle width="23%">240</TD>
<TD align=middle width="22%">F0</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">8</TD></TR>
<TR>
<TD align=middle width="23%">242</TD>
<TD align=middle width="22%">F2</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">9</TD></TR>
<TR>
<TD align=middle width="23%">244</TD>
<TD align=middle width="22%">F4</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">10</TD></TR>
<TR>
<TD align=middle width="23%">246</TD>
<TD align=middle width="22%">F6</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">11</TD></TR>
<TR>
<TD align=middle width="23%">248</TD>
<TD align=middle width="22%">F8</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">12</TD></TR>
<TR>
<TD align=middle width="23%">250</TD>
<TD align=middle width="22%">FA</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">13</TD></TR>
<TR>
<TD align=middle width="23%">252</TD>
<TD align=middle width="22%">FC</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">14</TD></TR>
<TR>
<TD align=middle width="23%">254</TD>
<TD align=middle width="22%">FE</TD>
<TD align=middle width="25%">1</TD>
<TD align=middle width="30%">15</TD></TR></TBODY></TABLE></CENTER></DIV>
<P align=left>Take care not to set more than one sonar to the same address,
there will be a bus collision and very unpredictable results.</P>
<P align=left><B>Current Consumption</B><BR>Average current consumption measured
on our prototype is around 12mA during ranging, and 3mA standby. The module will
automatically go to standby mode after a ranging, whilst waiting for a new
command on the I2C bus. The actual measured current profile is as follows; </P>
<DIV align=center>
<CENTER>
<TABLE cellSpacing=0 width=400 bgColor=#ffffcc border=1>
<TBODY>
<TR>
<TD align=middle width=253>Operation</TD>
<TD align=middle width=62>Current</TD>
<TD align=middle width=65>Duration</TD></TR>
<TR>
<TD align=middle width=253>Ranging command received - Power on</TD>
<TD align=middle width=62>275mA</TD>
<TD align=middle width=65>3uS</TD></TR>
<TR>
<TD align=middle width=253>+/- 10v generator Stabilization</TD>
<TD align=middle width=62>
<P align=center>25mA</P></TD>
<TD align=middle width=65>600uS</TD></TR>
<TR>
<TD align=middle width=253>8 cycles of 40kHz "ping"</TD>
<TD align=middle width=62>40mA</TD>
<TD align=middle width=65>200uS</TD></TR>
<TR>
<TD align=middle width=253>Ranging</TD>
<TD align=middle width=62>11mA</TD>
<TD align=middle width=65>65mS max</TD></TR>
<TR>
<TD align=middle width=253>Standby</TD>
<TD align=middle width=62>3mA</TD>
<TD align=middle width=65>indefinite</TD></TR></TBODY></TABLE></CENTER></DIV>
<P align=left>The above values are for guidance only, they are not tested on
production units. </P>
<P align=left>&nbsp;You can have a&nbsp; look at the <A
href="http://www.robot-electronics.co.uk/images/srf08schematic.gif">schematic</A>
and <A href="http://www.robot-electronics.co.uk/files/srf08.c">software</A> </P>
<P align=left>Your feedback/comments/criticisms and wish lists are very welcome,
as always.<BR>Regards, Gerry.
<BR>gerry@robot-electronics.co.uk</P></BODY></HTML>
/programy/avr/SFR08/SRF08 Ultra sonic range finder_files/srf08con.jpg
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/programy/avr/SFR08/i2c.c
0,0 → 1,172
 
/****************************************************************************
Title : C file for the I2C FUNCTIONS library (i2c.c)
Author: Chris efstathiou hendrix@otenet.gr
Date: 13/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
 
*****************************************************************************/
 
#include <io.h>
#include "i2c.h"
 
#ifndef CONCAT1
#define CONCAT1(a, b) CONCAT2(a, b)
#endif
 
#ifndef CONCAT2
#define CONCAT2(a, b) a ## b
#endif
 
 
/* Conversion of microseconds to the right value for the delay function */
#define I2C_DELAY ( (I2C_DELAY_TIME*(F_CPU/60000))/100 )
#define I2C_TIMEOUT ( (I2C_TIMEOUT_TIME*(F_CPU/60000))/100 )
 
/* Register name forming */
#define I2C_SDA_OUT_REG CONCAT1(PORT, I2C_SDA_PORT)
#define I2C_SCL_OUT_REG CONCAT1(PORT, I2C_SCL_PORT)
#define I2C_SDA_DDR_REG CONCAT1(DDR, I2C_SDA_PORT)
#define I2C_SCL_DDR_REG CONCAT1(DDR, I2C_SCL_PORT)
#define I2C_SDA_PIN_REG CONCAT1(PIN, I2C_SDA_PORT)
#define I2C_SCL_PIN_REG CONCAT1(PIN, I2C_SCL_PORT)
 
/* Conversion of microseconds to the right value for the delay function */
#define I2C_DELAY ( (I2C_DELAY_TIME*(F_CPU/60000))/100 )
#define I2C_TIMEOUT ( (I2C_TIMEOUT_TIME*(F_CPU/60000))/100 )
 
/* Pin states */
#define SCL_1() cbi(I2C_SCL_DDR_REG, SCL_PIN)
#define SCL_0() sbi(I2C_SCL_DDR_REG, SCL_PIN)
#define SDA_1() cbi(I2C_SDA_DDR_REG, SDA_PIN)
#define SDA_0() sbi(I2C_SDA_DDR_REG, SDA_PIN)
 
#define RELEASE_I2C_BUS() { SCL_1(); SDA_1(); }
 
/*#################################################################################################*/
 
static void delay(unsigned long us)
{
 
while ( us ) { us--; } /* 6 cpu cycles per loop */
}
/*#################################################################################################*/
 
void i2c_init(void)
{
cbi(I2C_SDA_OUT_REG, SDA_PIN);
cbi(I2C_SCL_OUT_REG, SCL_PIN);
RELEASE_I2C_BUS();
delay(I2C_TIMEOUT);
i2c_start();
delay(I2C_TIMEOUT);
i2c_stop();
delay(I2C_TIMEOUT);
 
 
return;
}
/*#################################################################################################*/
 
void i2c_start(void)
{
RELEASE_I2C_BUS();
delay(I2C_DELAY);
SDA_0();
delay(I2C_DELAY);
SCL_0();
delay(I2C_DELAY);
 
return;
}
/*#################################################################################################*/
 
void i2c_stop(void)
{
SDA_0();
SCL_1();
delay(I2C_DELAY);
SDA_1();
delay(I2C_DELAY);
SCL_0();
delay(I2C_DELAY);
 
return;
}
/*#################################################################################################*/
 
unsigned char i2c_transmit(unsigned char data)
{
register unsigned char bit=0;
 
for(bit=0; bit<=7; bit++)
{
if( data & 0x80 ) { SDA_1(); } else { SDA_0(); }
SCL_1();
delay(I2C_DELAY);
SCL_0();
delay(I2C_DELAY);
data = (data<<1);
}
/* Look for AKNOWLEDGE */
RELEASE_I2C_BUS();
delay(I2C_DELAY);
 
 
if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) )
{
SCL_0();
delay(I2C_DELAY);
}
else{
delay(I2C_TIMEOUT);
if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) )
{
SCL_0();
delay(I2C_DELAY);
}
else { return(I2C_ERROR_DEVICE_NOT_RESPONDING); }
}
 
 
if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) )
{
delay(I2C_TIMEOUT);
if( bit_is_clear(I2C_SDA_PIN_REG, SDA_PIN) ) { return(I2C_ERROR_DEVICE_BUSY); }
}
 
 
return(I2C_NO_ERROR);
}
/*#################################################################################################*/
 
unsigned char i2c_receive(unsigned char ack)
{
register unsigned char bit=0, data=0;
 
SDA_1();
for(bit=0; bit<=7; bit++)
{
SCL_1();
delay(I2C_DELAY);
data = (data<<1);
if( bit_is_set(I2C_SDA_PIN_REG, SDA_PIN) ) { data++; }
SCL_0();
delay(I2C_DELAY);
}
/* if CONTINUE then send AKNOWLEDGE else if QUIT do not send AKNOWLEDGE (send Nack) */
if(ack==I2C_CONTINUE) { SDA_0(); } else { SDA_1(); }
SCL_1();
delay(I2C_DELAY);
SCL_0();
delay(I2C_DELAY);
 
return data;
}
/*#################################################################################################*/
 
 
/programy/avr/SFR08/i2c.h
0,0 → 1,76
 
/****************************************************************************
Title : C include file for the I2C FUNCTIONS library (i2c.h)
Author: Chris efstathiou hendrix@otenet.gr
Date: 13/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
 
*****************************************************************************/
 
 
#ifndef I2C_H
#define I2C_H 1
 
/*##############################################################################################*/
/* START OF CONFIGURATION BLOCK */
/*##############################################################################################*/
 
#ifndef F_CPU
#define F_CPU 3686400L /* The cpu clock frequency in Hertz (used to calculate time)*/
#endif
 
#define I2C_SDA_PORT D /* The SDA port. Use capital letter (A,B,C,D... etc.) */
#define SDA_PIN 4 /* The SDA port pin */
 
#define I2C_SCL_PORT D /* The SCL port. Use capital letter (A,B,C,D... etc.) */
#define SCL_PIN 5 /* The SCL port pin */
/*
The I2C_DELAY_TIME normally is 5 microseconds for a 100 Khz I2C bus ( (1/100000)/2 ).
but due to bus capacitance and device responce time in my application i use 50 microseconds.
The I2C_TIMEOUT_TIME is set to whatever is the maximum time you think your device will take
to perform the requested task. After that time the i2c_transmit function will return
a "I2C_ERROR_DEVICE_NOT_RESPONDING" or "I2C_ERROR_DEVICE_BUSY" error code.
*/
#define I2C_DELAY_TIME 50 /* in microseconds (max over 1 second) */
#define I2C_TIMEOUT_TIME 1000 /* in microseconds (max over 1 second) */
 
/*##############################################################################################*/
/* END OF CONFIGURATION BLOCK */
/*##############################################################################################*/
 
/* Keyword definitions */
 
#define I2C_READ 1
#define I2C_WRITE 0
 
#define I2C_QUIT 0
#define I2C_CONTINUE 1
 
#define I2C_NO_ERROR 0
#define I2C_ERROR_DEVICE_BUSY 1
#define I2C_ERROR_DEVICE_NOT_RESPONDING 2
 
 
/* Function Declaration */
 
extern void i2c_init(void);
extern void i2c_start(void);
extern void i2c_stop(void);
extern unsigned char i2c_transmit(unsigned char data);
extern unsigned char i2c_receive(unsigned char ack);
 
 
 
/* Macro definitions */
 
#define I2C_START(ADDRESS) { i2c_start(); i2c_transmit(ADDRESS); }
#define I2C_START_TX(ADDRESS) I2C_START(ADDRESS)
#define I2C_START_RX(ADDRESS) I2C_START(ADDRESS | I2C_READ)
 
#endif /* #ifndef I2C_H */
/*######################################################################################################*/
/* T H E E N D */
/*######################################################################################################*/
 
/programy/avr/SFR08/lcd_io.c
0,0 → 1,1040
 
/****************************************************************************
Title : C file for the HD44780U LCD library (lcd_io.c)
Author: Chris efstathiou hendrix@otenet.gr
Date: 1/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
*****************************************************************************/
#ifndef _IO_REG_MACRO_MODE_
#define _IO_REG_MACRO_MODE_ 1 /* In case you have the new assignment mode io headers */
#endif
 
#ifndef _SFR_ASM_COMPAT
#define _SFR_ASM_COMPAT 1 /* This is for GCC 3.2 */
#endif
 
#include <io.h>
#include <progmem.h>
#include <eeprom.h>
#include "lcd_io.h"
 
/* constants/macros */
#ifndef CONCAT1
#define CONCAT1(a, b) CONCAT2(a, b)
#endif
 
#ifndef CONCAT2
#define CONCAT2(a, b) a ## b
#endif
 
#define LCD_POWER_ON_DELAY ( (20000*(F_CPU/60000))/100 ) /* 20 milliseconds */
#define LCD_INIT_DELAY ( (5000*(F_CPU/60000))/100 ) /* 5 milliseconds */
 
#define INIT_MODE 2
#define DATA_MODE 1
#define CMD_MODE 0
 
 
/* CONVERSION OF LCD_DELAY_TIME TO TRUE MICROSECONDS */
#if LCD_READ_REQUIRED == 0 || LCD_IO_MODE == 2 || LCD_IO_MODE == 7
#define LCD_DELAY_SHORT ( (LCD_DELAY_TIME*(F_CPU/60000))/100 )
#define LCD_DELAY_LONG ( LCD_DELAY_SHORT*40 )
#endif
 
 
 
/*######################################################################################################*/
#if LCD_IO_MODE == 2
/*######################################################################################################*/
 
#define LCD_DATA_PORT_IS_IO 1
#define LCD_CLOCK_PORT_IS_IO 1
 
#define LCD_DATA_PORT CONCAT1(PORT,LCD_DATA_SIGNAL_PORT)
#define LCD_DATA_DDR_REG CONCAT1(DDR,LCD_DATA_SIGNAL_PORT)
 
#define LCD_CLOCK_PORT CONCAT1(PORT,LCD_CLOCK_SIGNAL_PORT)
#define LCD_CLOCK_DDR_REG CONCAT1(DDR,LCD_CLOCK_SIGNAL_PORT)
 
#define LCD_READ_REQUIRED 0
 
 
 
#if defined(__AVR_ATmega103__)
 
#if LCD_DATA_PORT == PORTC
#undef LCD_DATA_PORT_IS_IO
#undef LCD_DATA_DDR_REG
#define LCD_DATA_PORT_IS_IO 0
#endif
 
#if LCD_CLOCK_PORT == PORTC
#undef LCD_CLOCK_PORT_IS_IO
#undef LCD_CLOCK_DDR_REG
#define LCD_CLOCK_PORT_IS_IO 0
#endif
#endif /* #if defined(__AVR_ATmega103__) */
 
/*######################################################################################################*/
#elif LCD_IO_MODE == 6
/*######################################################################################################*/
#define lcd_toggle_e() ({ cbi(LCD_E_PORT, LCD_E_PIN); delay(F_CPU/6000000); \
sbi(LCD_E_PORT, LCD_E_PIN); })
 
#if LCD_READ_REQUIRED == 1
#undef LCD_MULTIPLEX_REQUIRED
#define LCD_MULTIPLEX_REQUIRED 0
#define BUSY_FLAG 0
#define DATA 1
#endif
 
#if LCD_LINES == 1 || LCD_LINES == 2 || LCD_LINES == 4
#else
#error THE LCD LINES MUST BE 1 OR 2 OR 4 !
#endif
 
#define LCD_D4_PORT_IS_IO 1
#define LCD_D5_PORT_IS_IO 1
#define LCD_D6_PORT_IS_IO 1
#define LCD_D7_PORT_IS_IO 1
#define LCD_RS_PORT_IS_IO 1
#define LCD_RW_PORT_IS_IO 1
#define LCD_E_PORT_IS_IO 1
 
#define LCD_D4_PORT CONCAT1(PORT, LCD_DATA4_PORT)
#define LCD_D5_PORT CONCAT1(PORT, LCD_DATA5_PORT)
#define LCD_D6_PORT CONCAT1(PORT, LCD_DATA6_PORT)
#define LCD_D7_PORT CONCAT1(PORT, LCD_DATA7_PORT)
#define LCD_RS_PORT CONCAT1(PORT, LCD_RS_SIGNAL_PORT)
#define LCD_RW_PORT CONCAT1(PORT, LCD_RW_SIGNAL_PORT)
#define LCD_E_PORT CONCAT1(PORT, LCD_E_SIGNAL_PORT)
 
#define LCD_D4_DDR_REG CONCAT1(DDR, LCD_DATA4_PORT)
#define LCD_D5_DDR_REG CONCAT1(DDR, LCD_DATA5_PORT)
#define LCD_D6_DDR_REG CONCAT1(DDR, LCD_DATA6_PORT)
#define LCD_D7_DDR_REG CONCAT1(DDR, LCD_DATA7_PORT)
#define LCD_RS_DDR_REG CONCAT1(DDR, LCD_RS_SIGNAL_PORT)
#define LCD_RW_DDR_REG CONCAT1(DDR, LCD_RW_SIGNAL_PORT)
#define LCD_E_DDR_REG CONCAT1(DDR, LCD_E_SIGNAL_PORT)
 
 
 
#if LCD_READ_REQUIRED == 1
 
#define LCD_D4_PIN_REG CONCAT1(PIN, LCD_DATA4_PORT)
#define LCD_D5_PIN_REG CONCAT1(PIN, LCD_DATA5_PORT)
#define LCD_D6_PIN_REG CONCAT1(PIN, LCD_DATA6_PORT)
#define LCD_D7_PIN_REG CONCAT1(PIN, LCD_DATA7_PORT)
 
#elif LCD_READ_REQUIRED == 0
 
#undef LCD_RW_PORT
#undef LCD_RW_DDR_REG
#undef LCD_RW_PORT_IS_IO
 
#endif
 
 
 
#if defined(__AVR_ATmega103__)
 
#if LCD_D4_PORT == PORTC
#if LCD_READ_REQUIRED == 1
#error THE PORT FOR LCD_D4 IS OUTPUT ONLY!
#endif
#undef LCD_D4_PORT_IS_IO
#undef LCD_D4_DDR_REG
#define LCD_D4_PORT_IS_IO 0
#endif
 
#if LCD_D5_PORT == PORTC
#if LCD_READ_REQUIRED == 1
#error THE PORT FOR LCD_D5 IS OUTPUT ONLY!
#endif
#undef LCD_D5_PORT_IS_IO
#undef LCD_D5_DDR_REG
#define LCD_D5_PORT_IS_IO 0
#endif
 
#if LCD_D6_PORT == PORTC
#if LCD_READ_REQUIRED == 1
#error THE PORT FOR LCD_D6 IS OUTPUT ONLY!
#endif
#undef LCD_D6_PORT_IS_IO
#undef LCD_D6_DDR_REG
#define LCD_D6_PORT_IS_IO 0
#endif
 
#if LCD_D7_PORT == PORTC
#if LCD_READ_REQUIRED == 1
#error THE PORT FOR LCD_D7 IS OUTPUT ONLY!
#endif
#undef LCD_D7_PORT_IS_IO
#undef LCD_D7_DDR_REG
#define LCD_D7_PORT_IS_IO 0
#endif
 
#if LCD_RS_PORT == PORTC
#undef LCD_RS_PORT_IS_IO
#undef LCD_RS_DDR_REG
#define LCD_RS_PORT_IS_IO 0
#endif
 
#if LCD_READ_REQUIRED == 1
#if LCD_RW_PORT == PORTC
#undef LCD_RW_PORT_IS_IO
#undef LCD_RW_DDR_REG
#define LCD_RW_PORT_IS_IO 0
#endif
#endif
 
#if LCD_E_PORT == PORTC
#undef LCD_E_PORT_IS_IO
#undef LCD_E_DDR_REG
#define LCD_E_PORT_IS_IO 0
#endif
 
#endif /* #if defined(__AVR_ATmega103__) */
 
/*######################################################################################################*/
#elif LCD_IO_MODE == 7
/*######################################################################################################*/
 
#define lcd_toggle_e() ({ cbivar(lcd_E_port, lcd_E_pin); delay(F_CPU/6000000); \
sbivar(lcd_E_port, lcd_E_pin); })
#if SREG > 0X3F
#define IO_TO_MEM_OFFSET 0
#else
#define IO_TO_MEM_OFFSET 0X20
#endif
 
#define LCD_READ_REQUIRED 0
 
#if LCD_0_LINES == 1 || LCD_0_LINES == 2 || LCD_0_LINES == 4
#else
#error THE LCD LINES MUST BE 1 OR 2 OR 4 !
#endif
 
#if LCD_1_LINES == 1 || LCD_1_LINES == 2 || LCD_1_LINES == 4
#else
#error THE LCD LINES MUST BE 1 OR 2 OR 4 !
#endif
 
#if NUMBER_OF_LCD_UNITS >= 3
#if LCD_2_LINES == 1 || LCD_2_LINES == 2 || LCD_2_LINES == 4
#else
#error THE LCD LINES MUST BE 1 OR 2 OR 4 !
#endif
#endif
 
#define LCD_D4_PORT_IS_IO 1
#define LCD_D5_PORT_IS_IO 1
#define LCD_D6_PORT_IS_IO 1
#define LCD_D7_PORT_IS_IO 1
#define LCD_RS_PORT_IS_IO 1
#define LCD_0_E_PORT_IS_IO 1
#define LCD_1_E_PORT_IS_IO 1
 
#if NUMBER_OF_LCD_UNITS >=3
#define LCD_2_E_PORT_IS_IO 1
#endif
 
#define LCD_D4_PORT CONCAT1(PORT, LCD_DATA4_PORT)
#define LCD_D5_PORT CONCAT1(PORT, LCD_DATA5_PORT)
#define LCD_D6_PORT CONCAT1(PORT, LCD_DATA6_PORT)
#define LCD_D7_PORT CONCAT1(PORT, LCD_DATA7_PORT)
#define LCD_RS_PORT CONCAT1(PORT, LCD_RS_SIGNAL_PORT)
#define LCD_0_E_PORT CONCAT1(PORT, LCD_0_E_SIGNAL_PORT)
#define LCD_1_E_PORT CONCAT1(PORT, LCD_1_E_SIGNAL_PORT)
 
#if NUMBER_OF_LCD_UNITS >=3
#define LCD_2_E_PORT CONCAT1(PORT, LCD_2_E_SIGNAL_PORT)
#endif
 
#define LCD_D4_DDR_REG CONCAT1(DDR, LCD_DATA4_PORT)
#define LCD_D5_DDR_REG CONCAT1(DDR, LCD_DATA5_PORT)
#define LCD_D6_DDR_REG CONCAT1(DDR, LCD_DATA6_PORT)
#define LCD_D7_DDR_REG CONCAT1(DDR, LCD_DATA7_PORT)
#define LCD_RS_DDR_REG CONCAT1(DDR, LCD_RS_SIGNAL_PORT)
#define LCD_0_E_DDR_REG CONCAT1(DDR, LCD_0_E_SIGNAL_PORT)
#define LCD_1_E_DDR_REG CONCAT1(DDR, LCD_1_E_SIGNAL_PORT)
 
#if NUMBER_OF_LCD_UNITS >=3
#define LCD_2_E_DDR_REG CONCAT1(DDR, LCD_2_E_SIGNAL_PORT)
#endif
 
 
#if defined(__AVR_ATmega103__)
 
#if LCD_D4_PORT == PORTC
#undef LCD_D4_PORT_IS_IO
#undef LCD_D4_DDR_REG
#define LCD_D4_PORT_IS_IO 0
#endif
 
#if LCD_D5_PORT == PORTC
#undef LCD_D5_PORT_IS_IO
#undef LCD_D5_DDR_REG
#define LCD_D5_PORT_IS_IO 0
#endif
 
#if LCD_D6_PORT == PORTC
#undef LCD_D6_PORT_IS_IO
#undef LCD_D6_DDR_REG
#define LCD_D6_PORT_IS_IO 0
#endif
 
#if LCD_D7_PORT == PORTC
#undef LCD_D7_PORT_IS_IO
#undef LCD_D7_DDR_REG
#define LCD_D7_PORT_IS_IO 0
#endif
 
#if LCD_RS_PORT == PORTC
#undef LCD_RS_PORT_IS_IO
#undef LCD_RS_DDR_REG
#define LCD_RS_PORT_IS_IO 0
#endif
 
#if LCD_0_E_PORT == PORTC
#undef LCD_0_E_PORT_IS_IO
#undef LCD_0_E_DDR_REG
#define LCD_0_E_PORT_IS_IO 0
#endif
 
#if LCD_1_E_PORT == PORTC
#undef LCD_1_E_PORT_IS_IO
#undef LCD_1_E_DDR_REG
#define LCD_1_E_PORT_IS_IO 0
#endif
 
#if NUMBER_OF_LCD_UNITS >=3
#if LCD_2_E_PORT == PORTC
#undef LCD_2_E_PORT_IS_IO
#undef LCD_2_E_DDR_REG
#define LCD_2_E_PORT_IS_IO 0
#endif
#endif /* #if NUMBER_OF_LCD_UNITS >=3 */
 
#endif /* #if defined(__AVR_ATmega103__) */
 
#endif /* #elif LCD_IO_MODE == 7 */
/*######################################################################################################*/
 
/* type definitions */
 
typedef unsigned char u08;
typedef unsigned short u16;
 
/*######################################################################################################*/
/* FUNCTION PROTOTYPES */
/*######################################################################################################*/
 
#if LCD_IO_MODE == 7
static void sbivar(unsigned char port, unsigned char bit);
static void cbivar(unsigned char port, unsigned char bit);
#endif
 
#if LCD_READ_REQUIRED == 1
static unsigned char lcd_read(unsigned char rs);
static inline unsigned char lcd_waitbusy(void);
#endif
 
static void delay(unsigned long int us);
 
/*######################################################################################################*/
/* GLOBAL variables */
/*######################################################################################################*/
 
static unsigned char x,y, putc_lock=0;
#if LCD_IO_MODE == 7
static unsigned char lcd_E_port=0, lcd_E_pin=0, lcd_chars_per_line=0, lcd_lines=0, current_lcd_unit=0;
static struct xy {
unsigned char x;
unsigned char y;
} xy_coordinates[NUMBER_OF_LCD_UNITS];
 
#endif
 
/*######################################################################################################*/
/* local functions */
/*######################################################################################################*/
 
static void delay(unsigned long int us)
/* delay for a minimum of <us> microseconds (with a 6 Mhz crystal, the resolution is 1 us) */
{
while ( us ) { us--; } /* 6 cpu cycles per loop */
}
 
/*######################################################################################################*/
#if LCD_IO_MODE == 7 /* lcd_write() function for 6 bit i/o one lcd unit */
/*######################################################################################################*/
 
 
static void sbivar(unsigned char port, unsigned char bit)
{
register unsigned char temp=0;
 
temp=*((unsigned char*)(port+IO_TO_MEM_OFFSET));
temp|= (1<<bit);
*((unsigned char*)(port+IO_TO_MEM_OFFSET))=temp;
 
return;
}
/*######################################################################################################*/
 
static void cbivar(unsigned char port, unsigned char bit)
{
register unsigned char temp=0;
 
temp=*((unsigned char*)(port+IO_TO_MEM_OFFSET));
temp &= ~(1<<bit);
*((unsigned char*)(port+IO_TO_MEM_OFFSET))=temp;
 
return;
}
/*######################################################################################################*/
 
static void lcd_write(unsigned char data, unsigned char mode)
{
register unsigned char rs=0;
 
if(mode==DATA_MODE) rs=1; else rs=0; /* set the rs value */
/* output high nibble first */
if(data&0x10) sbi(LCD_D4_PORT, LCD_D4_PIN); else cbi(LCD_D4_PORT, LCD_D4_PIN);
if(data&0x20) sbi(LCD_D5_PORT, LCD_D5_PIN); else cbi(LCD_D5_PORT, LCD_D5_PIN);
if(data&0x40) sbi(LCD_D6_PORT, LCD_D6_PIN); else cbi(LCD_D6_PORT, LCD_D6_PIN);
if(data&0x80) sbi(LCD_D7_PORT, LCD_D7_PIN); else cbi(LCD_D7_PORT, LCD_D7_PIN);
if(rs) sbi(LCD_RS_PORT, LCD_RS_PIN); else cbi(LCD_RS_PORT, LCD_RS_PIN);
lcd_toggle_e();
/* output low nibble */
/* if INIT_MODE skip this section else execute it */
if(mode!=INIT_MODE)
{
if(data&0x01) sbi(LCD_D4_PORT, LCD_D4_PIN); else cbi(LCD_D4_PORT, LCD_D4_PIN);
if(data&0x02) sbi(LCD_D5_PORT, LCD_D5_PIN); else cbi(LCD_D5_PORT, LCD_D5_PIN);
if(data&0x04) sbi(LCD_D6_PORT, LCD_D6_PIN); else cbi(LCD_D6_PORT, LCD_D6_PIN);
if(data&0x08) sbi(LCD_D7_PORT, LCD_D7_PIN); else cbi(LCD_D7_PORT, LCD_D7_PIN);
if(rs) sbi(LCD_RS_PORT, LCD_RS_PIN); else cbi(LCD_RS_PORT, LCD_RS_PIN);
lcd_toggle_e();
}
 
delay(LCD_DELAY_SHORT);
 
}
/*------------------------------------------------------------------------------------------------------*/
void select_lcd(unsigned char lcd_unit)
{
/* Save the current lcd unit x,y coordinates */
xy_coordinates[current_lcd_unit].x=x;
xy_coordinates[current_lcd_unit].y=y;
 
if(lcd_unit==0)
{
lcd_E_port= LCD_0_E_PORT;
lcd_E_pin = LCD_0_E_PIN;
lcd_chars_per_line = LCD_0_CHARS_PER_LINE;
lcd_lines = LCD_0_LINES;
current_lcd_unit=lcd_unit; /* Make the requested lcd unit current (active) */
x=xy_coordinates[lcd_unit].x; /* Load the saved x,y coordinates of the specified lcd unit */
y=xy_coordinates[lcd_unit].y;
}
else if(lcd_unit==1)
{
lcd_E_port= LCD_1_E_PORT;
lcd_E_pin = LCD_1_E_PIN;
lcd_chars_per_line = LCD_1_CHARS_PER_LINE;
lcd_lines = LCD_1_LINES;
current_lcd_unit=lcd_unit;
x=xy_coordinates[lcd_unit].x;
y=xy_coordinates[lcd_unit].y;
}
#if NUMBER_OF_LCD_UNITS >=3
else if(lcd_unit==2)
{
lcd_E_port= LCD_2_E_PORT;
lcd_E_pin = LCD_2_E_PIN;
lcd_chars_per_line = LCD_2_CHARS_PER_LINE;
lcd_lines = LCD_2_LINES;
current_lcd_unit=lcd_unit;
x=xy_coordinates[lcd_unit].x;
y=xy_coordinates[lcd_unit].y;
}
#endif
return;
}
/*######################################################################################################*/
#elif LCD_IO_MODE == 6 /* lcd_write() function for 6 bit i/o with multi lcd units */
/*######################################################################################################*/
 
#if LCD_READ_REQUIRED == 1
 
#define LCD_READ_DELAY ( (10*(F_CPU/60000))/100 )
 
static unsigned char lcd_read(unsigned char rs)
{
register unsigned char data=0;
/* RS=1: read data, RS=0: read busy flag, RW=1 read mode */
if (rs) sbi(LCD_RS_PORT, LCD_RS_PIN); else cbi(LCD_RS_PORT, LCD_RS_PIN);
 
/* configure data pins as input */
cbi(LCD_D4_DDR_REG, LCD_D4_PIN );
cbi(LCD_D5_DDR_REG, LCD_D5_PIN );
cbi(LCD_D6_DDR_REG, LCD_D6_PIN );
cbi(LCD_D7_DDR_REG, LCD_D7_PIN );
 
/* set R/W pin for reading from LCD */
sbi(LCD_RW_PORT, LCD_RW_PIN);
delay(LCD_READ_DELAY);
 
if(bit_is_set(LCD_D7_PIN_REG, LCD_D7_PIN)) { data+=1; }
data=(data<<1);
if(bit_is_set(LCD_D6_PIN_REG, LCD_D6_PIN)) { data+=1; }
data=(data<<1);
if(bit_is_set(LCD_D5_PIN_REG, LCD_D5_PIN)) { data+=1; }
data=(data<<1);
if(bit_is_set(LCD_D4_PIN_REG, LCD_D4_PIN)) { data+=1; }
data=(data<<1);
 
lcd_toggle_e();
delay(LCD_READ_DELAY);
 
if(bit_is_set(LCD_D7_PIN_REG, LCD_D7_PIN)) { data+=1; }
data=(data<<1);
if(bit_is_set(LCD_D6_PIN_REG, LCD_D6_PIN)) { data+=1; }
data=(data<<1);
if(bit_is_set(LCD_D5_PIN_REG, LCD_D5_PIN)) { data+=1; }
data=(data<<1);
if(bit_is_set(LCD_D4_PIN_REG, LCD_D4_PIN)) { data+=1; }
lcd_toggle_e();
 
/* clear R/W pin for writting to LCD */
cbi(LCD_RW_PORT, LCD_RW_PIN);
 
/* configure data pins as outputs */
sbi(LCD_D4_DDR_REG, LCD_D4_PIN );
sbi(LCD_D5_DDR_REG, LCD_D5_PIN );
sbi(LCD_D6_DDR_REG, LCD_D6_PIN );
sbi(LCD_D7_DDR_REG, LCD_D7_PIN );
 
return (data);
}
/*######################################################################################################*/
static inline unsigned char lcd_waitbusy(void)
/* loops while lcd is busy, reads address counter */
{
register unsigned char c;
while ( (c=lcd_read(BUSY_FLAG) & (1<<LCD_BUSY)) );
 
return (c); // return address counter
}
 
#endif /* #if LCD_READ_REQUIRED == 1 */
/*######################################################################################################*/
 
static void lcd_write(unsigned char data, unsigned char mode)
{
register unsigned char rs=0;
 
/* save and set DDR(X) register(s) in case another program altered those values */
#if LCD_MULTIPLEX_ENABLE == 1
 
#if LCD_D4_PORT_IS_IO==1
unsigned char d4_is_output=0;
if(inp(LCD_D4_DDR_REG)&(1<<LCD_D4_PIN)) { d4_is_output=1; }
sbi(LCD_D4_DDR_REG, LCD_D4_PIN );
#endif
#if LCD_D5_PORT_IS_IO==1
unsigned char d5_is_output=0;
if(inp(LCD_D5_DDR_REG)&(1<<LCD_D5_PIN)) { d5_is_output=1; }
sbi(LCD_D5_DDR_REG, LCD_D5_PIN );
#endif
#if LCD_D6_PORT_IS_IO==1
unsigned char d6_is_output=0;
if(inp(LCD_D6_DDR_REG)&(1<<LCD_D6_PIN)) { d6_is_output=1; }
sbi(LCD_D6_DDR_REG, LCD_D6_PIN );
#endif
#if LCD_D7_PORT_IS_IO==1
unsigned char d7_is_output=0;
if(inp(LCD_D7_DDR_REG)&(1<<LCD_D7_PIN)) { d7_is_output=1; }
sbi(LCD_D7_DDR_REG, LCD_D7_PIN );
#endif
#if LCD_RS_PORT_IS_IO==1
unsigned char rs_is_output=0;
if(inp(LCD_RS_DDR_REG)&(1<<LCD_RS_PIN)) { rs_is_output=1; }
sbi(LCD_RS_DDR_REG, LCD_RS_PIN );
#endif
 
#endif /* LCD_MULTIPLEX_ENABLE == 1 */
 
if(mode==DATA_MODE) rs=1; else rs=0; /* set the rs value */
/* output high nibble first */
if(data&0x10) sbi(LCD_D4_PORT, LCD_D4_PIN); else cbi(LCD_D4_PORT, LCD_D4_PIN);
if(data&0x20) sbi(LCD_D5_PORT, LCD_D5_PIN); else cbi(LCD_D5_PORT, LCD_D5_PIN);
if(data&0x40) sbi(LCD_D6_PORT, LCD_D6_PIN); else cbi(LCD_D6_PORT, LCD_D6_PIN);
if(data&0x80) sbi(LCD_D7_PORT, LCD_D7_PIN); else cbi(LCD_D7_PORT, LCD_D7_PIN);
if(rs) sbi(LCD_RS_PORT, LCD_RS_PIN); else cbi(LCD_RS_PORT, LCD_RS_PIN);
lcd_toggle_e();
/* output low nibble */
/* if INIT_MODE skip this section else execute it */
if(mode!=INIT_MODE)
{
if(data&0x01) sbi(LCD_D4_PORT, LCD_D4_PIN); else cbi(LCD_D4_PORT, LCD_D4_PIN);
if(data&0x02) sbi(LCD_D5_PORT, LCD_D5_PIN); else cbi(LCD_D5_PORT, LCD_D5_PIN);
if(data&0x04) sbi(LCD_D6_PORT, LCD_D6_PIN); else cbi(LCD_D6_PORT, LCD_D6_PIN);
if(data&0x08) sbi(LCD_D7_PORT, LCD_D7_PIN); else cbi(LCD_D7_PORT, LCD_D7_PIN);
if(rs) sbi(LCD_RS_PORT, LCD_RS_PIN); else cbi(LCD_RS_PORT, LCD_RS_PIN);
lcd_toggle_e();
}
#if LCD_READ_REQUIRED == 0
delay(LCD_DELAY_SHORT);
#elif LCD_READ_REQUIRED == 1
lcd_waitbusy();
#endif
 
/* Restore the DDR registers, if multiplexing wanted */
#if LCD_MULTIPLEX_ENABLE == 1
 
#if LCD_D4_PORT_IS_IO==1
if(!d4_is_output) { cbi(LCD_D4_DDR_REG, LCD_D4_PIN ); }
#endif
#if LCD_D5_PORT_IS_IO==1
if(!d5_is_output) { cbi(LCD_D5_DDR_REG, LCD_D5_PIN ); }
#endif
#if LCD_D6_PORT_IS_IO==1
if(!d6_is_output) { cbi(LCD_D6_DDR_REG, LCD_D6_PIN ); }
#endif
#if LCD_D7_PORT_IS_IO==1
if(!d7_is_output) { cbi(LCD_D7_DDR_REG, LCD_D7_PIN ); }
#endif
#if LCD_RS_PORT_IS_IO==1
if(!rs_is_output) { cbi(LCD_RS_DDR_REG, LCD_RS_PIN ); }
#endif
 
#endif /* LCD_MULTIPLEX_ENABLE == 1 */
}
/*######################################################################################################*/
#elif LCD_IO_MODE == 2 /* lcd_write() function for 2 bit i/o */
/*######################################################################################################*/
 
static void lcd_write(unsigned char lcd_data,unsigned char mode)
{
#define toggle_clock() ({ sbi(LCD_CLOCK_PORT, LCD_CLOCK_PIN); cbi(LCD_CLOCK_PORT, LCD_CLOCK_PIN); })
#define data(x) ({ if(x) sbi(LCD_DATA_PORT, LCD_DATA_PIN); else cbi(LCD_DATA_PORT, LCD_DATA_PIN); })
#define toggle_data() ({ data(1); delay(F_CPU/6000000); data(0); })
register unsigned char x=0, rs=0;
 
/* INITIALIZATION */
/* Set clock and data pins as outputs, at low state and set rs value */
#if LCD_CLOCK_PORT_IS_IO
sbi(LCD_CLOCK_DDR_REG, LCD_CLOCK_PIN);
#endif
#if LCD_DATA_PORT_IS_IO
sbi(LCD_DATA_DDR_REG, LCD_DATA_PIN);
#endif
cbi(LCD_CLOCK_PORT, LCD_CLOCK_PIN); cbi(LCD_DATA_PORT, LCD_DATA_PIN);
if(mode==DATA_MODE) rs=1; else rs=0;
/* send high nibble first */
x=6; while(x--) { toggle_clock(); } /* clear shift register */
data(1); toggle_clock(); /* send E "AND" signal */
data(rs); toggle_clock(); /* send RS signal */
x=0x80; while(x>=0x10) { data(lcd_data&x); toggle_clock(); x=(x>>1); }
/* Strobe E pin making sure that the pulse is 450 ns min */
toggle_data();
/* send low nibble Clock and Data are already low */
x=6; while(x--) { toggle_clock(); } /* clear shift register */
data(1); toggle_clock(); /* send E "AND" signal */
data(rs); toggle_clock(); /* send RS signal */
x=0x08; while(x>=0x01) { data(lcd_data&x); toggle_clock(); x=(x>>1); }
/* if INIT_MODE do NOT strobe the E pin else strobe it */
if(mode!=INIT_MODE) { toggle_data(); }
delay(LCD_DELAY_SHORT); /* wait for command to execute */
}
/*######################################################################################################*/
#endif /* #elif LCD_IO_MODE == 2 */
/*######################################################################################################*/
 
/*######################################################################################################*/
/* PUBLIC FUNCTIONS */
/*######################################################################################################*/
void lcd_command(unsigned char cmd)
/* send command <cmd> to LCD */
{
lcd_write(cmd,CMD_MODE);
}
/*######################################################################################################*/
 
void lcd_gotoxy(unsigned char lcd_x, unsigned char lcd_y)
/* goto position (x,y) */
{
#if LCD_IO_MODE == 7
 
if(lcd_x >= lcd_chars_per_line || lcd_y >= lcd_lines) { putc_lock=1; return; }
else putc_lock=0;
 
if (lcd_y==0 ) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+lcd_x); }
else if(lcd_y==1) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+lcd_x); }
else if(lcd_y==2) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+lcd_x); }
else { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+lcd_x); }
/*------------------------------------------------------------------------------------------------------*/
#elif LCD_IO_MODE == 6 || LCD_IO_MODE == 2
/*------------------------------------------------------------------------------------------------------*/
 
if(lcd_x >= LCD_CHARS_PER_LINE || lcd_y >= LCD_LINES) { putc_lock=1; return; }
else putc_lock=0;
#if LCD_LINES==1
if (lcd_y==0 ) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+lcd_x); }
#endif
#if LCD_LINES==2
if (lcd_y==0 ) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+lcd_x); }
else { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+lcd_x); }
#endif
 
#if LCD_LINES==4
if (lcd_y==0 ) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE1+lcd_x); }
else if(lcd_y==1) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE2+lcd_x); }
else if(lcd_y==2) { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE3+lcd_x); }
else { lcd_command((1<<LCD_DDRAM)+LCD_START_LINE4+lcd_x); }
#endif
#endif
x=lcd_x;
y=lcd_y;
 
}/* lcd_gotoxy */
/*######################################################################################################*/
 
unsigned int lcd_getxy(void)
{
return((y*100)+x);
}
/*######################################################################################################*/
 
void lcd_clrscr(void)
/* clear lcd and set cursor to home position */
{
lcd_command(1<<LCD_CLR);
#if LCD_READ_REQUIRED == 0 || LCD_IO_MODE == 2 || LCD_IO_MODE == 7
delay(LCD_DELAY_LONG); /* this command needs more waiting time to execute */
#elif LCD_READ_REQUIRED == 1 && LCD_IO_MODE == 6
lcd_waitbusy();
#endif
x=0; y=0;
}
/*######################################################################################################*/
 
void lcd_clrline(unsigned char line)
/* clear a specific lcd line and set cursor at the start of the line */
{
#if LCD_IO_MODE == 7
if(lcd_lines==1)
{
lcd_gotoxy(0, 0);
while(x<lcd_chars_per_line) { lcd_putc(' '); }
lcd_gotoxy(0, 0);
}
if(line<lcd_lines)
{
lcd_gotoxy(0, line);
while(x<lcd_chars_per_line) { lcd_putc(' '); }
lcd_gotoxy(0, line);
}
 
#elif LCD_IO_MODE == 6 || LCD_IO_MODE == 2
 
#if LCD_LINES == 1
lcd_gotoxy(0, 0);
while(x<LCD_CHARS_PER_LINE) { lcd_putc(' '); }
lcd_gotoxy(0, 0);
#else /* #if LCD_LINES == 1 */
if(line<LCD_LINES)
{
lcd_gotoxy(0, line);
while(x<LCD_CHARS_PER_LINE) { lcd_putc(' '); }
lcd_gotoxy(0, line);
}
#endif /* #if LCD_LINES == 1 */
#endif /* #if LCD_IO_MODE == 7 */
}
/*######################################################################################################*/
 
void lcd_home(void)
/* set cursor to home position */
{
lcd_command(1<<LCD_HOME);
#if LCD_READ_REQUIRED == 0 || LCD_IO_MODE == 2 || LCD_IO_MODE == 7
delay(LCD_DELAY_LONG); /* this command needs more waiting time to execute */
#elif LCD_READ_REQUIRED == 1 && LCD_IO_MODE == 6
lcd_waitbusy();
#endif
x=0; y=0;
}
/*######################################################################################################*/
 
void lcd_putc(unsigned char c)
/* print character at current cursor position */
{
if(!putc_lock)
{
#if LCD_IO_MODE == 7
if(lcd_lines !=1)
{ if(c=='\n') { if(y<lcd_lines-1) lcd_gotoxy(0,(y+1)); }
else if(x<lcd_chars_per_line) { lcd_write(c, DATA_MODE); x++; }
#if LCD_AUTO_LINE_FEED == 1
else if(y<lcd_lines-1) { lcd_gotoxy(0,(y+1)); lcd_write(c, DATA_MODE); x++; }
else { lcd_gotoxy(0,0); lcd_write(c, DATA_MODE); x++; }
#endif
}
else{
if(c=='\n') { return; }
if(x<lcd_chars_per_line) { lcd_write(c, DATA_MODE); x++; }
}
#elif LCD_IO_MODE == 6 || LCD_IO_MODE == 2
 
#if LCD_LINES!=1
if(c=='\n') { if(y<LCD_LINES-1) lcd_gotoxy(0,(y+1)); }
else if(x<LCD_CHARS_PER_LINE) { lcd_write(c, DATA_MODE); x++; }
#if LCD_AUTO_LINE_FEED == 1
else if(y<LCD_LINES-1) { lcd_gotoxy(0,(y+1)); lcd_write(c, DATA_MODE); x++; }
else { lcd_gotoxy(0,0); lcd_write(c, DATA_MODE); x++; }
#endif
 
#else
if(c=='\n') { return; }
if(x<LCD_CHARS_PER_LINE) { lcd_write(c, DATA_MODE); x++; }
#endif
 
#endif /* #if LCD_IO_MODE == 7 */
}
}
/*######################################################################################################*/
 
void lcd_puts(const unsigned char *s)
/* print string on lcd (no auto linefeed) */
{
register unsigned char c;
 
while ( (c = *s++) ) { lcd_putc(c); }
 
}
/*######################################################################################################*/
 
void lcd_puts_p(const unsigned char *progmem_s)
/* print string from program memory on lcd (no auto linefeed) */
{
register unsigned char c;
 
while ( (c = PRG_RDB(progmem_s++)) ) { lcd_putc(c); }
 
}
/*######################################################################################################*/
 
void lcd_puts_e(unsigned char *eeprom_s)
/* print string from eeprom on lcd (no auto linefeed) */
{
register unsigned char c;
while( (c=eeprom_rb((unsigned int)eeprom_s++))&& c!=0xFF ) { lcd_putc(c); }
/*{ if(c==0xFF) break; lcd_putc(c); }*/
}
/*######################################################################################################*/
 
void lcd_puti(int value, unsigned char dot_position)
/* print signed integer on lcd with or without comma (no auto linefeed) */
{
unsigned char lcd_data[6]={'0','0','0','0','0','0' }, position=sizeof(lcd_data), radix=10;
 
/* convert int to ascii */
if(value<0) { lcd_putc('-'); value=-value; }
do { position--; *(lcd_data+position)=(value%radix)+'0'; value/=radix; } while(value);
 
/* some fractional digit corrections */
if( dot_position>=sizeof(lcd_data) ) return;
while( (sizeof(lcd_data)-dot_position)<=position ) position--;
 
/* start displaying the number */
for(;position<=(sizeof(lcd_data)-1);position++)
{
if( position==sizeof(lcd_data)-dot_position ) lcd_putc(',');
lcd_putc(lcd_data[position]);
}
 
return;
}
/*######################################################################################################*/
#if LCD_IO_MODE == 6 || LCD_IO_MODE == 2
/*######################################################################################################*/
 
void lcd_init(void)
{
/* initialize display and select type of cursor */
/* dispAttr: LCD_DISP_OFF, LCD_DISP_ON, LCD_DISP_ON_CURSOR, LCD_DISP_CURSOR_BLINK */
#if LCD_LINES==1
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_1LINE
#else
#define LCD_FUNCTION_DEFAULT LCD_FUNCTION_4BIT_2LINES
#endif
 
#if LCD_IO_MODE == 6
 
#if LCD_E_PORT_IS_IO==1
sbi(LCD_E_DDR_REG, LCD_E_PIN );
#endif
sbi(LCD_E_PORT, LCD_E_PIN );
 
#if LCD_MULTIPLEX_ENABLE == 0
 
#if LCD_D4_PORT_IS_IO==1
sbi(LCD_D4_DDR_REG, LCD_D4_PIN );
#endif
#if LCD_D5_PORT_IS_IO==1
sbi(LCD_D5_DDR_REG, LCD_D5_PIN );
#endif
#if LCD_D6_PORT_IS_IO==1
sbi(LCD_D6_DDR_REG, LCD_D6_PIN );
#endif
#if LCD_D7_PORT_IS_IO==1
sbi(LCD_D7_DDR_REG, LCD_D7_PIN );
#endif
#if LCD_RS_PORT_IS_IO==1
sbi(LCD_RS_DDR_REG, LCD_RS_PIN );
#endif
 
#if LCD_READ_REQUIRED == 1
#if LCD_RW_PORT_IS_IO == 1
sbi(LCD_RW_DDR_REG, LCD_RW_PIN );
#endif
cbi(LCD_RW_PORT, LCD_RW_PIN );
#endif
 
#endif /* #if LCD_MULTIPLEX_ENABLE == 0 */
 
#endif /* #if LCD_IO_MODE == 6 */
/*------ Initialize lcd to 4 bit i/o mode -------*/
/* initial write to lcd is 8bit using delay since busy flag can't be checked here anyway */
 
delay(LCD_POWER_ON_DELAY); /* Wait 20 milliseconds */
lcd_write(LCD_FUNCTION_8BIT_1LINE, INIT_MODE);
delay(LCD_INIT_DELAY); /* Wait 5 milliseconds */
lcd_write(LCD_FUNCTION_8BIT_1LINE, INIT_MODE);
lcd_write(LCD_FUNCTION_8BIT_1LINE, INIT_MODE);
lcd_write(LCD_FUNCTION_4BIT_1LINE, INIT_MODE); /* set IO mode to 4bit */
/* from now on the lcd accepts only 4 bit I/O, so we can use lcd_command() */
 
lcd_command(LCD_FUNCTION_DEFAULT); /* function set: display lines */
lcd_command(LCD_DISP_OFF); /* display off */
lcd_clrscr(); /* display clear */
lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
lcd_command(LCD_DISP_ON); /* LCD DISPLAY ON (DEFAULT) */
 
}/* lcd_init */
/*######################################################################################################*/
#elif LCD_IO_MODE == 7
/*######################################################################################################*/
 
void lcd_init(void)
{
unsigned char lcd_unit=0;
/* initialize display and select type of cursor */
/* dispAttr: LCD_DISP_OFF, LCD_DISP_ON, LCD_DISP_ON_CURSOR, LCD_DISP_CURSOR_BLINK */
 
#if LCD_D4_PORT_IS_IO == 1
sbi(LCD_D4_DDR_REG, LCD_D4_PIN );
#endif
#if LCD_D5_PORT_IS_IO == 1
sbi(LCD_D5_DDR_REG, LCD_D5_PIN );
#endif
#if LCD_D6_PORT_IS_IO == 1
sbi(LCD_D6_DDR_REG, LCD_D6_PIN );
#endif
#if LCD_D7_PORT_IS_IO == 1
sbi(LCD_D7_DDR_REG, LCD_D7_PIN );
#endif
#if LCD_RS_PORT_IS_IO == 1
sbi(LCD_RS_DDR_REG, LCD_RS_PIN );
#endif
 
#if LCD_0_E_PORT_IS_IO == 1
sbi(LCD_0_E_DDR_REG, LCD_0_E_PIN );
#endif
sbi(LCD_0_E_PORT, LCD_0_E_PIN );
 
#if LCD_1_E_PORT_IS_IO == 1
sbi(LCD_1_E_DDR_REG, LCD_1_E_PIN );
#endif
sbi(LCD_1_E_PORT, LCD_1_E_PIN );
 
#if NUMBER_OF_LCD_UNITS >= 3
#if LCD_2_E_PORT_IS_IO == 1
sbi(LCD_2_E_DDR_REG, LCD_2_E_PIN );
#endif
sbi(LCD_2_E_PORT, LCD_2_E_PIN );
#endif
 
/*------ Initialize lcd to 4 bit i/o mode -------*/
/* initial write to lcd is 8bit using delay since busy flag can't be checked here anyway */
xy_coordinates[LCD_0].x=0;
xy_coordinates[LCD_0].y=0;
xy_coordinates[LCD_1].x=0;
xy_coordinates[LCD_1].y=0;
#if NUMBER_OF_LCD_UNITS >=3
xy_coordinates[LCD_2].x=0;
xy_coordinates[LCD_2].y=0;
#endif
 
 
for(lcd_unit=0; lcd_unit<NUMBER_OF_LCD_UNITS; lcd_unit++)
{
select_lcd(lcd_unit);
 
delay(LCD_POWER_ON_DELAY); /* Wait 20 milliseconds */
lcd_write(LCD_FUNCTION_8BIT_1LINE, INIT_MODE);
delay(LCD_INIT_DELAY); /* Wait 5 milliseconds */
lcd_write(LCD_FUNCTION_8BIT_1LINE, INIT_MODE);
lcd_write(LCD_FUNCTION_8BIT_1LINE, INIT_MODE);
lcd_write(LCD_FUNCTION_4BIT_1LINE, INIT_MODE); /* set IO mode to 4bit */
/* from now on the lcd accepts only 4 bit I/O, so we can use lcd_command() */
/* function set: set how many lines the lcd unit has. */
if(lcd_lines==1) { lcd_command(LCD_FUNCTION_4BIT_1LINE); }
else { lcd_command(LCD_FUNCTION_4BIT_2LINES); }
lcd_command(LCD_DISP_OFF); /* display off */
lcd_clrscr(); /* display clear */
lcd_command(LCD_MODE_DEFAULT); /* set entry mode */
lcd_command(LCD_DISP_ON); /* Display on */
 
}
select_lcd(0);
 
return;
}/* lcd_init */
 
#endif
/*######################################################################################################*/
/* T H E E N D */
/*######################################################################################################*/
 
/programy/avr/SFR08/lcd_io.h
0,0 → 1,384
/*******************************************************************************************************
Title : C include file for the HD44780U LCD library (lcd_io.c)
Author: Chris efstathiou hendrix@otenet.gr
Date: 1/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
 
DESCRIPTION
Basic routines for interfacing a HD44780U-based text lcd display
Based on Volker Oth's lcd library (http://members.xoom.com/volkeroth),
Peter Fleury's work <pfleury@gmx.ch> http://jump.to/fleury .
and the very good lcd page at www.myke.com
 
With this driver you can select from 2 different I/O modes.
1) MODE 6 - 6 or 7 pin I/O mode
2) MODE 2 - 2 pin I/O mode with an additional 74LS174
3) MODE 7 - multiple lcd unit mode
 
MODE 6 INFORMATION
mode 6 now needs only 6 pins as long the pins can function as output
freeing two bits to be used as general i/o.
R/W pin on the lcd must be connected to ground.
Also the pins can be scattered all over the place (any pin in any port).
( the other pins of the port(s) are not affected )
Be carefull not to change the status of the E lcd pin by using the outp()
command (both in PORT(X) and DDR(X) ) elsewhere in your program otherwise
your program will crash and you will have a lot of fun for the whole family.
Use sbi() and cbi() commands instead.
 
MODE 7 INFORMATION
mode 7 supports up to 3 lcd units and all the characteristics of mode 6
except that lcd reading is not possible.
The lcd diplays can be of different type.
 
 
MODE 2 INFORMATION
mode 2 uses only 2 pins in any combination you want as long the pin
can function as output.
You also need to make a very simple cirquit (really silly) with 74LS174.
See the included JPG photo for the schematic.
Also the pins can be scattered all over the place (any pin in any port).
( the other pins of the port(s) are not affected )
YOU MAY NOT! MULTIPLEX THE DATA AND CLOCK PINS WITH OTHER DEVICES
The pins are automatically set as outputs when you call an lcd function
Be carefull not to change the status of the CLOCK and DATA pins by using the outp()
command (both in PORT(X) and DDR(X) ) elsewhere in your program otherwise
your program will crash and you will have a lot of fun for the whole family (again!).
Use sbi() and cbi() commands instead.
MEMORY MAPPED MODE IS NOT SUPPORTED BY THIS DRIVER !!!
CAUTION!!! FOR SLOW LCD UNITS INCREASE THE "LCD_DELAY_TIME" VALUE!!!
The driver does not read anything back from the lcd because that way i only need 6
I/O lines and furthermore i can use the output only port found in MEGA103.
Since i dont read anything back, i just wait for commands to be executed
so below i define the time to wait for the two categories of commands of HD44780 .
The two CATEGORIES are:
1) 2ms for clear screen and return home commands (nominal value=1,52 ms)
and it is derived from "LCD_DELAY_TIME" .
2) 50us for all other commands (nominal value=37 us)
Even the slowest units will work reliably with LCD_DELAY_TIME=160.
The Longer delay needed for CATEGORY 1 is calculated from the "LCD_DELAY_TIME" value.
The specifications for HD44780 @ 270KHZ are 37 us for CATEGORY 2 and 1,52 ms for CATEGORY 1
 
LCD MODULE INFORMATION!
The maximum time required by each instruction for the slowest lcd units is
4.1 msecs for clearing the display or moving the cursor/display to the "home position",
160 usecs for all other commands. (i use 50 because i use good units)
 
Usual HD44780 Pins connections
1 = Ground
2 = Vcc
3 = Contrast Voltage
4 = "R/S" _Instruction/Register Select
5 = "R/W" _Read/Write LCD Registers (Connected to GND for this driver to work!)
6 = "E" Clock
7 - 14 = Data I/O Pins 0 to 7 (0=7, 1=8,... 7=14 )
15 - GND for the BACKLIGHTING (Check to be sure because some units have it for VCC)
16 - VCC for the BACKLIGHTING (Check to be sure because some units have it for GND)
 
CONNECTION TABLE AS USED IN THIS lcd_io.h FILE
|^^^^^^^^^^^^^^^^^^^^^^^^^^|
| port_pin0->lcd_D4_pin11 |
| port_pin1->lcd_D5_pin12 |
| port_pin2->lcd_D6_pin13 |
| port_pin3->lcd_D7_pin14 |
| port_pin4->lcd_RS_pin4 |
| port_pin5->lcd_E_pin6 |
| lcd_E_pin5->GND |
^^^^^^^^^^^^^^^^^^^^^^^^^^^
*******************************************************************************************************/
#ifndef LCD_IO_H
#define LCD_IO_H
 
/*############################################################################################*/
/* CONFIGURATION BLOCK STARTS HERE. Change these definitions to adapt setting */
/*############################################################################################*/
/* GLOBAL SETTINGS (settings described here are aplyied everywhere) */
 
#ifndef F_CPU
#define F_CPU 3686400L /* CPU CLOCK FREQUENCY */
#endif
 
#define LCD_IO_MODE 6 /* 6 = 6 PIN I/O, 2 = 2 PIN I/O, 7 = multi lcd mode */
 
#define LCD_AUTO_LINE_FEED 0 /* 1 = Auto line feed, 0 = no Auto line feed */
 
#define LCD_DELAY_TIME 100 /* Read the INTRO about this */
/***********************************************************************************************/
#if LCD_IO_MODE == 2
/*
CONFIGURATION OF BELOW LINES ONLY NECESSARY IN 2 PIN MODE
If you plan to use just one port for all pins then just edit "LCD_PORT"
otherwise you must specify the port of each lcd signal. the port(s) must be able
to function as output. It can be any combination!
USE CAPITAL LETTER FOR PORT DESIGNATION! (A,B,C,D...etc.)
*/
#define LCD_CHARS_PER_LINE 20 /* visible chars per lcd line */
#define LCD_LINES 4 /* visible lines */
 
#define LCD_PORT B
 
#define LCD_CLOCK_SIGNAL_PORT LCD_PORT /* Put your lcd clock port here (A,B,C...etc.) */
#define LCD_CLOCK_PIN 0 /* Put your lcd clock pin here */
 
#define LCD_DATA_SIGNAL_PORT LCD_PORT /* Put your lcd data port here (A,B,C...etc.) */
#define LCD_DATA_PIN 1 /* Put your lcd data pin here */
 
#endif
/***********************************************************************************************/
/* END OF 2 PIN CONFIGURATION BLOCK */
/***********************************************************************************************/
#if LCD_IO_MODE == 6
/*
CONFIGURATION OF BELOW LINES ONLY NECESSARY IN MODE 6
If you plan to use just one port for all pins then just edit "LCD_PORT"
otherwise you must specify the port of each lcd signal. the port(s) must be able
to function as output. It can be any combination!
PUT YOUR LCD PORT LETTER HERE USING CAPITAL LETTER (A,B,C,D...etc)
*/
#define LCD_CHARS_PER_LINE 20 /* visible chars per lcd line */
#define LCD_LINES 4 /* visible lines */
 
#define LCD_MULTIPLEX_ENABLE 0 /* 1= the DDR's used are saved and restored */
#define LCD_READ_REQUIRED 0 /* 0=use delay, 1=read busy flag (7 pins needed) */
 
 
 
#define LCD_PORT B
 
#define LCD_DATA4_PORT LCD_PORT /* port for data 0 pin */
#define LCD_D4_PIN 0 /* AVR port pin number */
 
#define LCD_DATA5_PORT LCD_PORT /* port for data 1 pin */
#define LCD_D5_PIN 1 /* AVR port pin number */
 
#define LCD_DATA6_PORT LCD_PORT /* port for data 2 pin */
#define LCD_D6_PIN 2 /* AVR port pin number */
 
#define LCD_DATA7_PORT LCD_PORT /* port for data 3 pin */
#define LCD_D7_PIN 3 /* AVR port pin number */
 
#define LCD_RS_SIGNAL_PORT LCD_PORT /* port for RS line */
#define LCD_RS_PIN 4 /* AVR port pin number */
 
#define LCD_E_SIGNAL_PORT LCD_PORT /* port for Enable line */
#define LCD_E_PIN 5 /* AVR port pin number */
 
 
 
/* YOU NEED TO EDIT "LCD_RW_SIGNAL_PORT" AND "LCD_RW_PIN" ONLY IF "LCD_READ_REQUIRED == 1" */
#if LCD_READ_REQUIRED == 1
#define LCD_RW_SIGNAL_PORT LCD_PORT /* port for R/W line */
#define LCD_RW_PIN 6 /* AVR port pin number */
#endif
 
#endif
/***********************************************************************************************/
/* END OF 6 PIN CONFIGURATION BLOCK */
/***********************************************************************************************/
#if LCD_IO_MODE == 7
/*
CONFIGURATION OF BELOW LINES ONLY NECESSARY IN MODE 7
If you plan to use just one port for all pins then just edit "LCD_PORT"
otherwise you must specify the port of each lcd signal. the port(s) must be able
to function as output. It can be any combination!
PUT YOUR LCD PORT LETTER HERE USING CAPITAL LETTER (A,B,C,D...etc)
*/
#define NUMBER_OF_LCD_UNITS 2 /* 2 or 3. if you set it to 1, mode 6 will be selected */
 
#define LCD_0_CHARS_PER_LINE 20 /* visible chars per lcd line */
#define LCD_0_LINES 4 /* visible lines */
 
#define LCD_1_CHARS_PER_LINE 20 /* visible chars per lcd line */
#define LCD_1_LINES 4 /* visible lines */
 
#if NUMBER_OF_LCD_UNITS >=3
#define LCD_2_CHARS_PER_LINE 20 /* visible chars per lcd line */
#define LCD_2_LINES 4 /* visible lines */
#endif
 
 
 
#define LCD_PORT B
 
#define LCD_DATA4_PORT LCD_PORT /* port for data 0 pin */
#define LCD_D4_PIN 0 /* AVR port pin number */
 
#define LCD_DATA5_PORT LCD_PORT /* port for data 1 pin */
#define LCD_D5_PIN 1 /* AVR port pin number */
 
#define LCD_DATA6_PORT LCD_PORT /* port for data 2 pin */
#define LCD_D6_PIN 2 /* AVR port pin number */
 
#define LCD_DATA7_PORT LCD_PORT /* port for data 3 pin */
#define LCD_D7_PIN 3 /* AVR port pin number */
 
#define LCD_RS_SIGNAL_PORT LCD_PORT /* port for RS line */
#define LCD_RS_PIN 4 /* AVR port pin number */
 
#define LCD_0_E_SIGNAL_PORT LCD_PORT /* port for Enable line */
#define LCD_0_E_PIN 5 /* AVR port pin number */
 
#define LCD_1_E_SIGNAL_PORT LCD_PORT /* port for Enable line */
#define LCD_1_E_PIN 6 /* AVR port pin number */
 
/* EDIT THE BELOW LINES IF YOU USE 3 LCD UNITS */
#if NUMBER_OF_LCD_UNITS >=3
#define LCD_2_E_SIGNAL_PORT LCD_PORT /* port for Enable line */
#define LCD_2_E_PIN 7 /* AVR port pin number */
#endif
 
#endif /* LCD_IO_MODE == 7 */
 
/*############################################################################################*/
/* CONFIGURATION BLOCK ENDS HERE. */
/*############################################################################################*/
 
/* you shouldn't need to change anything below this line */
 
/* Some clever thinking triks */
#if LCD_IO_MODE == 7 && NUMBER_OF_LCD_UNITS == 1
 
#undef LCD_IO_MODE
#define LCD_IO_MODE 6
#define LCD_READ_REQUIRED 0
#define LCD_E_SIGNAL_PORT LCD_0_E_SIGNAL_PORT
#define LCD_E_PIN LCD_0_E_PIN
#define LCD_CHARS_PER_LINE LCD_0_CHARS_PER_LINE
#define LCD_LINES LCD_0_LINES
#undef LCD_MULTIPLEX_ENABLE
#define LCD_MULTIPLEX_ENABLE 0
#undef LCD_READ_REQUIRED
#define LCD_READ_REQUIRED 0
#undef LCD_1_CHARS_PER_LINE
#undef LCD_1_LINES
#undef LCD_1_E_SIGNAL_PORT
#undef LCD_1_E_PIN
 
#elif LCD_IO_MODE == 7 && NUMBER_OF_LCD_UNITS > 1
 
#define LCD_0 0
#define LCD_1 1
#define LCD_2 2
 
#endif /* #if LCD_IO_MODE == 7 && NUMBER_OF_LCD_UNITS == 1 */
 
/*-----------------------------------------------------------------------------------*/
/* HD44780 PARAMETERS */
/*-----------------------------------------------------------------------------------*/
 
#define LCD_LINE_LENGTH 0x40 /* internal line length */
#define LCD_START_LINE1 0x00 /* DDRAM address of first char of line 1 */
#define LCD_START_LINE2 0x40 /* DDRAM address of first char of line 2 */
#define LCD_START_LINE3 0x14 /* DDRAM address of first char of line 3 */
#define LCD_START_LINE4 0x54 /* DDRAM address of first char of line 4 */
 
/* instruction register bit positions */
#define LCD_CLR 0 /* DB0: clear display */
#define LCD_HOME 1 /* DB1: return to home position */
#define LCD_ENTRY_MODE 2 /* DB2: set entry mode */
#define LCD_ENTRY_INC 1 /* DB1: 1=increment, 0=decrement */
#define LCD_ENTRY_SHIFT 0 /* DB2: 1=display shift on */
#define LCD_ON 3 /* DB3: turn lcd/cursor on */
#define LCD_ON_DISPLAY 2 /* DB2: turn display on */
#define LCD_ON_CURSOR 1 /* DB1: turn cursor on */
#define LCD_ON_BLINK 0 /* DB0: blinking cursor ? */
#define LCD_MOVE 4 /* DB4: move cursor/display */
#define LCD_MOVE_DISP 3 /* DB3: move display (0-> cursor) ? */
#define LCD_MOVE_RIGHT 2 /* DB2: move right (0-> left) ? */
#define LCD_FUNCTION 5 /* DB5: function set */
#define LCD_FUNCTION_8BIT 4 /* DB4: set 8BIT mode (0->4BIT mode) */
#define LCD_FUNCTION_2LINES 3 /* DB3: two lines (0->one line) */
#define LCD_FUNCTION_10DOTS 2 /* DB2: 5x10 font (0->5x7 font) */
#define LCD_CGRAM 6 /* DB6: set CG RAM address */
#define LCD_DDRAM 7 /* DB7: set DD RAM address */
#define LCD_BUSY 7 /* DB7: LCD is busy */
 
/* set entry mode: display shift on/off, dec/inc cursor move direction */
#define LCD_ENTRY_DEC 0x04 /* display shift off, dec cursor move dir */
#define LCD_ENTRY_DEC_SHIFT 0x05 /* display shift on, dec cursor move dir */
#define LCD_ENTRY_INC_ 0x06 /* display shift off, inc cursor move dir */
#define LCD_ENTRY_INC_SHIFT 0x07 /* display shift on, inc cursor move dir */
 
/* display on/off, cursor on/off, blinking char at cursor position */
#define LCD_DISP_OFF 0x08 /* display off */
#define LCD_DISP_ON 0x0C /* display on, cursor off */
#define LCD_DISP_ON_BLINK 0x0D /* display on, cursor off, blink char */
#define LCD_DISP_ON_CURSOR 0x0E /* display on, cursor on */
#define LCD_DISP_ON_CURSOR_BLINK 0x0F /* display on, cursor on, blink char */
 
/* move cursor/shift display */
#define LCD_MOVE_CURSOR_LEFT 0x10 /* move cursor left (decrement) */
#define LCD_MOVE_CURSOR_RIGHT 0x14 /* move cursor right (increment) */
#define LCD_MOVE_DISP_LEFT 0x18 /* shift display left */
#define LCD_MOVE_DISP_RIGHT 0x1C /* shift display right */
 
/* function set: set interface data length and number of display lines */
#define LCD_FUNCTION_4BIT_1LINE 0x20 /* 4-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_4BIT_2LINES 0x28 /* 4-bit interface, dual line, 5x7 dots */
#define LCD_FUNCTION_8BIT_1LINE 0x30 /* 8-bit interface, single line, 5x7 dots */
#define LCD_FUNCTION_8BIT_2LINES 0x38 /* 8-bit interface, dual line, 5x7 dots */
 
 
#define LCD_MODE_DEFAULT ((1<<LCD_ENTRY_MODE) | (1<<LCD_ENTRY_INC) )
 
 
 
/*-----------------------------------------------------------------------------------*/
/* function prototypes */
/*-----------------------------------------------------------------------------------*/
 
extern void lcd_init(void);
extern void lcd_command(unsigned char cmd);
extern void lcd_gotoxy(unsigned char lcd_x, unsigned char lcd_y);
extern void lcd_clrscr(void);
extern void lcd_clrline(unsigned char line);
extern void lcd_home(void);
extern void lcd_putc(unsigned char c);
extern void lcd_puts(const unsigned char *s);
extern void lcd_puts_p(const unsigned char *progmem_s);
extern void lcd_puts_e(unsigned char *eeprom_s);
extern void lcd_puti(int value, unsigned char dot_position);
extern unsigned int lcd_getxy(void);
 
 
/*
1) Suppose we want to display a 16 bit var with a rvalue 0f 325
2) We give the command lcd_puti(var_name, 0); were var=325
The display will show 325
3) alternatives:
a) We give the command lcd_puti(var_name,1);
The display will show 32,5
b) We give the command lcd_puti(var_name,2);
The display will show 3,25
c) We give the command lcd_puti(var_name,3);
The display will show 0,325
d) We give the command lcd_puti(var_name,4);
The display will show 0,0325
e) We give the command lcd_puti(var_name,1); var=-325
The display will show -32,5
f) We give the command lcd_puti(var_name,3); var=-325
The display will show -0,325
 
*/
/*
** macros for automatically storing string constant in program memory
*/
#ifndef P
#define P(s) ({static const char c[] __attribute__ ((progmem)) = s;c;})
#endif
#define lcd_puts_P(__s) lcd_puts_p(P(__s))
 
#endif //LCD_IO_H
/*######################################################################################################*/
/* T H E E N D */
/*######################################################################################################*/
 
 
/programy/avr/SFR08/makefile
0,0 → 1,43
# Simple Makefile
# Volker Oth (c) 1999
 
 
########### change this lines according to your project ##################
 
#put the name of the target mcu here (at90s8515, at90s8535, attiny22, atmega603 etc.)
MCU = atmega103
 
#put the name of the target file here (without extension)
TRG = test_srf08
 
#put your C sourcefiles here
SRC = $(TRG).c lcd_io.c i2c.c srf08.c
 
#put additional assembler source file here
ASRC =
 
#additional libraries and object files to link
LIB =
 
#additional includes to compile
INC =
 
#compiler flags
CPFLAGS = -g -Os -Wall -Wstrict-prototypes -Wa,-ahlms=$(<:.c=.lst)
 
#linker flags
LDFLAGS = -Wl,-Map=$(TRG).map,--cref
 
########### you should not need to change the following line #############
#include $(AVR)/include/avr_make
 
###### dependecies, add any dependencies you need here ###################
$(TRG).o : $(TRG).c lcd_io.h srf08.h
srf08.o : srf08.c srf08.h i2c.h
lcd_io.o : lcd_io.c lcd_io.h
i2c.o : i2c.C i2c.h
 
 
 
 
 
/programy/avr/SFR08/srf08.c
0,0 → 1,169
 
/****************************************************************************
Title : C file for the SRF08 FUNCTIONS library (srf08.c)
Author: Chris efstathiou hendrix@otenet.gr
Date: 13/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
 
*****************************************************************************/
 
#include <io.h>
#include <eeprom.h>
#include "i2c.h"
#include "srf08.h"
 
/* Global Variables */
static unsigned char address=SRF08_UNIT_0;
 
/*#################################################################################################*/
 
void srf08_init(void)
{
unsigned int range=0;
i2c_init();
I2C_START_TX(address);
i2c_transmit(0);
i2c_transmit(0x51);
do{
i2c_start();
range=i2c_transmit(address);
i2c_stop();
}while(range != I2C_NO_ERROR);
 
return;
}
/*#################################################################################################*/
 
void srf08_set_gain(unsigned char gain)
{
if(gain>31) { gain=31; }
I2C_START_TX(address);
i2c_transmit(1);
i2c_transmit(gain);
i2c_stop();
 
return;
}
/*#################################################################################################*/
 
void srf08_set_range(unsigned int millimeters)
{
millimeters= (millimeters/43);
if(millimeters > 0xff ) { millimeters=0xff; }
I2C_START_TX(address);
i2c_transmit(2);
i2c_transmit(millimeters);
i2c_stop();
 
return;
}
/*#################################################################################################*/
 
unsigned int srf08_ping(unsigned char metric_unit)
{
union i2c_union {
unsigned int rx_word;
unsigned char rx_byte[2];
} i2c;
 
I2C_START_TX(address);
i2c_transmit(0);
i2c_transmit(metric_unit);
do{
i2c_start();
i2c.rx_byte[0]=i2c_transmit(address);
i2c_stop();
}while(i2c.rx_byte[0] != I2C_NO_ERROR);
 
I2C_START_TX(address);
i2c_transmit(SRF08_ECHO_1);
I2C_START_RX(address);
i2c.rx_byte[1]=i2c_receive(I2C_CONTINUE); /* get high byte msb first */
i2c.rx_byte[0]=i2c_receive(I2C_QUIT); /* get low byte msb first */
i2c_stop();
 
return(i2c.rx_word);
}
/*#################################################################################################*/
 
unsigned int srf08_read_register(unsigned char srf08_register)
{
union i2c_union {
unsigned int rx_word;
unsigned char rx_byte[2];
} i2c;
 
 
I2C_START_TX(address);
i2c_transmit(srf08_register);
I2C_START_RX(address);
/* get high byte msb first */
if(srf08_register>=2) { i2c.rx_byte[1]=i2c_receive(I2C_CONTINUE); }
/* get low byte msb first */
i2c.rx_byte[0]=i2c_receive(I2C_QUIT);
 
i2c_stop();
 
return(i2c.rx_word);
}
/*#################################################################################################*/
 
void srf08_change_i2c_address(unsigned char new_i2c_address)
{
 
 
/* Start the I2C address changing procedure */
I2C_START_TX(address);
i2c_transmit(SRF08_COMMAND);
i2c_transmit(0XA0);
i2c_stop();
I2C_START_TX(address);
i2c_transmit(SRF08_COMMAND);
i2c_transmit(0XAA);
i2c_stop();
 
I2C_START_TX(address);
i2c_transmit(SRF08_COMMAND);
i2c_transmit(0XA5);
i2c_stop();
 
I2C_START_TX(address);
i2c_transmit(SRF08_COMMAND);
i2c_transmit(new_i2c_address);
i2c_stop();
 
/* Make the new i2c address the active one. */
address=new_i2c_address;
 
return;
}
/*#################################################################################################*/
 
void srf08_select_unit(unsigned char srf08_address)
{
/* New address validity check */
 
if( (srf08_address<0xE0 || srf08_address>0XFE) && srf08_address != 0 ) { return; }
if(srf08_address%2) { return; }
 
/* Make the new i2c address the active one. */
address=srf08_address;
 
return;
}
 
 
/*######################################################################################################*/
/* T H E E N D */
/*######################################################################################################*/
 
/programy/avr/SFR08/srf08.h
0,0 → 1,91
 
/****************************************************************************
Title : C include file for the SRF08 FUNCTIONS library (srf08.h)
Author: Chris efstathiou hendrix@otenet.gr
Date: 13/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
 
*****************************************************************************/
 
#ifndef SRF08_H
#define SRF08_H 1
 
/*##############################################################################################*/
/* START OF CONFIGURATION BLOCK */
/*##############################################################################################*/
/* Normally you shouldn't need to change anything */
 
#define SRF08_UNIT_0 0xE0 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_1 0xE2 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_2 0xE4 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_3 0xE6 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_4 0xE8 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_5 0xEA /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_6 0xEC /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_7 0xEE /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_8 0xF0 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_9 0xF2 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_10 0xF4 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_11 0xF6 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_12 0xF8 /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_13 0xFA /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_14 0xFC /* the SRF08 MODULE I2C address */
#define SRF08_UNIT_15 0xFE /* the SRF08 MODULE I2C address */
 
/*##############################################################################################*/
/* END OF CONFIGURATION BLOCK */
/*##############################################################################################*/
 
#define SRF08_I2C_BROADCAST_ADDRESS 0X00
 
#define SRF08_MIN_GAIN 0 /* sets gain to 94 */
#define SRF08_MAX_GAIN 31 /* sets gain to 1025 */
#define SRF08_MIN_RANGE 0 /* in millimeters */
#define SRF08_MAX_RANGE 11008 /* in millimeters */
 
#define SRF08_INCHES 0X50
#define SRF08_CENTIMETERS 0X51
#define SRF08_MICROSECONDS 0X52
 
/* register positions */
#define SRF08_COMMAND 0
#define SRF08_LIGHT 1
#define SRF08_ECHO_1 2
#define SRF08_ECHO_2 4
#define SRF08_ECHO_3 6
#define SRF08_ECHO_4 8
#define SRF08_ECHO_5 10
#define SRF08_ECHO_6 12
#define SRF08_ECHO_7 14
#define SRF08_ECHO_8 16
#define SRF08_ECHO_9 18
#define SRF08_ECHO_10 20
#define SRF08_ECHO_11 22
#define SRF08_ECHO_12 24
#define SRF08_ECHO_13 26
#define SRF08_ECHO_14 28
#define SRF08_ECHO_15 30
#define SRF08_ECHO_16 32
#define SRF08_ECHO_17 34
 
/* Function Declaration */
 
extern void srf08_select_unit(unsigned char srf08_address);
extern void srf08_init(void);
 
extern void srf08_set_gain(unsigned char gain);
extern void srf08_set_range(unsigned int millimeters);
 
extern unsigned int srf08_ping(unsigned char metric_unit);
extern unsigned int srf08_read_register(unsigned char srf08_register);
 
extern void srf08_change_i2c_address(unsigned char new_i2c_address);
 
 
#endif /* #ifndef SRF08_H */
/*######################################################################################################*/
/* T H E E N D */
/*######################################################################################################*/
 
/programy/avr/SFR08/test_lcd.c
0,0 → 1,59
/****************************************************************************
Title : C Test program for the LCD FUNCTIONS library (test_lcd.c)
Author: Chris efstathiou hendrix@otenet.gr
Date: 1/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
 
*****************************************************************************/
#define F_CPU 3686400L
 
#include <io.h>
#include "lcd_io.h"
 
 
void main(void)
{
/* Since we also test the eeprom DONT! forget to write the test_lcd.eep to AVR's eeprom
otherwise the lcd will not show the eeprom_string */
static unsigned char eeprom_string[]__attribute__((section(".eeprom")))={"lcd_puts_e testing"};
unsigned char ram_string[]={"DONE TESTING..."};
unsigned int pos=0;
 
lcd_init(); /* lcd(s) is(are) initialized and if more than 1, lcd unit 0 gets active */
 
lcd_clrscr();
lcd_gotoxy(0,0); lcd_puts_P("NOT VISIBLE LINE");
lcd_clrline(0); lcd_puts_P( "Hello World\nthis is line 2" );
 
#if LCD_AUTO_LINE_FEED == 1
lcd_gotoxy(0,2); lcd_puts_e(eeprom_string); lcd_puts(ram_string);
#elif LCD_AUTO_LINE_FEED == 0
/*---------------------------------------------------------------------------------------------------*/
/*
I puted this command here to test the correct saving of the lcd x,y coordinates
between lcd unit switching, if you select mode 7
*/
lcd_gotoxy(0,2);
/*---------------------------------------------------------------------------------------------------*/
#if LCD_IO_MODE == 7
select_lcd(LCD_1);
lcd_clrscr();
lcd_clrline(0); lcd_puts_P( "This is display #2" );
select_lcd(LCD_0);
#endif
/*---------------------------------------------------------------------------------------------------*/
lcd_puts_e(eeprom_string);
lcd_gotoxy(0,3); lcd_puts(ram_string);
#endif /* #elif LCD_AUTO_LINE_FEED == 0 */
 
lcd_gotoxy(16,3); lcd_puti(pos,2); pos=lcd_getxy();
lcd_gotoxy(16,3); lcd_puti(pos,2);
}
/*######################################################################################################*/
/* T H E E N D */
/*######################################################################################################*/
 
/programy/avr/SFR08/test_srf08.c
0,0 → 1,90
 
/****************************************************************************
Title : C test file for the SRF08 FUNCTIONS library (test_srf08.c)
Author: Chris efstathiou hendrix@otenet.gr
Date: 13/Jul/2002
Software: AVR-GCC with AVR-AS
Target: any AVR device
Comments: This software is FREE.
 
*****************************************************************************/
 
#define F_CPU 3686400L
 
#include <io.h>
#include "lcd_io.h"
#include "srf08.h"
 
#define AVG_FLT_SAMPLES 3
 
/*#################################################################################################*/
void delay(unsigned long us)
{
 
while ( us ) { us--; } /* 6 cpu cycles per loop */
}
/*#################################################################################################*/
 
void main(void)
{
unsigned int range=0;
unsigned char counter1=0, gain=0;
 
/* Delay is there to ensure that SRF08 is out of reset and operational */
/*
delay(1000000);
srf08_change_i2c_address(SRF08_UNIT_1);
delay(100000);
*/
 
/*
By default SRF_UNIT_0 is selected so the below command shows that the change of i2c address
by the above "srf08_change_i2c_address(SRF08_UNIT_1);" command was succesfull.
All commands after this, refer to that unit only!
*/
srf08_select_unit(SRF08_UNIT_1);
 
srf08_init(); /* Only the selected SRF08 unit will be initialized! */
gain=SRF08_MAX_GAIN;
srf08_set_gain(gain);
srf08_set_range(SRF08_MAX_RANGE); /* Set range to 11008 mm */
 
lcd_init();
lcd_clrscr();
lcd_gotoxy(0,0); lcd_puts_P("RANGE (E1) = ");
lcd_gotoxy(0,1); lcd_puts_P("RANGE (E2) = ");
lcd_gotoxy(0,2); lcd_puts_P("RANGE (E5) = ");
lcd_gotoxy(0,3); lcd_puts_P("LIGHT sensor= ");
 
while(1)
{
/* AVERAGING FILTER */
for(counter1=0,range=0; counter1<AVG_FLT_SAMPLES; counter1++)
{
range+=srf08_ping(SRF08_CENTIMETERS);
}
range /= AVG_FLT_SAMPLES;
 
/* AUTOMATIC GAIN CONTROL */
if(srf08_read_register(SRF08_ECHO_5)!=0 )
{
if(gain>=5) { srf08_set_gain(gain-=5); } else { srf08_set_gain(gain=0); }
}
else if(srf08_read_register(SRF08_ECHO_2)<=0 && gain!=31) { srf08_set_gain(++gain); }
 
/* DISPLAY TO LCD */
lcd_gotoxy(14,0); lcd_puti(range,2);
lcd_gotoxy(14,1); lcd_puti(srf08_read_register(SRF08_ECHO_2), 2);
lcd_gotoxy(14,2); lcd_puti(srf08_read_register(SRF08_ECHO_5), 2);
lcd_gotoxy(14,3); lcd_puti(srf08_read_register(SRF08_LIGHT), 2);
 
 
}
 
return;
}
/*#################################################################################################*/