Thursday, December 8, 2011

Scrolling text with shift registers

Using a couple of 74HC595 shift registers, I have done away with most of the wires leading from the Arduino to the breadboard. This also simplifies the code - simply send a couple of bytes to the first shift register, and the data sorts itself out (the first byte is displaced by the second one and flows into the second shift register - I will probably add a third to the chain, to control the green LEDs).  The text is now proportionally-spaced, rather than using 8 pixels per character.

Edit: adding a third shift register to the chain worked, but at the price of making the display rather dim (because of the time spent transferring all the data, I suspect).  The green LEDs aren't as bright as the red ones, which made the effect worse - the red ones were just about acceptable.



#include <string.h>
#include "ascii_hex.h"

#define SPEED 5
#define DELAY 2
#define ROW_OFF LOW
#define ROW_ON HIGH
#define COL_OFF HIGH
#define COL_ON LOW

//Pin Definitions
const byte latchPin = 8;
const byte clockPin = 12;
const byte dataPin  = 11;
const byte mask[]       = {1,2,4,8,16,32,64,128};
      byte led_state[8] = {0, 0, 0, 0, 0, 0, 0, 0};


void setup()
{ 
    pinMode(latchPin, OUTPUT);
    pinMode(clockPin, OUTPUT);
    pinMode(dataPin, OUTPUT);
}
  
void loop()
{
    char to_print[] = "andrew.norman@leicester.ac.uk ()[]{} ";

    int  length = strlen(to_print);
    const byte *next;
         
    for (int pos = 0; pos < length; pos++)
    {
        next = alphabet[to_print[pos]];
        // next[8] is the width of the character
        for (int i = 0; i < next[8]; i++)
        {
            // Update each row of the current dispay
            // by shifting right, and inserting the 
            // appropriate bits of the next frame
            for (int j = 0; j < 8; j++)
            {
                led_state[j] = (led_state[j] << 1) | 
                    ((next[j] >> (7 - i)));
            }
            showArray();
        }
        
        // Insert a space between letters
        for (int j = 0; j < 8; j++)
        {
            led_state[j] <<= 1;
        }
        showArray();
    }
}

void showArray(void)
{
    byte columnSelect;
    // Show the array multiple times to slow down 
    // the "refresh rate"
    for (int s = 0; s < SPEED; s++)
    {                 
        for(int column = 0; column < 8; column++)
        {    
            columnSelect = ~mask[column];  
            sendControl(0x00, columnSelect);      
            sendControl(led_state[column], columnSelect); 
            delay(DELAY);  
        } 
    } 
}

void sendControl(byte rc, byte cc)
{
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, MSBFIRST, cc);
    shiftOut(dataPin, clockPin, MSBFIRST, rc);
    digitalWrite(latchPin, HIGH);
}

Here is the header file with all the character definitions - I put together an Excel spreadsheet to help me generate these (by ticking cells until I had the right shape, and then reading off the hex values). 



#include <Arduino.h>

