1. /***********************************************************************
  2.  * HT1624.pde - Arduino demo program for Holtek HT1632 LED driver chip,
  3.  *            As implemented on the Sure Electronics DE-DP016 display board
  4.  *            (16*24 dot matrix LED module.)
  5.  * Nov, 2008 by Bill Westfield ("WestfW")
  6.  *   Copyrighted and distributed under the terms of the Berkely license
  7.  *   (copy freely, but include this notice of original author.)
  8.  *
  9.  * Adapted for 8x32 display by FlorinC.
  10.  ***********************************************************************/
  11.  
  12. // comment out this line for the 8x32 display;
  13. //#define _16x24_
  14.  
  15. #include <Arduino.h>
  16. #include "ht1632.h"
  17. #include <avr/pgmspace.h>
  18. #include "font3.h"
  19.  
  20. #ifdef _16x24_
  21.   #define X_MAX 23
  22.   #define Y_MAX 15
  23. #else
  24.   #define X_MAX 31
  25.   #define Y_MAX 7
  26. #endif
  27.  
  28. //(fc) switched to a different set of pins than the original, to accomodate the SD shield;
  29. #define HT1632_DATA     6    // Data pin (pin 7)
  30. #define HT1632_WRCLK    7    // Write clock pin (pin 5)
  31. #define HT1632_CS       8    // Chip Select (1, 2, 3, or 4)
  32.  
  33. #define plot(x,y,v)  ht1632_plot(x,y,v)
  34. #define cls          ht1632_clear
  35.  
  36. #define DISPDELAY 0
  37.  
  38. char* msg = "     Hello world";
  39. int crtPos = 0;
  40.  
  41.  
  42.  
  43. /***********************************************************************
  44.  * ht1632_chipselect / ht1632_chipfree
  45.  * Select or de-select a particular ht1632 chip.
  46.  * De-selecting a chip ends the commands being sent to a chip.
  47.  * CD pins are active-low; writing 0 to the pin selects the chip.
  48.  ***********************************************************************/
  49.  
  50. void ht1632_chipselect(byte chipno)
  51. {
  52.   DEBUGPRINT("\nHT1632(%d) ", chipno);
  53.   digitalWrite(chipno, 0);
  54. }
  55.  
  56. void ht1632_chipfree(byte chipno)
  57. {
  58.   DEBUGPRINT(" [done %d]", chipno);
  59.   digitalWrite(chipno, 1);
  60. }
  61.  
  62.  
  63. /*
  64.  * we keep a copy of the display controller contents so that we can
  65.  * know which bits are on without having to (slowly) read the device.
  66.  * Note that we only use the low four bits of the shadow ram, since
  67.  * we're shadowing 4-bit memory.  This makes things faster, and we
  68.  * use the other half for a "snapshot" when we want to plot new data
  69.  * based on older data...
  70.  */
  71. // (fc) covers the case for 32x8 as well (64 bytes, 4 bits)
  72. byte ht1632_shadowram[96];  // our copy of the display's RAM
  73.  
  74.  
  75. /*
  76.  * ht1632_writebits
  77.  * Write bits (up to 8) to h1632 on pins HT1632_DATA, HT1632_WRCLK
  78.  * Chip is assumed to already be chip-selected
  79.  * Bits are shifted out from MSB to LSB, with the first bit sent
  80.  * being (bits & firstbit), shifted till firsbit is zero.
  81.  */
  82. void ht1632_writebits (byte bits, byte firstbit)
  83. {
  84.   DEBUGPRINT(" ");
  85.   while (firstbit) {
  86.     DEBUGPRINT((bits&firstbit ? "1" : "0"));
  87.     digitalWrite(HT1632_WRCLK, LOW);
  88.     if (bits & firstbit) {
  89.       digitalWrite(HT1632_DATA, HIGH);
  90.     }
  91.     else {
  92.       digitalWrite(HT1632_DATA, LOW);
  93.     }
  94.     digitalWrite(HT1632_WRCLK, HIGH);
  95.     firstbit >>= 1;
  96.   }
  97. }
  98.  
  99.  
  100. /*
  101.  * ht1632_sendcmd
  102.  * Send a command to the ht1632 chip.
  103.  * A command consists of a 3-bit "CMD" ID, an 8bit command, and
  104.  * one "don't care bit".
  105.  *   Select 1 0 0 c7 c6 c5 c4 c3 c2 c1 c0 xx Free
  106.  */
  107. static void ht1632_sendcmd (byte command)
  108. {
  109.   ht1632_chipselect(HT1632_CS);  // Select chip
  110.   ht1632_writebits(HT1632_ID_CMD, 1<<2);  // send 3 bits of id: COMMMAND
  111.   ht1632_writebits(command, 1<<7);  // send the actual command
  112.   ht1632_writebits(0, 1);   /* one extra dont-care bit in commands. */
  113.   ht1632_chipfree(HT1632_CS); //done
  114. }
  115.  
  116. /*
  117.  * ht1632_clear
  118.  * clear the display, and the shadow memory, and the snapshot
  119.  * memory.  This uses the "write multiple words" capability of
  120.  * the chipset by writing all 96 words of memory without raising
  121.  * the chipselect signal.
  122.  */
  123. void ht1632_clear()
  124. {
  125.   char i;
  126.  
  127.   ht1632_chipselect(HT1632_CS);  // Select chip
  128.   ht1632_writebits(HT1632_ID_WR, 1<<2);  // send ID: WRITE to RAM
  129.   ht1632_writebits(0, 1<<6); // Send address
  130.   for (i = 0; i < 96/2; i++) // Clear entire display
  131.     ht1632_writebits(0, 1<<7); // send 8 bits of data
  132.   ht1632_chipfree(HT1632_CS); // done
  133.   for (i=0; i < 96; i++)
  134.     ht1632_shadowram[i] = 0;
  135. }
  136.  
  137.  
  138. /*
  139.  * ht1632_senddata
  140.  * send a nibble (4 bits) of data to a particular memory location of the
  141.  * ht1632.  The command has 3 bit ID, 7 bits of address, and 4 bits of data.
  142.  *    Select 1 0 1 A6 A5 A4 A3 A2 A1 A0 D0 D1 D2 D3 Free
  143.  * Note that the address is sent MSB first, while the data is sent LSB first!
  144.  * This means that somewhere a bit reversal will have to be done to get
  145.  * zero-based addressing of words and dots within words.
  146.  */
  147. static void ht1632_senddata (byte address, byte data)
  148. {
  149.   ht1632_chipselect(HT1632_CS);  // Select chip
  150.   ht1632_writebits(HT1632_ID_WR, 1<<2);  // send ID: WRITE to RAM
  151.   ht1632_writebits(address, 1<<6); // Send address
  152.   ht1632_writebits(data, 1<<3); // send 4 bits of data
  153.   ht1632_chipfree(HT1632_CS); // done
  154. }
  155.  
  156. void ht1632_setup()
  157. {
  158.   pinMode(HT1632_CS, OUTPUT);
  159.   digitalWrite(HT1632_CS, HIGH);    // unselect (active low)
  160.   pinMode(HT1632_WRCLK, OUTPUT);
  161.   pinMode(HT1632_DATA, OUTPUT);
  162.     ht1632_sendcmd(HT1632_CMD_SYSDIS);  // Disable system
  163.     ht1632_sendcmd(HT1632_CMD_COMS00);
  164.     ht1632_sendcmd(HT1632_CMD_MSTMD);  /* Master Mode */
  165.     ht1632_sendcmd(HT1632_CMD_RCCLK);  // HT1632C
  166.     ht1632_sendcmd(HT1632_CMD_SYSON);  /* System on */
  167.     ht1632_sendcmd(HT1632_CMD_LEDON);  /* LEDs on */
  168.  
  169.   for (byte i=0; i<64; i++)
  170.     ht1632_senddata(i, 0);  // clear the display!
  171.  
  172.   delay(100);  // ?
  173. }
  174.  
  175.  
  176. /*
  177.  * Copy a character glyph from the myfont data structure to
  178.  * display memory, with its upper left at the given coordinate
  179.  * This is unoptimized and simply uses plot() to draw each dot.
  180.  */
  181. void ht1632_putchar(int x, int y, char c)
  182. {
  183.   // fonts defined for ascii 32 and beyond (index 0 in font array is ascii 32);
  184.   byte charIndex;
  185.  
  186.   // replace undisplayable characters with blank;
  187.   if (c < 32 || c > 126)
  188.   {
  189.     charIndex = 0;
  190.   }
  191.   else
  192.   {
  193.     charIndex = c - 32;
  194.   }
  195.  
  196.   // move character definition, pixel by pixel, onto the display;
  197.   // fonts are defined as one byte per row;
  198.   for (byte row=0; row<8; row++)
  199.   {
  200.     byte rowDots = pgm_read_byte_near(&myfont[charIndex][row]);
  201.     for (byte col=0; col<6; col++)
  202.     {
  203.       if (rowDots & (1<<(5-col)))
  204.         plot(x+col, y+row, 1);
  205.       else
  206.         plot(x+col, y+row, 0);
  207.     }
  208.   }
  209. }
  210.  
  211.  
  212.  
  213. /*
  214.  * plot a point on the display, with the upper left hand corner
  215.  * being (0,0), and the lower right hand corner being (23, 15).
  216.  * Note that Y increases going "downward" in contrast with most
  217.  * mathematical coordiate systems, but in common with many displays
  218.  * No error checking; bad things may happen if arguments are out of
  219.  * bounds!  (The ASSERTS compile to nothing by default
  220.  */
  221. void ht1632_plot (int x, int y, char val)
  222. {
  223.   if (x<0 || x>X_MAX || y<0 || y>Y_MAX)
  224.      return;
  225.  
  226.   char addr, bitval;
  227.  
  228.   /*
  229.    * The 4 bits in a single memory word go DOWN, with the LSB
  230.    * (first transmitted) bit being on top.  However, writebits()
  231.    * sends the MSB first, so we have to do a sort of bit-reversal
  232.    * somewhere.  Here, this is done by shifting the single bit in
  233.    * the opposite direction from what you might expect.
  234.    */
  235.   bitval = 8>>(y&3);  // compute which bit will need set
  236.  
  237. #ifdef _16x24_
  238.   addr = (x<<2) + (y>>2);  // compute which memory word this is in
  239. #else
  240. // (fc)
  241.   addr = (x<<1) + (y>>2);  // compute which memory word this is in
  242. #endif
  243.  
  244.   if (val) {  // Modify the shadow memory
  245.     ht1632_shadowram[addr] |= bitval;
  246.   }
  247.   else {
  248.     ht1632_shadowram[addr] &= ~bitval;
  249.   }
  250.   // Now copy the new memory value to the display
  251.   ht1632_senddata(addr, ht1632_shadowram[addr]);
  252. }
  253.  
  254.  
  255. /*
  256.  * get_shadowram
  257.  * return the value of a pixel from the shadow ram.
  258.  */
  259. byte get_shadowram(byte x, byte y)
  260. {
  261.   byte addr, bitval;
  262.  
  263.   bitval = 8>>(y&3);  // compute which bit will need set
  264.   addr = (x<<2) + (y>>2);  // compute which memory word this is in
  265.   return (0 != (ht1632_shadowram[addr] & bitval));
  266. }
  267.  
  268.  
  269. /*
  270.  * snapshot_shadowram
  271.  * Copy the shadow ram into the snapshot ram (the upper bits)
  272.  * This gives us a separate copy so we can plot new data while
  273.  * still having a copy of the old data.  snapshotram is NOT
  274.  * updated by the plot functions (except "clear")
  275.  */
  276. void snapshot_shadowram()
  277. {
  278.   for (char i=0; i< sizeof ht1632_shadowram; i++) {
  279.     ht1632_shadowram[i] = (ht1632_shadowram[i] & 0x0F) | ht1632_shadowram[i] << 4;  // Use the upper bits
  280.   }
  281. }
  282.  
  283.  
  284. /*
  285.  * get_snapshotram
  286.  * get a pixel value from the snapshot ram (instead of
  287.  * the actual displayed (shadow) memory
  288.  */
  289. byte get_snapshotram(byte x, byte y)
  290. {
  291.   byte addr, bitval;
  292.  
  293.   bitval = 128>>(y&3);  // user upper bits!
  294.  
  295. #ifdef _16x24_
  296.   addr = (x<<2) + (y>>2);  // compute which memory word this is in
  297. #else
  298. // (fc)
  299.   addr = (x<<1) + (y>>2);  // compute which memory word this is in
  300. #endif
  301.  
  302.   if (ht1632_shadowram[addr] & bitval)
  303.     return 1;
  304.   return 0;
  305. }
  306.  
  307.  
  308. /*
  309. * This works equally well for both 16x24 and 8x32 matrices.
  310. */
  311. void displayScrollingLine()
  312. {
  313.   // shift the whole screen 6 times, one column at a time;
  314.   for (int x=0; x < 6; x++)
  315.   {
  316.     ht1632_putchar(-x, 0, msg[crtPos]);
  317.     ht1632_putchar(-x+6,  0, ((crtPos+1 < strlen(msg)) ? msg[crtPos+1] : ' '));
  318.     ht1632_putchar(-x+12, 0, ((crtPos+2 < strlen(msg)) ? msg[crtPos+2] : ' '));
  319.     ht1632_putchar(-x+18, 0, ((crtPos+3 < strlen(msg)) ? msg[crtPos+3] : ' '));
  320.     ht1632_putchar(-x+24, 0, ((crtPos+4 < strlen(msg)) ? msg[crtPos+4] : ' '));
  321.     ht1632_putchar(-x+30, 0, ((crtPos+5 < strlen(msg)) ? msg[crtPos+5] : ' '));
  322.     ht1632_putchar(-x+36, 0, ((crtPos+6 < strlen(msg)) ? msg[crtPos+6] : ' '));
  323.     delay(DISPDELAY);
  324.   }
  325.  
  326.   crtPos++;
  327.   if (crtPos >= strlen(msg))
  328.   {
  329.     crtPos = 0;
  330.   }
  331. }
  332.  
  333.  
  334. /***********************************************************************
  335.  * traditional Arduino sketch functions: setup and loop.
  336.  ***********************************************************************/
  337.  
  338. void setup ()
  339. {
  340.   ht1632_setup();
  341.   Serial.begin(9600);
  342.   cls();
  343. }
  344.  
  345. void loop ()
  346. {
  347.   // display line;
  348.   displayScrollingLine();
  349. }