Back again! In this post I will discuss my progress combining the typewriter and the Edison together. In case you missed them, here are my previous posts:
In my last post, I mentioned that my LED testing board revealed a problem with my circuit: the inputs are sensitive to vibration and give off a lot of glitches as I type. I had come up with some code to get around this, but later I thought that it might be better to try to solve the problem with hardware instead of software. By the way, I was researching switch/button debouncing and I came across an article that I thought was very informative. You can check it out here.
If you have ever used a typewriter, you know that every time you type a letter - any letter - certain actions happen. The carriage advances slightly, the ribbon reel turns a bit. This happens for every key stroke, regardless of which key you typed. I realized that there must be some mechanism moving around inside the typewriter every time any key is pressed. How does this help my "glitch" problem? Well if I can use that mechanism to trigger a separate input (let's call this input key_pressed), then I can have the Edison only read the states of the keys whenever key_pressed gets triggered. So I looked around inside the machine and found exactly what I needed. In the gallery below, you can see a closeup of the inside of the typewriter. There is this little metal piece surrounded by rubber padding. This piece is outlined pink in the second picture. When I type any key, as the type bar gets very close to the paper, this piece gets pressed against the perpendicular metal tab below it (outlined in red in the second picture). This metal tab is a part of the chassis which I already have connected to ground. So I stripped a couple inches off a jumper wire and wrapped the bare wire around the rubber padding. The other end of that jumper wire goes to a separate input on the Edison (along with a pull-up resistor). Now that this is in place, the Edison can detect when I am pressing a key and then read the data from the shift registers.
{gallery:autoplay=false} "key_pressed" mechanism |
---|
Mechanism |
Mechanism outlined |
So with this new modification, I needed to change my code. I still intend to use the "frames" method that I outlined in my last post, but now I will only read frames for as long as the key_pressed input is active. Once the key is released, all these frames will be ANDed together to determine the key that was pressed. Before I can get to that though, I wanted to make sure that I could read the data from the shift registers and pass this data from the MCU to the CPU. I had a lot of problems, mostly because I was trying too many things at once. I had to break the code down and try everything one step at a time and build it up slowly. This was somewhat painful because every time you want to change the code on the MCU, you have to uninstall the previous code, then restart the Edison, then install your new code, then restart the Edison again. Not a fun way to debug. But in the end I managed to get some results that I can work with.
I disconnected my testing board and wired everything together - the keys to the shift registers and the shift registers to the Edison. You can see my circuit in the gallery below. It's pretty messy, but it's hard to be neat with over 50 wires on one breadboard. (I put the typewriter on some books to keep the sharp edges on the bottom from resting on the wires)
{gallery:autoplay=false} Typewriter + Edison |
---|
Isn't it beautiful? |
Close-up |
The code that I have running on the MCU is below. Basically, whenever the key_pressed input goes low, the MCU starts reading data and sending it to the CPU.
#include "mcu_api.h" #include "mcu_errno.h" //Data pins are the serial data coming from //shift registers. In order, IO2 = IO7. int datapins[6] = {128, 12, 129, 13, 182, 48}; //This pin goes low when a key is pressed. int key_pressed = 131; //Control signals for shift registers. int SH_LD = 49; //IO8 int CLK_INH = 183; //IO9 int CLK = 41; //IO10 char result[20]; unsigned char frame[6]; int i, j; //loop variables /* * See datasheet for proper operation of shift * register (74HC165). */ void shift_in(){ //Load into register gpio_write(SH_LD, 0); gpio_write(SH_LD, 1); //Turn off clock inhibit gpio_write(CLK_INH, 0); //Get data from register for(i = 0; i < 8; i++){ for(j = 0; j < 6; j++){ //Shift data in frame[j] <<= 1; frame[j] |= gpio_read(datapins[j]); } //Cycle the clock gpio_write(CLK, 1); gpio_write(CLK, 0); } //Turn clock inhibit back on gpio_write(CLK_INH, 1); } void mcu_main() { int len = 0; for (i = 0; i < 6; i++){ gpio_setup(datapins[i], 0); } gpio_setup(SH_LD, 1); gpio_setup(CLK_INH, 1); gpio_setup(CLK, 1); gpio_setup(key_pressed, 0); gpio_write(CLK_INH, 1); gpio_write(CLK, 1); gpio_write(SH_LD, 0); while (1) { if(!gpio_read(key_pressed)){ shift_in(); len = mcu_snprintf(result, 20, "%d, %d, %d, %d, %d, %d\n", frame[0], frame[1], frame[2], frame[3], frame[4], frame[5]); host_send((unsigned char *)result, len); } else { for(i = 0; i < 6; i++){ frame[i] = frame[i] & 0; } } } }
The CPU then receives the data from the MCU in a form similar to this:
128, 0, 0, 0, 0, 0
128, 0, 0, 0, 0, 0
128, 0, 0, 0, 0, 0
This would correspond to a 1 on the the "H" bit of the 1st shift register - which is connected to the 'q' key of the typewriter. Initially, I was trying a slightly different approach where the CPU would request the data, then the MCU would read the data from the registers and send it back to the CPU, then the CPU would print it out like above. However, when I ran this code, it would work at first but then for some reason the python script just stopped printing lines. It was very strange - the CPU didn't freeze up, I could ctrl-c out of the script and then restart it and it would work fine but eventually it would freeze up again. I still don't know what was causing this. However, I changed the code to what you see above and it works fine. And when I say it works fine, I mean that if type
cat /dev/ttymcu0 > output.txt
at the console, then hit some keys on the keyboard, I can read those keystrokes in the output.txt file. I'm thinking now that I could put the above command into a startup script. Then when it's time to actually send the email, the Edison could just read what's in the "output.txt" file.
So what's next? Well I still need to actually "decode" the data from the shift registers. I am wondering if it would be better to do the decoding in the MCU and have the MCU send the typed character to the CPU or should I have the MCU send the raw data (like it's doing now) and have the CPU decode it to determine the typed key? It would probably be more efficient to send the raw data and then have the CPU decode it when it's time to send the email. If you have any thoughts on this, please let me know!
And of course I still need to write the code that actually sends the email, but I think this will be easy. In a past project, I wrote python code that would read email, so I'm sure it won't be too much trouble.
I hope you enjoyed this update, stay tuned for my next post! Let me know if you have any questions, comments, concerns, or criticisms.
Top Comments