|
|
View previous topic :: View next topic |
Author |
Message |
rovtech
Joined: 24 Sep 2006 Posts: 262
|
I2C on Digole serial control module for LCDs |
Posted: Thu Nov 27, 2014 10:36 am |
|
|
I am trying to display on a Digole LCDSP_T Ver2.0 serial control module with LCD display.
I am using I2C code that worked on another project but with a different PIC and for a different purpose.
1.5k pullups on both lines. Both lines active with pulses. The display shows "I2C address:0x27" so the control module and display seem to be working. It does not respond to any commands like CS0 to turn the cursor off. I assume that is how I'm supposed to use it. The PIC blinks an output in a different test program.
Does this code look correct? Are the three ways to send a Z correct? I corrected what was here previously. I don't know what changed it.
CCS PCM C Compiler, Version 5.019
Code: | #include <16F882.H>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT, BROWNOUT, MCLR
#use delay (clock=2000000)
#use I2C (master, SCL=PIN_C3, SDA=PIN_C4)
#byte portc = getenv("SFR:PORTC")
// define I2C addresses
#define LCD_WRT_ADDR 0X27 // LCD display
// The main function
void main(void)
{
set_tris_c (0x00); // all outputs
while (1)
{
// output_toggle(PIN_C3);
// send to LCD
I2C_START (); // start I2C
I2C_WRITE (0x27); // addr of LCD
I2C_WRITE (0x5A); // send Z
I2C_WRITE ("Z"); // send Z
I2C_WRITE (90); // send Z
I2C_STOP (); // stop I2C
delay_ms(3000);
} // end of while loop
} // end of main function
// end
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 27, 2014 2:43 pm |
|
|
Quote: | I2C: Slave Mode, 7-bit address, default address is Hex:27, change able |
The address they give is in 7-bit format. CCS uses 8-bit format, so you
must shift their address left by 1 bit to convert it to CCS format. Doing
this gives the address as: 0x4E
The Digole board must also be jumpered to put it in i2c mode. It is
shipped with UART mode enabled by default.
Connect your PIC to the Digole board. Then run this program
on your PIC and see if it finds the board as an i2c slave device.
http://www.ccsinfo.com/forum/viewtopic.php?t=49713 |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Working now |
Posted: Thu Nov 27, 2014 4:35 pm |
|
|
Thanks PCM Programmer. The address was all that was wrong.
I had modified my program to increment the address each second and send again but the display and backlight vanished and I had to reset long before I got to the correct address. Your program is much more elegant.
I can
Code: | I2C_WRITE(84);
I2C_WRITE(0x54); |
but cannot
is there a way to put the actual letter into the statement?
I will play with an array in a loop next to display a message unless you have a function to do this.
Much appreciated. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 27, 2014 5:51 pm |
|
|
When a function has byte parameter, you should put an ASCII character
in single quotes. Example:
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Nesting functions |
Posted: Thu Nov 27, 2014 6:36 pm |
|
|
Thanks again, that works.
My attempt to write functions to display ended with a compile error that I cannot nest functions.
How do I get around that one?
I will try searching on I2C programs, someone must have done it already.
It seems that
OLED 128x64 SSD1306 I2C PIC16F1788 driver
nests functions. I will see where i'm going wrong |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Nov 27, 2014 7:39 pm |
|
|
Post a short test program that shows the error. We can copy it into
MPLAB and try to compile it and see your problem. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
|
Posted: Thu Nov 27, 2014 9:48 pm |
|
|
I put the closing brackets for the main function AFTER the functions at the end.
I think everything will work OK and I have the
OLED 128x64 SSD1306 I2C PIC16F1788 driver
examples to learn from.
Thanks PCM programmer, you have incredible patience with us part-time programmers. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Pleased with Digole LCDSP_T serial control module |
Posted: Fri Nov 28, 2014 2:19 pm |
|
|
I am pleased with the Digole module and have an application that uses 5 LCD displays that can now be controlled on a pair of wires from one PIC.
The next one I will tackle is their Universal Graphic Serial LCD Adapter since I want to be able to place graphics on an LCD and this seems to be the easiest way.
The working code for my 16x2 alphanumeric display is below. I left in the brute force way of sending to I2C just as an illustration.
Code: | /* Pre-processor directives */
#include <16F882.H>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT, BROWNOUT, MCLR
#use delay (clock=2000000)
#use I2C (master, SCL=PIN_C3, SDA=PIN_C4)
#byte portc = getenv("SFR:PORTC")
// define I2C address and LCD size
#define LCD_WRT_ADDR 0X4E // LCD display
#define num_of_char 17 // characters per line plus 1
// Function prototypes
void clear_LCD (void); // Clear LCD
void cursor(short ctrl); // Turn cursor ON(1) or OFF(0)
void control_addr (short ctrl); // Turn on mode
void text_position (int line, int column); // set start for next text
void text(char txt [num_of_char]); // Send string to LCD
// The main function
void main(void)
{
// declare variables
set_tris_c (0x00); // all outputs
int1 ON=TRUE;
int1 OFF=FALSE;
// declare a literal string which is automatically terminated by
// a null character and the size is calculated automatically
char text_array[]="Short test"; // insert text up to 16 characters here
char text_array2[]="Hello World"; // insert text up to 16 characters here
// Start the display sequence
control_addr(ON); // control startup display
delay_ms(2000); // display start screen for 2 secs
clear_LCD(); // clear the LCD
delay_ms(2000); // show cursor at start for 2 secs
cursor(OFF); // turn cursor OFF
delay_ms(2000); // show cursor is off for 2 secs
text(text_array); // display text array
delay_ms(3000); // for 3 seconds
clear_LCD(); // clear the LCD
text(text_array2); // display text array
delay_ms(3000); // for 3 seconds
// clear_LCD(); // clear the LCD
text_position(3,1); // 3rd column, 2nd line
// send to LCD the old way
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('T'); // T
I2C_WRITE ('T'); // T
I2C_WRITE ('H'); // H
I2C_WRITE (69); // E
I2C_WRITE (76); // L
I2C_WRITE (76); // L
I2C_WRITE (79); // O
I2C_WRITE (32); // SPACE
I2C_WRITE (0X41); // A
I2C_WRITE (0X47); // G
I2C_WRITE (0X41); // A
I2C_WRITE (0X49); // I
I2C_WRITE (0X4E); // N
I2C_WRITE (0); // 0 TO TERMINATE
I2C_STOP (); // stop I2C
delay_ms(2000);
} // end of main function
// Functions
// Clear Display
void clear_LCD (void)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('C'); // C CL to clear display
I2C_WRITE ('L'); // L
I2C_STOP (); // stop I2C
}
// Turn cursor ON or OFF
void cursor(short ctrl)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('C'); // C, CS0 to control cursor
I2C_WRITE ('S'); // S
I2C_WRITE (ctrl); // 1=ON, 0=OFF
I2C_STOP (); // stop I2C
}
// Display Configuration: Control address display
void control_addr (short ctrl)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE (0x44); // D, to display I2C address
I2C_WRITE (0x43); // C
I2C_WRITE (ctrl); // 1=on, 0 to turn off
I2C_STOP (); // stop I2C
}
// set position of next text
void text_position(int line, int column)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('T'); // T, TP set text position
I2C_WRITE ('P'); // P
I2C_WRITE (line); // line position
I2C_WRITE (column); // column position
I2C_STOP (); // stop I2C
}
// send string to LCD
void text(char txt [num_of_char])
{
int i;
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE('T'); // send TT for text coming
I2C_WRITE('T');
for (i=0; i<num_of_char; i++)
{
I2C_WRITE(txt[i]); // start with a Z
}
I2C_WRITE(0);
I2C_STOP (); // stop I2C
}
// end |
29 Nov 2014: Note I have added "#define num_of_char 17" so the size of LCD can be changed easily. I made it 17 because of the advice below. I also corrected the text position statement which had line,col instead of col,line
Last edited by rovtech on Sat Nov 29, 2014 9:52 am; edited 4 times in total |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Display formatting |
Posted: Sat Nov 29, 2014 8:02 am |
|
|
Now that I have the serial adapter working I wondered how I can display a floating point number like 3.27 volts. It would be nice to be able to use proper C code such as
Code: | printf(lcd_putc, "Battery %2.2fv", volts);
|
that I have used with the CCS LCD functions. One option is to modify the CCS code to use the I2C to parallel adapter and have the LCD driver in software instead of using the hardware with the driver in firmware. I do like this adapter though, which is what this project is about, and would like to be able to send floating point numbers to the display.
Any suggestions? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19553
|
|
Posted: Sat Nov 29, 2014 8:58 am |
|
|
You can get close with what you already show.
Code: |
char buff[17]; //Remember a 'string' is one character longer than the data.
sprintf(buff, "Battery %5.2fv", volts);
text(buff);
|
Remember in C, the number in front of the decimal point in a format declaration, is the total field width _not_ the number of characters in front of the decimal. '.2f' required a field width of 3, so your code would be overflowing the field width all the time....
To have 16 usable characters to display (if the number got that large), you have to have the source array able to hold 17 characters. You also need to be aware that if (for instance) the number got to over 99999, then the print statement could overflow the space available in the array:
'Battery 100000.00' is 17 characters long, and would result in the next variable being overwritten with the null terminator character. You either need to ensure this cannot happen (depending on how 'volts' is calculated), or testthe value before formatting, or allow a longer target string, and then accept the data being lost off the end.... |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Formatting and a correction |
Posted: Sat Nov 29, 2014 9:43 am |
|
|
Thanks, I will try that.
I have added "#define num_of_char 17" so the size of LCD can be changed easily. I also corrected the text position statement which had line,col instead of col,line. |
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
Formatting works! |
Posted: Sat Nov 29, 2014 10:49 am |
|
|
Thanks Ttelmah, that works perfectly.
Code: | /* Pre-processor directives */
#include <16F882.H>
#fuses INTRC_IO, NOWDT, PUT, NOPROTECT, BROWNOUT, MCLR
#use delay (clock=2000000)
#use I2C (master, SCL=PIN_C3, SDA=PIN_C4)
#byte portc = getenv("SFR:PORTC")
// define I2C address
#define LCD_WRT_ADDR 0X4E // LCD display
#define buff_size 17 // characters per line plus one
// Function prototypes
void clear_LCD (void); // Clear LCD
void cursor(short ctrl); // Turn cursor ON(1) or OFF(0)
void control_addr (short ctrl); // Turn on mode
void text_position (int line, int column); // set start for next text
void sen_str(char buff[buff_size]); // Send string to LCD
// The main function
void main(void)
{
// declare variables
set_tris_c (0x00); // all outputs
int1 ON=TRUE;
int1 OFF=FALSE;
char buff[buff_size];
float BV=2.43;
// declare a literal string which is automaticall terminated by a
// null character and the array size is calculated automatically
char text_1[]="Battery State:"; // insert text up to 16 characters here
// Start the display sequence
delay_ms(500); // allow I2C module to start
control_addr(OFF); // control startup display
clear_LCD(); // clear the LCD
cursor(OFF); // turn cursor OFF
sen_str(text_1); // display text array
text_position(1,1); // 2nd line, 5th column
sprintf(buff, "Battery %5.2fv", BV);
sen_str(buff);
} // end of main function
// Functions
// Clear Display
void clear_LCD (void)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('C'); // C CL to clear display
I2C_WRITE ('L'); // L
I2C_STOP (); // stop I2C
}
// Turn cursor ON or OFF
void cursor(short ctrl)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('C'); // C, CS0 to control cursor
I2C_WRITE ('S'); // S
I2C_WRITE (ctrl); // 1=ON, 0=OFF
I2C_STOP (); // stop I2C
}
// Display Configuration: Control address display
void control_addr (short ctrl)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE (0x44); // D, to display I2C address
I2C_WRITE (0x43); // C
I2C_WRITE (ctrl); // 1=on, 0 to turn off
I2C_STOP (); // stop I2C
}
// set position of next text
void text_position(int line, int column)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE ('T'); // T, TP set text position
I2C_WRITE ('P'); // P
I2C_WRITE (line); // line position
I2C_WRITE (column); // column position
I2C_STOP (); // stop I2C
}
// send string to LCD
void sen_str(char buff[buff_size])
{
int i;
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE('T'); // send TT for text coming
I2C_WRITE('T');
for (i=0; i<buff_size; i++)
{
I2C_WRITE(buff[i]); // start with a Z
}
I2C_WRITE(0);
I2C_STOP (); // stop I2C
}
// end |
I could also use sprintf instead of making special strings as I did for "Battery State:" in the above code. Replacing with this works perfectly:
Code: | sprintf(buff, "Battery State:");
sen_str(buff); // display text array |
|
|
|
rovtech
Joined: 24 Sep 2006 Posts: 262
|
I2C to 8 bit board |
Posted: Sat Nov 29, 2014 3:47 pm |
|
|
I tried a "dumb" I2C to 8 bit adapter, Ebay item
http://www.ebay.ca/itm/321475410959?ssPageName=STRK:MEWAX:IT&_trksid=p3984.m1423.l2649
It also specifies address 0x27 but uses the 8 bit version 0x4E
Can anyone explain what this is all about?
What, besides a teletype, sends 7 bits?
It works to translate I2C to 8 bits without any smarts.
It was connected to an LCD and this flashes the backlight (see schematic download):
Code: | While(1)
{
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE (0x08); // turn on LED
I2C_STOP (); // stop I2C
delay_ms(500);
I2C_START (); // start I2C
I2C_WRITE (LCD_WRT_ADDR); // addr of LCD
I2C_WRITE (0x00); // turn on LED
I2C_STOP (); // stop I2C
delay_ms(2000);
} |
It could have several uses. Just remember tha address 0x4E.
The address lines have pullups and the edge pads are grounded and are jumpered to ground the line, despite what the instructions say.
I don't intend to go any further with this device. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|