/programy/C/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/C/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. </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> 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) </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. 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. </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%"> </TD> |
<TD align=middle width="18%"> </TD> |
<TD align=left width="94%"> </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%"> </TD> |
<TD align=middle width="18%"> </TD> |
<TD align=left width="94%"> </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. </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. </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 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. <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. 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. </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). <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 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> You can have a 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/C/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/C/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/C/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/C/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/C/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/C/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/C/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/C/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/C/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/C/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; |
} |
/*#################################################################################################*/ |