|
Forum Index : Microcontroller and PC projects : MM2(+): TM1637 7-segment clock display
| Author | Message | ||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10572 |
If you want a cheap and cheerful clock display you can't get cheaper than this These displays use the TM1637 controller which has a i2c-like interface (pullups required on the clock and data leads) The attached code drives this display using simple bit-banging from Basic (not a CFunction in sight) option explicit option default none dim digittosegment%(15)=(&H3F,&H06,&H5B,&H4F,&H66,&H6D,&H7D,&H07,&H7F,&H6F,&H77,&H7C,&H39,&H47,&H79,&H71) dim integer m_brightness 'holds the brightness value for the display 0-15 are valid DIM INTEGER displaydata(3)=(0,0,0,0) 'holds the bit values of the segments to be lit, ordered left to right const colon=1 const nocolon=0 const noleadingzeros=1 const leadingzeros=0 const TM1637_I2C_COMM1 = &H40 const TM1637_I2C_COMM2 = &HC0 const TM1637_I2C_COMM3 = &H80 '************************************************************************************************* ' ' Test / demo program ' dim mytime$ length 8 DIM integer j TM1637Init(44,1)' initialise the display using pin 44 for the clock and pin 1 for the data setbrightness(12)' load the brightness into the global variable setsegments(displaydata()) 'displaydata is set to zeroes so clear the display mytime$=time$ pause 1000 timer=0 do if mytime$<>time$ then 'the clock seconds have changed if val(right$(time$,1)) mod 2 then 'flash the colon each second converttime(displaydata(),colon,noleadingzeros) 'set the time into the display array including the colon but no leading zeroes else converttime(displaydata(),nocolon,noleadingzeros)'set the time into the display array without the colon or leading zeroes endif setsegments(displaydata()) 'update the display mytime$=time$ endif loop while timer <60000 'update the time over a minute ' for j=-999 to 1999 step 17 'demo positive and negative numbers without leading zeroes convertnumber(displaydata(),j,noleadingzeros) setsegments(displaydata()) next j for j=-999 to 1999 step 17 'demo positive and negative numbers with leading zeroes convertnumber(displaydata(),j,leadingzeros) setsegments(displaydata()) next j end '************************************************************************************************ sub TM1637Init(pinClk as integer, pinDIO as integer) dim integer m_pinClk,m_pinDIO ' Copy the pin numbers m_pinClk = pinClk m_pinDIO = pinDIO ' Set the pin direction and default value. ' Both pins are set as inputs, allowing the pull-up resistors to pull them up pin(m_pinDIO)=0 pin(m_pinClk)=0 setpin m_pinDIO,DIN setpin m_pinClk,DIN end sub sub setBrightness(brightness as integer) m_brightness = brightness end sub sub setSegments(segments() as integer) local integer k ' Write COMM1 start writeByte(TM1637_I2C_COMM1) stop ' Write COMM2 + first digit address start writeByte(TM1637_I2C_COMM2) ' Write the data bytes for k=0 to 3 writeByte(segments(k)) next k stop ' Write COMM3 + brightness start writeByte(TM1637_I2C_COMM3 + (m_brightness AND &H0f)) stop end sub sub start setpin m_pinDIO, DOUT ' bitDelay end sub sub stop setpin m_pinDIO, dout setpin m_pinClk, DIN setpin m_pinDIO, DIN end sub sub writeByte(b as integer) as integer local integer i,ack,data = b ' 8 Data Bits for i=0 to 7 ' CLK low setpin m_pinClk,dout ' Set data bit if (data and 1) then setpin m_pinDIO,DIN else setpin m_pinDIO,DOUT endif ' CLK high setpin m_pinClk, DIN data = data >> 1 next i ' Wait for acknowledge ' CLK to zero setpin m_pinClk, dout setpin m_pinDIO, DIN ' CLK to high setpin m_pinClk, din ack = pin(m_pinDIO) if (ack = 0) then setpin m_pinDIO, dout endif setpin m_pinClk, dout end sub function encodeDigit(digit as integer) as integer encodeDigit=digitToSegment%(digit and &H0f) end function sub convertnumber(dd() as integer, n as integer, nolead as integer) local integer d(2),m m=abs(n mod 10000) if n<0 then m=abs(n mod 1000) d(0)=(m - (m mod 1000)) d(1)=(m - d(0) - (m MOD 100)) d(2)=(m - d(0) - d(1) - (m mod 10)) dd(3)=encodeDigit(m - d(0) -d(1)- d(2)) dd(0)=encodeDigit(d(0)\1000) dd(1)=encodeDigit(d(1)\100) dd(2)=encodeDigit(d(2)\10) if nolead then if d(0)=0 then dd(0)=0 if d(1)=0 then dd(1)=0 if d(2)=0 then dd(2)=0 endif endif endif if n<0 then if dd(2)=0 then dd(2)=64 else if(dd(1)=0) then dd(1)=64 else dd(0)=64 endif endif endif else IF n<0 then dd(0)= 64 endif end sub sub converttime(dd() as integer, displaycolon as integer, nolead as integer) as integer local integer i=val(left$(time$,2))*100+val(mid$(time$,4,2)) convertnumber(dd(),i,nolead) if displaycolon then dd(1)=dd(1) OR &H80 end sub |
||||
| viscomjim Guru Joined: 08/01/2014 Location: United StatesPosts: 925 |
This is a very cost effective display. I am wondering what the protocol is and why it is different that I2C. Can't find too much data on this one. Thanks for the code, just ordered a couple of these to play with. |
||||
| Nabuky Newbie Joined: 09/07/2019 Location: SpainPosts: 3 |
Hi all, I am a newbie in electronics and I need to adapt this program to handle the TM1637 display from VBA, in which I have experience. Is it crazy? The intention is simple, show on a display the time of the PC with Windows OS. I have it connected through a USB-I2C adapter, CH341A without socket. ![]() The first problem is with the hardware, I need to know if this converter is able to communicate with the TM1637 directly or is another circuit needed? The second problem is with the software, it seems that a link to some library is missing, there are some variables and functions that I am unable to adapt (p.ex. pin (m_pinDIO) = 0, setpin m_pinDIO, din). Can someone give me an idea? All tips are also welcome, even if they involve the use of another display. Thanks in advance. Regards. |
||||
| CaptainBoing Guru Joined: 07/09/2016 Location: United KingdomPosts: 2171 |
Hello Nabuky. welcome to the forum. I hope you are well. matherp's prog above should give you all the registers you need to drive the module. I don't know how much success you going to have doing it directly from a PC to i2c as the module isn't a pure i2c interface. I would be tempted to put something in between e.g. a Micromite Mk2 and issue commands via a com port on your PC with a USB<->serial module. The commands could then be interpreted by your microcontroller to drive the i2c using a modified version of the code above. This isn't as difficult or expensive as you might think and having a microcontroller allows you to have a lot more flexibility and then your VBA can vary it's command set easily - the PC end will be easy to tweak. |
||||
| Bill7300 Senior Member Joined: 05/08/2014 Location: AustraliaPosts: 159 |
I see the eBay link Peter provided now says the sale has ended because the seller had an error in the advertisement - probably the price? Bill Bill |
||||
| PeterB Guru Joined: 05/02/2015 Location: AustraliaPosts: 655 |
If you Google 4 digit 7 segment display or similar, every man and his dog sells them. You may need to look at the Arduino stuff. Peter |
||||
| Nabuky Newbie Joined: 09/07/2019 Location: SpainPosts: 3 |
Thank you for your answers. I'm missing some parameters that I do not know, probably from some library. I would appreciate some additional documentation of the program. This is a main problem. The term "I2C" should not be used if it is not a device that meets the standards or is at least compatible, the TM1637 only uses 7 bits, should be called "I2C-Arduino". My specialty is management software and databases, mainy for bussines. I regret that my knowledge in microcontrollers are so scarce, I can not consider now the development of a solution with them. It is very easy to find other valid links, with acceptable prices. I try to avoid using Arduino. Maybe I'm annoyed with them because of their lack of rigor in the use of the standards. I never imagined that it would be so complicated to show the PC time on an external display. Thanks again. Regards. |
||||
| CaptainBoing Guru Joined: 07/09/2016 Location: United KingdomPosts: 2171 |
Mine too! but my first love is micro electronics. get hold of a small 28 pin micromite unit - there are lots of suppliers here who can sell you a ready to go board for not much $$$. You only need a USB lead to talk to it - really easy - no, really! It will present as a COM port on your PC - no need for your USB <-> i2c module. You can do the whole thing with putty and notepad... no need to load an IDE or anything. With no affiliation and just grabbing a link out of the air for Europe, you have this which is ideal Explore28 or the "keyring" if you can solder and you want to save a few $ (but I wouldn't if I was at the stage you are). If you had the bits, this could be working tonight - This thread contains all the know-how to put it all together and someone has even given you the code! Connect up the display as detailed above, load the code onto the MM and it should immediately(ish?) work. There is a good IDE for MMs though if you are happier with an integrated environment - search this forum for MMEdit - it is a little less hardcore than Putty & Notepad++ Then send "commands" from your PC to the COMx port, augment the above code a little bit at a time to parse those commands and you are pretty much done. You can add more to the code over time to increase the functionality - perhaps flipping between the time and temperature, or supply voltages etc? I really do understand this looks like a black art but it is easy and you can just come back to the forum here if/when you get stuck. Once you have done the first project your head will be buzzing with the next when you realise what a capable little thing the MM is have fun |
||||
| Nabuky Newbie Joined: 09/07/2019 Location: SpainPosts: 3 |
Thank you CaptainBoing. Everything seems very easy when the subject is mastered, it is not my case. Of course I would like to practice with the Explore28, but this should be an optional improvement of the project it has taken up too much time. I think I should postpone this improvement for when the project is already working and I have more time to "play" with the microcontroller. Best regards. |
||||
jman![]() Guru Joined: 12/06/2011 Location: New ZealandPosts: 711 |
@matherp Should this run on the MM(28 pin) after the appropriate pin changes ? I see the PCB's have 10k pull ups fitted and looks like 100pf caps to ground (clock and data). I have a couple of displays but no joy with the supplied code on a 28 pin device. With added pullups still no result. Many thanks Jman |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10572 |
Yes, but no Recent releases of MMbasic releases have tightened up on using reserved words as variable names and my programs used some. Try the attached option explicit option default none dim digittosegment%(15)=(&H3F,&H06,&H5B,&H4F,&H66,&H6D,&H7D,&H07,&H7F,&H6F,&H77,&H7C,&H39,&H47,&H79,&H71) dim integer m_brightness 'holds the brightness value for the display 0-15 are valid DIM INTEGER displaydata(3)=(0,0,0,0) 'holds the bit values of the segments to be lit, ordered left to right const colon=1 const nocolon=0 const noleadingzeros=1 const leadingzeros=0 const TM1637_I2C_COMM1 = &H40 const TM1637_I2C_COMM2 = &HC0 const TM1637_I2C_COMM3 = &H80 '************************************************************************************************* ' ' Test /demo program ' dim mytime$ length 8 DIM integer j TM1637Init(18,17)' initialise the display using pin 44 for the clock and pin 1 for the data setbrightness(15)' load the brightness into the global variable setsegments(displaydata()) 'displaydata is set to zeroes so clear the display j=ds18b20(4)*10 convertnumber(displaydata(),j,noleadingzeros) displaydata(3)=&B01011000 setsegments(displaydata()) 'displaydata is set to zeroes so clear the display mytime$=time$ pause 1000 timer=0 do if mytime$<>time$ then 'the clock seconds have changed if val(right$(time$,1)) mod 2 then 'flash the colon each second converttime(displaydata(),colon,noleadingzeros) 'set the time into the display array including the colon but no leading zeroes else converttime(displaydata(),nocolon,noleadingzeros)'set the time into the display array without the colon or leading zeroes endif setsegments(displaydata()) 'update the display mytime$=time$ endif loop while timer <60000 'update the time over a minute ' for j=-999 to 1999 step 17 'demo positive and negative numbers without leading zeroes convertnumber(displaydata(),j,noleadingzeros) setsegments(displaydata()) next j for j=-999 to 1999 step 17 'demo positive and negative numbers with leading zeroes convertnumber(displaydata(),j,leadingzeros) setsegments(displaydata()) next j end '************************************************************************************************ sub TM1637Init(pinClk as integer, pinDIO as integer) dim integer m_pinClk,m_pinDIO ' Copy the pin numbers m_pinClk = pinClk m_pinDIO = pinDIO ' Set the pin direction and default value. ' Both pins are set as inputs, allowing the pull-up resistors to pull them up pin(m_pinDIO)=0 pin(m_pinClk)=0 setpin m_pinDIO,DIN setpin m_pinClk,DIN end sub sub setBrightness(brightness as integer) m_brightness = brightness end sub sub setSegments(segments() as integer) local integer k ' Write COMM1 sendstart writeByte(TM1637_I2C_COMM1) sendstop ' Write COMM2 + first digit address sendstart writeByte(TM1637_I2C_COMM2) ' Write the data bytes for k=0 to 3 writeByte(segments(k)) next k sendstop ' Write COMM3 + brightness sendstart writeByte(TM1637_I2C_COMM3 + (m_brightness AND &H0f)) sendstop end sub sub sendstart setpin m_pinDIO, DOUT ' bitDelay end sub sub sendstop setpin m_pinDIO, dout setpin m_pinClk, DIN setpin m_pinDIO, DIN end sub sub writeByte(b as integer) as integer local integer i,ack,odata = b ' 8 Data Bits for i=0 to 7 ' CLK low setpin m_pinClk,dout ' Set data bit if (odata and 1) then setpin m_pinDIO,DIN else setpin m_pinDIO,DOUT endif ' CLK high setpin m_pinClk, DIN odata = odata >> 1 next i ' Wait for acknowledge ' CLK to zero setpin m_pinClk, dout setpin m_pinDIO, DIN ' CLK to high setpin m_pinClk, din ack = pin(m_pinDIO) if (ack = 0) then setpin m_pinDIO, dout endif setpin m_pinClk, dout end sub function encodeDigit(digit as integer) as integer encodeDigit=digitToSegment%(digit and &H0f) end function sub convertnumber(dd() as integer,n as integer, nolead as integer) local integer d(2),m m=abs(n mod 10000) if n<0 then m=abs(n mod 1000) d(0)=(m - (m mod 1000)) d(1)=(m - d(0) - (m MOD 100)) d(2)=(m - d(0) - d(1) - (m mod 10)) dd(3)=encodeDigit(m - d(0) -d(1)- d(2)) dd(0)=encodeDigit(d(0)1000) dd(1)=encodeDigit(d(1)100) dd(2)=encodeDigit(d(2)10) if nolead then if d(0)=0 then dd(0)=0 if d(1)=0 then dd(1)=0 if d(2)=0 then dd(2)=0 endif endif endif if n<0 then if dd(2)=0 then dd(2)=64 else if(dd(1)=0) then dd(1)=64 else dd(0)=64 endif endif endif else IF n<0 then dd(0)= 64 endif end sub sub converttime(dd() as integer,displaycolon as integer,nolead as integer) as integer local integer i=val(left$(time$,2))*100+val(mid$(time$,4,2)) convertnumber(dd(),i,nolead) if displaycolon then dd(1)=dd(1) OR &H80 end sub Edited 2019-08-09 00:03 by matherp |
||||
jman![]() Guru Joined: 12/06/2011 Location: New ZealandPosts: 711 |
Hi Thanks for the help. Unfortunately still no go (No errors just no display) I have just tried it with an E100 and same result, could be dodgy modules (all 3 do the same thing) Thanks Jman |
||||
| matherp Guru Joined: 11/12/2012 Location: United KingdomPosts: 10572 |
Looks like the BB is corrupting the listing Try tm1637.zip Connect pin 18 to clk and 17 to dio (28-pin with pullups) Edited 2019-08-09 07:54 by matherp |
||||
TassyJim![]() Guru Joined: 07/08/2011 Location: AustraliaPosts: 6353 |
Lines 148-150 use \ (the backslash). The forum is having problems with the backslash. dd(0)=encodeDigit(d(0)\1000) dd(1)=encodeDigit(d(1)\100) dd(2)=encodeDigit(d(2)\10) It works OK in the preview but not when saving the post I will let Glenn know. Jim Edited 2019-08-09 08:21 by TassyJim VK7JH MMedit |
||||
jman![]() Guru Joined: 12/06/2011 Location: New ZealandPosts: 711 |
Try tm1637.zip Connect pin 18 to clk and 17 to dio (28-pin with pullups) Awesome that did the trick Many thanks Jman |
||||
| The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |