Library for TM1650 LED controller (32 LEDs max, 28 keys max)

Dependents:   mbed_TM1650

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers TM1650.cpp Source File

TM1650.cpp

00001 /* mbed TM1650 Library, for TM1650 LED controller
00002  * Copyright (c) 2017, v01: WH, Initial version
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy
00005  * of this software and associated documentation files (the "Software"), to deal
00006  * in the Software without restriction, inclumosig without limitation the rights
00007  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00008  * copies of the Software, and to permit persons to whom the Software is
00009  * furnished to do so, subject to the following conditions:
00010  *
00011  * The above copyright notice and this permission notice shall be included in
00012  * all copies or substantial portions of the Software.
00013  *
00014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00015  * IMPLIED, INCLUmosiG BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
00017  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00018  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
00019  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
00020  * THE SOFTWARE.
00021  */
00022 #include "mbed.h" 
00023 #include "TM1650.h"
00024 
00025 /** Constructor for class for driving TM1650 LED controller with Serial bus interface device. 
00026  *  @brief Supports 4 digits @ 8 segments. Also supports upto 28 Keys.
00027  *   
00028  *  @param  PinName dio Serial bus DIO pin 
00029  *  @param  PinName clk Serial bus CLK pin
00030 */
00031 TM1650::TM1650(PinName dio, PinName clk) : _dio(dio), _clk(clk) {
00032 
00033   _init();
00034 }
00035 
00036 
00037 /** Init the Serial interface and the controller
00038   * @param  none
00039   * @return none
00040   */ 
00041 void TM1650::_init(){
00042   
00043 //TM1650 uses a Serial bus that looks like I2C, but really is not.
00044 //It has Start and Stop conditions like I2C and an Ack pulse, but instead of slaveaddresses and a RW bit it just transmits commands and data.
00045 
00046 //init Serial bus
00047   _dio.output();
00048 //  _dio.mode(PullUp);
00049   wait_us(1);
00050 
00051   _dio=1;  
00052   _clk=1;  
00053 
00054 //init controller  
00055   _bright  = TM1650_BRT_DEF; 
00056   _segment = TM1650_DSP_8S; 
00057   _display = TM1650_DSP_ON;  
00058   _writeCmd(TM1650_DSP_CTRL_CMD, _bright | _segment | _display );  // Display control cmd, brightness, 7/8 segments, display on/off
00059 }   
00060 
00061 
00062 /** Clear the screen and locate to 0
00063  */  
00064 void TM1650::cls() {
00065 
00066   for (int cnt=0; cnt<TM1650_DISPLAY_MEM; cnt++) {
00067     _start();     
00068     _write(TM1650_DATA_WR_CMD | (cnt << 1)); // Set Address cmd (no auto incr supported)
00069     _write(0x00);                            // Write data 
00070     _stop();      
00071   }
00072 
00073 }  
00074 
00075 /** Set Brightness
00076   *
00077   * @param  char brightness (3 significant bits, valid range 0..7 (1/16 .. 14/14 dutycycle)  
00078   * @return none
00079   */
00080 void TM1650::setBrightness(char brightness){
00081 
00082   _bright = brightness & TM1650_BRT_MSK; // mask invalid bits
00083   
00084   _writeCmd(TM1650_DSP_CTRL_CMD, _bright | _segment | _display );  // Display control cmd, brightness, 7/8 segments, display on/off
00085 }
00086 
00087 /** Set the Display mode On/off
00088   *
00089   * @param bool display mode
00090   */
00091 void TM1650::setDisplay(bool on) {
00092   
00093   if (on) {
00094     _display = TM1650_DSP_ON;
00095   }
00096   else {
00097     _display = TM1650_DSP_OFF;
00098   }
00099   
00100   _writeCmd(TM1650_DSP_CTRL_CMD, _bright | _segment | _display );  // Display control cmd, brightness, 7/8 segments, display on/off
00101 }
00102 
00103 /** Write databyte to TM1650
00104   *  @param  int address display memory location to write byte
00105   *  @param  char data byte written at given address
00106   *  @return none
00107   */ 
00108 void TM1650::writeData(char data, int address) {
00109   
00110   _start();
00111 
00112   _write(TM1650_DATA_WR_CMD | ((address & TM1650_ADDR_MSK) << 1)); // Set Address cmd     
00113   _write(data);                                                    // Write data 
00114 
00115   _stop();  
00116 }
00117 
00118 /** Write Display datablock to TM1650
00119   *  @param  DisplayData_t data Array of TM1650_DISPLAY_MEM (=4) bytes for displaydata
00120   *  @param  length number bytes to write (valid range 0..(TM1650_MAX_NR_GRIDS * TM1650_BYTES_PER_GRID) (=4), when starting at address 0)  
00121   *  @param  int address display memory location to write bytes (default = 0) 
00122   *  @return none
00123   */  
00124 void TM1650::writeData(DisplayData_t data, int length, int address) {
00125 
00126 // sanity check
00127   address &= TM1650_ADDR_MSK;
00128   if (length < 0) {length = 0;}
00129   if ((length + address) > TM1650_DISPLAY_MEM) {length = (TM1650_DISPLAY_MEM - address);}
00130     
00131   for (int idx=0; idx<length; idx++) {    
00132     _start();
00133     _write(TM1650_DATA_WR_CMD | ((address + idx) << 1)); // Set Address cmd (no auto incr supported)
00134     _write(data[address + idx]);                         // Write data 
00135     _stop();      
00136   }
00137 }
00138 
00139 /** Read keydata block from TM1650
00140   *  @param  *keydata Ptr to bytes for keydata
00141   *  @return bool keypress True when at least one key was pressed
00142   */   
00143 bool TM1650::getKeys(KeyData_t *keydata) {
00144 
00145   _start();
00146 
00147   // Enable Key Read mode
00148   _write(TM1650_KEY_RD_CMD); // Read Key cmd
00149 
00150   // Read key
00151   *keydata = _read();
00152 //  printf("Key = 0x%02x\r\n", *keydata);  // debug
00153 
00154   _stop();  
00155       
00156   // Check if valid key bits are set
00157   return ( (*keydata & TM1650_SW_MSK) == TM1650_SW_MSK );
00158 }
00159   
00160 
00161 /** Generate Start condition for TM1650
00162   *  @param  none
00163   *  @return none
00164   */ 
00165 void TM1650::_start() {
00166 
00167   _dio=0;
00168   wait_us(1);
00169   _clk=0;
00170   wait_us(1);
00171 }
00172   
00173 /** Generate Stop condition for TM1650
00174   *  @param  none
00175   *  @return none
00176   */ 
00177 void TM1650::_stop() {
00178 
00179   _dio=0;
00180   wait_us(1);  
00181   _clk=1;
00182   wait_us(1);
00183   _dio=1;
00184   wait_us(1);
00185 }
00186 
00187 /** Send byte to TM1650
00188   *  @param  int data
00189   *  @return none
00190   */ 
00191 void TM1650::_write(int data) {
00192  
00193   for (int bit=7; bit >= 0; bit--) {    
00194     //The TM1650 expects MSB first
00195     if (((data >> bit) & 0x01) == 0x01) {
00196       _dio=1;      
00197     }
00198     else {    
00199       _dio=0;      
00200     }  
00201     wait_us(1);
00202     _clk=1;
00203     wait_us(1);
00204     _clk=0;  
00205     wait_us(1);
00206   }  
00207 
00208   _dio=1;
00209   
00210   // Prepare DIO to read data
00211   _dio.input();
00212   wait_us(3);
00213       
00214   // dummy Ack
00215   _clk=1;
00216   wait_us(1);
00217 //  _ack = _dio;  
00218   _clk=0;  
00219   wait_us(1); 
00220   
00221   // Return DIO to output mode
00222   _dio.output();  
00223   wait_us(3);  
00224 
00225   _dio=1; //idle  
00226 }
00227 
00228 /** Read byte from TM1650
00229   *  @param  none
00230   *  @return read byte 
00231   */ 
00232 char TM1650::_read() {
00233   char keycode = 0;
00234 
00235   // Prepare DIO to read data
00236   _dio.input();
00237   wait_us(3);
00238     
00239   for (int bit=0; bit<8; bit++) {    
00240    
00241     //The TM1650 sends bitpattern: D7..D0
00242     //Data is shifted out by the TM1650 on the falling edge of CLK
00243     //Observe sufficient delay to allow the Open Drain DIO to rise to H levels
00244     // Prepare to read next bit, MSB (ie D7) first. 
00245     keycode = keycode << 1;  
00246 
00247     _clk=1;
00248     wait_us(1);
00249     
00250     // Read next bit
00251     if (_dio) { keycode |= 0x01; }        
00252 
00253     _clk=0;        
00254     wait_us(5); // Delay to allow for slow risetime
00255   }  
00256   
00257   // Return DIO to output mode
00258   _dio.output();
00259   wait_us(3);  
00260 
00261   // dummy Ack
00262   _dio=0; //Ack   
00263   wait_us(1);
00264   
00265   _clk=1;
00266   wait_us(1);
00267   _clk=0;  
00268   wait_us(1); 
00269 
00270   _dio=1; //idle
00271 
00272   return keycode;
00273 }
00274 
00275 /** Write command (and parameters) to TM1650
00276   *  @param  int cmd Command byte
00277   *  @Param  int data Parameters for command
00278   *  @return none
00279   */  
00280 void TM1650::_writeCmd(int cmd, int data){
00281     
00282   _start();
00283 
00284   _write(cmd);   
00285   _write(data);  
00286    
00287   _stop();          
00288 }  
00289 
00290 
00291 #if (MEIBAI_TEST == 1) 
00292 // Derived class for TM1650 used in MEIBAI display unit
00293 //
00294 
00295 /** Constructor for class for driving TM1650 LED controller
00296  *
00297  * @brief Supports 4 Digits of 7 Segments + DP.
00298  *        Also supports 3 keys.
00299  *        Serial bus interface device. 
00300  *
00301  *  @param  PinName dio Serial bus DIO pin
00302  *  @param  PinName sck Serial bus CLK pin 
00303  */
00304 TM1650_MEIBAI::TM1650_MEIBAI(PinName dio, PinName clk) : TM1650(dio, clk) {
00305   _column  = 0;
00306   _columns = MEIBAI_NR_DIGITS;    
00307 }  
00308 
00309 #if(0)
00310 #if DOXYGEN_ONLY
00311     /** Write a character to the Display
00312      *
00313      * @param c The character to write to the display
00314      * @return c
00315      */
00316     int putc(int c);
00317 
00318     /** Write a formatted string to the Display
00319      *
00320      * @param format A printf-style format string, followed by the
00321      *               variables to use in formatting the string.
00322      */
00323     int printf(const char* format, ...);   
00324 #endif
00325 #endif
00326 
00327 /** Locate cursor to a screen column
00328   *
00329   * @param column  The horizontal position from the left, indexed from 0
00330   * @return none  
00331   */
00332 void TM1650_MEIBAI::locate(int column) {
00333   //sanity check
00334   if (column < 0) {column = 0;}
00335   if (column > (_columns - 1)) {column = _columns - 1;}  
00336   
00337   _column = column;       
00338 }
00339 
00340 
00341 /** Number of screen columns
00342   *
00343   * @param none
00344   * @return columns
00345   */
00346 int TM1650_MEIBAI::columns() {
00347     return _columns;
00348 }
00349 
00350     
00351 /** Clear the screen and locate to 0
00352   * 
00353   * @param bool clrAll Clear Icons also (default = false)
00354   * @return none  
00355   */ 
00356 void TM1650_MEIBAI::cls(bool clrAll) {  
00357 
00358   if (clrAll) {
00359     //clear local buffer (inclumosig Icons)
00360     for (int idx=0; idx < MEIBAI_NR_GRIDS; idx++) {
00361       _displaybuffer[idx] = 0x00;  
00362     }
00363   }  
00364   else {
00365     //clear local buffer (preserving Icons)
00366     for (int idx=0; idx < MEIBAI_NR_GRIDS; idx++) {
00367       _displaybuffer[idx] = _displaybuffer[idx] & MASK_ICON_GRID[idx];  
00368     }  
00369   }
00370 
00371   writeData(_displaybuffer, (MEIBAI_NR_GRIDS * TM1650_BYTES_PER_GRID), 0);
00372 
00373   _column = 0;   
00374 }     
00375 
00376 /** Set Icon
00377   *
00378   * @param Icon icon Enums Icon has Grid position encoded in 8 MSBs, Icon pattern encoded in 16 LSBs
00379   * @return none
00380   */
00381 void TM1650_MEIBAI::setIcon(Icon icon) {
00382   int addr, icn;
00383 
00384    icn =        icon  & 0xFFFF;
00385   addr = (icon >> 24) & 0xFF; 
00386   addr = (addr - 1);
00387     
00388   //Save char...and set bits for icon to write
00389   _displaybuffer[addr] = _displaybuffer[addr] | LO(icn);      
00390 //  writeData(_displaybuffer, (MEIBAI_NR_GRIDS * TM1650_BYTES_PER_GRID), 0);
00391   writeData(_displaybuffer, TM1650_BYTES_PER_GRID, addr);  
00392 }
00393 
00394 /** Clr Icon
00395   *
00396   * @param Icon icon Enums Icon has Grid position encoded in 8 MSBs, Icon pattern encoded in 16 LSBs
00397   * @return none
00398   */
00399 void TM1650_MEIBAI::clrIcon(Icon icon) {
00400   int addr, icn;
00401 
00402    icn =        icon  & 0xFFFF;
00403   addr = (icon >> 24) & 0xFF; 
00404   addr = (addr - 1);
00405     
00406   //Save char...and clr bits for icon to write
00407   _displaybuffer[addr] = _displaybuffer[addr] & ~LO(icn);      
00408 //  writeData(_displaybuffer, (MEIBAI_NR_GRIDS * TM1650_BYTES_PER_GRID), 0);
00409   writeData(_displaybuffer, TM1650_BYTES_PER_GRID, addr);    
00410 }
00411 
00412 
00413 /** Set User Defined Characters (UDC)
00414   *
00415   * @param unsigned char udc_idx  The Index of the UDC (0..7)
00416   * @param int udc_data           The bitpattern for the UDC (8 bits)
00417   * @return none  
00418   */
00419 void TM1650_MEIBAI::setUDC(unsigned char udc_idx, int udc_data) {
00420 
00421   //Sanity check
00422   if (udc_idx > (MEIBAI_NR_UDC-1)) {
00423     return;
00424   }
00425   // Mask out Icon bits?
00426 
00427   _UDC_7S[udc_idx] = LO(udc_data);
00428 }
00429 
00430 
00431 /** Write a single character (Stream implementation)
00432   *
00433   * @param c The character to write to the display
00434   * @return c
00435   */
00436 int TM1650_MEIBAI::_putc(int value) {
00437 //The MEIBAI mapping between Digit positions (Left to Right) and Grids is:
00438 //  GR1 GR2 GR3 GR4
00439 //The memory addresses or column numbers are:
00440 //   0   1   2   3
00441     
00442     int addr;
00443     bool validChar = false;
00444     char pattern   = 0x00;
00445     
00446     if ((value == '\n') || (value == '\r')) {
00447       //No character to write
00448       validChar = false;
00449       
00450       //Update Cursor      
00451       _column = 0;
00452     }
00453     else if ((value == '.') || (value == ',')) {
00454       //No character to write
00455       validChar = false;
00456       pattern = S7_DP; // placeholder for all DPs
00457       
00458       // Check to see that DP can be shown for current column
00459       if (_column > 0) {
00460         //Translate between _column and displaybuffer entries
00461         //Add DP to bitpattern of digit left of current column.
00462         addr = (_column - 1);
00463       
00464         //Save icons...and set bits for decimal point to write
00465         _displaybuffer[addr] = _displaybuffer[addr] | pattern;
00466 //        writeData(_displaybuffer, (MEIBAI_NR_GRIDS * TM1650_BYTES_PER_GRID));
00467         writeData(_displaybuffer, TM1650_BYTES_PER_GRID, addr); 
00468         
00469         //No Cursor Update
00470       }
00471     }
00472     else if ((value >= 0) && (value < MEIBAI_NR_UDC)) {
00473       //Character to write
00474       validChar = true;
00475       pattern = _UDC_7S[value];
00476     }  
00477     
00478 #if (SHOW_ASCII == 1)
00479     //display all ASCII characters
00480     else if ((value >= FONT_7S_START) && (value <= FONT_7S_END)) {   
00481       //Character to write
00482       validChar = true;
00483       pattern = FONT_7S[value - FONT_7S_START];
00484     } // else
00485 #else    
00486     //display only digits and hex characters      
00487     else if (value == '-') {
00488       //Character to write
00489       validChar = true;
00490       pattern = C7_MIN;         
00491     }
00492     else if ((value >= (int)'0') && (value <= (int) '9')) {   
00493       //Character to write
00494       validChar = true;
00495       pattern = FONT_7S[value - (int) '0'];
00496     }
00497     else if ((value >= (int) 'A') && (value <= (int) 'F')) {   
00498       //Character to write
00499       validChar = true;
00500       pattern = FONT_7S[10 + value - (int) 'A'];
00501     }
00502     else if ((value >= (int) 'a') && (value <= (int) 'f')) {   
00503       //Character to write
00504       validChar = true;
00505       pattern = FONT_7S[10 + value - (int) 'a'];
00506     } //else
00507 #endif
00508 
00509     if (validChar) {
00510       //Character to write
00511  
00512       //Translate between _column and displaybuffer entries
00513       addr = _column;
00514 
00515       //Save icons...and set bits for character to write
00516       _displaybuffer[addr] = (_displaybuffer[addr] & MASK_ICON_GRID[_column]) | pattern;
00517 
00518 //      writeData(_displaybuffer, (MEIBAI_NR_GRIDS * TM1650_BYTES_PER_GRID));
00519       writeData(_displaybuffer, TM1650_BYTES_PER_GRID, addr);        
00520                                 
00521       //Update Cursor
00522       _column++;
00523       if (_column > (MEIBAI_NR_DIGITS - 1)) {
00524         _column = 0;
00525       }
00526 
00527     } // if validChar           
00528 
00529     return value;
00530 }
00531 
00532 
00533 /** Get a single character (Stream implementation)
00534   *
00535   * @param none
00536   * @return -1
00537   */
00538 int TM1650_MEIBAI::_getc() {
00539     return -1;
00540 }
00541 
00542 #endif