byte alphabet[128][9] =
{
    // First 32 characters (0 to 31) are control characters, don't print
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 000 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 001 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 002 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 003 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 004 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 005 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 006 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 007 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 008 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 009 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 010 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 011 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 012 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 013 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 014 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 015 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 016 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 017 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 018 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 019 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 020 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 021 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 022 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 023 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 024 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 025 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 026 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 027 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 028 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 029 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 030 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}, /* ASCII 031 */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 4}, /* ASCII 032 = Space */
    {0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 1}, /* ASCII 033 = ! */
    {0xA0, 0xA0, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 3}, /* ASCII 034 = " */
    {0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50, 0x00, 5}, /* ASCII 035 = # */
    {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20, 0x00, 5}, /* ASCII 036 = $ */
    {0x42, 0xA4, 0x48, 0x10, 0x24, 0x4A, 0x84, 0x00, 7}, /* ASCII 037 = % */
    {0x60, 0x90, 0x80, 0x68, 0x90, 0x90, 0x68, 0x00, 6}, /* ASCII 038 = & */
    {0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 1}, /* ASCII 039 = ' */
    {0x40, 0x80, 0x80, 0x80, 0x80, 0x80, 0x40, 0x00, 2}, /* ASCII 040 = ( */
    {0x80, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80, 0x00, 2}, /* ASCII 041 = ) */
    {0x10, 0x92, 0x54, 0x38, 0x54, 0x92, 0x10, 0x00, 7}, /* ASCII 042 = * */
    {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00, 0x00, 5}, /* ASCII 043 = + */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x80, 2}, /* ASCII 044 = , */
    {0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 5}, /* ASCII 045 = - */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 1}, /* ASCII 046 = . */
    {0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 7}, /* ASCII 047 = / */
    {0x60, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00, 4}, /* ASCII 048 = 0 */
    {0x20, 0x60, 0x20, 0x20, 0x20, 0x20, 0x70, 0x00, 4}, /* ASCII 049 = 1 */
    {0x60, 0x90, 0x10, 0x20, 0x40, 0x80, 0xF0, 0x00, 4}, /* ASCII 050 = 2 */
    {0x60, 0x90, 0x10, 0x60, 0x10, 0x90, 0x60, 0x00, 4}, /* ASCII 051 = 3 */
    {0x20, 0x60, 0xA0, 0xA0, 0xF0, 0x20, 0x20, 0x00, 4}, /* ASCII 052 = 4 */
    {0xF0, 0x80, 0x80, 0xE0, 0x10, 0x90, 0x60, 0x00, 4}, /* ASCII 053 = 5 */
    {0x60, 0x90, 0x80, 0xE0, 0x90, 0x90, 0x60, 0x00, 4}, /* ASCII 054 = 6 */
    {0xF0, 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x00, 4}, /* ASCII 055 = 7 */
    {0x60, 0x90, 0x90, 0x60, 0x90, 0x90, 0x60, 0x00, 4}, /* ASCII 056 = 8 */
    {0x60, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 0x00, 4}, /* ASCII 057 = 9 */
    {0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 1}, /* ASCII 058 = : */
    {0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x80, 2}, /* ASCII 059 = ; */
    {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10, 0x00, 4}, /* ASCII 060 = < */
    {0x00, 0x00, 0xF0, 0x00, 0xF0, 0x00, 0x00, 0x00, 4}, /* ASCII 061 = = */
    {0x80, 0x40, 0x20, 0x10, 0x20, 0x40, 0x80, 0x00, 4}, /* ASCII 062 = > */
    {0x70, 0x88, 0x88, 0x10, 0x20, 0x00, 0x20, 0x00, 5}, /* ASCII 063 = ? */
    {0x30, 0x48, 0x98, 0xA8, 0x98, 0x40, 0x38, 0x00, 5}, /* ASCII 064 = @ */
    {0x20, 0x50, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x00, 5}, /* ASCII 065 = A */
    {0xE0, 0x90, 0x90, 0xE0, 0x90, 0x90, 0xE0, 0x00, 4}, /* ASCII 066 = B */
    {0x60, 0x90, 0x80, 0x80, 0x80, 0x90, 0x60, 0x00, 4}, /* ASCII 067 = C */
    {0xE0, 0x90, 0x90, 0x90, 0x90, 0x90, 0xE0, 0x00, 4}, /* ASCII 068 = D */
    {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0xF0, 0x00, 4}, /* ASCII 069 = E */
    {0xF0, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x80, 0x00, 4}, /* ASCII 070 = F */
    {0x60, 0x90, 0x80, 0x80, 0xB0, 0x90, 0x60, 0x00, 4}, /* ASCII 071 = G */
    {0x90, 0x90, 0x90, 0xF0, 0x90, 0x90, 0x90, 0x00, 4}, /* ASCII 072 = H */
    {0xE0, 0x40, 0x40, 0x40, 0x40, 0x40, 0xE0, 0x00, 3}, /* ASCII 073 = I */
    {0x10, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60, 0x00, 4}, /* ASCII 074 = J */
    {0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88, 0x00, 5}, /* ASCII 075 = K */
    {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF0, 0x00, 4}, /* ASCII 076 = L */
    {0x88, 0xD8, 0xA8, 0xA8, 0x88, 0x88, 0x88, 0x00, 5}, /* ASCII 077 = M */
    {0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88, 0x88, 0x00, 5}, /* ASCII 078 = N */
    {0x20, 0x50, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, 5}, /* ASCII 079 = O */
    {0xE0, 0x90, 0x90, 0xE0, 0x80, 0x80, 0x80, 0x00, 4}, /* ASCII 080 = P */
    {0x20, 0x50, 0x88, 0x88, 0xA8, 0x50, 0x28, 0x00, 5}, /* ASCII 081 = Q */
    {0xE0, 0x90, 0x90, 0xE0, 0xC0, 0xA0, 0x90, 0x00, 4}, /* ASCII 082 = R */
    {0x60, 0x90, 0x80, 0x60, 0x10, 0x90, 0x60, 0x00, 4}, /* ASCII 083 = S */
    {0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 5}, /* ASCII 084 = T */
    {0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00, 4}, /* ASCII 085 = U */
    {0x88, 0x88, 0x88, 0x88, 0x50, 0x50, 0x20, 0x00, 5}, /* ASCII 086 = V */
    {0x88, 0x88, 0x88, 0xA8, 0xA8, 0xA8, 0x50, 0x00, 5}, /* ASCII 087 = W */
    {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88, 0x00, 5}, /* ASCII 088 = X */
    {0x88, 0x88, 0x50, 0x20, 0x20, 0x20, 0x20, 0x00, 5}, /* ASCII 089 = Y */
    {0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8, 0x00, 5}, /* ASCII 090 = Z */
    {0xE0, 0x80, 0x80, 0x80, 0x80, 0x80, 0xE0, 0x00, 3}, /* ASCII 091 = [ */
    {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x00, 7}, /* ASCII 092 = \ */
    {0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0xE0, 0x00, 3}, /* ASCII 093 = ] */
    {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 5}, /* ASCII 094 = ^ */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 4}, /* ASCII 095 = _ */
    {0x80, 0x40, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 3}, /* ASCII 096 = ` */
    {0x00, 0x00, 0x60, 0x10, 0x70, 0x90, 0x70, 0x00, 4}, /* ASCII 097 = a */
    {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0xE0, 0x00, 4}, /* ASCII 098 = b */
    {0x00, 0x00, 0x60, 0x80, 0x80, 0x80, 0x60, 0x00, 3}, /* ASCII 099 = c */
    {0x10, 0x10, 0x70, 0x90, 0x90, 0x90, 0x70, 0x00, 4}, /* ASCII 100 = d */
    {0x00, 0x00, 0x60, 0x90, 0xF0, 0x80, 0x70, 0x00, 4}, /* ASCII 101 = e */
    {0x20, 0x50, 0x40, 0xE0, 0x40, 0x40, 0x40, 0x00, 4}, /* ASCII 102 = f */
    {0x00, 0x00, 0x60, 0x90, 0x90, 0x60, 0x10, 0x60, 4}, /* ASCII 103 = g */
    {0x80, 0x80, 0xE0, 0x90, 0x90, 0x90, 0x90, 0x00, 4}, /* ASCII 104 = h */
    {0x00, 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 1}, /* ASCII 105 = i */
    {0x00, 0x20, 0x00, 0x20, 0x20, 0x20, 0xA0, 0x40, 3}, /* ASCII 106 = j */
    {0x80, 0x80, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x00, 4}, /* ASCII 107 = k */
    {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 1}, /* ASCII 108 = l */
    {0x00, 0x00, 0x50, 0xA8, 0xA8, 0xA8, 0xA8, 0x00, 5}, /* ASCII 109 = m */
    {0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x90, 0x00, 4}, /* ASCII 110 = n */
    {0x00, 0x00, 0x60, 0x90, 0x90, 0x90, 0x60, 0x00, 4}, /* ASCII 111 = o */
    {0x00, 0x00, 0x60, 0x90, 0x90, 0xE0, 0x80, 0x80, 4}, /* ASCII 112 = p */
    {0x00, 0x00, 0x60, 0x90, 0x90, 0x70, 0x10, 0x10, 4}, /* ASCII 113 = q */
    {0x00, 0x00, 0x60, 0x90, 0x80, 0x80, 0x80, 0x00, 4}, /* ASCII 114 = r */
    {0x00, 0x00, 0x70, 0x80, 0x60, 0x10, 0xE0, 0x00, 4}, /* ASCII 115 = s */
    {0x40, 0x40, 0xE0, 0x40, 0x40, 0x50, 0x20, 0x00, 4}, /* ASCII 116 = t */
    {0x00, 0x00, 0x90, 0x90, 0x90, 0x90, 0x60, 0x00, 4}, /* ASCII 117 = u */
    {0x00, 0x00, 0x88, 0x88, 0x88, 0x50, 0x20, 0x00, 5}, /* ASCII 118 = v */
    {0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50, 0x00, 5}, /* ASCII 119 = w */
    {0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88, 0x00, 5}, /* ASCII 120 = x */
    {0x00, 0x00, 0x90, 0x90, 0x70, 0x10, 0x90, 0x60, 4}, /* ASCII 121 = y */
    {0x00, 0x00, 0xF0, 0x20, 0x40, 0x80, 0xF0, 0x00, 4}, /* ASCII 122 = z */
    {0x20, 0x40, 0x40, 0x80, 0x40, 0x40, 0x20, 0x00, 3}, /* ASCII 123 = { */
    {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 1}, /* ASCII 124 = | */
    {0x80, 0x40, 0x40, 0x20, 0x40, 0x40, 0x80, 0x00, 3}, /* ASCII 125 = } */
    {0x00, 0x50, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 4}, /* ASCII 126 = ~ */
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0}  /* ASCII 127 = DEL (don't print)*/
};

const byte invader1[9]   = {0x18, 0x3c, 0x7e, 0xdb, 0xff, 0x24, 0x5a, 0xa5, 8}; 
const byte invader2[9]   = {0x3c, 0x7e, 0xff, 0x99, 0xff, 0x66, 0xdb, 0x81, 8}; 


No comments:

Post a Comment