Cheap I2C OLED display with 08M2

paraglider_nut

New Member
I got a very cheap I2C display (<£3) from eBay, intending to use it with an 08M2 but couldn't find much information about it. After a few hours research and some experimenting, I managed to get the display working and thought it might be helpful to share the results.



I started with the excellent information in this thread, which is for a different display but with much in common: http://www.picaxeforum.co.uk/archive/index.php/t-23134.html I also got inspiration for the font lookup from this thread: http://www.picaxeforum.co.uk/entry.php?30-Notes-behind-Magic-Morse

This is the display I purchased: http://www.ebay.co.uk/itm/162337263365?_trksid=p2057872.m2749.l2649&ssPageName=STRK:MEBIDX:IT

Although it says its 128 * 64, the display is actually 128 * 32 but the display memory holds 128 * 64. As each byte is written to the display memory it appears on screen so the display builds as it is sent. To avoid this, you can point the display to start at a specific memory location and as there is exactly enough memory for 2 screens of data you can write the message to the unused block and then point the display to it for instant update.

I needed to design a font to use with the display so I used excel to play around with different options. I settled on an 8 * 8 block for each character as this fitted very well with the display dimensions, giving four rows of sixteen characters. This is the spreadsheet I used:
https://www.dropbox.com/s/vw8mgrwu5hhi9dj/OLED Font.xls?dl=0
It converts the pixels into the eeprom commands needed to load the font into the 08M2. I only needed numbers and upper case characters (the programme will display any lower case characters as upper case). It would be straightforward to add any other characters that may be needed.

To send a message to the display you poke the required characters to memory locations 28 to 91 and then the programme looks up the font data and sends it to the display. When all the data has been sent, the display is pointed to the start of the latest message in display memory.

The code to drive the display is shown below. In this example the main programme just loads a message to memory locations 28 - 91, calls the sendtodisplay subroutine and then loops. As it only uses 413 bytes there is plenty of room for other code which could create its own messages.

Code:
symbol counter = w0
symbol subcounter = b2
symbol fontlookup = b3
symbol pixels = b4
symbol displaybank = b5

; save Font codes in EEPROM

eeprom 0,(124,130,130,130,124)   	; 0 (ASCII 48)
eeprom 5,(136,132,254,128,128)   	; 1
eeprom 10,(196,162,162,146,140)   	; 2
eeprom 15,(68,130,146,146,108)   	; 3
eeprom 20,(48,40,36,254,32)   	        ; 4
eeprom 25,(110,138,138,138,114)   	; 5
eeprom 30,(124,146,146,146,100)   	; 6
eeprom 35,(2,2,2,2,254)   		        ; 7
eeprom 40,(108,146,146,146,108)   	; 8
eeprom 45,(30,18,18,18,254)   	        ; 9 (ASCII 57)
eeprom 50,(254,18,18,18,254)   	; A (ASCII 65)
eeprom 55,(254,146,146,146,108)   	; B
eeprom 60,(254,130,130,130,130)   	; C
eeprom 65,(254,130,130,68,56)   	; D
eeprom 70,(254,146,146,146,130)   	; E
eeprom 75,(254,18,18,18,2)   		; F
eeprom 80,(254,130,130,146,242)   	; G
eeprom 85,(254,16,16,16,254)   	; H
eeprom 90,(130,130,254,130,130)   	; I
eeprom 95,(226,130,254,2,2)   	        ; J
eeprom 100,(254,16,40,68,130)   	; K
eeprom 105,(254,128,128,128,128)   	; L
eeprom 110,(254,2,254,2,254)   	; M
eeprom 115,(254,4,56,64,254)   	; N
eeprom 120,(254,130,130,130,254)   	; O
eeprom 125,(254,18,18,18,12)   	; P
eeprom 130,(124,130,162,66,188)   	; Q
eeprom 135,(254,18,50,82,140)   	; R
eeprom 140,(222,146,146,146,246)   	; S
eeprom 145,(2,2,254,2,2)   		; T
eeprom 150,(126,128,128,128,126)   	; U
eeprom 155,(30,96,128,96,30)   	; V
eeprom 160,(254,128,254,128,254)   	; W
eeprom 165,(198,40,16,40,198)   	; X
eeprom 170,(6,8,240,8,6)   		; Y
eeprom 175,(194,162,146,138,134)   	; Z (ASCII 90)


initialise:
; initialise i2c for display (ID 0x78) and then send power up instructions
					
hi2csetup i2cmaster,%01111000,i2cfast,i2cbyte	
hi2cout 0x80,(0xAE,0x00,0x00,0xB0,0x20,0x00,0xD5,0x80,0xA8,0x1F,0xD3,0x00,0x8D, _
0x14,0xA1,0x00,0xC8,0xDA,0x02,0x81,0xCF,0xD9,0xF1, 0xDB,0x30,0xA4,0xA6)

gosub sendtodisplay			        ; send 4 blank lines to clear display
let displaybank = 0			        ; flag rows 0-3 for display
hi2cout 0x80,(0xAF)			        ; turn display on


main:
; Insert your programme code here and then poke 28-91 with message to be displayed

