
LCD Help needed, 16x2s are boring
#41
Posted 04 January 2011 - 11:51 PM
#42
Posted 04 January 2011 - 11:52 PM
public void WriteText(string text, bool noSpace = true) { DataMode = true; if (noSpace) foreach (char c in text.ToCharArray()) _dataPort.Write(NokiaCharacters.ASCII[c - 0x20]); else { byte[] letter = new byte[6]; foreach (char c in text.ToCharArray()) { for (int i = 0; i < 5; i++) letter[i] = NokiaCharacters.ASCII[c - 0x20][i]; letter[5] = 0x00; _dataPort.Write(letter); } } }This will give you the option of adding a little one pixel line between letters, it makes them easier to read but less characters will fit on one line.
#43
Posted 05 January 2011 - 12:11 AM

#44
Posted 05 January 2011 - 12:46 AM
Omar, take another look at the second example on the Arduino site. They have an example of writing to random X,Y locations.
I cant't find it, could you get me a link or point me in the right direction? Also will you be posting a Projects showcase thing for this LCD? I think you should since you did most, if not all, of the work.
#45
Posted 05 January 2011 - 08:56 AM
void gotoXY(int x, int y) { LcdWrite( 0, 0x80 | x); // column LcdWrite( 0, 0x40 | y); // row }
This is from http://www.arduino.c...nd/Code/PCD8544
Look for the text that reads:
Writing individual pixels will be tricky (but certainly 'do-able') because the display does not have a plain vanilla X,Y bitmap. The datasheet goes into more detail on the arrangement of the bitmap; it seems to be optimized for 6 lines of characters. You might be better off creating a 84x48 array (i.e. a backbuffer) in the Netduino memory, writing pixels to the backbuffer, transforming it as appropriate for the LCD display and then copying the entire backbuffer to the display. That is what I am trying to do. It's only 504 bytes for the entire display, so it should be quick enough for animation.A simple modified example of interfacing with the Nokia 3310 LCD that will print characters at an XY position on LCD and also will draw lines on LCD.
#46
Posted 06 January 2011 - 02:07 PM


#47
Posted 06 January 2011 - 02:44 PM
LOL I ordered mine yesterday!I might have to get one now that you've done all the hard work

#48
Posted 07 January 2011 - 07:13 AM
The routines in this code will allow you to write to arbitary pixels on the Nokia 84x48 screen. It is SLOW, but it works and should be a reasonable proof of concept for others to improve upon. The code is ugly and unorthodox, but the bmapSet(), bmapLine() and bmapWrite() methods should be useful to someone trying to figure out how to write to this little Nokia cellphone screen.
Believe it or not, this screen is similar in layout to the Commodore64 bitmap screen so it is tricky (but do-able) to draw things like diagonal lines because you have to build the line bit by bit.
The loop near the bottom of the program draws a single pixel that will move diagonally around the screen. The movement is quite slow since my code redraws the entire screen each time. The performance of this can definitely be improved.
I hope this is useful; I had a bit of fun writing it.
EDIT: I just realized that I used some method calls to a Netduino library that I am writing, so things like 'backlight.Brightness = 50;' will not work for you. I'll remove that stuff and post a cleaner (and faster) version tonight.
Attached Files
#49
Posted 07 January 2011 - 08:57 PM
I hacked the attached code together and (against my better judgement) post this without cleaning it up for others to see.
I was actually finishing up the code I was working on. I decided not to make a draw pixel based on x and y. I decided to allow the use to store an array of bytes, custom characters that can be sent later. I'll post the code below.
#50
Posted 07 January 2011 - 09:03 PM
#51
Posted 08 January 2011 - 02:58 AM
Attached Files
#52
Posted 08 January 2011 - 04:13 AM
#53
Posted 08 January 2011 - 01:50 PM
I am almost done with my bitmap drawing program. I have a c sharp program in which you make the image and then send it via serial to the netduino and the netduino will then draw it. I might be posting it next weekend though because I have midterms coming up next week so I am going to be pretty busy studying.
Alfred we should really try to figure out a way to put our code together and come up with a well balanced and useful library for this thing, we kinda went off in different directions. let me know if you'd like to do that.
Sure, I'd love to. I think that our efforts are complimentary, but we have very different coding styles.
#54
Posted 08 January 2011 - 10:50 PM
I looked at your code... I'm scared of it... I have no clue what is going on in there.... its so different than what I'm used to! Its alright though, I guess we can just offer people different styles and they can choose one. Not saying you code isnt nice, I'm just lost, I've never really seen that style before.Sure, I'd love to. I think that our efforts are complimentary, but we have very different coding styles.
I am actually redoing my code again, i decided that since its best to send the bytes all at once I'll do it Windows form style, with a refresh method... idk, I think it might work out best, I actually think that you went in that direction too right? thats why you got the bool[48*84] ? i think... so yeah I'll do that too and see how it works out.
#55
Posted 09 January 2011 - 03:19 AM
#56
Posted 09 January 2011 - 03:39 AM
Omar, did you run my code? It's fully self contained and it won't damage your Netduino or your LCD, I promise. (You might find the resulting pattern on the LCD 'kinda cute.)
You likely be interested in bmapWrite(). It does what I imagine you want to do i.e. take a 84x48 bitmap and display it on the LCD. It does the transformation from an 84x48 array of bool into a 504 array of byte array for writing to the LCD via SPI.
Oh I'm sorry, I didn't mean I was scared of what it does, I meant scared to go through it and try to understand it. I know you would never harm someone's netduino. I'll test it soon.
I did that bool system, just finished it actually. Mine uses a bool[48][] instead of bool[4032]. I am working on: public void DrawRectangle(int x, int y, int width, int height, bool filled) now. I am loving this screen. I was used to computers and their huge memory and processing power, with the Netduino I've learned to make things as efficient as I can. The netduino is great, obviously when compared to a computer... yeah.
#57
Posted 09 January 2011 - 04:24 AM
IMPORTANT: Please note that the pins have changed!
public class Nokia_5110 { private bool[] _offRow = new bool[84]; private readonly byte[] _pow = new byte[] { 1, 2, 4, 8, 16, 32, 64, 128 }; private OutputPort _resetPort, _daComPin; private PWM _backlightPort; private SPI _dataPort; public bool[][] _pixelMap = new bool[48][]; private byte[] _byteMap = new byte[504]; private uint _backlight = 0; private bool _invd = false, _autoRefresh = true; public Nokia_5110(Cpu.Pin chipSelect = Pins.GPIO_PIN_D3, Cpu.Pin backlight = Pins.GPIO_PIN_D9, Cpu.Pin reset = Pins.GPIO_PIN_D7, Cpu.Pin dataCommand = Pins.GPIO_PIN_D8) { SPI.Configuration spiConfiguration = new SPI.Configuration( chipSelect, // chip select port false, // IC is accessed when chip select is low 0, // setup time 1 ms 0, // hold chip select 1 ms after transfer false, // clock line is low if device is not selected true, // data is sampled at leading edge of clock 2000, // clockrate is 15 MHz SPI.SPI_module.SPI1 // use first SPI bus ); _dataPort = new SPI(spiConfiguration); _backlightPort = new PWM(backlight); _resetPort = new OutputPort(reset, true); _daComPin = new OutputPort(dataCommand, true); Initialize(); Clear(); } private void Initialize() { _resetPort.Write(false); _resetPort.Write(true); DataMode = false; _dataPort.Write(new byte[] { 0x21, 0xBF, 0x04, 0x14, 0x0C, 0x20, 0x0C }); DataMode = true; Clear(); } public void SetCursor(float x, float y) { DataMode = false; _dataPort.Write(new byte[] { (byte)(0x80 | (int)(x * 4)), (byte)(0x40 | (int)(y)) }); DataMode = true; } public void WriteText(string text, bool noSpace = true) { DataMode = true; if (noSpace) foreach (char c in text.ToCharArray()) _dataPort.Write(NokiaCharacters.ASCII[c - 0x20]); else { byte[] letter = new byte[6]; foreach (char c in text.ToCharArray()) { for (int i = 0; i < 5; i++) letter[i] = NokiaCharacters.ASCII[c - 0x20][i]; letter[5] = 0x00; _dataPort.Write(letter); } } } public void DrawRectangle(int x, int y, int width, int height, bool filled) { // thats what lines are for! oh right... I need to make a Draw line method... if (width <= 1 || height <= 1) return; int endX = x + width, endY = y + height - 2; bool[] line = new bool[84]; for (int p = x; p < endX; p++) line[p] = true; _pixelMap[y] = line; _pixelMap[endY] = line; if (!filled) { line = new bool[84]; line[x] = true; line[endX - 1] = true; } for (int h = y + 1; h < endY; h++) _pixelMap[h] = line; if (AutoRefresh) Refresh(); } public void Refresh() { int byteID = 0; for (int y = 0; y < 6; y++) { for (int x = 0; x < 84; x++) { _byteMap[byteID] = ConvertToByte(_pixelMap[y * 8][x], _pixelMap[y * 8 + 1][x], _pixelMap[y * 8 + 2][x], _pixelMap[y * 8 + 3][x], _pixelMap[y * 8 + 4][x], _pixelMap[y * 8 + 5][x], _pixelMap[y * 8 + 6][x], _pixelMap[y * 8 + 7][x]); byteID++; } } _dataPort.Write(_byteMap); SetCursor(0, 0); } private byte ConvertToByte(bool b0, bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7) { byte result = 0; result += (byte)((b7) ? _pow[7] : 0); result += (byte)((b6) ? _pow[6] : 0); result += (byte)((b5) ? _pow[5] : 0); result += (byte)((b4) ? _pow[4] : 0); result += (byte)((b3) ? _pow[3] : 0); result += (byte)((b2) ? _pow[2] : 0); result += (byte)((b1) ? _pow[1] : 0); result += (byte)((b0) ? _pow[0] : 0); return result; } public void Clear() { for (int r = 0; r < 48; r++) _pixelMap[r] = _offRow; if(_autoRefresh) Refresh(); } private void Inverse(bool inverse) { _invd = inverse; DataMode = false; _dataPort.Write(inverse ? new byte[] { 0x0D } : new byte[] { 0x0C }); DataMode = true; } public bool InverseColors { get { return _invd; } set { Inverse(value); } } private bool DataMode { get { return _daComPin.Read(); } set { _daComPin.Write(value); } } public uint BacklightBrightness { get { return _backlight; } set { if (value > 100) value = 100; _backlightPort.SetDutyCycle(value); _backlight = 100; } } public bool AutoRefresh { get { return _autoRefresh; } set { _autoRefresh = value; } } }
Random Filled squares example:
Random r = new Random(); lcd.BacklightBrightness = 80; while (true) { int width = r.Next(84); int height = r.Next(48); lcd.DrawRectangle(r.Next(84 - width), r.Next(48 - height), width, height, true); Thread.Sleep(500); lcd.Clear(); }
#58
Posted 09 January 2011 - 04:34 AM
#59
Posted 09 January 2011 - 05:18 AM

And for fun, I drew a cute picture!
I hope you enjoy!
Attached Files
#60
Posted 09 January 2011 - 06:34 AM
Alfred I decided to use your genius struct system, thanks for that code. I added the Rectangle struct. The code below will be changing as I make things work and finish methods... This will be some of my cleanest, most efficient code. I'll try very hard to comment it all (for both your sake and mine). Again I got midterms coming up, and I've dodged studying enough already sooo this might be done a week or two from now...
Here is what I hope to accomplish/have so far:
public class Nokia_5110 { private OutputPort reset, dataMode; private PWM backlight; private SPI spi; public byte[] ByteMap = new byte[504]; private uint _backlightVal = 0; private bool _invd = false; public Nokia_5110(Cpu.Pin latch = Pins.GPIO_PIN_D3, Cpu.Pin backlight = Pins.GPIO_PIN_D9, Cpu.Pin reset = Pins.GPIO_PIN_D7, Cpu.Pin dataCommand = Pins.GPIO_PIN_D8) { SPI.Configuration spiConfiguration = new SPI.Configuration( latch, // chip select port false, // IC is accessed when chip select is low 0, // setup time 1 ms 0, // hold chip select 1 ms after transfer false, // clock line is low if device is not selected true, // data is sampled at leading edge of clock 4000, // clockrate is 15 MHz SPI.SPI_module.SPI1 // use first SPI bus ); spi = new SPI(spiConfiguration); this.backlight = new PWM(backlight); this.reset = new OutputPort(reset, true); this.dataMode = new OutputPort(dataCommand, true); Initialize(); } private void Initialize() { reset.Write(false); reset.Write(true); dataMode.Write(false); spi.Write(new byte[] { 0x21, 0xBF, 0x04, 0x14, 0x0C, 0x20, 0x0C }); dataMode.Write(true); Clear(); Refresh(); } public void WriteText(string text, bool noSpace = true) { if (noSpace) foreach (char c in text.ToCharArray()) spi.Write(NokiaCharacters.ASCII[c - 0x20]); else { byte[] letter = new byte[6]; foreach (char c in text.ToCharArray()) { for (int i = 0; i < 5; i++) letter[i] = NokiaCharacters.ASCII[c - 0x20][i]; letter[5] = 0x00; spi.Write(letter); } } } public bool DrawPoint(short x, short y, bool on) { if (x < 0 || x >= 84 || y < 0 || y >= 48) return true; // out of the range! return true to indicate failure. ushort index = (ushort)((x % 84) + (int)(y * 0.125) * 84); byte bitMask = (byte)(1 << (y % 8)); if (on) ByteMap[index] |= bitMask; else ByteMap[index] &= (byte)~bitMask; return false; // all is good (false = no error), return false to continue } public void DrawLine(short x1, short y1, short x2, short y2, bool on) { // This is a common line drawing algorithm. Read about it here: // http://en.wikipedia.org/wiki/Bresenham's_line_algorithm short sx = (x1 < x2) ? sx = 1 : sx = -1; short sy = (y1 < y2) ? sy = 1 : sy = -1; short dx = (short)((x2 > x1) ? x2 - x1 : x1 - x2); short dy = (short)((y2 > x1) ? y2 - y1 : y1 - y2); float err = dx - dy, e2; // if there is an error with drawing a point or the line is finished get out of the loop! while (!((x1 == x2 && y1 == y2) || DrawPoint(x1, y1, on))) { e2 = 2 * err; if (e2 > -dy) { err -= dy; x1 += sx; } if (e2 < dx) { err += dx; y1 += sy; } } } public void DrawRectangle(short X, short Y, short width, short height, bool on, bool filled) { // this is easier to do with points instead of lines since the line algorithm isn't that great. // this is only best to do with points because its straight lines. short xe = (short)(X + width); short ye = (short)(Y + height); if (filled) for (short y = Y; y != ye; y++) for (short x = X; x != xe; x++) DrawPoint(x, y, on); else { xe -= 1; ye -= 1; for (short x = X; x != xe; x++) DrawPoint(x, Y, on); for (short x = X; x <= xe; x++) DrawPoint(x, ye, on); for (short y = Y; y != ye; y++) DrawPoint(X, y, on); for (short y = Y; y <= ye; y++) DrawPoint(xe, y, on); } } public void Refresh() { spi.Write(ByteMap); } public void Clear() { ByteMap = new byte[504]; dataMode.Write(false); spi.Write(new byte[]{ 0x80, 0x40}); dataMode.Write(true); } private void Inverse(bool inverse) { _invd = inverse; dataMode.Write(false); spi.Write(inverse ? new byte[] { 0x0D } : new byte[] { 0x0C }); dataMode.Write(true); } public bool InverseColors { get { return _invd; } set { Inverse(value); } } public uint BacklightBrightness { get { return _backlightVal; } set { if (value > 100) value = 100; backlight.SetDutyCycle(value); _backlightVal = 100; } } }
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users