
Druzyek
-
Content Count
76 -
Joined
-
Last visited
-
Days Won
3
Reputation Activity
-
Druzyek got a reaction from GastonP in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from larryfraz in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from bluehash in RPN Scientific Calculator
@@petertux, good question. I had several AS6C1008s handy with nothing planned for them so I decided to use them. A 23A1024 would have worked well too and probably wouldn't have been much slower.
-
Druzyek got a reaction from igor in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from Rickta59 in [ ENDED ] Nov 2013 - Jan 2014 - 43oh Project of the Month Contest
My entry to the POTM contest is an RPN Scientific Calculator:
More info about the project is here: http://forum.43oh.com/topic/5003-rpn-scientific-calculator/ My GitHub with the source code is here: https://github.com/druzyek/RPN_Calculator
-
Druzyek got a reaction from tripwire in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from bluehash in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from dubnet in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from yosh in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from petertux in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from Rickta59 in RPN Scientific Calculator
Overview
This is a scientific calculator I built that uses RPN notation. Features:
BCD number format with 1-255 places Internal accuracy configurable from 6 to 32 decimal places Two separate 200 level stacks Optional scientific notation Functions: (a)sin, (a)cos, (a)tan, y^x, x root y, e^x, ln, 10^x, log, mod 20x4 character LCD 42 buttons The source code is available on https://github.com/druzyek/RPN_Calculator.
Software
The interface shows 4 levels of the stack, similar to some HP calculators. While I was writing the code for BCD calculations, I used a console program to test the routines. You can download it from GitHub if you want to test out the functionality: rpnmain_pc.c It will compile for Windows if #WINDOWS is defined or for Linux with the ncurses library if #LINUX is defined.
On Windows: gcc -o rpncalc.exe rpnmain_pc.c On Linux: gcc -lncurses -o rpncalc rpnmain_pc.c Numbers are stored in unpacked BCD format on an external SRAM chip. I wanted to access this memory using variables but there is no convenient way to do this since every variable requires a function to access it. A simple functions like:
X+=Y*Z-Q; would become something like this (assuming we are passing pointers):
RAM_Write(X,RAM_Read(X)+(RAM_Read(Y)*RAM_Read(Z)-RAM_Read(Q)); To simplify things, I wrote a preprocessor program that looks for any variables that need to be stored in external RAM and converts access to them to function calls. External variables are all stored as pointers, so the PC version will work exactly the same with or without the preprocessor. To mark variables as external, #pragma directives are used. These are usually ignored by the compiler if they are not recognized, so they are a convenient way to communicate with the preprocessor. Here is an example:
//Before processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;msg[i];i++) putchar(msg[i]); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char text1[30]; unsigned char text2[30]; #pragma MM_END text1[0]='A'; text1[1]=0; puts(text1); } //After processing void puts(unsigned char *msg) { #pragma MM_VAR msg for (int i=0;RAM_Read(msg+i);i++) putchar(RAM_Read(msg+i)); } int main() { #pragma MM_OFFSET 200 #pragma MM_DECLARE unsigned char *text1=(unsigned char*)200; unsigned char *text2=(unsigned char*)230; #pragma MM_END RAM_Write(text1+0,'A'); RAM_Write(text1+1,0); puts(text1); } The trig and log functions are computed using CORDIC routines. This is a very efficient way to compute these functions for processors that cannot multiply or divide quickly. Instead, a lookup table is used with adds and shifts, which are much faster. I was able to speed the shifting up even more by using another lookup table that let me right shift 4 digits at a time. One way to measure the accuracy of calculations is with the calculator forensic found here: http://www.rskey.org/~mwsebastian/miscprj/forensics.htm. After setting accuracy to 24 places arcsin(arccos(arctan(tan(cos(sin(9)))))) evaluates to this:
The settings page allows the accuracy to be set from 6 to 32 decimal places. With the default of 12, trig functions calculate in about a second. With 32 decimal places calculations take 3-4 seconds. After setting the accuracy, the program finds the largest element in the CORDIC table that is still significant, so that no time is wasted on elements that have no effect on the answer. The settings page also shows the current battery charge.
When I began this project I wasn't sure how much I could fit into 16kB of firmware space. In the end it grew bigger than this and I had to use two MSP430s to hold everything. Part of this is due to all of the functions used to access external memory. The interface code also added a lot more to the size than I expected but I was able to add checks for most of the functions and add some meaningful error messages.
Hardware
My design uses two MSP430G2553s connected over UART. One of them (the master) reads the keyboard matrix, updates the LCD, and manages the interface. The other is connected to the data lines of 128k of parallel SRAM and does all of the calculating. The address lines of the SRAM are driven by two 74HC595 shift registers controlled by the second MSP430. The 17th address pin is controlled by the first MSP430 and allows the program to switch between two separate stacks. Here is the schematic:
The keypad is formed from 42 tactile buttons arranged in a 6x7 matrix and read with a 74HC165 shift register by the master MSP430. The LCD and keyboard share the same pins since they are never used at the same time. Here is the layout of the keys.
The LCD is an HD44780 compatible 20x4 character LCD. It is rated for 5v but the logic works fine at 3.6v. The contrast needs to be close to 5v for anything to show up on the screen, so I used a 555 timer and some diodes to supply around -1.2v to the contrast pin. The result is very solid and clear.
The calculator runs on four AA batteries regulated by an LM1117 configured to supply around 3.5 volts. To run at 16MHz the MSP430s need at least 3.3 volts. The wiggle room between the two voltages will let me see when the batteries are starting to wear down. By the time the voltage gets down to 3.3v, the batteries will be down to 1.15v or so, which can be considered dead.
The PCB is made from perfboard. The top of the board contains female headers so that the keyboard and LCD can be unplugged. Part of the board had to be cut away so that it will fit in the case with the batteries. Although it is quite small, I ended up using over three meters of wire.
The case is soldered out of copper clad. I used a lot of solder on it and it feels very sturdy. I will give it a coat of paint tomorrow before assembling everything.
-
Druzyek got a reaction from bluehash in Simulating a TI calculator with crazy 11-bit opcodes
I have been working on something similar for the last few months. Mine is based more on HP calculators, though. I'm using a 20x4 LCD so the interface should look similar to an HP-28 or HP-48 series model. I wanted to add keystroke programming too but the firmware is already at 14K without it. I added a second G2553 so I can hopefully split up the tasks between the two and still have enough flash. I think a G2553 would work fine to remake either of those calculators.
Here is my blog in case you are interested: http://joldosh.blogspot.com/
-
Druzyek got a reaction from simpleavr in Simulating a TI calculator with crazy 11-bit opcodes
I have been working on something similar for the last few months. Mine is based more on HP calculators, though. I'm using a 20x4 LCD so the interface should look similar to an HP-28 or HP-48 series model. I wanted to add keystroke programming too but the firmware is already at 14K without it. I added a second G2553 so I can hopefully split up the tasks between the two and still have enough flash. I think a G2553 would work fine to remake either of those calculators.
Here is my blog in case you are interested: http://joldosh.blogspot.com/
-
Druzyek got a reaction from sirri in light alarm clock project using msp430
I would check all the physical connections too. I had a strange case where a shift register was hooked up to some LEDs. It worked the first time but instead of resetting after power was completely removed, it would show the last thing it had displayed when the power was reconnected. I couldn't get the MSP430 to communicate with it again until I removed both chips and put them back in. It turned out that one of the wires to ground had come loose.
-
Druzyek got a reaction from roadrunner84 in Binary Calculator Using LEDs
For my first project I decided to make a calculator that can add and subtract binary numbers. The number is represented by 8 LEDs. It uses RPN instead of algebraic notation since I am a fan of HP calculators which also use that format. I have 8 buttons to work with so I decided on the functions 1, 0, Push, Pop, Dupe, Swap, +, and -. The circuit is basically just an MSP4302533 with a 595 and a 165 shift register. It was a fun project because I got to practice soldering and using interrupts and shift registers. Here are some pictures and the source code. Let me know if you see anything to improve.
#include <msp430g2533.h> #include <stdbool.h> #define Button1 BIT7 #define Button0 BIT6 #define ButtonPush BIT5 #define ButtonPop BIT4 #define ButtonSwap BIT2 #define ButtonDupe BIT3 #define ButtonAdd BIT1 #define ButtonSubtract BIT0 //165 shift register #define IN_CLOCK BIT2 //pin 2 #define IN_LOAD BIT1 //pin 1 #define IN_DATA BIT0 //pin 9 //595 shift register #define OUT_CLOCK BIT1 //pin 11 #define OUT_LATCH BIT2 //pin 12 #define OUT_DATA BIT4 //pin 14 #define OUT_RESET BIT5 //pin 10 void WriteBits(unsigned char bits); unsigned char ReadBits(void); bool StartNew; unsigned char memory[100]; unsigned char ButtonStatus[8]; unsigned char Stabilized; int ptr; int main(void) { volatile unsigned int i=0; WDTCTL=WDTPW + WDTHOLD; for (i=0;i<8;i++) ButtonStatus[i]=0; for (i=0;i<100;i++) memory[i]=0; StartNew=false; Stabilized=10; int ptr=0; BCSCTL1=CALBC1_1MHZ; DCOCTL=CALDCO_1MHZ; BCSCTL3 |= LFXT1S_2; P1DIR=0xFF; P2DIR=0xFF & ~IN_DATA; //reset shift register P1OUT&=~OUT_RESET; P1OUT|=OUT_RESET; //Draw a pattern of lights to show it's on int j,k=1; for (j=0;j<8;j++) { WriteBits(k); k=k*2; for (i=0;i<20000;i++); } WriteBits(0x0); //VLO is 12000HZ. This should trigger at 40Hz TACCR0 = 300; TACCTL0 = CCIE; TACTL = MC_1|ID_0|TASSEL_1|TACLR; __enable_interrupt(); for (; {_BIS_SR(LPM3_bits);} } void WriteBits(unsigned char bits) { int i; P1OUT|=OUT_LATCH; P1OUT&=~OUT_LATCH; for (i=0;i<8;i++) { if (bits & (1<<(7-i))) P1OUT|=OUT_DATA; else P1OUT&=~OUT_DATA; P1OUT|=OUT_CLOCK; P1OUT&=~OUT_CLOCK; } P1OUT|=OUT_LATCH; P1OUT&=~OUT_LATCH; } unsigned char ReadBits(void) { unsigned char output=0; int i=0; P2OUT&=~IN_LOAD; P2OUT|=IN_LOAD; for (i=0;i<7;i++) { output*=2; if ((P2IN & IN_DATA)==0) output++; P2OUT|=IN_CLOCK; P2OUT&=~IN_CLOCK; } output*=2; if ((P2IN & IN_DATA)==0) output++; return output; } __attribute__((interrupt(TIMER0_A0_VECTOR))) static void TA0_ISR(void) { unsigned char ButtonRead,buff; volatile int j; if (Stabilized!=0) { Stabilized--; return; } ButtonRead=ReadBits(); for (j=0;j<8;j++) { if (ButtonRead & 1<<j) { if (ButtonStatus[j]==0) { ButtonStatus[j]=1; switch (1<<j) { case Button1: if ((StartNew)&&(ptr<99)) { ptr++; memory[ptr]=0; StartNew=false; } memory[ptr]=memory[ptr]*2+1; break; case Button0: if ((StartNew)&&(ptr<99)) { ptr++; memory[ptr]=0; StartNew=false; } memory[ptr]*=2; break; case ButtonPush: if (ptr<99) { ptr++; memory[ptr]=0; } break; case ButtonPop: memory[ptr]=0; if (ptr>0) { ptr--; StartNew=true; } break; case ButtonDupe: if (ptr<99) { ptr++; memory[ptr]=memory[ptr-1]; StartNew=true; } break; case ButtonSwap: if (ptr>0) { buff=memory[ptr]; memory[ptr]=memory[ptr-1]; memory[ptr-1]=buff; StartNew=true; } /*else if (ptr<99) { ptr++; memory[ptr]=0; //StartNew=true; }*/ break; case ButtonAdd: if (ptr>0) { memory[ptr-1]+=memory[ptr]; memory[ptr]=0; ptr--; StartNew=true; } break; case ButtonSubtract: if (ptr>0) { memory[ptr-1]-=memory[ptr]; memory[ptr]=0; ptr--; StartNew=true; } break; } WriteBits(memory[ptr]); } } else ButtonStatus[j]=0; } }