poke 28," ","T","H","I","S"," ","I","S"," ","A"," ","T","E","S","T"," ";data to send to display (4 * 16)
poke 44,"O","F"," ","T","H","E"," ","O","U","T","P","U","T"," ","T","O"
poke 60,"T","H","E"," ","O","L","E","D"," ","D","I","S","P","L","A","Y"
poke 76,"F","R","O","M"," ","A","N"," ","0","8","M","2"," ","P","I","C"

displaybank = 1 - displaybank		; toggle lines to display
gosub sendtodisplay			        ; load message to display memory and point display at it

; Insert any further code you require here

goto main

sendtodisplay:				                                ; sends characters in memory locations 28-91 to the display
for counter = 28 to 91
	PEEK counter, fontlookup				        ; load character to output
	select case fontlookup
		case 48 to 57					        ; 0-9
			fontlookup = fontlookup - 48 * 5
		case 65 to 90					        ; A-Z
			fontlookup = fontlookup -65 * 5 + 50
		case 97 to 122					        ; a-z output as A-Z
			fontlookup = fontlookup - 97 * 5 + 50
		else
			fontlookup = 244	; all other characters will display a blank
	endselect					
	hi2cout 0x40,(0)			; one blank column
	for subcounter = 0 to 4
		read fontlookup, pixels		
		hi2cout 0x40,(pixels)		; followed by 5 columns per character
		fontlookup = fontlookup + 1
	next subcounter
	hi2cout 0x40,(0,0)			; two blank columns
next counter					; this completes the 8x8 character output
If displaybank = 0 then
	hi2cout 0x80,(0x40)			; point display to lines 0-3 of display memory
	else hi2cout 0x80,(0x60)		; point display to lines 4-7 of display memory
Endif
return
This is my first attempt at Picaxe programming, so any pointers to improve the way I've gone about it would be greatly appreciated and I hope it is of some use!
 
Last edited:
  • Like
Reactions: mrm

stan74

Senior Member
Although it says its 128 * 64, the display is actually 128 * 32 but the display memory holds 128 * 64. As each byte is written to the display memory it appears on screen so the display builds as it is sent. To avoid this, you can point the display to start at a specific memory location and as there is exactly enough memory for 2 screens of data you can write the message to the unused block and then point the display to it for instant update.
The display is 1024 bytes and every byte sent appears on the display 8 lines of 128 bytes.
Do you mean
hi2cout (0,SSD1306_PAGEADDR)
hi2cout (0,0) ;set row=0
hi2cout (0,7)
;
hi2cout (0,SSD1306_COLUMNADDR)
hi2cout (0,0) ;set column=0
hi2cout (0,127)
If you have 1K ram you can write to a buffer then send that to the screen or plot points by or-ing bytes in the buffer. I posted stuff here. There's a game in audio/visual projects-oled tron and code since you have the same display.
 
Last edited by a moderator:

paraglider_nut

