characterlcd.bmx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840
  1. ' Copyright (c) .NET Foundation and Contributors
  2. ' Copyright (c) 2019 Bruce A Henderson
  3. '
  4. ' All rights reserved.
  5. '
  6. ' Permission is hereby granted, free of charge, to any person obtaining a copy
  7. ' of this software and associated documentation files (the "Software"), to deal
  8. ' in the Software without restriction, including without limitation the rights
  9. ' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. ' copies of the Software, and to permit persons to whom the Software is
  11. ' furnished to do so, subject to the following conditions:
  12. '
  13. ' The above copyright notice and this permission notice shall be included in all
  14. ' copies or substantial portions of the Software.
  15. '
  16. ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17. ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18. ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  19. ' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20. ' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21. ' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  22. ' SOFTWARE.
  23. '
  24. SuperStrict
  25. Rem
  26. bbdoc: Character LCDs.
  27. End Rem
  28. Module iot.CharacterLCD
  29. Import iot.core
  30. Import brl.color
  31. Rem
  32. bbdoc: Abstraction layer for accessing the lcd IC.
  33. End Rem
  34. Type TLCDInterface Implements IDisposable Abstract
  35. Field waitMultiplier:Double = 1.0
  36. Field backlightOn:Int
  37. Field eightBitMode:Int
  38. Method SendData(value:Byte) Abstract
  39. Method SendCommand(command:Byte) Abstract
  40. Method SendData(buffer:Byte Ptr, size:Size_T) Abstract
  41. Method SendCommands(buffer:Byte Ptr, size:Size_T) Abstract
  42. Method GetWaitMultiplier:Double()
  43. Return waitMultiplier
  44. End Method
  45. Method SetWaitMultiplier(value:Double)
  46. waitMultiplier = value
  47. End Method
  48. Method IsBacklightOn:Int()
  49. Return backlightOn
  50. End Method
  51. Method SetBacklightOn(value:Int)
  52. backlightOn = value
  53. End Method
  54. Method GetEightBitMode:Int()
  55. Return eightBitMode
  56. End Method
  57. Method WaitForNotBusy(microseconds:Int)
  58. ' TODO
  59. End Method
  60. End Type
  61. Rem
  62. bbdoc: Standard direct pin access to the HD44780 controller.
  63. End Rem
  64. Type TLCDGpio Extends TLCDInterface
  65. Field ReadOnly rsPin:Int
  66. Field ReadOnly rwPin:Int
  67. Field ReadOnly enablePin:Int
  68. Field ReadOnly backlight:Int
  69. Field backlightBrightness:Int
  70. Field lastByte:Byte
  71. Field useLastByte:Int
  72. Field ReadOnly dataPins:Int[]
  73. Field controller:TGpioController
  74. Field pinBuffer:SPinValuePair[8]
  75. Method New(registerSelectPin:Int, enablePin:Int, dataPins:Int[], backlightPin:Int = -1, backlightBrightness:Float = 1.0, readWritePin:Int = -1, controller:TGpioController = Null)
  76. rsPin = registerSelectPin
  77. rwPin = readWritePin
  78. Self.enablePin = enablePin
  79. Self.dataPins = dataPins
  80. backlight = backlightPin
  81. Self.backlightBrightness = backlightBrightness
  82. If dataPins.length = 8 Then
  83. eightBitMode = True
  84. Else If dataPins.length <> 4 Then
  85. Throw New TArgumentException("")
  86. End If
  87. If controller Then
  88. Self.controller = controller
  89. Else
  90. Self.controller = New TGpioController
  91. End If
  92. Initialize()
  93. End Method
  94. Method Initialize()
  95. ' prep the pin
  96. controller.OpenPin(rsPin, EPinMode.Output)
  97. If rwPin <> -1 Then
  98. controller.OpenPin(rwPin, EPinMode.Output)
  99. ' Set to write. Once we enable reading have reading pull high and reset
  100. ' after reading to give maximum performance to write (i.e. assume that
  101. ' the pin is low when writing).
  102. controller.Write(rwPin, EPinValue.Low)
  103. End If
  104. If backlight <> -1 Then
  105. controller.OpenPin(backlight, EPinMode.Output)
  106. If backlightBrightness > 0 Then
  107. ' Turn on the backlight
  108. controller.Write(backlight, EPinValue.High)
  109. End If
  110. End If
  111. controller.OpenPin(enablePin, EPinMode.Output)
  112. For Local i:Int = 0 Until dataPins.length
  113. controller.OpenPin(dataPins[i], EPinMode.Output)
  114. Next
  115. ' The HD44780 self-initializes when power is turned on to the following settings:
  116. '
  117. ' - 8 bit, 1 line, 5x7 font
  118. ' - Display, cursor, and blink off
  119. ' - Increment with no shift
  120. '
  121. ' It is possible that the initialization will fail if the power is not provided
  122. ' within specific tolerances. As such, we'll always perform the software based
  123. ' initialization as described on pages 45/46 of the HD44780 data sheet. We give
  124. ' a little extra time to the required waits as described.
  125. If dataPins.length = 8 Then
  126. ' Init to 8 bit mode (this is the default, but other drivers may set the controller to 4 bit mode, so reset to be safe.)
  127. Delay(50)
  128. WriteBits($30, 8)
  129. Delay(5)
  130. WriteBits($30, 8)
  131. Delay(100)
  132. WriteBits($30, 8)
  133. Else
  134. ' Init to 4 bit mode, setting rspin to low as we're writing 4 bits directly.
  135. ' (Send writes the whole byte in two 4bit/nibble chunks)
  136. controller.Write(rsPin, EPinValue.Low)
  137. Delay(50)
  138. WriteBits($3, 4)
  139. Delay(5)
  140. WriteBits($3, 4)
  141. Delay(100)
  142. WriteBits($3, 4)
  143. WriteBits($2, 4)
  144. End If
  145. ' The busy flag can NOT be checked until this point.
  146. End Method
  147. Method IsBacklightOn:Int()
  148. Return backlight <> -1 And controller.Read(backlight) = EPinValue.High
  149. End Method
  150. Method SetBackLigntOn(value:Int)
  151. If backlight <> -1 Then
  152. If value Then
  153. controller.Write(backlight, EPinValue.High)
  154. Else
  155. controller.Write(backlight, EPinValue.Low)
  156. End If
  157. End If
  158. End Method
  159. Method SendData(value:Byte)
  160. controller.Write(rsPin, EPinValue.High)
  161. SendByte(value)
  162. End Method
  163. Method SendCommand(command:Byte)
  164. controller.Write(rsPin, EPinValue.Low)
  165. SendByte(command)
  166. End Method
  167. Method SendData(buffer:Byte Ptr, size:Size_T)
  168. controller.Write(rsPin, EPinValue.High)
  169. For Local i:Int = 0 Until size
  170. SendByte(buffer[i])
  171. Next
  172. End Method
  173. Method SendCommands(buffer:Byte Ptr, size:Size_T)
  174. controller.Write(rsPin, EPinValue.Low)
  175. For Local i:Int = 0 Until size
  176. SendByte(buffer[i])
  177. Next
  178. End Method
  179. Method SendByte(value:Byte)
  180. If dataPins.Length = 8 Then
  181. WriteBits(value, 8)
  182. Else
  183. WriteBits(Byte(value Shr 4), 4)
  184. WriteBits(value, 4)
  185. End If
  186. WaitForNotBusy(37)
  187. End Method
  188. Method WriteBits(bits:Byte, count:Int)
  189. Local changedCount:Int
  190. For Local i:Int = 0 Until count
  191. Local newBit:Int = (bits Shr i) & 1
  192. If useLastByte Then
  193. ' Each bit change takes ~23μs, so only change what we have to
  194. ' This is particularly impactful when using all 8 data lines.
  195. Local oldBit:Int = (lastByte Shr i) & 1
  196. If oldBit <> newBit Then
  197. pinBuffer[changedCount] = New SPinValuePair(dataPins[i], newBit)
  198. End If
  199. changedCount:+ 1
  200. Else
  201. pinBuffer[changedCount] = New SPinValuePair(dataPins[i], newBit)
  202. changedCount:+ 1
  203. End If
  204. Next
  205. If changedCount > 0 Then
  206. controller.Write(pinBuffer, changedCount)
  207. End If
  208. useLastByte = True
  209. lastByte = bits
  210. ' Enable pin needs to be high for at least 450ns when running on 3V
  211. ' and 230ns on 5V. (PWeh on page 49/52 and Figure 25 on page 58)
  212. controller.Write(enablePin, EPinValue.High)
  213. UDelay(1)
  214. controller.Write(enablePin, EPinValue.Low)
  215. End Method
  216. Method Dispose()
  217. If controller Then
  218. controller.Dispose()
  219. End If
  220. End Method
  221. End Type
  222. Rem
  223. bbdoc:
  224. End Rem
  225. Type TLCDI2c Extends TLCDInterface
  226. Field ReadOnly device:TI2cDevice
  227. Method New(device:TI2cDevice)
  228. Self.device = device
  229. End Method
  230. Method GetEightBitMode:Int() Override
  231. Return True
  232. End Method
  233. Method IsBacklightOn:Int() Override
  234. Throw New TNotImplementedException
  235. End Method
  236. Method SetBacklightOn(value:Int) Override
  237. Throw New TNotImplementedException
  238. End Method
  239. Method SendCommand(command:Byte) Override
  240. Local buffer:Byte Ptr = StackAlloc(2)
  241. buffer[0] = 0
  242. buffer[1] = command
  243. device.Write(buffer, 2)
  244. End Method
  245. Method SendCommands(commands:Byte Ptr, size:Size_T) Override
  246. If size > 20 Then
  247. Throw New TArgumentOutOfRangeException("Too many commands in one request.")
  248. End If
  249. Local buffer:Byte Ptr = StackAlloc(size + 1)
  250. buffer[0] = 0
  251. MemCopy(buffer + 1, commands, size)
  252. device.Write(buffer, size + 1)
  253. End Method
  254. Method SendData(value:Byte) Override
  255. Local buffer:Byte Ptr = StackAlloc(2)
  256. buffer[0] = EControlByteFlags.RegisterSelect.Ordinal()
  257. buffer[1] = value
  258. device.Write(buffer, 2)
  259. End Method
  260. Method SendData(data:Byte Ptr, size:Size_T) Override
  261. ' limit sending to 20 byte chunks
  262. Local buffer:Byte Ptr = StackAlloc(21)
  263. buffer[0] = EControlByteFlags.RegisterSelect.Ordinal()
  264. Local offset:Int
  265. While size > 0
  266. Local toCopy:Size_T = Min(size, 20)
  267. MemCopy(buffer + 1, data + offset, toCopy)
  268. device.Write(buffer, toCopy + 1)
  269. offset :+ toCopy
  270. size :- toCopy
  271. Wend
  272. End Method
  273. Method Dispose()
  274. End Method
  275. End Type
  276. Enum EControlByteFlags:Byte Flags
  277. ControlByteFollows = $80
  278. RegisterSelect = $40
  279. End Enum
  280. Rem
  281. bbdoc: Supports LCD character displays compatible with the HD44780 LCD controller/driver.
  282. about: Also supports serial interface adapters such as the MCP23008.
  283. End Rem
  284. Type THd44780 Implements IDisposable
  285. Const CLEAR_DISPLAY_COMMAND:Int = $0001
  286. Const RETURN_HOME_COMMAND:Int = $0002
  287. Const SET_CG_RAM_ADDRESS_COMMAND:Int = $0040
  288. Const SET_DD_RAM_ADDRESS_COMMAND:Int = $0080
  289. Field displayFunction:EDisplayFunction = EDisplayFunction.Command
  290. Field displayControl:EDisplayControl = EDisplayControl.Command
  291. Field displayMode:EDisplayEntryMode = EDisplayEntryMode.Command
  292. Field rowOffsets:Byte[]
  293. Field lcdInterface:TLCDInterface
  294. Field size:SSize
  295. Method GetSize:SSize()
  296. Return size
  297. End Method
  298. Method New(size:SSize, lcdInterface:TLCDInterface)
  299. Self.size = size
  300. Self.lcdInterface = lcdInterface
  301. If lcdInterface.eightBitMode Then
  302. displayFunction :| EDisplayFunction.EightBit
  303. End If
  304. Initialize(size.height)
  305. rowOffsets = InitializeRowOffsets(size.height)
  306. End Method
  307. Method Initialize(rows:Int)
  308. ' While the chip supports 5x10 pixel characters for one line displays they
  309. ' don't seem to be generally available. Supporting 5x10 would require extra
  310. ' support for CreateCustomCharacter
  311. If GetTwoLineMode(rows) Then
  312. displayFunction :| EDisplayFunction.TwoLine
  313. End If
  314. displayControl :| EDisplayControl.DisplayOn
  315. displayMode :| EDisplayEntryMode.Increment
  316. Local commands:Byte Ptr = StackAlloc(4)
  317. commands[0] = displayFunction.Ordinal()
  318. commands[1] = displayControl.Ordinal()
  319. commands[2] = displayMode.Ordinal()
  320. commands[3] = CLEAR_DISPLAY_COMMAND
  321. SendCommands(commands, 4)
  322. End Method
  323. Method SendData(value:Byte)
  324. lcdInterface.SendData(value)
  325. End Method
  326. Method SendCommand(command:Byte)
  327. lcdInterface.SendCommand(command)
  328. End Method
  329. Method SendData(buffer:Byte Ptr, size:Size_T)
  330. lcdInterface.SendData(buffer, size)
  331. End Method
  332. Method SendCommands(buffer:Byte Ptr, size:Size_T)
  333. lcdInterface.SendCommands(buffer, size)
  334. End Method
  335. Method GetTwoLineMode:Int(rows:Int)
  336. Return rows > 1
  337. End Method
  338. Method InitializeRowOffsets:Byte[](rows:Int)
  339. Local rowOffsets:Byte[]
  340. Select rows
  341. Case 1
  342. rowOffsets = New Byte[1]
  343. Case 2
  344. rowOffsets = [0:Byte, 64:Byte]
  345. Case 4
  346. rowOffsets = [0:Byte, 64:Byte, 20:Byte, 84:Byte]
  347. Default
  348. Throw New TArgumentOutOfRangeException("rows")
  349. End Select
  350. Return rowOffsets
  351. End Method
  352. Method WaitForNotBusy(microseconds:Int)
  353. lcdInterface.WaitForNotBusy(microseconds)
  354. End Method
  355. Rem
  356. bbdoc: Clears the LCD, returning the cursor to home and unshifting if shifted.
  357. about: Will also set to Increment.
  358. End Rem
  359. Method Clear()
  360. SendCommand(CLEAR_DISPLAY_COMMAND)
  361. WaitForNotBusy(2000)
  362. End Method
  363. Rem
  364. bbdoc: Moves the cursor to the first line and first column, unshifting if shifted.
  365. End Rem
  366. Method Home()
  367. SendCommand(RETURN_HOME_COMMAND)
  368. WaitForNotBusy(1520)
  369. End Method
  370. Rem
  371. bbdoc: Moves the cursor to an explicit column and row position.
  372. End Rem
  373. Method SetCursorPosition(Left:Int, top:Int)
  374. Local rows:Int = rowOffsets.length
  375. If top < 0 Or top >= rows Then
  376. Throw New TArgumentOutOfRangeException("rows")
  377. End If
  378. Local newAddress:Int = Left + rowOffsets[top]
  379. If Left < 0 Or (rows = 1 And newAddress >= 80) Or (rows > 1 And newAddress >= 104) Then
  380. Throw New TArgumentOutOfRangeException("left")
  381. End If
  382. SendCommand(Byte(SET_DD_RAM_ADDRESS_COMMAND | newAddress))
  383. End Method
  384. Rem
  385. bbdoc: Determines whether the display is on or not.
  386. returns: #True if the display is on, #False otherwise.
  387. End Rem
  388. Method IsDisplayOn:Int()
  389. Return (displayControl & EDisplayControl.DisplayOn).Ordinal()
  390. End Method
  391. Rem
  392. bbdoc: Enable/disable the display.
  393. End Rem
  394. Method SetDisplayOn(value:Int)
  395. If value Then
  396. displayControl :| EDisplayControl.CursorOn
  397. Else
  398. displayControl :& ~EDisplayControl.CursorOn
  399. End If
  400. SendCommand(displayControl.Ordinal())
  401. End Method
  402. Rem
  403. bbdoc: Determines whether the underlins cursor is visible or not.
  404. returns: #True if the underline cursor is visible, #False otherwise.
  405. End Rem
  406. Method IsUnderlineCursorVisible:Int()
  407. Return (displayControl & EDisplayControl.CursorOn).Ordinal()
  408. End Method
  409. Rem
  410. bbdoc: Enables/disables the underline cursor.
  411. End Rem
  412. Method SetUnderlineCursorVisible(value:Int)
  413. If value Then
  414. displayControl :| EDisplayControl.CursorOn
  415. Else
  416. displayControl :& ~EDisplayControl.CursorOn
  417. End If
  418. SendCommand(displayControl.Ordinal())
  419. End Method
  420. Rem
  421. bbdoc: Determines whether the blinking cursor is visible or not.
  422. returns: #True if the blinking cursor is visible, #False otherwise.
  423. End Rem
  424. Method IsBlinkingCursorVisible:Int()
  425. Return (displayControl & EDisplayControl.BlinkOn).Ordinal()
  426. End Method
  427. Rem
  428. bbdoc: Enables/disables the blinking cursor.
  429. End Rem
  430. Method SetBlinkingCursorVisible(value:Int)
  431. If value Then
  432. displayControl :| EDisplayControl.BlinkOn
  433. Else
  434. displayControl :& ~EDisplayControl.BlinkOn
  435. End If
  436. SendCommand(displayControl.Ordinal())
  437. End Method
  438. Rem
  439. bbdoc: Returns whether auto shift is enabled.
  440. about: When enabled the display will shift rather than the cursor.
  441. End Rem
  442. Method GetAutoShift:Int()
  443. Return (displayMode & EDisplayEntryMode.DisplayShift).Ordinal()
  444. End Method
  445. Rem
  446. bbdoc: Enables/disabled auto shift.
  447. about: When enabled the display will shift rather than the cursor.
  448. End Rem
  449. Method SetAutoShift(value:Int)
  450. If value Then
  451. displayMode :| EDisplayEntryMode.DisplayShift
  452. Else
  453. displayMode :& ~EDisplayEntryMode.DisplayShift
  454. End If
  455. SendCommand(displayControl.Ordinal())
  456. End Method
  457. Rem
  458. bbdoc: Gets whether the cursor location increments or decrements.
  459. End Rem
  460. Method GetIncrement:Int()
  461. Return (displayMode & EDisplayEntryMode.Increment).Ordinal()
  462. End Method
  463. Rem
  464. bbdoc: Sets whether the cursor location increments (#True) or decrements (#False).
  465. End Rem
  466. Method SetIncrement(value:Int)
  467. If value Then
  468. displayMode :| EDisplayEntryMode.Increment
  469. Else
  470. displayMode :& ~EDisplayEntryMode.Increment
  471. End If
  472. SendCommand(displayControl.Ordinal())
  473. End Method
  474. Rem
  475. bbdoc: Moves the display left by one position.
  476. End Rem
  477. Method ShiftDisplayLeft()
  478. SendCommand((EDisplayShift.Command | EDisplayShift.Display).Ordinal())
  479. End Method
  480. Rem
  481. bbdoc: Moves the display right by one position.
  482. End Rem
  483. Method ShiftDisplayRight()
  484. SendCommand((EDisplayShift.Command | EDisplayShift.Display | EDisplayShift.Right).Ordinal())
  485. End Method
  486. Rem
  487. bbdoc: Moves the cursor left by one position.
  488. End Rem
  489. Method ShiftCursorLeft()
  490. SendCommand((EDisplayShift.Command | EDisplayShift.Display).Ordinal())
  491. End Method
  492. Rem
  493. bbdoc: Moves the cursor right by one position.
  494. End Rem
  495. Method ShiftCursorRight()
  496. SendCommand((EDisplayShift.Command | EDisplayShift.Display | EDisplayShift.Right).Ordinal())
  497. End Method
  498. Rem
  499. bbdoc: Fill one of the 8 CGRAM locations (character codes 0 - 7) with custom characters.
  500. about: The custom characters also occupy character codes 8 - 15.
  501. You can find help designing characters at https://www.quinapalus.com/hd44780udg.html
  502. The datasheet description for custom characters is very difficult to follow. Here is a rehash of the technical details that is hopefully easier:
  503. > Only 6 bits of addresses are available for character ram. That makes for 64 bytes of
  504. > available character data. 8 bytes of data are used for each character, which is where
  505. > the 8 total custom characters comes from (64/8).
  506. >
  507. > Each byte corresponds to a character line. Characters are only 5 bits wide so only
  508. > bits 0-4 are used for display. Whatever is in bits 5-7 is just ignored. Store bits
  509. > there if it makes you happy, but it won't impact the display. '1' is on, '0' is off.
  510. >
  511. > In the built-in characters the 8th byte is usually empty as this is where the underline
  512. > cursor will be if enabled. You can put data there if you like, which gives you the full
  513. > 5x8 character. The underline cursor just turns on the entire bottom row.
  514. >
  515. > 5x10 mode is effectively useless as displays aren't available that utilize it. In 5x10
  516. > mode *16* bytes of data are used for each character. That leaves room for only *4*
  517. > custom characters. The first character is addressable from code 0, 1, 8, and 9. The
  518. > second is 2, 3, 10, 11 and so on...
  519. >
  520. > In this mode *11* bytes of data are actually used for the character data, which
  521. > effectively gives you a 5x11 character, although typically the last line is blank to
  522. > leave room for the underline cursor. Why the modes are referred to as 5x8 and 5x10 as
  523. > opposed to 5x7 and 5x10 or 5x8 and 5x11 is a mystery. In an early pre-release data
  524. > book 5x7 and 5x10 is used (Advance Copy #AP4 from July 1985). Perhaps it was a
  525. > marketing change?
  526. >
  527. > As only 11 bytes are used in 5x10 mode, but 16 bytes are reserved, the last 5 bytes
  528. > are useless. The datasheet helpfully suggests that you can store your own data there.
  529. > The same would be true for bits 5-7 of lines that matter for both 5x8 and 5x10.
  530. End Rem
  531. Method CreateCustomCharacter(location:Byte, characterMap:Byte[])
  532. If location > 7 Then
  533. Throw New TArgumentOutOfRangeException("location")
  534. End If
  535. If characterMap.Length <> 8 Then
  536. Throw New TArgumentException("characterMap")
  537. End If
  538. ' The character address is set in bits 3-5 of the command byte
  539. SendCommand(Byte(SET_CG_RAM_ADDRESS_COMMAND | (location Shl 3)))
  540. SendData(characterMap, characterMap.Length)
  541. End Method
  542. Rem
  543. bbdoc: Writes text to the display.
  544. End Rem
  545. Method Write(value:String)
  546. Local buf:Byte Ptr = value.ToCString()
  547. SendData(buf, Size_T(value.Length))
  548. MemFree(buf)
  549. End Method
  550. Method Dispose()
  551. If lcdInterface Then
  552. lcdInterface.Dispose()
  553. lcdInterface = Null
  554. End If
  555. End Method
  556. End Type
  557. Rem
  558. bbdoc: 16x2 HD44780 compatible character LCD display.
  559. End Rem
  560. Type TLcd1602 Extends THd44780
  561. Rem
  562. bbdoc: Constructs a new HD44780 based 16x2 LCD controller, using GPIO pins.
  563. End Rem
  564. Method New(registerSelectPin:Int, enablePin:Int, dataPins:Int[] , backlightPin:Int = -1, backlightBrightness:Float = 1.0, readWritePin:Int = -1, controller:TGpioController = Null)
  565. Super.New(New SSize(16, 2), New TLCDGpio(registerSelectPin, enablePin, dataPins, backlightPin, backlightBrightness, readWritePin, controller))
  566. End Method
  567. Rem
  568. bbdoc: Constructs a new HD44780 based 16x2 LCD controller with integrated I2c support.
  569. End Rem
  570. Method New(device:TI2cDevice)
  571. Super.New(New SSize(16, 2), New TLCDI2c(device))
  572. End Method
  573. End Type
  574. Rem
  575. bbdoc: Supports I2c LCDs with I2c RGB backlight, such as the Grove - LCD RGB Backlight (16x2 LCD character display with RGB backlight).
  576. End Rem
  577. Type TLcdRgb1602 Extends TLcd1602
  578. Field rgbDevice:TI2cDevice
  579. Field currentColor:SColor8
  580. Field backlightOn:Int = True
  581. Method New(lcdDevice:TI2cDevice, rgbDevice:TI2cDevice)
  582. Super.New(lcdDevice)
  583. Self.rgbDevice = rgbDevice
  584. InitRgb()
  585. End Method
  586. Rem
  587. bbdoc: Enables or disables the backlight.
  588. End Rem
  589. Method SetBacklightOn(value:Int)
  590. If value Then
  591. ForceSetBacklightColor(currentColor)
  592. Else
  593. ForceSetBacklightColor(SCOlor8.Black)
  594. End If
  595. backlightOn = value
  596. End Method
  597. Rem
  598. bbdoc: Returns #True if the backlight is on, #False otherwise.
  599. End Rem
  600. Method IsBacklightOn:Int()
  601. Return backlightOn
  602. End Method
  603. Rem
  604. bbdoc: Sets the backlight color.
  605. End Rem
  606. Method SetBacklightColor(color:SColor8)
  607. If Not backlightOn Then
  608. Return
  609. End If
  610. ForceSetBacklightColor(color)
  611. currentColor = color
  612. End Method
  613. Private
  614. Method InitRgb()
  615. ' backlight init
  616. SetRgbRegister(ERgbRegisters.REG_MODE1, 0)
  617. ' set LEDs controllable by both PWM and GRPPWM registers
  618. SetRgbRegister(ERgbRegisters.REG_LEDOUT, $FF)
  619. ' set MODE2 values
  620. SetRgbRegister(ERgbRegisters.REG_MODE2, $20)
  621. SetBacklightColor(SColor8.White)
  622. End Method
  623. Method SetRgbRegister(addr:ERgbRegisters, value:Byte)
  624. Local buffer:Byte Ptr = StackAlloc(2)
  625. buffer[0] = addr.Ordinal()
  626. buffer[1] = value
  627. rgbDevice.Write(buffer, 2)
  628. End Method
  629. Method ForceSetBacklightColor(color:SColor8)
  630. SetRgbRegister(ERgbRegisters.REG_RED, color.r)
  631. SetRgbRegister(ERgbRegisters.REG_GREEN, color.g)
  632. SetRgbRegister(ERgbRegisters.REG_BLUE, color.b)
  633. End Method
  634. Public
  635. Method Dispose()
  636. If rgbDevice Then
  637. rgbDevice.Dispose()
  638. End If
  639. End Method
  640. End Type
  641. Rem
  642. bbdoc: 20x4 HD44780 compatible character LCD display.
  643. End Rem
  644. Type TLcd2004 Extends THd44780
  645. Rem
  646. bbdoc: Constructs a new HD44780 based 20x4 LCD controller.
  647. End Rem
  648. Method New(registerSelectPin:Int, enablePin:Int, dataPins:Int[] , backlightPin:Int = -1, backlightBrightness:Float = 1.0, readWritePin:Int = -1, controller:TGpioController = Null)
  649. Super.New(New SSize(20, 4), New TLCDGpio(registerSelectPin, enablePin, dataPins, backlightPin, backlightBrightness, readWritePin, controller))
  650. End Method
  651. End Type
  652. Struct SSize
  653. Field width:Int
  654. Field height:Int
  655. Method New(width:Int, height:Int)
  656. Self.width = width
  657. Self.height = height
  658. End Method
  659. End Struct
  660. Enum ERgbRegisters:Byte
  661. REG_MODE1 = $00
  662. REG_MODE2 = $01
  663. REG_LEDOUT = $08
  664. REG_RED = $04
  665. REG_GREEN = $03
  666. REG_BLUE = $02
  667. End Enum
  668. Enum EDisplayEntryMode:Byte Flags
  669. DisplayShift = $1
  670. Increment = $2
  671. Command = $4
  672. End Enum
  673. Enum EDisplayControl:Byte Flags
  674. BlinkOn = $1
  675. CursorOn = $2
  676. DisplayOn = $4
  677. Command = $8
  678. End Enum
  679. Enum EDisplayShift:Byte Flags
  680. Right = $04
  681. Display = $08
  682. Command = $10
  683. End Enum
  684. Enum EDisplayFunction:Byte Flags
  685. ExtendedInstructionSet = $01
  686. Font5x10 = $04
  687. TwoLine = $08
  688. EightBit = $10
  689. Command = $20
  690. End Enum