Model Railroad System  2.2.1
Model RR signals with an Arduino
SignalDriverMax72xx.ino
1 #include <LedControl.h>
2 #include <stdio.h>
3 #include <string.h>
4 
5 /** @defgroup SignalDriverMax72xx Ardunio Signal Driver using a MAX72XX
6  * This is the software downloaded to the Ardunio to interface to the MAX72XX
7  * LED multiplexer driving the signals.
8  *
9  * @{
10  */
11 
12 
13 /** Create a new LedControl.
14  * We use pins 12,11 and 10 for the SPI interface
15  * With our hardware we have connected pin 12 to the DATA IN-pin (1) of the first MAX7221
16  * pin 11 is connected to the CLK-pin(13) of the first MAX7221
17  * pin 10 is connected to the LOAD-pin(12) of the first MAX7221
18  * We will only have a single MAX7221 attached to the arduino
19  */
20 LedControl lc1=LedControl(12,11,10,1);
21 
22 /*
23  * Testing control variables.
24  */
25 
26 /** Start digit. */
27 int s_digit,
28 /** End digit. */
30 /** Current digit. */
32 /** Current bits. */
34 /** Flag indicating if we are in test mode. */
35 boolean test = false;
36 
37 
38 /** The setup function initializes the MAX72xx chip and sends an
39  * announcement to the host computer over the serial port.
40  */
41 void setup() {
42  /* Set max intensity */
43  lc1.setIntensity(0,15);
44  /* Set all signals to 'dark' (no lights on). */
45  lc1.clearDisplay(0);
46  /* Wake up display. */
47  lc1.shutdown(0,false);
48  /* Announce ourself to the host */
49  Serial.begin(115200);
50  Serial.println("Signal Driver Max72XX 0.1");
51  Serial.print("\n>>");
52  Serial.flush();
53  test = false;
54 }
55 
56 /* Signal Aspects */
57 /** Red over Red (Stop) */
58 #define R_R B00001001
59 /** Red over Yellow (Approach Limited) */
60 #define R_Y B00001010
61 /** Red over Green (Slow Clear) */
62 #define R_G B00001100
63 /** Yellow over Red (Approach) */
64 #define Y_R B00010001
65 /** Green over red (Clear) */
66 #define G_R B00100001
67 /** Dark (all lights off) */
68 #define DARK B00000000
69 
70 /** Test for each signal aspect string and when a match
71  * Occurs, return the corresponding bit pattern.
72  * @param aspectname The aspect text sent from the host.
73  * @returns The bit pattern to display the selected aspect.
74  */
75 int GetAspectBits(const char *aspectname) {
76  if (strcasecmp("R_R",aspectname) == 0) return R_R;
77  else if (strcasecmp("R_Y",aspectname) == 0) return R_Y;
78  else if (strcasecmp("R_G",aspectname) == 0) return R_G;
79  else if (strcasecmp("Y_R",aspectname) == 0) return Y_R;
80  else if (strcasecmp("G_R",aspectname) == 0) return G_R;
81  else if (strcasecmp("DARK",aspectname) == 0) return DARK;
82  else return -1;
83 }
84 
85 /** The main loop function. Here we read a one line command from
86  * the host computer and decide what to do. There are only three commands
87  * defined:
88  * - One to turn all of the LEDs off.
89  * - One to set the aspect of one signal.
90  * - And one to initiate a test sequence.
91  */
92 void loop() {
93  char buffer[256]; /* Command line buffer. */
94  char p_buffer[32]; /* Test prompt buffer. */
95  int len; /* Line length. */
96  char unused;
97  int n;
98 
99  /* check if in test mode. */
100  if (test) {
101  /* Display the current test pattern on the current signal. */
102  lc1.setRow(0, i_digit, i_bits);
103  /* Print the current signal number and the current test pattern. */
104  sprintf(p_buffer,"\n%d:%02x>>", i_digit, i_bits);
105  Serial.print(p_buffer);
106  Serial.flush();
107  delay(1000); /* One second sleep. */
108  /* Compute the next pattern and/or signal number. */
109  switch(i_bits) {
110  case B00000000: /* Last pattern. Next signal number. */
111  if (i_digit >= e_digit) { /* Last signal number, go to first signal number. */
112  i_digit = s_digit;
113  } else { /* Next signal number. */
114  i_digit++;
115  }
116  i_bits = B00000001; /* First pattern. */
117  break;
118  case B11111111: /* If at all on, go to all off. */
119  i_bits = B00000000;
120  break;
121  case B10000000: /* If at top LED, go to all on. */
122  i_bits = B11111111;
123  break;
124  default: /* Otherwise, shift left one bit. */
125  i_bits = i_bits << 1;
126  break;
127  }
128  }
129  /* If there is serial data available... */
130  if (Serial.available() > 0) {
131  /* If testing, stop the test and clear the signal. */
132  if (test) {
133  test = false;
134  lc1.setRow(0, i_digit, B00000000);
135  }
136  /* Read a line from the serial port (USB connection
137  from the host computer. */
138  len = Serial.readBytesUntil('\r',buffer,sizeof(buffer)-1);
139  if (len <= 1) {
140  /* Reissue command prompt. */
141  Serial.print("\n>>");
142  Serial.flush();
143  return;
144  }
145  buffer[len] = '\0';
146  switch (toupper(buffer[0])) {
147  case 'D': /* Clear all signals to Dark. */
148  lc1.clearDisplay(0);
149  break;
150  case 'S': /* Set one signal. */
151  {
152 
153  char aspect[10];
154  int signalnum, aspectbits;
155  if (sscanf(buffer,"%c %d %9s",&unused,&signalnum,aspect) != 3) {
156  Serial.println("\nSyntax error (Set command)!");
157  } else {
158  /* Parse aspect string. */
159  aspectbits = GetAspectBits(aspect);
160  /* Check for legal aspect string. */
161  if (aspectbits < 0) {
162  Serial.println("\nSyntax error (Bad aspect)!");
163  /* Check for legal signal number. */
164  } else if (signalnum >= 0 && signalnum < 8) {
165  lc1.setRow(0, signalnum, (byte) aspectbits);
166  } else {
167  Serial.println("\nSyntax error (Bad signal number)!");
168  }
169  }
170  break;
171  }
172  case 'T': /*
173  * Test mode. Test one or more signals, lighting LEDs in a sequence of patterns:
174  * First one LED, from bottom to top, then all on, than all off. Repeat with the
175  * next signal. After the last signal in the test, start over with the first
176  * signal in the test. Repeat forever or until another command is sent.
177  */
178  /* Parse command, getting the number of conversions.
179  * One conversion means no arguments -- test all eight signals. Two conversions means one
180  * argument -- test one signal. Three conversions means two arguments -- test a range of
181  * signals. */
182  n = sscanf(buffer,"%c %d %d",&unused,&s_digit,&e_digit);
183  /* sprintf(p_buffer,"\n*** n = %d",n);
184  Serial.println(p_buffer);*/
185  /* Fan out on conversion count. */
186  switch (n) {
187  case 1: /* No arguments -- test all signals. */
188  s_digit = 0;
189  e_digit = 7;
190  i_digit = s_digit;
191  i_bits = B00000001;
192  test = true;
193  break;
194  case 2: /* One argument -- test one signal. */
195  e_digit = s_digit;
196  if (s_digit < 0 || s_digit > 7) {
197  Serial.println("\nSyntax error (Bad signal number)!");
198  break;
199  }
200  i_digit = s_digit;
201  i_bits = B00000001;
202  test = true;
203  break;
204  case 3: /* Two arguments -- test a range of signals. */
205  if (s_digit < 0 || s_digit > 7) {
206  Serial.println("\nSyntax error (Bad signal number)!");
207  break;
208  }
209  if (e_digit < 0 || e_digit > 7) {
210  Serial.println("\nSyntax error (Bad signal number)!");
211  break;
212  }
213  i_digit = s_digit;
214  i_bits = B00000001;
215  test = true;
216  break;
217  default: /* Something else -- spit out an error message. */
218  Serial.println("\nUnknown command!");
219  break;
220  }
221  break;
222  default:
223  Serial.println("\nUnknown command!");
224  break;
225  }
226  /* Reissue command prompt. */
227  Serial.print("\n>>");
228  Serial.flush();
229  }
230 } /* End of Main loop */
231 
232 /** @} */
test
boolean test
Flag indicating if we are in test mode.
Definition: SignalDriverMax72xx.ino:35
Y_R
#define Y_R
Yellow over Red (Approach)
Definition: SignalDriverMax72xx.ino:64
s_digit
int s_digit
Start digit.
Definition: SignalDriverMax72xx.ino:27
e_digit
int e_digit
End digit.
Definition: SignalDriverMax72xx.ino:29
i_digit
int i_digit
Current digit.
Definition: SignalDriverMax72xx.ino:31
lc1
LedControl lc1
Create a new LedControl.
Definition: SignalDriverMax72xx.ino:20
R_G
#define R_G
Red over Green (Slow Clear)
Definition: SignalDriverMax72xx.ino:62
DARK
#define DARK
Dark (all lights off)
Definition: SignalDriverMax72xx.ino:68
R_Y
#define R_Y
Red over Yellow (Approach Limited)
Definition: SignalDriverMax72xx.ino:60
loop
void loop()
The main loop function.
Definition: SignalDriverMax72xx.ino:92
setup
void setup()
The setup function initializes the MAX72xx chip and sends an announcement to the host computer over t...
Definition: SignalDriverMax72xx.ino:41
i_bits
int i_bits
Current bits.
Definition: SignalDriverMax72xx.ino:33
G_R
#define G_R
Green over red (Clear)
Definition: SignalDriverMax72xx.ino:66
GetAspectBits
int GetAspectBits(const char *aspectname)
Test for each signal aspect string and when a match Occurs, return the corresponding bit pattern.
Definition: SignalDriverMax72xx.ino:75
R_R
#define R_R
Red over Red (Stop)
Definition: SignalDriverMax72xx.ino:58