{"id":1099,"date":"2015-04-06T18:00:55","date_gmt":"2015-04-06T22:00:55","guid":{"rendered":"https:\/\/ve2cuy.wordpress.com\/?page_id=1099"},"modified":"2015-04-06T18:00:55","modified_gmt":"2015-04-06T22:00:55","slug":"18f4620-2-x-i2c-lcd-with-pcf8574","status":"publish","type":"page","link":"https:\/\/ve2cuy.com\/blog\/index.php\/18f4620-2-x-i2c-lcd-with-pcf8574\/","title":{"rendered":"18F4620 &#8211; 2 x I2C LCD with PCF8574"},"content":{"rendered":"<h1>To\u00a0my English language readers<\/h1>\n<p>The following article is in French.<\/p>\n<p>Here is a\u00a0summary:<\/p>\n<p>How to\u00a0display on a I2C LCD using a PCF8574 and a PIC 18F4620.<\/p>\n<p>The Proteus project is available <a href=\"https:\/\/drive.google.com\/uc?export=download&amp;id=0BwVyrqVfxGkRWFZ4aW9ZQUwyTTA\">here<\/a>.<\/p>\n<p><strong>Note<\/strong>: source code is commented in English.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1104\" src=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/18f4620-i2c-lcd2.gif\" alt=\"18F4620 I2C LCD\" width=\"660\" height=\"526\" \/><\/p>\n<hr \/>\n<h1>Mise en situation<\/h1>\n<p>Contrairement \u00e0 nos amis Arduiniens, quand vient le moment d\u2019interconnecter des p\u00e9riph\u00e9riques \u00e0 une puce PIC, c\u2019est souvent la recherche sans fin dans Internet.<\/p>\n<p>Pour Pic, moins de librairies sp\u00e9cialis\u00e9es comme : LiquidCrystal , Wire, Ethernet,\u00a0Firmata,\u00a0Servo,\u00a0WiFi,\u00a0TFT, EEPROM.<\/p>\n<p>Arduino supportant un nombre limit\u00e9 de puces, cela rend la normalisation des librairies plus simple.<\/p>\n<p>De plus, un grand nombre de contributeurs aident \u00e0 enrichir les outils de d\u00e9veloppement.<\/p>\n<h1>De retour chez PIC<\/h1>\n<p>Parfois, interfacer une puce PIC \u00e0 un p\u00e9riph\u00e9rique est assez facile, <a href=\"https:\/\/www.google.ca\/webhp?sourceid=chrome-instant&amp;ion=1&amp;espv=2&amp;ie=UTF-8#q=lcd+interfacing+with+pic+xc8\">LCD sous PIC<\/a>, d\u2019autres fois, pas vraiment.<\/p>\n<p>Tentez de trouver une solution pour connecter un \u00e9cran LCD en utilisant le protocole I2C via une puce PCF8574.<\/p>\n<p>Le genre de circuit\u00a0mille fois disponible sur <a href=\"http:\/\/www.ebay.com\/sch\/i.html?_from=R40&amp;_trksid=p2050601.m570.l1313.TR4.TRC1.A0.H0.Xlcd+i2c.TRS0&amp;_nkw=lcd+i2c&amp;_sacat=0\">eBay<\/a>.<\/p>\n<p><a href=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1177\" src=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board.png\" alt=\"i2c lcd board\" width=\"630\" height=\"228\" srcset=\"https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board.png 735w, https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board-300x109.png 300w\" sizes=\"auto, (max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>Vrai, il existe des solutions \u00e0 gauche ou droite, mais quelle mis\u00e8re\u2026<\/p>\n<p>Pour en arriver \u00e0 une solution fonctionnelle, il faut ramer!<\/p>\n<p><strong>Sc\u00e9nario 1<\/strong><\/p>\n<p>Le module PCF8574 n&rsquo;est pas document\u00e9:<\/p>\n<blockquote><p>ou est RS, CS, E?<\/p>\n<p>et pour le data?<\/p><\/blockquote>\n<p>Dans mon cas, j&rsquo;ai du passer \u00e0 l&rsquo;ohmm\u00e8tre les broches RS, RW,E et D4 \u00e0 D7 de mon afficheur I2C LCD made in China,<\/p>\n<p>R\u00e9sultat:<\/p>\n<blockquote><p>Data PCA8574: P7,P6,P5,P4<br \/>\nControl: P3: Back Light, P2: E-Enable, P1:RW, P0: RS<\/p><\/blockquote>\n<p><strong>Sc\u00e9nario 2<\/strong><\/p>\n<p>Vous avez trouvez un bout de code mais mis\u00e8re, pas le bon compilateur, la bonne famille ou le bon langage&#8230;<\/p>\n<p><strong>Sc\u00e9nario 3<\/strong><\/p>\n<p>Vous avez la documentation en main et tout va bien, chanceux!<\/p>\n<p><strong>Sc\u00e9nario 4<\/strong><\/p>\n<p>On vous fournit une solution &#8211; Proteus &#8211; \u00a0cl\u00e9 en main, possible? \u00a0Voir le lien de t\u00e9l\u00e9chargement au bas de l&rsquo;article.<\/p>\n<h1><\/h1>\n<h1>Fonctionnement de la plaquette I2C vers LCD<\/h1>\n<p>Les plaquettes de conversion des \u00e9crans LCD de I2C vers BUS LCD 4 bits utilisent, g\u00e9n\u00e9ralement, la puce PCF8574 ou la PCF8574A.<\/p>\n<p>Ce circuit a pour fonction de d\u00e9s\u00e9rialiser les donn\u00e9es du BUS I2C vers un octet donc, de pr\u00e9senter l&rsquo;information en parall\u00e8le sur 8 bits.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1178\" src=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574.png\" alt=\"PCF8574\" width=\"630\" height=\"357\" srcset=\"https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574.png 656w, https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574-300x170.png 300w\" sizes=\"auto, (max-width: 630px) 100vw, 630px\" \/><\/p>\n<p>Les \u00e9crans LCD HD44780 1602 pouvant \u00eatre op\u00e9r\u00e9s en mode 4 bits, il sera alors possible d\u2019utiliser une partie de l\u2019octet (nibble du bas) pour les signaux de contr\u00f4le : RS, RW, E, retro \u00e9clairage et l\u2019autre partie (nibble du haut) pour les donn\u00e9es.<\/p>\n<p>La difficult\u00e9 sera de combiner correctement les signaux de contr\u00f4le et les donn\u00e9es dans un m\u00eame octet.<\/p>\n<p>L&rsquo;extraction des nibbles d&rsquo;un octet de donn\u00e9es est habituellement obtenu ainsi:<\/p>\n<blockquote><p>#define HI_NIBBLE(b) (((b) &gt;&gt; 4) &amp; 0x0F)<br \/>\n#define LO_NIBBLE(b) ((b) &amp; 0x0F)<\/p><\/blockquote>\n<p>\u00c9tant donn\u00e9 que les signaux de contr\u00f4le du LCD sont connect\u00e9s sur les broches P0 \u00e0 P3 du PCF8574 et les donn\u00e9es sur P4 \u00e0 P7, nous utiliseront plut\u00f4t l&rsquo;approche suivante:<\/p>\n<blockquote><p>#define LO_NIBBLE(b) (((b) &lt;&lt; 4) &amp; 0xF0)<br \/>\n#define HI_NIBBLE(b) ((b) &amp; 0xF0)<\/p><\/blockquote>\n<p>Pour l&rsquo;ajout des signaux de contr\u00f4le \u00e0 un des deux nibbles nous utiliseront des op\u00e9rations bit \u00e0 bit (Bitwise operation).<\/p>\n<p>Par example,<\/p>\n<blockquote><p>lcddata = HI_NIBBLE(data) | LCD_BL | LCD_RS;<\/p><\/blockquote>\n<h1><\/h1>\n<h1>Adresse I2C de PCF8574<\/h1>\n<p>L\u2019adresse I2C de PCF8574 est situ\u00e9e dans la plage 20H \u00e0 27H et de 38H \u00e0 3Fh pour PCF8574A.<\/p>\n<p>En utilisant ces deux puces dans un m\u00eame circuit, il serait possible de connecter 16 \u00e9crans LCD.<\/p>\n<p>Voici les tableaux d&rsquo;adressage:<\/p>\n<p><a href=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574-address-map.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1179\" src=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574-address-map.png\" alt=\"PCF8574 address map\" width=\"630\" height=\"270\" srcset=\"https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574-address-map.png 791w, https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574-address-map-300x129.png 300w, https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574-address-map-768x329.png 768w\" sizes=\"auto, (max-width: 630px) 100vw, 630px\" \/><\/a> <a href=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574a-address-map.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1180\" src=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574a-address-map.png\" alt=\"PCF8574A address map\" width=\"630\" height=\"270\" srcset=\"https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574a-address-map.png 791w, https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574a-address-map-300x129.png 300w, https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/pcf8574a-address-map-768x329.png 768w\" sizes=\"auto, (max-width: 630px) 100vw, 630px\" \/><\/a><\/p>\n<p>Dans la cas des plaquettes que j\u2019utilise, les broches d\u2019adressage de PCF8674 (A0..A2) sont connect\u00e9es \u00e0 VCC via une r\u00e9sistance de tirage (pull-up resistor). \u00a0L\u2019adresse maximale de 27H est donc obtenue par d\u00e9faut.<\/p>\n<p>Il suffit de souder un cavalier sur les bornes A0..A2 pour ramener les broches \u00e0 0 et faire ainsi varier l\u2019adresse I2C du circuit.<\/p>\n<p><a href=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board-address.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-1188\" src=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board-address.png?w=300\" alt=\"i2c lcd board address\" width=\"300\" height=\"109\" srcset=\"https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board-address.png 735w, https:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/i2c-lcd-board-address-300x109.png 300w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<h1><\/h1>\n<h1>\u00c0 bien y regarder, pas si simple<\/h1>\n<p>M\u00eame si vous avez bien saisie l&rsquo;arithm\u00e9tique des nibbles et les op\u00e9rations bit \u00e0 bit, ce n&rsquo;est encore pas suffisant pour afficher sur l&rsquo;\u00e9cran LCD. Pour ce faire, il faudra aussi comprendre la m\u00e9canique de programmation et la synchronisation des signaux de la puce contr\u00f4lant l&rsquo;affichage: HD44780.<br \/>\nDans le code source du projet, il y a la s\u00e9quence suivante :<\/p>\n<blockquote><p>void LCD_init(unsigned char addr)<br \/>\n{<br \/>\n__delay_ms(20); \/\/ Wait &gt; 15 ms after power ON<\/p>\n<p>LCD_putcmd(addr, LCD_INIT_BYTE,0);__delay_ms(5); \/\/ Wait &gt; 4.1 ms<br \/>\nLCD_putcmd(addr, LCD_INIT_BYTE,0);<br \/>\nLCD_putcmd(addr, LCD_INIT_BYTE,0);<br \/>\nLCD_putcmd(addr, LCD_BUS_WIDTH_4Bit,0);<br \/>\nLCD_putcmd(addr, LCD_4BITS_2LINES_5x8FONT,1);<br \/>\nLCD_putcmd(addr, LCD_DISPLAY_OFF_CURSOR_OFF_BLINK_OFF,1);<br \/>\nLCD_putcmd(addr, LCD_CLEAR,1);<br \/>\nLCD_putcmd(addr, LCD_INCREMENT_NO_SHIFT,1);<br \/>\nLCD_putcmd(addr, LCD_DISPLAY_ON_CURSOR_OFF,1);<br \/>\n} \/\/ LCD_init()<\/p><\/blockquote>\n<p>Ces instructions servent \u00e0 initialiser le LCD en mode 4 bits, \u00e0 allumer l&rsquo;\u00e9cran, \u00e0 masquer le curseur, &#8230;<\/p>\n<p>Remarquez que des d\u00e9lais sont ins\u00e9r\u00e9s ici et l\u00e0. \u00a0Il y a des d\u00e9lais aussi dans la fonction LCD_putcmd.<\/p>\n<p>Ces d\u00e9lais sont importants pour assurer le bon fontionnement \u00a0de l&rsquo;\u00e9cran.<\/p>\n<p>Pour conna\u00eetre les commandes de contr\u00f4les et les d\u00e9lais de programmation de la puce\u00a0HD44780, je vous revoie \u00e0 la <a href=\"http:\/\/fr.wikipedia.org\/wiki\/HD44780\">documentation<\/a>.<\/p>\n<h1><\/h1>\n<h1>Le projet<\/h1>\n<p>Apr\u00e8s deux jours de recherches et de prototypage, j&rsquo;en suis arriv\u00e9 \u00e0 une solution de contr\u00f4le de deux (2) LCD via I2C\u00a0pilot\u00e9s par 2 puces PCF8574.<\/p>\n<p>Mes recherches, dans Internet, m&rsquo;ont amen\u00e9 \u00e0 plusieurs endroits, mais la source d&rsquo;information que j&rsquo;ai retenue est situ\u00e9 \u00e0 l&rsquo;adresse suivante: <a href=\"http:\/\/paulfjujo.free.fr\/_18FxxKxx\/Test_LCD_I2C_PIC18F26k22.htm\">http:\/\/paulfjujo.free.fr\/_18FxxKxx\/Test_LCD_I2C_PIC18F26k22.htm<\/a>.<\/p>\n<p>Paul Freyer propose un\u00a0prototype\u00a0fonctionnel de l&rsquo;utilisation d&rsquo;une PCF8574.<\/p>\n<p>Je me suis inspir\u00e9 de son approche.<\/p>\n<p>Voici la solution:<\/p>\n<p>&nbsp;<\/p>\n<p><a href=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/18f4620-i2c-lcd-video2.gif\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-1150\" src=\"http:\/\/ve2cuy.com\/blog\/wp-content\/uploads\/2015\/04\/18f4620-i2c-lcd-video2.gif\" alt=\"18F4620 I2C LCD video2\" width=\"660\" height=\"371\" \/><\/a><br \/>\n<a href=\"https:\/\/drive.google.com\/uc?export=download&amp;id=0BwVyrqVfxGkRWFZ4aW9ZQUwyTTA\">T\u00e9l\u00e9charger<\/a>\u00a0le projet Proteus.<\/p>\n<hr \/>\n<h1>Les codes sources<\/h1>\n<h1>main.c<\/h1>\n<p>[sourcecode language=\u00a0\u00bbc\u00a0\u00bb wraplines=\u00a0\u00bbfalse\u00a0\u00bb collapse=\u00a0\u00bbfalse\u00a0\u00bb]<\/p>\n<p>\/*<br \/>\n * File: main.c<br \/>\n * By: Alain Boudreault (ve2cuy)<br \/>\n * Date: 2015.04.04<br \/>\n * Completed: 2015.04.05<br \/>\n * &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\n * Description: Use a PCA8574 to control 2 LCD using I2C protocol.<br \/>\n *<br \/>\n * Version fonctionnelle termin\u00e9e le 2015.04.05.<br \/>\n * &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-<br \/>\n * standard I2C LCD from eBay<br \/>\n * http:\/\/www.ebay.com\/sch\/i.html?_from=R40&amp;_trksid=p2050601.m570.l1313.TR4.TRC2.A0.H0.Xi2c+lcd.TRS0&amp;_nkw=i2c+lcd&amp;_sacat=0<br \/>\n * LCD Data PCA8574: P7,P6,P5,P4<br \/>\n * LCD Control: P3: Back Light, P2: E-Enable, P1:RW, P0: RS<br \/>\n * &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\n * This program is free software: you can redistribute it and\/or modify<br \/>\n * it under the terms of the GNU General Public License as published by<br \/>\n * the Free Software Foundation, either version 3 of the License, or<br \/>\n * (at your option) any later version.<br \/>\n *<br \/>\n * This program is distributed in the hope that it will be useful,<br \/>\n * but WITHOUT ANY WARRANTY; without even the implied warranty of<br \/>\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br \/>\n * GNU General Public License for more details.<br \/>\n *<br \/>\n * You should have received a copy of the GNU General Public License<br \/>\n * along with this program. If not, see &lt;http:\/\/www.gnu.org\/licenses\/&gt;.<br \/>\n*\/<\/p>\n<p>#include &lt;xc.h&gt;<br \/>\n#include &lt;stdio.h&gt; \/\/ for sprintf()<br \/>\n#include &quot;lcd.h&quot; <\/p>\n<p>\/\/ #define proteus_simulation 1<\/p>\n<p>#pragma config OSC = INTIO7 \/\/ Internal osc<br \/>\n#pragma config WDT = OFF \/\/ No watch dog<\/p>\n<p>#define _XTAL_FREQ 8000000<br \/>\n#define TEXT_BUFFER 80<\/p>\n<p>char text[TEXT_BUFFER]; <\/p>\n<p>#ifdef proteus_simulation<br \/>\n char LCD_01_ADDRESS = 0x40;<br \/>\n char LCD_02_ADDRESS = 0x42;<br \/>\n#else<br \/>\n char LCD_01_ADDRESS = 0b1001110; \/\/ default address<br \/>\n char LCD_02_ADDRESS = 0b1001100; \/\/ jumper on A0<br \/>\n#endif<\/p>\n<p>void longDelay(int time){<br \/>\n for (int i = 0 ; i &lt; time; i++) __delay_ms(50);<br \/>\n}<\/p>\n<p>\/\/ Program entry point<br \/>\nvoid main() {<\/p>\n<p> \/\/ADCON1 = 0xF; ADCON2 = 0xF; \/\/ No analog, all digital i\/o<br \/>\n OSCCON = 0b01110010; \/\/ Fosc = 8MHz<br \/>\n SSPADD = 19; \/\/ SCL (i2c clock) speed: ((8 Mhz) \/ (4 * 100 khz)) &#8211; 1 = 19<br \/>\n \/\/TRISC = 0xFF; PORTC = 0x00; LATC = 0x00;<\/p>\n<p> OpenI2C(MASTER, SLEW_OFF);<br \/>\n LCD_init(LCD_01_ADDRESS);<br \/>\n LCD_init(LCD_02_ADDRESS);<\/p>\n<p> unsigned int counter = 0;<\/p>\n<p> while(1) {<br \/>\n LCD_putcmd(LCD_01_ADDRESS, LCD_CLEAR,1);<br \/>\n sprintf(text, &quot;%d times&quot;, counter++);<br \/>\n LCD_puts(LCD_01_ADDRESS, &quot;I2C print on LCD 1&#092;&#048;&quot;);<br \/>\n LCD_goto(LCD_01_ADDRESS,2,1);<br \/>\n LCD_puts(LCD_01_ADDRESS, text);<br \/>\n LCD_goto(LCD_01_ADDRESS,3,1);<br \/>\n LCD_puts(LCD_01_ADDRESS, &quot;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;&#092;&#048;&quot;);<br \/>\n LCD_goto(LCD_01_ADDRESS,4,1);<br \/>\n LCD_puts(LCD_01_ADDRESS, &quot;18F4620, PCF6574+LCD&#092;&#048;&quot;);<br \/>\n longDelay(10); <\/p>\n<p> LCD_putcmd(LCD_02_ADDRESS, LCD_CLEAR,1);<br \/>\n sprintf(text, &quot;%u times&quot;, ~counter);<br \/>\n LCD_puts(LCD_02_ADDRESS, &quot;I2C print on LCD 2&#092;&#048;&quot;);<br \/>\n LCD_goto(LCD_02_ADDRESS,2,1);<br \/>\n LCD_puts(LCD_02_ADDRESS, text);<br \/>\n LCD_goto(LCD_02_ADDRESS,3,1);<br \/>\n LCD_puts(LCD_02_ADDRESS, &quot;&#8212;&#8212;(cl)2015&#8212;&#8212;&#092;&#048;&quot;);<br \/>\n LCD_goto(LCD_02_ADDRESS,4,1);<br \/>\n LCD_puts(LCD_02_ADDRESS, &quot;Project by VE2CUY&#092;&#048;&quot;);<br \/>\n longDelay(10); <\/p>\n<p> } \/\/ while(1)<br \/>\n} \/\/ main()<\/p>\n<p>[\/sourcecode]<\/p>\n<h1><\/h1>\n<hr \/>\n<h1>lcd.h<\/h1>\n<p>[sourcecode language=\u00a0\u00bbc\u00a0\u00bb wraplines=\u00a0\u00bbfalse\u00a0\u00bb collapse=\u00a0\u00bbfalse\u00a0\u00bb]<br \/>\n\/*<br \/>\n * File: lcd.h<br \/>\n * Author: Alain Boudreault &#8211; ve2cuy<br \/>\n *<br \/>\n * Created on 6 avril 2015, 15:57<br \/>\n *<br \/>\n * &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\n * This program is free software: you can redistribute it and\/or modify<br \/>\n * it under the terms of the GNU General Public License as published by<br \/>\n * the Free Software Foundation, either version 3 of the License, or<br \/>\n * (at your option) any later version.<br \/>\n *<br \/>\n * This program is distributed in the hope that it will be useful,<br \/>\n * but WITHOUT ANY WARRANTY; without even the implied warranty of<br \/>\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br \/>\n * GNU General Public License for more details.<br \/>\n *<br \/>\n * You should have received a copy of the GNU General Public License<br \/>\n * along with this program. If not, see &lt;http:\/\/www.gnu.org\/licenses\/&gt;.<br \/>\n *\/<\/p>\n<p>#ifndef LCD_H<br \/>\n#define LCD_H<\/p>\n<p>#ifdef __cplusplus<br \/>\nextern &quot;C&quot; {<br \/>\n#endif<\/p>\n<p>#ifdef __cplusplus<br \/>\n}<br \/>\n#endif<\/p>\n<p>\/\/\/ ###### I2C LCD defines ######<br \/>\n#define LCD_WAIT_DELAY 2<br \/>\n#define LCD_BL 0x08<br \/>\n#define LCD_EN 0x04<br \/>\n#define LCD_RW 0x02<br \/>\n#define LCD_RS 0x01<\/p>\n<p>\/\/ LCD Command<br \/>\n#define LCD_INIT_BYTE 0x30<br \/>\n#define LCD_BUS_WIDTH_4Bit 0x20<br \/>\n#define LCD_BUS_WIDTH_8Bit 0x30<br \/>\n#define LCD_CLEAR 0x01<br \/>\n#define LCD_HOME 0x02<br \/>\n#define LCD_ON 0x0C<br \/>\n#define LCD_OFF 0x08<br \/>\n#define LCD_LINE1 0x80<br \/>\n#define LCD_LINE2 0xC0<br \/>\n#define LCD_LINE3 0x94<br \/>\n#define LCD_LINE4 0xD4<br \/>\n#define LCD_CURSOR_OFF 0x0C<br \/>\n#define LCD_UNDERLINE_ON 0x0E<br \/>\n#define LCD_BLINK_CURSOR_ON 0x0F<br \/>\n#define LCD_MOVE_CURSOR_LEFT 0x10<br \/>\n#define LCD_MOVE_CURSOR_RIGHT 0x14<br \/>\n#define LCD_SHIFT_LEFT 0x18<br \/>\n#define LCD_SHIFT_RIGHT 0x1E <\/p>\n<p>#define LCD_DISPLAY_ON_CURSOR_OFF 0x0c<br \/>\n#define LCD_DISPLAY_OFF_CURSOR_OFF_BLINK_OFF 0x08<br \/>\n#define LCD_4BITS_2LINES_5x8FONT 0x28<br \/>\n#define LCD_INCREMENT_NO_SHIFT 0x06<br \/>\n#define Byte unsigned char<\/p>\n<p>#define LO_NIBBLE(b) (((b) &lt;&lt; 4) &amp; 0xF0)<br \/>\n#define HI_NIBBLE(b) ((b) &amp; 0xF0)<\/p>\n<p>\/\/ function prototypes<br \/>\nunsigned char I2C_PCF8574_Write(Byte Adr,Byte value);<br \/>\nvoid LCD_init(unsigned char addr);<br \/>\nvoid LCD_putcmd(unsigned char addr, unsigned char data,unsigned char cmdtype);<br \/>\nvoid LCD_putch(unsigned char addr, unsigned char data);<br \/>\nvoid LCD_puts(unsigned char addr, char *s);<br \/>\nvoid LCD_goto(unsigned char addr, char row, char column);<\/p>\n<p>#endif \/* LCD_H *\/<\/p>\n<p>[\/sourcecode]<\/p>\n<h1><\/h1>\n<hr \/>\n<h1>i2c_lcd.c<\/h1>\n<p>[sourcecode language=\u00a0\u00bbc\u00a0\u00bb wraplines=\u00a0\u00bbfalse\u00a0\u00bb collapse=\u00a0\u00bbfalse\u00a0\u00bb]<br \/>\n\/*<br \/>\n * File: i2c_lcd.c<br \/>\n * Author: Alain Boudreault &#8211; ve2cuy<br \/>\n *<br \/>\n * Created on 6 avril 2015, 15:57<br \/>\n * Note: Certains morceaux de code inspir\u00e9s de http:\/\/paulfjujo.free.fr\/_18FxxKxx\/datas\/18F26k22_LCD_PCF8574_I2C_Hardw_master_10Mhz.c<br \/>\n * &#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br \/>\n * This program is free software: you can redistribute it and\/or modify<br \/>\n * it under the terms of the GNU General Public License as published by<br \/>\n * the Free Software Foundation, either version 3 of the License, or<br \/>\n * (at your option) any later version.<br \/>\n *<br \/>\n * This program is distributed in the hope that it will be useful,<br \/>\n * but WITHOUT ANY WARRANTY; without even the implied warranty of<br \/>\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the<br \/>\n * GNU General Public License for more details.<br \/>\n *<br \/>\n * You should have received a copy of the GNU General Public License<br \/>\n * along with this program. If not, see &lt;http:\/\/www.gnu.org\/licenses\/&gt;.<br \/>\n *\/<\/p>\n<p>#include &lt;xc.h&gt;<br \/>\n#include &quot;lcd.h&quot;<\/p>\n<p>#ifndef _XTAL_FREQ<br \/>\n#define _XTAL_FREQ 8000000<br \/>\n#endif<br \/>\n\/\/\/ ##############################################################################################<br \/>\n\/\/\/ Custom LCD_I2C functions<\/p>\n<p>unsigned char I2C_PCF8574_Write(Byte addr,Byte value)<br \/>\n{<br \/>\n unsigned char S,dummy;<br \/>\n StartI2C();<br \/>\n S = WriteI2C( addr );<br \/>\n if(S == -1) \/\/bus collision ?<br \/>\n {<br \/>\n dummy = SSPBUF; \/\/ clear the buffer,<br \/>\n SSPCON1bits.WCOL=0; \/\/ clear collision status bit<br \/>\n }<br \/>\n S = WriteI2C(value);<br \/>\n StopI2C();<br \/>\n \/\/ __delay_us(LCD_WAIT_DELAY); \/\/ No impact on my project!<br \/>\n return(S);<br \/>\n} \/\/ I2C_PCF8574_Write()<\/p>\n<p>void LCD_putcmd(unsigned char addr, unsigned char data,unsigned char cmdtype)<br \/>\n{<br \/>\n unsigned char lcddata; <\/p>\n<p> \/\/ Write high nibble<br \/>\n lcddata = HI_NIBBLE(data) |LCD_BL;<br \/>\n I2C_PCF8574_Write(addr,lcddata | LCD_EN);<br \/>\n I2C_PCF8574_Write(addr,lcddata &amp; ~LCD_EN); \/\/ Reset LCD bus<\/p>\n<p> \/\/ cmdtype = 0; One cycle write, cmdtype = 1; Two cycle writes<br \/>\n if (cmdtype) {<br \/>\n \/\/ Write low nibble<br \/>\n lcddata = LO_NIBBLE(data) |LCD_BL;<br \/>\n I2C_PCF8574_Write(addr,lcddata | LCD_EN);<br \/>\n I2C_PCF8574_Write(addr,lcddata &amp; ~LCD_EN); \/\/ Reset LCD bus<br \/>\n }<br \/>\n __delay_ms(2); \/\/ For most command, Wait &gt; 100 us is ok.<br \/>\n} \/\/ LCD_putcmd())<\/p>\n<p>\/\/ Extract data high and low nible and send it to I2C LCD<br \/>\nvoid LCD_putch(unsigned char addr, unsigned char data)<br \/>\n{<br \/>\n unsigned char lcddata;<br \/>\n lcddata = HI_NIBBLE(data)|LCD_BL|LCD_RS; \/\/ Get high nibble<br \/>\n I2C_PCF8574_Write(addr,lcddata | LCD_EN); \/\/ Send it!<br \/>\n I2C_PCF8574_Write(addr,lcddata &amp; ~LCD_EN); \/\/ Reset LCD bus<br \/>\n lcddata = LO_NIBBLE(data)|LCD_BL|LCD_RS; \/\/ Get low nibble<br \/>\n I2C_PCF8574_Write(addr,lcddata | LCD_EN); \/\/ Send it!<br \/>\n I2C_PCF8574_Write(addr,lcddata &amp; ~LCD_EN); \/\/ Reset LCD bus<br \/>\n} \/\/ LCD_putch()<\/p>\n<p>\/\/ Init the LCD: DATA bus 4 bits, cursor off, auto increment, no shift.<br \/>\nvoid LCD_init(unsigned char addr)<br \/>\n{<br \/>\n __delay_ms(20); \/\/ Wait &gt; 15 ms after power ON<\/p>\n<p> LCD_putcmd(addr, LCD_INIT_BYTE,0);__delay_ms(5); \/\/ Wait &gt; 4.1 ms<br \/>\n LCD_putcmd(addr, LCD_INIT_BYTE,0);<br \/>\n LCD_putcmd(addr, LCD_INIT_BYTE,0);<br \/>\n LCD_putcmd(addr, LCD_BUS_WIDTH_4Bit,0);<br \/>\n LCD_putcmd(addr, LCD_4BITS_2LINES_5x8FONT,1);<br \/>\n LCD_putcmd(addr, LCD_DISPLAY_OFF_CURSOR_OFF_BLINK_OFF,1);<br \/>\n LCD_putcmd(addr, LCD_CLEAR,1);<br \/>\n LCD_putcmd(addr, LCD_INCREMENT_NO_SHIFT,1);<br \/>\n LCD_putcmd(addr, LCD_DISPLAY_ON_CURSOR_OFF,1);<br \/>\n} \/\/ LCD_init() <\/p>\n<p>\/\/ Goto line number. On line err, goto line 1.<br \/>\nvoid LCD_goto(unsigned char addr, unsigned char row, unsigned char column){<br \/>\n switch(row){<br \/>\n case 1: LCD_putcmd(addr,LCD_LINE1 + (column &#8211; 1), 1); break;<br \/>\n case 2: LCD_putcmd(addr,LCD_LINE2 + (column &#8211; 1), 1); break;<br \/>\n case 3: LCD_putcmd(addr,LCD_LINE3 + (column &#8211; 1), 1); break;<br \/>\n case 4: LCD_putcmd(addr,LCD_LINE4 + (column &#8211; 1), 1); break;<br \/>\n default: LCD_putcmd(addr,LCD_LINE1 + (column &#8211; 1), 1); break;<br \/>\n }<br \/>\n } \/\/ LCD_GOTO()<\/p>\n<p>\/\/ Note: The string must be zero terminated!<br \/>\n\/\/ Example: char callSign[] = &quot;ve2cuy&#092;&#048;&quot;;<br \/>\nvoid LCD_puts(unsigned char addr, char *s)<br \/>\n{<br \/>\n int i=0;<br \/>\n while(*s != 0) LCD_putch(addr, *s++);<br \/>\n}<\/p>\n<p>[\/sourcecode]<\/p>\n<hr \/>\n<p style=\"text-align:right;\">Article r\u00e9dig\u00e9 par Alain Boudreault (ve2cuy) &#8211; Avril 2015 &#8211; <a href=\"http:\/\/bit.ly\/1O4k2l1\">Lien court<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>To\u00a0my English language readers The following article is in French. Here is a\u00a0summary: How to\u00a0display on a I2C LCD using a PCF8574 and a PIC 18F4620. The Proteus project is available here. Note: source code is commented in English. Mise en situation Contrairement \u00e0 nos amis Arduiniens, quand vient le moment d\u2019interconnecter des p\u00e9riph\u00e9riques \u00e0 [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"footnotes":""},"class_list":["post-1099","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ve2cuy.com\/blog\/index.php\/wp-json\/wp\/v2\/pages\/1099","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ve2cuy.com\/blog\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ve2cuy.com\/blog\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/blog\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/ve2cuy.com\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=1099"}],"version-history":[{"count":0,"href":"https:\/\/ve2cuy.com\/blog\/index.php\/wp-json\/wp\/v2\/pages\/1099\/revisions"}],"wp:attachment":[{"href":"https:\/\/ve2cuy.com\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=1099"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}