New Member
I must be missing something! If you follow the link (which isn't displaying, but I can follow it on a windows PC) to a photo of the display with the message in the programme, it is 16 characters wide and 4 characters deep and as each character is 8*8, isn't that 128 * 32?
 

julianE

Senior Member
paraglider_nut, thanks for the effort and sharing the code, I was able to get it working and am now able to display a count on the oled. I still need to understand all the intricacies but everything is there I just have to read and experiment. Again, thank you, if I lived to be a 100 I could not have written what you and Stan74 have done.
 

stan74

Senior Member
They are neat oleds. I found a bug in my not picaxe compiler that stops readadc working on ardweeny thing so they sent me the build to come and I posted this vid to show an Italian vs Chinese dweeny. If you throw enough speed at it,it performs.. a scope with 10 lines of basic. Not picaxe but relevent to this oled. similar results with picaxe but my ubiquitous plot code runs almost instant.
https://www.youtube.com/watch?v=3SJO1mT-pjg&feature=youtu.be
Code:
dir portc.0 in
dim volt as byte
dim xpos as byte
dim buffer1 (128)
dim buffer2 (128)
;
for xpos=0 to 127
  volt = READAD (an0)
  buffer1 (xpos)=volt/4
  buffer2 (xpos)=volt/4
next xpos
;
GLCDCLS
main:
for xpos=0 to 127
  pset xpos,buffer1(xpos),0 ;erase old data
  pset xpos,buffer2(xpos),1 ;plot new data
next xpos
;
for xpos=0 to 127
  buffer1 (xpos)=buffer2 (xpos) ;copy new data to old data
  volt = READAD (an0)
  buffer2 (xpos)=volt/4 ;save new data
next xpos
;
goto main
 

stan74

Senior Member
I must be missing something! If you follow the link (which isn't displaying, but I can follow it on a windows PC) to a photo of the display with the message in the programme, it is 16 characters wide and 4 characters deep and as each character is 8*8, isn't that 128 * 32?
It's up to you how many bytes/char you use. You can look at the oled code I posted and somewhere is the original link to a on a plate 28x2 128x64 oled print stuff example. Since 28x2 got 1K ram same as oled Hippy and others helped convert Bresenham's (although he din't invent it) line draw algo. Happy days. lots of hard sums but safe and help yourself to the hard work init? The control codes are what you need and they're there....for all the thanks I got. The oled tron is a good example of what's possible and just using the plot calc if you have 28x2 can do a scope thing to check your picaxe pins state albeit not a real scope but a bit of fun. Get your 3 quids worth is my moto..fnarr
 

stan74

Senior Member
Remember..if you write a byte to the oled it will send the next byte to the byte after the last so the row column controls are useful. you prob know send 0 then code or for data 64 then byte. When you figure it,it's interesting what you can do...think space invaders optimistic though :) have fun,@stan74
 

barneydog

Member
Hi,

Been looking into displays and this thread has regenerated my ideas for it. What I would like to achieve is the ability to draw a certain image that changes when certain things happen.

I have tried reading the info in the links and everywhere else just seem to get myself more confused.

this is what I would like to display http://www.how-to-draw-cartoons-online.com/image-files/r2d2-8.gif

and as certain conditions are met, the graphic could then be changed.

any help and pointers are much appreciated.

Just reading somewhere else that I can convert a bitmap image into a hex file. Would this work ?

I don't have the display yet so cant test anything, so its information gathering at the moment.

Code:
Instead of this 

poke 28," ","T","H","I","S"," ","I","S"," ","A"," ","T","E","S","T"," "; data to send to display (4 * 16)
poke 44,"O","F"," ","T","H","E"," ","O","U","T","P","U","T"," ","T","O"
poke 60,"T","H","E"," ","O","L","E","D"," ","D","I","S","P","L","A","Y"
poke 76,"F","R","O","M"," ","A","N"," ","0","8","M","2"," ","P","I","C"

could I do this for example

poke 28, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
poke 44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
poke 60, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
poke 76, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

on the real bitmap it wouldn't be all 0xFF be different codes to draw the graphic.
 
Last edited:

stan74

Senior Member
get graph paper and a grid 128x64 and draw it from the left edge, top.
then then from top left corner to right are rows of bytes vertical.
then the next row of your android
then the next row
the vertical dots in the bytes are the values of the byte ie top pixel=1 next 2 next 4 so add them up
you set the cursor position then write top row of bytes
you move the cursor and write second row of bytes
and again until image is written
you would have the bytes values read from a table
If I got a mo I'll post some code.
 

barneydog

Member
I had a play around, made an excel document into graph paper number top line 1 - 128 and going down 1 - 64.

I did the graphic and then thought to myself to save some space why not add some options next to the graphics, then on the actual panel could place buttons corresponding to the option on the screen. Here it is for you to look at and see what I mean rather than my terrible description.

Its in onedrive on live.co.uk, sorry for the strange link, if you have any issues I can try placing it somewhere else

https://1drv.ms/x/s!Am5M0LOL7vHVjnQxCoaIFpIyT27M
 

stan74

Senior Member
Get the image on screen,press prt sc,open paint,click paste-top left,click file-save as, attatch image in reply.
08m2 has little code memory and sending an image from it seems a lot of code.You don't send spaces just defined bytes.
Code:
hi2cout (0,0x22) ;SSD1306_PAGEADDR Page 0-7 represents line
hi2cout (0,3) ;set row=3 ;0 means control code to follow
hi2cout (0,7) ;control code
;
hi2cout (0,0x21) :SSD1306_COLUMNADDR
hi2cout (0,0) ;set column
hi2cout (0,127) ;control code
;
hi2cout (64,your_byte) ;64 means data to follow
if next byte is on same line then hi2cout (64,your_byte)
use as a subroutine maybe and a table of row-column-byte data
 
Last edited:

barneydog

Member
thanks for the code.

now if I understand what your saying

Code:
hi2cout (0,0x22) ; This is setting the type of display I'm using
hi2cout (0,3) ; This is setting me to row 3, if I changed it to (0,56) I would get row 56
hi2cout (0,7) ; I have no idea what this is meaning

hi2cout (0,0x21) :SSD1306_COLUMNADDR
hi2cout (0,0) ; This is setting the column to 0, if I changed it to (0,47) I would get column 47
hi2cout (0,127) ;Once again no idea what this means
;
hi2cout (64,your_byte) ;64 means data to follow, so would this be (64, 0xFF) or what would be in the byte
if next byte is on same line then hi2cout (64,your_byte)

so to send multiple bytes to the same 

hi2cout (0,0x22) ; set my display
hi2cout (0,4) ; set row=4
hi2cout (0,7) ; control 

hi2cout (0,0x21) ; set my column
hi2cout (0,1) ; set column=1
hi2cout (0,127) ; control

hi2cout (64, 0x34) ; my first byte
hi2cout (64, 0x44) ; second byte
Then I would repeat this until the row is populated how I want it. Then onto the next row.
Don't suppose you have a list of the control codes, or somewhere I can get them. Going to read up on the hi2cout command tomorrow, and try finding out every command I can send from it. Think I may need a bit bigger than a 08m2.

I really appreciate all your help.
 

stan74

Senior Member
#define SSD1306_SETCONTRAST 0x81
#define SSD1306_DISPLAYALLON_RESUME 0xA4
#define SSD1306_DISPLAYALLON 0xA5
#define SSD1306_NORMALDISPLAY 0xA6
#define SSD1306_INVERTDISPLAY 0xA7
#define SSD1306_DISPLAYOFF 0xAE
#define SSD1306_DISPLAYON 0xAF

#define SSD1306_SETDISPLAYOFFSET 0xD3
#define SSD1306_SETCOMPINS 0xDA

#define SSD1306_SETVCOMDETECT 0xDB

#define SSD1306_SETDISPLAYCLOCKDIV 0xD5
#define SSD1306_SETPRECHARGE 0xD9

#define SSD1306_SETMULTIPLEX 0xA8

#define SSD1306_SETLOWCOLUMN 0x00
#define SSD1306_SETHIGHCOLUMN 0x10

#define SSD1306_SETSTARTLINE 0x40

#define SSD1306_MEMORYMODE 0x20
#define SSD1306_COLUMNADDR 0x21
#define SSD1306_PAGEADDR 0x22

#define SSD1306_COMSCANINC 0xC0
#define SSD1306_COMSCANDEC 0xC8

#define SSD1306_SEGREMAP 0xA0

#define SSD1306_CHARGEPUMP 0x8D

#define SSD1306_EXTERNALVCC 0x01
#define SSD1306_SWITCHCAPVCC 0x02

' Scrolling #defines
#define SSD1306_ACTIVATE_SCROLL 0x2F
#define SSD1306_DEACTIVATE_SCROLL 0x2E
#define SSD1306_SET_VERTICAL_SCROLL_AREA 0xA3
#define SSD1306_RIGHT_HORIZONTAL_SCROLL 0x26
#define SSD1306_LEFT_HORIZONTAL_SCROLL 0x27
#define SSD1306_VERTICAL_AND_RIGHT_HORIZONTAL_SCROLL 0x29
#define SSD1306_VERTICAL_AND_LEFT_HORIZONTAL_SCROLL 0x2A
 

stan74

Senior Member
You'd be better off with an eeprom and send the image from windows with the ubiquitous free program to the 08m2 with serial and then store it..maybe
 

paraglider_nut

New Member
Barneydog,

I have saved a modified version of your excel spreadsheet here:

https://dl.dropboxusercontent.com/u/17449132/OLED%20128%20x%2064%20sample%20graphic%20trimmed.xls

I've added a macro to turn the 1's and 0's that generate the picture into Bytes that can be sent to the display. There's also a 2nd macro that looks for consecutive Bytes that are the same and it wraps them up in a for-next loop to get the size down. Even then, the resulting data is too large the the 08M2, so I modified the image a bit to further reduce the size and the code below will display the modified graphic, but it doesn't leave much room for your programme code! You could use the modified spreadsheet to produce a trimmed down graphic that suits your needs and (hopefully) leaves enough room for the other code.

https://www.dropbox.com/s/lb8eqvi65f9ak67/OLED%20with%20graphic.txt?dl=0

As Stan74 says, eeprom may be the better way forward!
 

stan74

Senior Member
If the image is symmetrical,ie the same parts of image repeated, then write 1/2 or 1/4 then copy it to other part of screen. Like draw a 1/4 of a dartboard then copy and write in different order the other 3/4....maybe.
nice code paraglider_nut. There's a buffer size command, mines set to 32 and write12c (64,x,x,x,x,x,x,x,x,x) works but hi2cout (64,x,x,x,x,x,x,x,x) doesn't
Here's one I made earlier https://youtu.be/iVNaNDmBrE0
 
Last edited:

hippy

Technical Support
Staff member
write12c (64,x,x,x,x,x,x,x,x,x) works but hi2cout (64,x,x,x,x,x,x,x,x) doesn't
That is inexplicable as WRITEI2C and HI2COUT are synonyms and generate the exact same code in the compiler. There must be something else going on.
 

Buzby

Senior Member
Why does one have 9 'x's , and the other 8 ?

And shouldn't the 64 be outside the paranthesis ?
 

hippy

Technical Support
Staff member
And shouldn't the 64 be outside the paranthesis ?
If a register address then technically yes, and we would recommend putting it outside, but that is mostly convention, makes it easier to read, and makes it more understandable as to what that represents. The actual data bit stream output for "HI2COUT 64,(x)" and HI2COUT (64,x)" will be the same.

For a device which has more than 256 register or location addresses the recommendation and practice of putting that address outside is even more applicable. That allows the address to be specified as a single numeric or word variable before the parenthesis, rather than two separate byte values or variables inside the parenthesis.

Always putting the register or location address outside the parenthesis provides consistence.
 

stan74

Senior Member
"Why does one have 9 'x's , and the other 8 ?" just an example Buzby. In another thread hippy and others were trying to speed up code for this oled for me like to coppy a buffer to the oled screen
for ptr=0 to 1023 ;you're really sending 2048 bytes which slows stuff
hi2cout (64,@ptr)
next ptr
changed to
hi2cout (64,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc)
it didn't work and I was scratching my head.
The original code I used for info used writei2c (64,x,x,x,x,x,x,x,x) to init lcd and also to clear the screen. suck it and see if you don't believe me.
;Writei2c (0x40, 0x00, 0x07, 0x00, 0x07, 0x00)
;Writei2c (0x40, 0x14, 0x7F, 0x14, 0x7F, 0x14)
;Writei2c (0x40, 0x24, 0x2A, 0x7F, 0x2A, 0x12)
;Writei2c (0x40, 0x23, 0x13, 0x08, 0x64, 0x62)
;Writei2c (0x40, 0x36, 0x49, 0x56, 0x20, 0x50) ;used to display char set on screen
it might be the buffer size reg SYMBOL TWI_BUFFER_LENGTH=32 but can't find reference to this
 

Buzby

Senior Member
...

for ptr=0 to 1023 ;you're really sending 2048 bytes which slows stuff
hi2cout (64,@ptr)
next ptr

changed to

hi2cout (64,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc)
it didn't work and I was scratching my head ....
Those two chunks of code do completely different things :-

for ptr=0 to 1023
hi2cout (64,@ptr) ''''' This code gets 1024 values from @ptr, and puts them all into address 64, one after the other.
next ptr

hi2cout (64,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc,@ptrinc) ' This code should work. Did you preset ptr before using the @ptrinc instructions ?

I've not got an OLED, but I can see what the code does.

Cheers,

Buzby
 

stan74

Senior Member
Hi Buzby. 64 means data is to follow...see previous post and it seems only one byte.
the code above send the 1024 bytes of 28x2 ram to oled screen ram
;set screen ram start see previous post
ptr=0
do until ptr=1024
hi2cout (64,0) ;send 0 to screen ram
inc ptr
loop
this will clear the oled screen.......buy one,they're fun
 

stan74

Senior Member
In case you consider these oleds, the screen is just 1k ram. you can't poke it,you write bytes. Some are control codes and control data, the rest is data you send. write a screen location and the byte appears on the screen ie 1 is a pixel so is 128,3 is 2 pixel,255 is 8 pixels.
the screen is memory mapped so from x and y vars a few lines of code gives a xy pixel position and the byte value ie which bit in screen byte is the pixel
say you want to plot 2 pixels. if you send 1 then the next is in the same screen byte,it will erase the 1st
so we use a 1k buffer which is mapped the same as the oled screen and send our pixel there but we or (add) it so it doesn't erase the pixel already there, then we send that byte to the screen
simple
ps
for ptr=0 to 1023
hi2cout (64,@ptr) ''''' This code gets 1024 values from @ptr, and puts them all into address 64, one after the other.
next ptr
When you send a byte to the screen it increments it's pointer to the next byte so 1024 bytes will clear the screen. Look at any oled vids I've posted and you can see! the screen clearing
sample code
Code:
ClearDisplay: ;clears oled screen
hi2cout (0,SSD1306_PAGEADDR)
hi2cout (0,0) ;set row=0
hi2cout (0,7)
;	
hi2cout (0,SSD1306_COLUMNADDR)
hi2cout (0,0) ;set column=0
hi2cout (0,127)
;
for ptr=0 to 1023
	hi2cout (64,0)
next 
return
;
plot2screenram:
pixel=py and 7
ptr=py and $F8<<4 Or px
@ptr=1<<pixel Or @ptr ;in buffer
;
let row=py>>3
hi2cout (0,SSD1306_PAGEADDR)
hi2cout (0,row)
hi2cout (0,7)
hi2cout (0,SSD1306_COLUMNADDR)
hi2cout (0,px)
hi2cout (0,127)
hi2cout (64,@ptr) ;oled screen byte
return
Ps again I forgot to say these oleds are write only so you can't play with screen ram. oleds with bigger screens and loads more pixels can be read so you don't need a picaxe with a buffer
 
Last edited:

barneydog

Member
wow you guys have been busy!!! lots and lots of information thank you all so much.

I think its time to go read everything previous again and all the new stuff.

One thing comes to mind; the 8x8 font that was created in the spreadsheet.

Instead of getting the image drawn on the screen like we have previously suggested, but taking out characters I don't need from the font list and replacing them with bits of the images, that when displayed together they would create the image. For example lets say the up arrow fits into Z character, leaving it to be called when Z is sent, but it displays the arrow instead.

Is this possible or am I making more work for myself, if this would work would it save lots of precious ram and avoid any additional components being added.

Thank you again, I really appreciate all your help
 

paraglider_nut

New Member
Barney dog,

I think that may be a good way to get what you want. To make life easier, you can design the layout so that it aligns with the 8 rows * 8 bits per row. For bigger graphics you could spread them across 2 or 4 font slots. This should save a lot of memory where a graphic is repeated, like the arrows. As Stan suggests in post #21 you could also flip the characters vertically or horizontally to get (for example) down arrows.
 

stan74

Senior Member
It looks hard but other people code does to me. Pretty basic BASIC,no functions or macros. 32 samples.It draws from 1 sample to the next and is slower than plotting 128 samples cos drawing the lines takes time. Like all moving graphics,do the calcs then erase/redraw so you don't see the gaps. I originally erased the whole line then redrew it but this code erases and redraws the line between 2 samples then the next and so on. but it's fast enough you can't really see the difference just different strobeing effect. It's not on picaxe.
Code:
#chip mega328p,16 ;plot samples
#option explicit
#include <UNO_mega328p.h>
#include <glcd.h>
#define HI2C_BAUD_RATE 400
#define HI2C_DATA
HI2CMode Master
#define GLCD_TYPE GLCD_TYPE_SSD1306
#define GLCD_I2C_Address 0x78
#define ADSpeed LowSpeed
;
dir portc.0 in
dim volt as byte
dim xpos as byte
dim buffer1 (128)
dim buffer2 (128)
;
for xpos=0 to 127 ;init read 128 samplesc 1st time
  volt = READAD (an0)
  buffer1 (xpos)=volt/4
  buffer2 (xpos)=volt/4
next xpos
;
glcdcls
;draw grid
line 0,31,128,32
line 63,0,63,63
;
for xpos=0 to 127
  pset xpos,buffer1(xpos),1 ;plot data 1st time for xor
next xpos
;
;start
do
for xpos=0 to 127
  pset xpos,buffer1(xpos),1 ;erase old data
  pset xpos,buffer2(xpos),1 ;plot new data
next xpos
;
for xpos=0 to 127
  buffer1 (xpos)=buffer2 (xpos) ;copy new data to old data
  volt = READAD (an0)
  Repeat 2
    set c off
    rotate volt right
  End Repeat
 buffer2 (xpos)=volt ;save new data
next xpos
;
loop
;------------------------------------------------
;display repetative wave forms on 128x64 oled i2c display with vectors
#chip mega328p,16
#option explicit
#include <UNO_mega328p.h>
#include <glcd.h>
#define HI2C_BAUD_RATE 400
#define HI2C_DATA
HI2CMode Master
#define GLCD_TYPE GLCD_TYPE_SSD1306
#define GLCD_I2C_Address 0x78
#define ADSpeed LowSpeed
;
dir portc.0 in
dim volt as byte
dim ptr1 as Byte
dim ptr2 as byte
dim buffer1 (32)
dim buffer2 (32)
dim xpos_new as byte
dim ypos_new as byte
dim xpos_old as byte
dim ypos_old as byte
dim xpos1_new as byte
dim ypos1_new as byte
dim xpos1_old as byte
dim ypos1_old as byte
;
for ptr1=0 to 31 ;read 32 samples
  volt = READAD (an0)
  buffer1 (ptr1)=volt/4
  buffer2 (ptr1)=volt/4
next ptr1
;
GLCDCLS
do
ptr1=0
ptr2=0
do until ptr1>30
ypos_old=buffer2 (ptr1) ;old data
ypos_new=buffer2 (ptr1+1)
xpos_old=ptr2
xpos_new=ptr2+4
;
ypos1_old=buffer1 (ptr1) ;new data
ypos1_new=buffer1 (ptr1+1)
xpos1_old=ptr2
xpos1_new=ptr2+4
;
line xpos_old,ypos_old,xpos_new,ypos_new,0 ;erase last data
line xpos1_old,ypos1_old,xpos1_new,ypos1_new,1 ;draw new data
;
ptr1=ptr1+1 ;data pointer
ptr2=ptr2+4 ;x position for start and end line x positions
loop
;
for ptr1=0 to 31 ;get new samples
  volt = READAD (an0)
  repeat 2 ;scale 256 bit sample to 64 pixels ie divide by 4
    set c off
    rotate volt right
  End Repeat
  buffer2 (ptr1)=buffer1 (ptr1) ;new data to old data
  buffer1 (ptr1)=volt ;update new data
next ptr1
;
loop
I posted this in audio/visual and it's my plot/line on picaxe. It draws the sine wave from a table. See how slow it is? https://www.youtube.com/watch?v=gGenryUZBa4
Code:
sine:
eeprom 46, (34,40,46,50,54,58,60,62,62,60,58,54,50,46,40,34,28,22,18,14,10,8,6,6,8,10,14,18,22,28,34)
x1=0
read 46,y1:y1=y1/2
for temp2=1 to 2
for temp1 = 47 to 76
read temp1,y2
y2=y2/2
x2=x1+2
gosub xorline
x1=x2
y1=y2
next temp1
next temp2
return
I posted this for julianE 08m2 light meter and the code and it looks posh with no code on picaxe. You just need imagination like cave wall drawings. https://www.youtube.com/watch?v=9W4wRA9Q01I
 
Last edited:

tecnition_ted

New Member
Hi Every one I have followed this thread and my display works great using the code example I have added extra messages (easy bit) but cant seem to add any extra characters. I am using this to experiment to learn more and still haven got to grips with how its operating. I understand loading characters into picaxe memory then sending each pixel strip piece by piece to the display memory then reveling the completed message (hope I have that right) just cant work out
how to re jig the fontlookup part can anyone point me in the right direction?

PS. many thanks for this paraglider_nut i wouldn't have known where to start been using blockie too long and need to get into some proper programming.
 

hippy

Technical Support
Staff member
just cant work out how to re jig the fontlookup part can anyone point me in the right direction?
Looking at the code in post #1 I would guess that's a three step process. First add a new character bitmap definition for display. After "eeprom 175, ..." add -
Code:
eeprom 180, ($40,$80,$AD,$A0,$60) ; "?"
That should I think create a question mark which looks like this ...
Code:
.111.
1...1
....1
..11.
..1..
.....
..1..
.....
It might end up upside down or facing the wrong way. Don't worry about that for now.

Then add something which allows that character to be put to the screen. After the "case 97 to 122 ... fontlookup = ..." add -
Code:
Case "?" : fontlookup = 180
Then in one of your messages put a question mark in and see what shows on the screen.
 

tecnition_ted

New Member
Thank you for your help I was able to add 1 character by adding to the code eeprom 180,(8,28,42,8,8)
case 97 to 123
But when I tried to add another by changing case 97 to 124 it all went a bit hieroglyphic on the screen; I don't understand what this bit is doing i understand it is looking at the font table but is it 97 x 5 + 50 and if so why? (fontlookup = fontlookup - 97 * 5 + 50
I also tried adding another line after adding eeprom 180,(8,28,42,8,8)
case 123 to 130
fontlookup = fontlookup - 123 * 5 + 50

And nothing happened
I have a lot to learn very different from 6502 processor programming
 

hippy

Technical Support
Staff member
What is being done is to map ASCII character codes to EEPROM addresses, where each character occupies five consecutive EEPROM addresses. The code is a little confusing because it uses decimal numbers rather than actual ASCII characters.

That Case 97 To 122 actually represents Case "a" To "z" converts those to the character bitmaps stored from EEPROM location 50 upwards. That -
Code:
Select Case fontlookup 
  Case 97 To 122
    fontlookup = fontlookup - 97 * 5 + 50
Would probably be better represented as -
Code:
Select Case asciiValue
  Case "a" To  "z"
    eepromAddress = asciiValue - "a" * 5 + EEPROM_ADDRESS_OF_BITMAP_FOR_A
If you extend that 122 / "z" further, to 123 / "{" or 124 / "|", those are the characters you will be checking with that case clause, those will be the new characters you can now use when outputting text, and the display bitmap for those characters will need to appear after those for "Z", at EEPROM address 180, then 185.

What you really need to decide is what characters you want to add into your output display, create bitmaps for those characters in EEPROM, then add a new CASE clause for those, perhaps multiple clauses, to map the ASCII character value to the EEPROM location of that character.

If you want to add characters 123 to 130 then you would use -
Code:
Eeprom 180, (....) ; Bitmap for character with ASCII Value 123
Eeprom 185, (....) ; Bitmap for character with ASCII Value 124
Eeprom 190, (....) ; Bitmap for character with ASCII Value 125
Eeprom 195, (....) ; Bitmap for character with ASCII Value 126
Eeprom 200, (....) ; Bitmap for character with ASCII Value 127
Eeprom 205, (....) ; Bitmap for character with ASCII Value 128
Eeprom 210, (....) ; Bitmap for character with ASCII Value 129
Eeprom 215, (....) ; Bitmap for character with ASCII Value 130
Code:
Case 123 To 130
  fontlookup = fontlookup - 123 * 5 + 180
You can test that, assuming a 130 ASCII value ...

130 - 123 = 7
7 * 5 = 35
35 + 180 = 215

And that 215 is the EEPROM address of where the bitmap for ASCII character of value 130 is.

It should have been the same if you had extended the CASE from "97 TO 122" to "97 TO 130" and kept the existing "+ 50", provided you had added those EEPROM definitions at 180 onwards. That it did not work suggests some mistake was made along the way, or the bitmap definitions were not correct.

130 - 97 = 33
33 * 5 = 165
165 + 50 = 215
 

tecnition_ted

New Member
Thank you for all your help with this.
It has been a while since I played with it. I am wondering if you can assist further, I may be barking up the wrong tree here using this type of code to do what I want but cant get any working results taking paraglider_nut's code apart. Writing direct i2c to the oel screen with ascii characters doesn't work.
I believe it is due to the oel not having any character mapping so each character has to be built by the controller.

The project has moved on to trying to display information retrieved from a battery management chip and display the results on the oel screen.
The BMS chip is a BQ7541 data into b10,11,12,13 is all correct and is shown correctly when debugged and w5 & w6 are viewed in decimal
I have attached a picture of both the battery management results and the picaxe results.
This may be of interest to others as I am monitoring the battery I am using to run the project and was lucky enough to get my hands on a EV2300

I am trying to print a word onto the screen using this program from a w0. I think w0 first needs to be converted from hex to decimal then placed into the poke statement so it can be accessed by the lookup and turned into character's that can be shown on the oel.
I have looked everywhere for Hippy's hex converter code and have tried just displaying the hex info on the oel without any joy Im a bit stuck.

there is two problems I have (besides me being rubbish at math's)
1 need to be able to show w5 and w6 on the oled
2 need to convert the hex value in w5 and w6 to decimal so it shows as as the actual value

Thank you for any assistance

CODE:
symbol counter = w0
symbol subcounter = b2
symbol fontlookup = b3
symbol pixels = b4
symbol displaybank = b5
symbol Volt = w5
symbol SOC = w6

; save Font codes in EEPROM

eeprom 0,(124,130,130,130,124) ; 0 (ASCII 48)
eeprom 5,(136,132,254,128,128) ; 1
eeprom 10,(196,162,162,146,140) ; 2
eeprom 15,(68,130,146,146,108) ; 3
eeprom 20,(48,40,36,254,32) ; 4
eeprom 25,(110,138,138,138,114) ; 5
eeprom 30,(124,146,146,146,100) ; 6
eeprom 35,(2,2,2,2,254) ; 7
eeprom 40,(108,146,146,146,108) ; 8
eeprom 45,(30,18,18,18,254) ; 9 (ASCII 57)
eeprom 50,(254,18,18,18,254) ; A (ASCII 65)
eeprom 55,(254,146,146,146,108) ; B
eeprom 60,(254,130,130,130,130) ; C
eeprom 65,(254,130,130,68,56) ; D
eeprom 70,(254,146,146,146,130) ; E
eeprom 75,(254,18,18,18,2) ; F
eeprom 80,(254,130,130,146,242) ; G
eeprom 85,(254,16,16,16,254) ; H
eeprom 90,(130,130,254,130,130) ; I
eeprom 95,(226,130,254,2,2) ; J
eeprom 100,(254,16,40,68,130) ; K
eeprom 105,(254,128,128,128,128) ; L
eeprom 110,(254,2,254,2,254) ; M
eeprom 115,(254,4,56,64,254) ; N
eeprom 120,(254,130,130,130,254) ; O
eeprom 125,(254,18,18,18,12) ; P
eeprom 130,(124,130,162,66,188) ; Q
eeprom 135,(254,18,50,82,140) ; R
eeprom 140,(222,146,146,146,246) ; S
eeprom 145,(2,2,254,2,2) ; T
eeprom 150,(126,128,128,128,126) ; U
eeprom 155,(30,96,128,96,30) ; V
eeprom 160,(254,128,254,128,254) ; W
eeprom 165,(198,40,16,40,198) ; X
eeprom 170,(6,8,240,8,6) ; Y
eeprom 175,(194,162,146,138,134) ; Z (ASCII 90)


initialise:
; initialise i2c for display (ID 0x78) and then send power up instructions

hi2csetup i2cmaster,%01111000,i2cfast,i2cbyte
hi2cout 0x80,(0xAE,0x00,0x00,0xB0,0x20,0x00,0xD5,0x80,0xA8,0x1F,0xD3,0x00,0x8D, _
0x14,0xA1,0x00,0xC8,0xDA,0x02,0x81,0xCF,0xD9,0xF1, 0xDB,0x30,0xA4,0xA6)

gosub sendtodisplay ; send 4 blank lines to clear display
let displaybank = 0 ; flag rows 0-3 for display
hi2cout 0x80,(0xAF) ; turn display on


main:
; Insert your programme code here and then poke 28-91 with message to be displayed

poke 28,w5,w6 ;data to send to display (4 * 16)
poke 44," "," ","V","o","l","t"," "," "," "," "," "," "," "," "," "," "
poke 60," "," ","S","o","c"," "," "," "," "," "," "," "," "," "," "," "
poke 76," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "," "

displaybank = 1 - displaybank ; toggle lines to display
gosub sendtodisplay ; load message to display memory and point display at it

; Insert any further code you require here
i2cslave 0xAA, i2cfast, i2cbyte ; set PICAXE as master and DS1307 slave address

readi2c 0x08,(b10) ; Read data from eeprom
readi2c 0x09,(b11) ; Read data from eeprom
pause 10
readi2c 0x2c,(b12) ; Read SOC from eeprom
readi2c 0x2d,(b13) ; Read SOC from eeprom

debug ; Show result


goto main

sendtodisplay: ; sends characters in memory locations 28-91 to the display
for counter = 28 to 91
PEEK counter, fontlookup ; load character to output
select case fontlookup
case 48 to 57 ; 0-9
fontlookup = fontlookup - 48 * 5
case 65 to 90 ; A-Z
fontlookup = fontlookup -65 * 5 + 50
case 97 to 122 ; a-z output as A-Z
fontlookup = fontlookup - 97 * 5 + 50

else
fontlookup = 244 ; all other characters will display a blank
endselect
hi2cout 0x40,(0) ; one blank column
for subcounter = 0 to 4
read fontlookup, pixels
hi2cout 0x40,(pixels) ; followed by 5 columns per character
fontlookup = fontlookup + 1
next subcounter
hi2cout 0x40,(0,0) ; two blank columns
next counter ; this completes the 8x8 character output
If displaybank = 0 then
hi2cout 0x80,(0x40) ; point display to lines 0-3 of display memory
else hi2cout 0x80,(0x60) ; point display to lines 4-7 of display memory
Endif
return
 

Attachments

hippy

Technical Support
Staff member
With the numbers in 'volt' and 'soc' being correct when shown in decimal using DEBUG, one way to output them would be to use BINTOASCII and then POKE the resultant character bytes to memory. An alternative is to do that long-hand so it only requires one extra byte vriable, 'bTmp'...
Code:
bTmp = volt / 1000 // 10 + "0" : Poke ??, bTmp
bTmp = volt / 100  // 10 + "0" : Poke ??, bTmp
bTmp = volt / 10   // 10 + "0" : Poke ??, bTmp
bTmp = volt        // 10 + "0" : Poke ??, bTmp
You will have to create a SYMBOL for 'bTmp' and the '??' are whatever locations you need to POKE into the display RAM. Similar for 'soc'.
 
Top