Jump to content


  • Content Count

  • Joined

  • Last visited

About davebranton

  • Rank
  • Birthday 12/10/1973

Profile Information

  • Gender
  • Location
    Christchurch, NZ
  1. Wonderful. I'm going to completely steal this, and use the extra space on the left side of my MIDI drum pads and play stadiums: http://forum.43oh.com/topic/8340-midi-drum-pads/
  2. I decided to have a crack at building some drum pads, because the keyboard that I'd acquired for the kids to learn piano on had a midi input, and somewhat acceptable drum sounds to boot. After several months of sitting around half-completed under a cupboard, I decided to pull it out over the easter weekend and actually make it work. In words, here's what I did. Six drum pads, made of a square of hardboard with 5mm closed-cell foam glued to the top and standing on 15mm foam pads. Each pad has a piezo electric transducer underneath, attached using hot glue. These six piezos are each hooked up to a buffer and biasing and clamping circuit, like below. The op-amp I used was an LMC648, which is great for this application but isn't that cheap. These six analog channels are connected to six of an MSP430's analog inputs. This micro samples these six inputs continuously, and uses a simple filter and threshold algorithm to determine when they've been hit. Once it detects a hit, it outputs the pad ID (zero to five) and the 'velocity' of the hit over I2C to another MSP430. This second micro in turn outputs the MIDI command, through a completely un-necassary additional chip to drive the MIDI output completely to spec. I know it's possible to output midi using 3.3v, but I used a driver chip anyway to run it at 5v - a TC4428 FET driver that I happened to have left over from another project. The second micro also translated the pad ID to a MIDI note, and can be reprogrammed via a couple of buttons that are used to change the drum sound that's assigned to the most recently hit pad. The assignments are stored in the MSP430's "information memory" segment, so that it remembers how you set it up when you turn it off. I'd originally planned to put a 16x2 LCD on there, but I ended up using that for something else. In pictures, here's what it looks like. Overall: PCB closeup - I would normally have a full eagle schematic and layout for this, even if I'm building it on stripboard, because I just make fewer mistakes that way. In this case though the layout of the six clamping circuits turned out to be much easier if I stood those components up out of the board (look on the right side of the picture) and wired them up over the top, and you can't really do that so easily in Eagle. Piezo closeup (under the pads) And finally, in code, here's the two projects. The ADC sampling micro : main.c The MIDI outputting micro : main.c Probably the most interesting aspect of this for me at least, was that when I was designing the (admittedly still rather crude) algorithm to determine how hard the pad had been hit, I needed to get the ADC samples off the chip so that I could experiment with algorithms offline and tweak their performance. I happen to have one of the rather wonderful saleae USB logic analysers (https://www.saleae.com/logic/), and so if you compile the ADC sampling micro's code with OUTPUT_SAMPLES defined, it will run the I2C at 1Mhz (instead of a much more reasonable 125kHz) and output all the ADC data as it receives it. This is pretty borderline for I2C, but if you keep the track length for the I2C nice and short you should be ok. In my case it's the orange and yellow wires in the PCB photo above - and of course you'll need both micros there because the I2C won't work if nothing's there to ACK. Anyway, doing this I was able to get the samples back into my PC, and using python and pylot etc, plot handy graphs like this: Python file, and two text files recorded from the inputs using I2C and the USB logic analyser : Archive.zip The algorithm just detects when the input rises over some threshold, and while integrates the value before it crosses back over zero again (this is after the ADC samples have had 512 subtracted from them of course, making them signed). This is then considered the 'velocity', and the MIDI micro then divides that down to get a 7-bit velocity value for MIDI. This works 'ok', but very light hits aren't detected, and sometimes hits are quite a bit louder than you'd expect. It's still fun though.
  3. Also, one more pic I forgot, here's everything plugged together showing some text. After reading something about how the text needs to be antialiased to allow for smooth scrolling, I modified the text rendering code to allow the characters to be placed by quarter pixels. This made a huge difference to the readability of text on such a small display, but makes it look a bit weird in photographs. The idea is to intersperse the timer display with occasional inspirational/subliminal messages Well, actually probably just stuff to entertain a bit - although I've not really had any good ideas on this. At the moment it just scrolls Robert Frost's 'Fire and Ice', which is a bit over their heads and perhaps a bit apocalyptic for bedtime anyway. I thought perhaps knock-knock jokes would be pretty fun.
  4. Having done quite a bit of work in the past with inertial sensors, I can say that it's next to impossible to distinguish one type of motion from another using accelerometers & gyros. Especially with the kind of cheap accelerometers that would fit on the back of a toothbrush. So although it's a pretty nice idea, I think in the end I'll have to trust them. I'll probably be behind them in the bathroom policing the whole thing anyway, and the timer is as much for me as it is for them. AND of course the whole thing is only an excuse to play with electronics and spend some cash of parts and PCB manufacture But in any case, the components turned up, I soldered them on & it worked first time - so I've attached some photos and a couple of grabs from the scope to show what the power supply looks like. I have another filter before the power gets to the MSP, which I've got on the scope traces separately. More by luck than judgement, this filtered power happened to max out at 3.6v! So: Populated board front & back: Scope trace of filtered & unfiltered power: & The same (except the traces are swapped) after I added a couple of extra thousand microfarads of capacitance to the power supply. This has a different time scale too, but you can see the min & max of the supply voltage at the bottom of the snap. & Again, just because I only just found out how to get my scope to upload screengrabs to my laptop, here's one of those spikes zoomed in. Presumably, when the power supply load changes as a new set of LEDs are switched on, the regulator reacts with this little short wobbly spike thing that lasts just under a microsecond. Hopefully this won't cause any issues with the serial communications between the shift registers (running off this noisy supply), and the micro (running off comparatively clean power).
  5. @@cubeberg Fantastic project, and impressive results. I wonder if you would be better off transmitting the co-ordinates in binary rather then text too? That might improve your bandwidth. I have a few questions if you'll permit me: 1) How much current do the motors draw? 2) How have you implemented the z-axis? 3) What kind of pen have you used? Have you experimented with others? Biro vs. a felt-tip for instance?
  6. Completed control board arrived. Still got a two-week wait for the parts though...
  7. @@bluehash I'm using a python script, and url2lib2: try: r = urllib2.Request('http://api.xively.com/v2/feeds/100842', json_data, {'Content-Type': 'application/json', 'X-ApiKey':apikey}) r.get_method = lambda: 'PUT' urllib2.urlopen(r) except urllib2.HTTPError, error: contents = error.read() print >> sys.stderr, contents s.write('E') continue except Exception as e: print >> sys.stderr, e s.write('E') continue where json_data is built up like so: json_data = '{"version":"1.0.0","datastreams":[{"id":"Humidity", "current_value":"%.1f"},{"id":"InsideTemp","current_value":"%.1f"}]}'%(float(temps[1])/10.0,float(temps[2]) / 10.0) and apikey is the api key as provided by cosm for write access to your datastream. Notice the line that set the get method - this is a hack because url2lib2 technically support HTTP PUT. It works though. It's running on a mac mini, if that helps. r.get_method = lambda: 'PUT' But I've actually moved away from cosm, although all the data is ending up there. They've been bought by someone else now, and I don't like their graphs so much anymore. Now I'm also logging the data to a local mysql server, and serving the data up to my personal devices using apache. I'm doing the plots using the javascript library flot, which I think makes nicer plots that the ones cosm uses. I'd hand out the URL here, but I rather think my mac mini won't thank me
  8. Two great suggestions, thanks. I have the PCBs on order from seeed as it happens, and I have some other boards in the pipeline so maybe I'll look into that. I couldn't find the ones you mentioned spirilis, but I did find this: http://www.seeedstudio.com/depot/the-nevergoingtomiss-glaringdevileye-huge-red-push-button-p-378.html?cPath=85 Costs as much as 10 custom PCBs!! We do have a fantastic thrift shop round these parts that I'll hit up first to see what I can find. Anyway, I wrote the code I mentioned earlier up in assembly, and unrolled the loops, and got the inter-byte time down from 25us to 8us. Then I upped the size of the framebuffer so that it covers all three panels, soldered up the other two boards, and it all works very nicely with no perceptible flicker. Next step is the control board. This is the one I have on order from seeed, which should be here in a week or so. This is a much more complex board that my first one, as it supports a few different peripherals, and a couple of power supply options. I'll put a picture of it up when I get it, but I mentioned it in this post here: http://forum.43oh.com/topic/1374-get-your-booster-packs-sponsored-10/?p=36212 For this project, I'll be boosting a couple of AAs to 3.3v, and at this point I've no idea how well the part I've chosen to do this is going to work. I did try this once with a different boost controller, and saw spikes up to 4v as the inductor discharged. I've made provision for a LC filter to help smooth these out, but I'll have to see if it's going to be required. The idea is that the project is asleep most of the time, waiting for the button to be pressed. While asleep the boost regulator is off, and the micro is powered by the AAs through the inductor and the diode (so that'll be battery voltage minus the drop of the diode, which I think is about 100mv at low currents). When it wakes up, it'll turn on the boost controller and then switch to a higher clock frequency. It remains to be seen what the power supply will look like when the regulator turns on, maybe there'll be horrible spikes that'll kill the micro? Who knows.
  9. @@igor , that's not a bad idea, I probably will Also, I wonder if anyone knows of any nice big smackable buttons that would be suitable for something like this. Kid proof, waterproof, and nice and big and satisfying. The kind you often find on slot machines I guess.
  10. What you're attempting may very well be beyond the capabilities of an MSP430. I did a project a while back driving RGB LEDs, and that required multiple FPGAs to actually drive the LEDs fast enough, and used megabit serial (!) to transmit data to the FPGAs. This was generated by an LPC1768 running at a clock speed well out of reach of an MSP430. Anyway, let's do some calculations: You have 16x16 display, which means you have 256*3 = 768 bits of data to output if all you were going to do is have each LED either on or off (no PWM). You are trying to PWM with 255 brightness levels for each LED, which means you must output 768 bits of data 255 times over, and fast enough to not perceive any flickering. I've found 75Hz is about what's required to avoid any perception of flickering, so you'll have to output 768*255*75 bits of data per second. That's about 14 megabits, which means you'd need a clock speed of 30Mhz just to get the data out - leaving no time over to calculate anything or load any data into registers or anything. Also, if you want to get this data into the MSP over serial, I presume you'll want to store the image data in RAM on the MSP. Your 16x16x3 bytes of memory is 768 bytes, which is more RAM than is available in the MSP. So my advice is to drop the number of brightness levels you need to (say) four, this is two bits per channel per pixel. Forget about trying to calculate HSV to RGB transformations on the MSP430. Work on just getting the LEDs on or off to start with, to make sure you can get everything running fast enough to get that going. And then try four brightness levels. My feeling is though that to get enough speed for this project you will either need to get into assembly or use a more powerful micro. The LPC1768 is a nice one, but anything with a bit more grunt is probably what you'll need. Your shift registers go up to 100Mhz input, why not use a micro that can give you that kind of speed?
  11. Thanks abecedarian, I'll do that next time. Ok, so I took a look at the assembly version of the loop I mentioned above, and I'm not all that impressed with the compiler's output. I'm probably expecting too much, because I've seen it do pretty clever stuff in the past. output = 0; for(bit = 8; bit ; bit--) { output <<= 1; output |= (framebuffer[row][bit] > pwm) ? 0 : 1; // on if over pwm } And here's the assembly, annotated to help with my own understanding of it. This is a release build using CCS with optimisations at maximum speed. MOV.B &line+0,r14 ; [] RLA.W r14 ; [] RLA.W r14 ; [] RLA.W r14 ; [] ADD.W #framebuffer+8,r14 ; [] // r14 = (framebuffer + 8) + (line * 8) MOV.W #0,r15 ; [] |81| MOV.W #8,r12 ; [] // r15 = 0, r12 = 8 // r12 is being used as the loop counter MOV.B #0,r13 ; [] |84| // r13 = 0 CMP.B @r14,&pwm+0 ; [] |84| // set flags as if (*r14) - pwm . // Jump if LO to $C$L2, JLO jumps if carry is not set JLO $C$L2 ; [] |84| // r13 = 1 MOV.B #1,r13 ; [] |84| C2L2: RLA.B r15 ; [] |84| OR.B r13,r15 ; [] |84| // r15 <<= 1 // OR r13 into r15 SUB.W #1,r14 ; [] |82| // move pointer // r14-- SUB.W #1,r12 ; [] |82| // loop counter // r13--, loop if nonzero JNE $C$L1 ; [] |82| So looking at this code reveals that it uses an unnecessary register (r13), which it loads with either zero or one, depending on the value of the carry flag. If carry is not set, it leaves r13 as zero, otherwise it loads it with one. It then OR's r13 into r15, having shifted r15 one bit to the left. Sound like the instruction RLC.B to you? Sure does to me. All the code between the MOV.W #8,r12 and the SUB.W #1,r14 can be replaced with the following two instructions. CMP.B @r14,&pwm+0 RLC.B r15 And moreover, since pwm doesn't change inside the loop, it can kept in a register during the loop thus saving an additional memory read during the instruction. I suspect that this will make the whole operation at least twice as fast - although I haven't tried it out yet. If that's still not enough, I think I might unroll the whole loop - since each iteration will only be three instructions long there will be plenty of program space. All of the above leaves me with a single question - how do I get my assembly into the code? I've written a single assembly function once, and I placed it in a separate file. I can do that again, but I'll need that file to have access to global variables declared in a C file. If anyone here is able to offer advice on how to achieve that I would be grateful. Actually I have another question too, in case anyone is still reading. What is the interrupt priority on the MSP430? I presume it doesn't nest interrupts, and so most of the time the priority is whichever happens first, but if two did happen to come along at once, which would be serviced first?
  12. Earlier this year I happened to be in Singapore in transit, and took the opportunity to visit Sim Lim Tower - a high-rise mall full of electronic components shops! Amazing place, and amongst other things (including super-cheap kits for the kids to build!) I picked up three 5x7 LED matrix panels for a dollar each (!!). They didn't have any part numbers that I could see, but after experimentation they turned out to be row-anode devices and once I figured out the pinout I decided to build a project out of them. As any of us who have children know, it's a daily battle to get kids to brush their teeth for long enough, and as any of us who have children also know, time spent on projects goes down better if there's a kid angle to it. So I decided to make a tooth brush timer, that will display a countdown from two minutes - interspersed with inspirational text and probably amusing patterns and other things to keep the kids entertained during their twice-daily two-minute ordeal. Poor things. Being given to doing things the hard way, I decided to design two boards - one for the LED panels, and one for the controller. I'll get to the controller board in a later post because it's quite complicated (since the board fab place makes 10 identical boards I decided to try to make it as multi-purpose as possible). The LED boards though are simpler, they just use a 4094 shift register to handle the columns (or rows, I decided to use my three matrices abutted end to end rather than side to side, giving me a display that's five LEDs high and twenty-one across. I found a nice 5x5 bitmap font on dafont.com, and decided that I had enough space for what I needed to display. Because if all the LEDs are on the 4094 will be over it's specified current limit, it drives the columns through seven PNP transistors. This meant quite a bit of routing, which is what led me to use a board fab house rather than attempt it all on veroboard. So, onto the code (I have attached the eagle files if anyone is interested). I wanted to use the USI module to drive the 4094's. Looking at the datasheet for a 4094, it clocks in it's data on a rising edge of the clock. So the USI module will need to be configured thusly (I'm running the CPU at 12Mhz). // Reset USI logic to allow configuration USICTL0 |= USISWRST; // Setup serial output for a 4094 shift register USICTL0 = USIPE6 // SDO enabled + USIPE5 // CLK enabled + USIMST // master mode + USIOE // output enable + USISWRST // leave in reset ; // clock phase = 1, interrupts enabled SICTL1 = USICKPH // phase = 1 + USIIE // interrupt enabled ; USICKCTL = USIDIV_4 // divide by 16, giving 500khz clock + USISSEL_2 // SMCLCK as clock source ; // release SPI for operation USICTL0 &= ~USISWRST; Now, the tricky part of this project is that I want to have greyscale (redscale!) on my LEDs. To do this I will have to not only row-scan the matrix, but also PWM each LED individually. And I want to do all this in the USI interrupt handler, and have a framebuffer in RAM that I can just write to at any time without having to worry about getting the LEDs to update. So first thing is the framebuffer, I'm just using one LED matrix at the moment so it's only a 5x7 array: unsigned char framebuffer[5][8]; // greyscale framebuffer So, for those unfamiliar with how to drive these types of LED matrices, here's a bullet-pointed flow-chart. Start at the first row. Clock bits into the 4094 shift register, corresponding to which LEDs in the current row are on. Because I'm using PNP transistors as high-side switches, a zero in the 4094 outputs will correspond to an LED being on. Once the bits are clocked in, set the 'strobe' input into the 4094 to high. This will latch the outputs of the 4094, causing them all to change at once to whatever you just clocked in. Now that the high-side transistors are all either on or off, according to which LED in the current row you want to be on, it's time to turn that row on using the low-side switch for that row. Of course there could be quite a bit of current flowing out through the row pin if all the LEDs in that row are on, so it's not safe to just hook it up to a GPIO pin. A FET is instead used as a low-side switch. Now the row is lit up. Move to the next row and goto 2. If we're at the last row, then instead goto 1 (which means start over). The above method, if run fast enough, will cause all the LEDs to appear illuminated in whatever pattern you desire. But it won't allow brightness control of individual LEDs. To get that we need another variable, that I'll call PWM. PWM will start at zero, and will be incremented at step 1 of the above bullet-pointed flowchart. When it reaches 16, it will be reset back to zero. So it's a rolling counter that will count up each time a frame is output to the matrix, and will roll over at 16. Using this, and the greyscale framebuffer above, we can modify the flowchart so that instead of just clocking in whichever LEDs are on into the 4094, we clock in whichever LEDs have a brightness value that is greater than the current PWM counter. Thus, when the framebuffer entry is zero for a particular LED, that LED is never illuminated because it's brightness value (zero) is never greater than the PWM value (zero to fifteen). And when the framebuffer entry is sixteen, it's always greater than the PWM counter, and thus that LED is illuminated every frame. In between values illumiate the LED for varying numbers of frames, which - if you run the whole process fast enough - will cause them to appear dimmer. The heart of this code is the following loop, which I would love some advice on how to optimise: output = 0; for(bit = 8; bit ; bit--) { output <<= 1; output |= (framebuffer[row][bit] > pwm) ? 0 : 1; // on if over pwm } This loop calculates what to output to the 4094 shift register for each row. It's quite alot of work for an interrupt handler, and it needs to be three times more work once I add the additional two LED panels. I'm sure the compiler in CCS does a good job of figuring out the loop and optimising it for me, but I should take a look at the assembly output and determine if I can do any better. Anyway, to kickstart the process, the main program calls NextRow(), and then sets up a timer and fiddles with the framebuffer at intervals. So, here's NextRow and the USI interrupt handler: unsigned char pwm = 0; unsigned char row = 0; void NextRow() { unsigned char bit; unsigned char output; // strobe low ready for next thingy P1OUT &= ~BIT3; // next row's data - work out if each pixel should be on output = 0; for(bit = 8; bit ; bit--) { output <<= 1; output |= (framebuffer[row][bit] > pwm) ? 0 : 1; // on if over pwm } USISRL = output; // 8 bits out, we'll come back to _usi once these bits have been clocked out. USICNT = 8; } #pragma vector = USI_VECTOR interrupt void _usi() { USICTL1 &= ~USIIFG; // reset interrupt flag // turn off rows P2OUT = 0; // latch data P1OUT |= BIT3; // Strobe high // turn on rows P2OUT = (1 << row); // next row row++; if (row == 5) { pwm++; pwm &= 0x0F; // loop pwm back to zero when it hits sixteen row= 0; // start at row zero again. } NextRow(); } I've left alot of stuff out here, setting up the clock module and the GPIO pins etc etc. Also there's code in the project that makes a pretty (ish) pattern, and the displays some numbers. The code and eagles files are attached, and assuming I can use the video feature of BBcode correctly, here's a video! http://www.youtube.com/watch?v=gvPZ8LyGYGY --Edit--- Well that youtube embed didn't work. Here's a link. How do you embed videos anyway? LED control.zip
  13. Well it looks like the culprit was Grace - which I think loaded the USICNT register with 8, causing the SPI clock to start. So by the time I got to my code the clock had already been running for a bit, and so writing 8 to the register caused me to see about 12 bits on the output. Once I threw away the grace project and started again doing everything by hand it all worked fine. I'm going to start another thread about this project because it involves a couple of custom boards and I don't want to have my stupid question at the top of the thread
  14. So I've finally finished this, and I thoght I might share the code I used to talk to the indoor temperaure and humidity sensor - a DHT-22. These sensor output their data using a 1-wire protocol that's completely different to the 1-wire protocol used by the dallas sensors. Sigh. I somethimes think that although hardware designers talk alot about compatibility, they hate it really because it cramps their style. Anyway, here's what I did. I've attached all the code to this post, but here's the relevant parts. First, setting up the one pin for the sensor, which I'd connected up to P2.0, and setting the state machine variables used by the GPIO interrupt. unsigned char State, Bit; unsigned int Humidity; unsigned int Temperature; unsigned char Checksum; // DHT-22 is P2.0 P2DIR &= ~BIT0; // P2.0 is an input P2OUT = 0 ; // State machine variables State = 0; Bit = 0; And then setting up a microsecond timer that I use to both count the intervals between the interrupts, and trigger a timeout if the device doesn't respond in a reasonable period of time (this causes a retry, and happens every so often - probably because my connection to the sensor is over several meters of wire). // Counter for DTH22 interrupts TA1CTL = TASSEL_2 + MC_2 + ID_3; // SMCLCK, cont. mode. counts up at 1Mhz. // TA1R counts up at 1us intervals TA1R = 0; I have SMCLCK at 8Mhz, and the ID_3 divides by 8, gving a 1Mhz timer which means it'll increment every microsecond. I have two #defines to make it clear what I'm doing on the DHT-22's pin. Since the output is set to zero, changing the pin from an input to an output will have the effect of either pulling it down, or allowing it to be pulled up by the external pullup resistor. #define DHT22_LOW() P2DIR |= BIT0 #define DHT22_FLOAT() P2DIR &= ~BIT0 So, in order to trigger the sensor one has to pull it's line low for at least 500 microseconds. Using the timer then I; // drive signal low DHT22_LOW(); // Wait 1ms (must be >500us) TA1R = 0; while(TA1R < 1000); Obviously that while loop causes the compiler to get upset that I'm not entering a low-power mode - but this is the indoor unit hooked up to power over USB so I'm not worried about power usage. Anyway, after that 1ms has elapsed, I set up the GPIO interrupts and then release the data line. // set up interrupts, we are looking for a falling edge initially, which we'll // see when the sensor announces itself P2IES |= BIT0; // falling edge P2IFG = 0; P2IE |= BIT0; // P2 IE for bit zero DHT22_FLOAT(); // release line. Also I change the timer mode to continuous mode, set the timeout to 1000, and turn on timer interrupts. Each time I see a transition from the GPIO interrupt, I set the timer counter back to zero. So if I don't see the transition within 1ms the timer interrupt will go off and I enter an error condition. In the actual code, this causes a retry after a couple of seconds. //now change timer mode TA1CTL = TASSEL_2 + MC_1 + ID_3; // SMCLCK, cont. mode. counts up at 1Mhz. (ID_3 = clock / 8) TA1R = 0; TA1CCR0 = 1000; // 1 millisecond. If we don't see a transition in this time, then we're going to ping // the sensor again TA1CCTL0 |= CCIE; // 'rupts on again And now the interrupt handler. This isn't pretty, and could be refactored to be much smaller, but it doesn't really matter. The handler first grabs the value of TA1R, which will be the number of microseconds since the last interrupt - and then resets TA1R. Then depending on whether or not P2.0 is high or low, I change P2IES to switch the interrupt handling from rising to falling edges. Then my 'state machine' kicks in, which is hardly worthy of the name, since all we're doing is collecting up all the bits output by the sensor and putting them into three variables. The first 16 go into the humidity variable, the second 16 into the temperature variable, and the last 8 into the checksum. interrupt(PORT2_VECTOR) Port2_Vector() { unsigned int t = TA1R; // capture counter unsigned char signal = (P2IN & BIT0); TA1R = 0; // and reset P2IFG = 0; if (signal) // what's P2.0 doing { P2IES |= BIT0; // falling edge } else { P2IES &= ~BIT0; // rising edge } switch(State) { case 0: // We should see a falling and then a rising edge when the sensor pulls the line low // to signal it's present, and again to signal the start of a bit // We want to see both of these before we transition to reading data if (!signal) { Bit++; if (Bit == 2) // seen two lows. One was the 'presence pulse' // and the second indicated the start of a bit. { Bit = 0; State = 1; } } break; case 1: // Reading humidity. We'll get two interrupts for each bit, when the // line has gone high the bit is complete if (!signal) { // line is low. t indicates how long it was high for //all_t[Bit] = t; if (t > 50) { // was a '1' Humidity |= 1; } Bit++; if (Bit == 16) { // Onto temp State = 2; Bit = 0; } else { Humidity <<= 1; } } break; case 2: // Reading temp. We'll get two interrupts for each bit, when the // line has gone high the bit is complete if (!signal) { if (t > 50) { // was a '1' Temperature |= 1; } Bit++; if (Bit == 16) { // Onto checksum State = 3; Bit = 0; } else { Temperature <<= 1; } } break; case 3: // Reading checksum. We'll get two interrupts for each bit, when the // line has gone high the bit is complete if (!signal) { if (t > 50) { // was a '1' Checksum |= 1; } Bit++; if (Bit == 8) { // Onto done P2IE = 0; State = 4; Bit = 0; // also turn off timer interrupt, the main loop will output this measurement now TA1CCTL0 &= ~CCIE; } else { Checksum <<= 1; } } } } Once this is done I turn off the GPIO interrupt (P2IE = 0), and set the state to 4. The main loop then picks up this & outputs the values over serial if the checksums match. The checksum code is. unsigned char CalcChecksum() { unsigned char c = 0; c += (unsigned char)(Humidity & 0xFF); c += (unsigned char)(Humidity >> 8); c += (unsigned char)(Temperature & 0xFF); c += (unsigned char)(Temperature >> 8); return c; } And that's it. Well except that it isn't of course, but I've attached all the code in case anyone would like to see it. TempRx.zip
  15. I have a schematic and board layout for an MSP that supports the following features - it's not a boosterpack though it's a standalone board that breaks out the debug pins so you can connect it to a launchpad for programming. I personally find this a more cost-effective approach because the chips by themselves are a couple of bucks, and the final product is more flexible. This board will be used in several projects. An LED matrix, A robot with ultrasonic sensors, and some audio project or other. Perhaps a digital guitar effects pedal or something. Two power supply options: Step up power supply using NCP1450 - can be enabled/disabled by the micro. In the robot project it won't power the micro, but will step up to 5v for the ultrasonic sensors. Linear regulator. Two DRV883 H-bridge motor driver footprints. One MCP4911 DAC for audio output. And six of the GPIO outputs can be connected up to FETs to control other types of output. I'm using these for the rows of an LED matrix, but they would be useful for anything. Footprints for either a surface mount or a thru-hole crystal. Optional LC power supply filtering for the output of the boost regulator (the inductor can just be bridged, which is what makes it optional ) Eagle files attached. 2min_timer_control.brd 2min_timer_control.sch
  • Create New...