bluehash 1,581 Posted December 6, 2013 Share Posted December 6, 2013 Hello All, After consulting with the members of the 43oh forum, I'd like to open the contest to Stellarisiti members too. There are alot of prizes to be won from sponsors. All you have to do is document your project here in the Stellarisiti forum projects section and provide a brief description of your project in this 43oh POTM thread. Unfortunately, you will have to regster at 43oh to do this as I've not integrated the membership between the two sites yet. Prizes: (1) Logic 8 Analyzer-----------------------------------------------------Saleae(1) Mastech MS8211N 2000 Count Handheld Digital Multimeter--Saelig(1) PanaVise Mount Package--------------------------------------------Panavise(1) 2" Pervasive Displays EPD - Kit-------------------------------------Pervasive Displays(1) DLP-7970ABP NFC/RFID Reader BoosterPack------------------DLP Design(1) $20 gift card Sparkfun/Amazon/Adafruit ---------------------------Abecederian(1) Your choice of Design, Laser Cut by 43oh Member Fred------Fred(2) Stellaris Launchpad Kits.---------------------------------------------Bluehash Last Date for entries31st Jan, 2014 Submitting your entryTo submit your entry, make an entry into this thread with the following:1 - A small description of your project.2 - A picture or video of your setup3 - Code.4 - Schematic and board files.5 - You will also need to make a copy of the entry under the Projects section. This will enable members to ask you questions and comment on your project. If you are from the Stellarisiti forum, describe your project in the Projects section at Stellarisiti. JudgingA day after the contest ends, a poll will be created with all the project entries. Only members of the forum will be allowed to vote. Voting will run for a week. Prize Distribution1. Winners can choose their prize from the pool in the order they win it.2. If there is a tie between multiple winners, the entry than made the earliest in this project thread will have priority in choosing a prize. Simple Rules- You must be a member of the 43oh/Stellarisiti forum at least a week before your submission.- One entry from each member will be permitted.- Your design has to be open source. if you can, select a license from here or here. 43oh will not claim any ownership.- Your project can be anything based around the MSP430/Tiva-C/Stellaris controllers. You may interface the MSP430 to another controller. But try to keep the above listed as the main controller.- You may reuse code from anywhere as long as you give credit to the original author.- You must submit code and schematics of your project with a proper description.- You can submit your MSP430 project, if it was created before the annoucement of the contest.- You must have at least 5 posts in the forums, for your entry to be considered when the voting begins.- Previous entries in other 43oh contests will not be permitted. Quote Link to post Share on other sites
joelfinkle 1 Posted December 23, 2013 Share Posted December 23, 2013 This is my first microcontroller project (aside from a couple of Hello World's after I received my Tiva), but I've been programming professionally for more than 30 years -- less so in the last decade. Tic Tac Toe, called noughts and crosses elsewhere in the world, is a pretty simple strategy game, and I thought it would be well suited for a first project. tic tac toe by joelfinkle, on Flickr There are 18 LEDs (9 each of red and green), not counting the onboard RGB (used for status). While there are plenty of pins on the Tiva, it seemed worth learning Charlieplexing. That provided an additional challenge, getting LEDs to line up nicely in the limited space of a standard breadboard, while getting in all the wires. I mostly succeeded, although the grid is a little skewed. The project uses a 4x4 keypad bought off Amazon for under $2 shipped (not realizing it would take weeks to arrive from China). There are two slider switches used to determine whether there is a computer player, and whether the computer is first or second. I could probably modify it to have both players be computer, but given that the strategy is deterministic (nothing random), it would be pretty dull -- every game would end the same way. I decided to program using Energia, mainly because I had trouble getting the TI dev environment to work, and I'm lazy. I'd looked at [roadrunner]'s charlieplexing module, but it added a lot of unneeded complexity, and I settled for a simple tick routine that changed which cell of the tic tac toe board it was looking at each time around the loop routine. i plan on upgrading the code to use more direct access to the pins (like [roadrunner] does), but thought I'd get it to work on a more pure Wiring program first. The strategy is clearly laid out in the code, using the suggestion of http://www.instructables.com/id/How-to-make-a-TIC-TAC-TOE-game-using-C/all/?lang=zh'>this Instructables post of storing a game state as empty=2, player 1=3 and player 2=5, and multiplying cell values together to get a state (winning is 27 or 125). I enhanced it to look for fork and fork-blocking moves. The onboard LED is blinked at intervals (also done using a routine called from loop, but could be an interrupt in future versions), with different colors to indicate player's turn, invalid move, win of player 1 or 2 and cat's game (draw). Enjoy! //////////////////////////////////////////////////////////////////////// // // Tic Tac Toe for Tiva - Energia Implementation // // (CC) Creative Commons Attribution Non-Commercial 2013 Joel Finkle // Recipients of this code may copy, distribute, display, and perform the work and make derivative works based on it only for noncommercial purposes // // Hardware requirements: // TI Tiva C development board // 18 LEDs, 9 each of red and green // 4x4 keypad // Five 330-ohm resistors // Two slider switches // Breadboard and wires #include <Keypad.h> // Game state globals int curPos = 0; int curScanRow = 0; int curPlayer = 0; // start with player 1 int blinkType = 0; // 0 = no blink, 1 = error, 2 = P1 win, 3 = P2 win, 4 = P1 turn, 5 = p2 turn, 6 = Cat's Game int blinkCtr = -1; int blinkTimer = 0; long blinker = -1000; int game[9] = {2,2,2,2,2,2,2,2,2}; // 2 = neither, 3 = P1, 5 = P2 for items 0-8 int humans[2] = {1,1}; int movesmade = 0; boolean stillplaying = true; // Constants for the value of a given move #define WINMOVE 0 #define BLOCKMOVE 1 #define FORKMOVE 2 #define FORKBLOCKMOVE 3 #define CENTERMOVE 4 #define OPPOMOVE 5 #define CORNERMOVE 6 #define EDGEMOVE 7 #define NOMOVE 999 // Charlieplexed LED Data #define PIN_COUNT 5 int pinlist[PIN_COUNT] = {PE_1,PE_2,PE_3,PE_4,PE_5}; // pinpairs provides a shortcut for charlieplexing, // since the alternate players use the same pair of pins with reversed polarity. // Each of the nine cells indicates the pair of pins in pinlist // with the direction indicated by the player. // Pins were chosen to all be in one set, for future changes to use register operations // instead of the Wiring routines int pinpairs[3][3][2] = { { { 0, 1 }, { 1, 2 }, { 2, 3 } }, { { 3, 4 }, { 4, 0 }, { 0, 2 } }, { { 2, 4 }, { 4, 1 }, { 1, 3 } } }; // Keypad data const byte ROWS = 4; // use 4X4 keypad for both instances const byte COLS = 4; char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; // Pins chosen below were the only set of eight in as row that don't have another function // so that the keypad's header could be plugged directly into the Tiva board byte rowPins[ROWS] = {38,37,36,35}; //connect to the row pinouts of the keypad byte colPins[COLS] = {34,33,32,31}; //co/nnect to the column pinouts of the keypad Keypad keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); //////////////////////////////////////////////////////////////////////// // Setup - set the initial game state, other than the data initialization above void setup() { // setup code here, to run once: int i = 0; for (i=0;i<PIN_COUNT;i++) { pinMode(pinlist[i], INPUT); } pinMode(PA_3, INPUT); // Play against computer? pinMode(PA_2, INPUT); // Which player is computer? pinMode(RED_LED, OUTPUT); // all three of these for statuses pinMode(GREEN_LED, OUTPUT); pinMode(BLUE_LED, OUTPUT); if (digitalRead(PA_3) == LOW) { // Yes, play against computer humans[digitalRead(PA_2) == HIGH ? 0 : 1] = 0; // set either player 1 or player 2 as computer player } updateBlink(blinkCtr, blinkType, blinkTimer); // Player 1's turn blinkType = 4; // 0 = no blink, 1 = error, 2 = P1 win, 3 = P2 win, 4 = P1 turn, 5 = p2 turn blinkCtr = 6; blinkTimer = 250; updateBlink(blinkCtr, blinkType, blinkTimer); } //////////////////////////////////////////////////////////////////////// // loop - main event loop void loop() { int move = NOMOVE; // Give time to the charlieplex display tickDisplay(curPos++); if (curPos > 8) { curPos = 0; } // Give time to the blinker handler updateBlink(blinkCtr, blinkType, blinkTimer); // Whose turn is it? Fetch a move if (stillplaying) { if (humans[curPlayer]) { move = humanplayer(); } else { move = computerplayer(); } } // If a move occurred (which should always happen if it's the computer's turn, but might not have yet for human)... if (move != NOMOVE) { // Was it a winning move? if (move == WINMOVE) { // game over blinkType = 2 + curPlayer; blinkCtr = 10; blinkTimer = 250; stillplaying = false; } else { // If not a winning move, update the game state movesmade++; // cats game if (movesmade > 8) { blinkType = 6; blinkCtr = 6; blinkTimer = 250; stillplaying = false; // or need another move } else { switchplayer(); } } } } //////////////////////////////////////////////////////////////////////// // humanplayer - Fetch a move from the keypad int humanplayer() { char key = keypad.getKey(); int button = -1; int move = NOMOVE; // The keypad is a 16-key pad, ignore right column (A-D) and bottom row (* 0 #) if (key >= '1' && key <= '9') { button = (byte)key - 49; } // subtract 1 extra to make it 0-based // If we got real input... if (button >= 0) { // Make sure the position isn't already used if (game[button] != 2) { // error -- already in use blinkCtr = 4; // three times on and off blinkType = 1; blinkTimer = 250; // milliseconds move = NOMOVE; // Then update the game board, and check whether it's a winning move } else { game[button] = curPlayer ? 5 : 3; // set to 5 for player 2 (value 1), 3 for player 1 (value 0) // did they win? move = bestmove(button, curPlayer, 0); } return move; } else { return NOMOVE; } } //////////////////////////////////////////////////////////////////////// // computerplayer - calculate best move int computerplayer() { int best = NOMOVE; int bestpos = -1; for (int j=0; j<9; j++) { // Since this can be time consuming, keep the screen updated tickDisplay(curPos++); if (curPos > 8) { curPos = 0; } updateBlink(blinkCtr, blinkType, blinkTimer); // end of screen update // Only check the value of a move where we actually can move if (game[j] == 2) { // spot is empty int thismove = bestmove(j, curPlayer, 1); // If this move is better than other ones we've chosen, keep it if (thismove < best) { // lower values are better bestpos = j; best = thismove; } } } // Update board and return the quality of the move (which indicates winning) game[bestpos] = curPlayer ? 5 : 3; // set to 5 for player 2 (value 1), 3 for player 1 (value 0) return best; } //////////////////////////////////////////////////////////////////////// // switchplayer - blink for the other guy void switchplayer() { // change players -- this shamefully works on globals curPlayer ^= 1; // XOR toggles between 0 and 1 blinkType = 4 + curPlayer; // 4 = P1 turn, 5 = p2 turn blinkCtr = 6; blinkTimer = 250; } //////////////////////////////////////////////////////////////////////// // tickDisplay -- give time to the Charlieplex void tickDisplay( int position) { // display the next LED if (game[position] != 2) { // there's something there displaySquare( position % 3, position / 3, (game[position])); // pass position value to permit clearing } if (game[position] == 8) { game[position] = 2; } // reset if needed } //////////////////////////////////////////////////////////////////////// // displaySquare -- update the output lines for the particular cell // TODO: switch to using internal registers instead of Wiring routines, for speed void displaySquare( int row, int col, int value) { int player = 0; switch (value) { case (3) : player = 0; break; case (5) : player = 1; } // set all pins to low and input to ensure that we don't have old junk sitting around for (int i = 0; i < PIN_COUNT; i++) { digitalWrite(pinlist[i], LOW); pinMode( pinlist[i], INPUT);} // set particular pins to output, and raise one of them high if (value != 8) { // don't do this if clearing pinMode(pinlist[pinpairs[row][col][0]], OUTPUT); pinMode(pinlist[pinpairs[row][col][1]], OUTPUT); digitalWrite( pinlist[pinpairs[row][col][player]], HIGH); } } //////////////////////////////////////////////////////////////////////// // updateBlink - change the blinker periodically. // // Todo: Change to interrupt-driven blinker void updateBlink( int &bCount, int bType, int bTimer) { if (bCount < 0) { blinker = 0; return; } // If bTimer expired then if (blinker + bTimer < millis()) { // timer expired // a) Toggle LED based on bType switch (bType) { case (0) : // nothing digitalWrite(RED_LED, LOW); digitalWrite(GREEN_LED, LOW); digitalWrite(BLUE_LED, LOW); break; case (1) : // error - yellow digitalWrite(RED_LED, (bCount & 1) ? LOW : HIGH); digitalWrite(GREEN_LED, (bCount & 1) ? LOW : HIGH); break; case (2) : // P1 Win - alternate red and blue digitalWrite(RED_LED, (bCount & 1) ? LOW : HIGH); digitalWrite(BLUE_LED, (bCount & 1) ? HIGH : LOW); break; case (3) : // P2 win - alternate green and blue digitalWrite(GREEN_LED, (bCount & 1) ? LOW : HIGH); digitalWrite(BLUE_LED, (bCount & 1) ? HIGH : LOW); break; case (4) : // P1 turn - red digitalWrite(RED_LED, (bCount & 1) ? LOW : HIGH); break; case (5) : // P2 turn - green digitalWrite(GREEN_LED, (bCount & 1) ? LOW : HIGH); break; case (6) : // Cat's Game - alternate yellow and blue digitalWrite(RED_LED, (bCount & 1) ? LOW : HIGH); digitalWrite(GREEN_LED, (bCount & 1) ? LOW : HIGH); digitalWrite(BLUE_LED, (bCount & 1) ? HIGH : LOW); } // Decrement bCount bCount--; if (bCount < 0) { digitalWrite(GREEN_LED, LOW); digitalWrite(RED_LED, LOW); digitalWrite(BLUE_LED, LOW); blinker = -1; } else { // c) reset bTimer blinker = millis(); } } } /* Strategy: Wikipedia suggests the following priority: 1) Win: If the player has two in a row, they can place a third to get three in a row. (same as posswin) 2) Block: If the [opponent] has two in a row, the player must play the third themself to block the opponent. 3) Fork: Create an opportunity where the player has two threats to win (two non-blocked lines of 2). 4) Blocking an opponent's fork: Option 1: The player should create two in a row to force the opponent into defending, as long as it doesn't result in them creating a fork. For example, if "X" has a corner, "O" has the center, and "X" has the opposite corner as well, "O" must not play a corner in order to win. (Playing a corner in this scenario creates a fork for "X" to win.) Option 2: If there is a configuration where the opponent can fork, the player should block that fork. 5) Center: A player marks the center. (If it is the first move of the game, playing on a corner gives "O" more opportunities to make a mistake and may therefore be the better choice; however, it makes no difference between perfect players.) 6) Opposite corner: If the opponent is in the corner, the player plays the opposite corner. 7) Empty corner: The player plays in a corner square. 8) Empty side: The player plays in a middle square on any of the 4 sides. The bestmove routine here uses 2 for an empty cell, 3 for a player-one cell, 5 for a player 2 cell, and calculates the product of three cells in a row There are four possible results from any cell: Three in a row, three in a column, three in a sinister diagonal (top right to bottom left), three in a dexter diagonal (top left to bottom right) Possible products for any set of 3 cells (row, col, sinister, dexter) a*b*c: 8 Nothing there (don't care) 12 One cell of player 1 (low priority) 18 Two of player 1, one empty = could indicate a fork if there's another 20 One cell of player 2 (low priority) 27 Three of player 1 = winner 30 One Player 1, One Player 2, One Empty = could indicate an opponent fork that could be blocked, if there's another 45 Two of player 1, one Player 2 = block for player 2 50 Two of player 2, one empty = forkable 75 Two of player 2, one Player 1 = block for player 1 125 Three of player 2 = winner 999 Invalid (i.e. looking for sinister when in any cell except the right to left diagonal [2,4,6]) So for each give empty square, look at the set of row, col, sin, dex a) if there's an 27/125 (for player 1 or 2), choose it and win if there are any 75/45, choose it and block c) if there are two 18/50, choose it and fork d) if there are two 30, choose it and prevent fork e) if given square is a corner, and opposite corner is not self, choose it f) if given square is corner, take it g) if given square is edge, take it */ //////////////////////////////////////////////////////////////////////// // bestmove - use above strategy to find the best possible move // TODO: make the first move more random? You can still force a win or cats from any cell int bestmove(int cell, int player, boolean testcell) { int row = int(cell / 3) * 3; int col = cell % 3; int oldCell = game[cell]; int forkcnt = 0; int forkblkcnt = 0; int thismove = NOMOVE; boolean block = false; int forks = 0; int forkblocks = 0; // If testcell is true, we're looking for a best move, versus just whether we won // in which case, pretend the move is made by filling the cell if (testcell) { game[cell] = (player ? 5 : 3); } // Check the four directions: Row, Col, Dexter, Sinister for (int dir=0; dir<4; dir++) { switch (dir) { case 0: // row thismove = game[row] * game[row+1] * game[row+2]; break; case 1: // column thismove = game[col] * game[col+3] * game[col+6]; break; case 2: // dexter diagonal if (cell % 4 == 0) { // cells 0, 4 or 8 thismove = game[0] * game[4] * game[8]; } else { thismove = NOMOVE; } break; case 3: // sinister diagonal if (cell == 2 || cell == 4 || cell == 6) { // no cute calculation here thismove = game[2] * game[4] * game[6]; } else { thismove = NOMOVE; } } // evaluate results if (thismove == 125 || thismove == 27) { // winner if (testcell) { game[cell] = oldCell; } return WINMOVE; // no need to keep testing, we've got a winner } else if ((thismove == 75 && player == 0) || (thismove == 45 && player == 1)) { // blocker, keep track block = true; } else if (thismove == 18 || thismove == 50) { // possible fork forks++; } else if (thismove == 30) { // possible forkblock forkblocks++; } } // now that we've looked at all 4, what's the best outcome of this spot (we've already returned if we would win) // BLOCK if (block) { thismove = BLOCKMOVE; // FORK if two directions found } else if (forks > 1) { thismove = FORKMOVE; // FORK BLOCK if two directions found } else if (forkblocks > 1) { thismove = FORKBLOCKMOVE; // CENTER } else if (cell == 4) { thismove = CENTERMOVE; // OPPOSITE CORNER } else if (cell % 2 == 0) { // all the corners are even, plus center which we already counted if (game[3*((row+2) & 3) + ((col+2) & 3)] != 2) { thismove = OPPOMOVE; } else { // CORNER thismove = CORNERMOVE; } // EDGE } else { thismove = EDGEMOVE; } // Reset the test cell if (testcell) { game[cell] = oldCell; }; return thismove; } Schematic -- if anyone has a Fritzing file for the Tiva/Stellaris, I'd appreciate it. I had to hack the SVG files for the Launchpad headers to get this to work, and it's still a little funky. tictactoe with keypad_schem by joelfinkle, on Flickr joelfinkle 1 Quote Link to post Share on other sites
igor 163 Posted December 25, 2013 Share Posted December 25, 2013 ("Your project can be anything based around the MSP430. You may interface the MSP430 to another controller. But try to keep it as the main controller.") So just to be sure I understand - while members of Stellarisiti may enter, it is still limited to projects based around the MSP430 chips? (i.e., we can't enter things based on TI's LM3, Stellaris or Tiva) bluehash 1 Quote Link to post Share on other sites
bluehash 1,581 Posted December 25, 2013 Author Share Posted December 25, 2013 ("Your project can be anything based around the MSP430. You may interface the MSP430 to another controller. But try to keep it as the main controller.") So just to be sure I understand - while members of Stellarisiti may enter, it is still limited to projects based around the MSP430 chips? (i.e., we can't enter things based on TI's LM3, Stellaris or Tiva) Yes.. I've updated the rules. Thanks @@igor. Quote Link to post Share on other sites
bluehash 1,581 Posted December 25, 2013 Author Share Posted December 25, 2013 @@joelfinkle Thanks! Looks neat. I've moved your post to the contest thread. Quote Link to post Share on other sites
gonya707 2 Posted December 26, 2013 Share Posted December 26, 2013 This is a FM synthesizer made for the Stellarpad using the AD9850 function generator. The FM synthesis is teorethicaly the same as the all-known frequency modoulation used for radio communications, but in this case the frequencies are suited to stay at the audio range, i.e. from 20Hz to 20kHz. Basically The AD9850 is used as a sine wave generator, and the microcontroller create each cycle a sample of ANOTHER sine wave, this one goes from 5Hz to 100Hz more or less. We can modulate this two sinewaves, the AD signal being the carrier and the stellaris signal the baseband. The outcoming spectrum can be represented by the Bessel functions for each harmonic, making some interesting sounds for electronic music. Attaching two potentiometers we can control the baseband sine frequency and its amplitude, thus controlling the modulation index.This is a recording I made with this project (is there any way to display souncloud embed on the forum?):https://soundcloud.com/gonya707/fm-synthesizer-grsynth-comThe first seconds were non-modulated waves and then I pressed a note (C3 if I recall correctly) and played with the potentiometers.. This is a simplfied schematic of the project. The complete schematic of each module can be found respectively here: AD9850 module: http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf MIDI boosterpack by RobG: http://forum.43oh.com/topic/1773-midi-booster-pack/page-3#entry23763 And finally, this is the main code for this project: // // FM Synthesizer for Stellaris Launchpad and AD9850 // Coded by Gonzalo Recio // #include "inc/hw_types.h" #include "inc/hw_memmap.h" #include "driverlib/sysctl.h" #include "driverlib/gpio.h" #include "inc/hw_gpio.h" #include "inc/hw_sysctl.h" #include "driverlib/pin_map.h" #include "driverlib/uart.h" #include "inc/hw_ints.h" #include "driverlib/interrupt.h" #include "driverlib/adc.h" #include "math.h" #include "midi.h" #include "STELLARIS_AD9850.h" #define PI 3.141592 #define GPIO_PB0_U1RX 0x00010001 #define GPIO_PB1_U1TX 0x00010401 // Global variables unsigned long message; unsigned long note, velocity; int on=0, off=0; int flagON = 0, flagOFF = 0; unsigned short i = 0, z,y; float t = 0; float freq = 0; unsigned long ulADC0_Value[4]; int main(void){ //50MHz clock SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN); //enable UART for MIDI T/R SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD); GPIOPinConfigure(GPIO_PB0_U1RX); //B0 receptor GPIOPinConfigure(GPIO_PB1_U1TX); //B1 transmitter GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1); UARTConfigSetExpClk(UART1_BASE, SysCtlClockGet(), 31250, (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE) ); //enable AD9850 SysCtlPeripheralEnable(PORT_ENABLE); GPIOPinTypeGPIOOutput(PORT, W_CLK|FQ_UD|DATA|RESET); AD9850_Init(); AD9850_Reset(); //ADC0 config SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0); SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS); ADCHardwareOversampleConfigure(ADC0_BASE, 4); ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE); GPIOPinTypeADC(GPIO_PORTE_BASE, GPIO_PIN_4|GPIO_PIN_5); ADCSequenceStepConfigure(ADC0_BASE, 1 , 0 , ADC_CTL_CH8 ); ADCSequenceStepConfigure(ADC0_BASE, 1 , 1 , ADC_CTL_CH9 | ADC_CTL_IE | ADC_CTL_END); ADCSequenceEnable(ADC0_BASE, 1); ADCIntClear(ADC0_BASE, 1); //Begin the interrupt detection IntMasterEnable(); IntEnable(INT_UART1); UARTIntEnable(UART1_BASE, UART_INT_RX | UART_INT_RT); while(1){ if (on == off){ AD9850_PowerDown(); } else{ ADCProcessorTrigger(ADC0_BASE, 1 ); while(!ADCIntStatus(ADC0_BASE, 1 , false)){ } ADCIntClear(ADC0_BASE, 1 ); ADCSequenceDataGet(ADC0_BASE, 1 , ulADC0_Value); AD9850_Osc(freq + y*sin(t), 0); } z=(ulADC0_Value[0] / 4 ) + 1; y=(ulADC0_Value[1]); i=(i + 1) % z; //timescale between 0 and 2*pi t=((float)i / (float)z ) * 2 * PI; } } //uart1handler void UARTIntHandler(void){ IntDisable(INT_UART1); unsigned long ulStatus = UARTIntStatus(UART1_BASE, true); //get interrupt status. RX or RT? UARTIntClear(UART1_BASE, ulStatus); //clear the asserted interrupts while(UARTCharsAvail(UART1_BASE)){ //loop while there are chars message = UARTCharGetNonBlocking(UART1_BASE); if(flagON){ // if the last message was a note ON, then this message is on++; // the note code. if (note != message){ note = message; freq = code2Freq(note); } } else if(flagOFF){ off++; } flagON = isNoteOn(message); flagOFF = isNoteOff(message); } IntEnable(INT_UART1); } The codes for the AD9850 library were also made by me, you can find them in this other thread.The MIDI library used in this project is here midi.c, midi.h. I was also the author for this one.If you don't have a MIDI boosterpack I've made also a no-MIDI version, the on-board switches trigger two different notes. You still need to attach a potentiometer to E4 and E5 though. You can find this version HERE. bluehash 1 Quote Link to post Share on other sites
bluehash 1,581 Posted December 26, 2013 Author Share Posted December 26, 2013 @@gonya707 Thanks for sharing! Quote Link to post Share on other sites
szymekrak1426459900 0 Posted December 29, 2013 Share Posted December 29, 2013 Hi, A very nice contest. I would like to submit my project which I began during the summer holidays, the MP3-thing. Sadly, I had no time to work on it for a long time, however this is not a dead project and I am currently doing some bugfixes and plan to add a feature or two tommorow. Would it be OK to submit this project anyway? Quote Link to post Share on other sites
spirilis 1,265 Posted December 29, 2013 Share Posted December 29, 2013 I would like to enter my Kitchen Roast Thermocouple Monitor project! This was a low-budget gift for my wife I put together in the last 3 days before christmas. I chose the Stellaris LaunchPad simply because I had no firm plans for it, and I have two Tiva-C LaunchPads that succeed it. The application itself would be much better fit for an MSP430 (and could be implemented with battery power too) but alas, it was a good test of my last-minute resourcefulness First, pics! We start with the TI Stellaris LaunchPad. Then home-etch a PCB using the laser toner-transfer process and ferric chloride, with some MG Liquid Tin for a nice tin protective coating: This board features the MAX31855 Thermocouple Amplifier chipset along with a Nordic nRF24L01+ PA+LNA board with external antenna. The latter is used to report temperatures to my Linux server, which posts them on a webpage every 30 seconds so my wife can view the state of her roast remotely with her iPad. Then add @@bluehash 's first attempt at the Nokia 1202 BoosterPack, unfortunately the LCD on this board had its white backing removed (noob mistake I have not repeated since) so the LCD has a weird background effect to it- Stack them all together: I am not good with woodworking, but I made an exception here and worked hard with a circular saw and dremel out in my garage. Used boiled linseed oil as a simple coating on the outside of the enclosure, milled out the holes with a drill & dremel... It could definitely use some strain relief for the cord, I'll probably wrap it around the bottom female headers of the Stellaris LaunchPad at some point: Anyway, my wife used it to make fudge and to make a rib roast for Christmas and it turned out perfectly! This unit is expandable, meaning I can pop the top and replace/re-etch the boosterpacks as I see fit. If she asks, I may implement more than one MAX31855 and possibly home-etch a Nokia 1202 boosterpack with pushbuttons with some implement to allow her to press them from the top wooden cover. Board files for the custom MAX31855+nRF24L01+ PCB: Thermocouple_BPak40_draft1.zip Nokia 1202 boosterpack from 43oh: http://forum.43oh.com/topic/3724-43oh-nokia-1202-lcd-display-boosterpack/ Code: Used Energia 11 for this one. First off, 2 libraries: Nokia1202 - https://github.com/spirilis/Nokia1202 Enrf24 - https://github.com/spirilis/Enrf24 Nokia1202 requires 9-bit SPI, while I have an alternative Energia SPI lib for MSP430, I didn't have one for Stellaris/Tiva-C. It required one update. Updated energia-0101E0011/hardware/lm4f/libraries/SPI/SPI.cpp and SPI.h files: SPI_lm4f_9bit.zip Energia sketch: #include <ste2007.h> #include <Nokia1202.h> #include <Enrf24.h> #include <nRF24L01.h> #include <SPI.h> struct MAX31855_DATUM { uint32_t rawData; int16_t tcDecimalC; int16_t tcC; int16_t tcF; int16_t ambDecimalC; int16_t ambC; int16_t ambF; uint8_t faultBits; }; void max31855_read(struct MAX31855_DATUM *); #define TC_CS PA_3 #define nRF24_CE PC_7 #define nRF24_CSN PE_0 #define nRF24_IRQ PD_6 #define LCD_BL PA_4 #define LCD_CS PA_5 #define LCD_RST PA_6 #define RADIO_CHANNEL 10 #define RADIO_ID 20 // 30-seconds between polls #define WAIT_TIME 30 const uint8_t radio_basestation[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x01}; Nokia1202 lcd(LCD_CS); Enrf24 radio(nRF24_CE, nRF24_CSN, nRF24_IRQ); void setup() { // put your setup code here, to run once: //Serial.setBufferSize(512, 64); Serial.begin(115200); Serial.println("Init TC CS, SPI-"); pinMode(TC_CS, OUTPUT); digitalWrite(TC_CS, HIGH); SPI.begin(); SPI.setDataMode(SPI_MODE0); SPI.setBitOrder(1); radio.begin(250000, RADIO_CHANNEL); radio.setCRC(true, true); radio.setTXaddress(radio_basestation); radio.autoAck(false); // Manually reset LCD Serial.println("Resetting LCD-"); pinMode(LCD_BL, OUTPUT); digitalWrite(LCD_BL, HIGH); pinMode(LCD_RST, OUTPUT); digitalWrite(LCD_RST, LOW); delay(250); digitalWrite(LCD_RST, HIGH); Serial.println("Init LCD-"); lcd.begin(); // Cursor enabled, contrast at medium, tabstop=4 lcd.clear(); Serial.println("Writing splash screen-"); lcd.print("Kitchen Roast!\nTemp Reporter\n\n"); lcd.print("From Eric with\nLove \n\n"); lcd.print("Web address:\nsisko.lan/roast"); delay(2500); Serial.println("LCD splash screen delay complete-"); } void loop() { uint8_t nrfmsg[32], cursor = 0; struct MAX31855_DATUM tc; uint32_t lastupdate; Serial.println("max31855_read()-"); max31855_read(&tc); // Update display Serial.println("LCD update-"); lcd.clear(); lcd.println("Kitchen Roast!"); lcd.setCursor(0,2); lcd.print("Temp: "); lcd.print(tc.tcF); lcd.print('\x7f'); lcd.println("F"); lcd.print(" ("); lcd.print(tc.tcC); lcd.print('\x7f'); lcd.println("C)"); if (tc.faultBits) { lcd.setCursor(0, 7); if (tc.faultBits & 0x01) lcd.print("DISCON "); if (tc.faultBits & 0x06) lcd.print("SHORT "); } lcd.setCursor(0, 6); lcd.print("sisko.lan/roast"); Serial.println("nRF24 radio transmit-"); nrfmsg[0] = 0x10; // PROTO = THERMOCOUPLE UPDATE nrfmsg[1] = 0x06; nrfmsg[2] = RADIO_ID; nrfmsg[3] = tc.tcC & 0x00FF; nrfmsg[4] = tc.tcC >> 8; nrfmsg[5] = tc.ambC & 0x00FF; nrfmsg[6] = tc.ambC >> 8; nrfmsg[7] = tc.faultBits; radio.write(nrfmsg, 8); radio.flush(); Serial.print("Waiting "); Serial.print(WAIT_TIME); Serial.println(" seconds before next update-"); lastupdate = millis(); while ( (millis() - lastupdate) < 1000*WAIT_TIME ) { delay(1000); lcd.setCursor(15, cursor); cursor ^= 1; } } void max31855_read(struct MAX31855_DATUM *datum) { uint32_t tcread; int16_t tmp; digitalWrite(TC_CS, LOW); tcread = SPI.transfer(0) << 24; tcread |= SPI.transfer(0) << 16; tcread |= SPI.transfer(0) << 8; tcread |= SPI.transfer(0); digitalWrite(TC_CS, HIGH); datum->rawData = tcread; // Thermocouple temp, degrees C and F tmp = (tcread & 0xFFFC0000) >> 18; if (tmp & 0x2000) tmp |= 0xC000; // sign-extend // tmp = TC deg C decimal datum->tcDecimalC = tmp; datum->tcC = tmp / 4; datum->tcF = ((tmp * 9) / 5 + (32*4)) / 4; // Ambient temp, degrees C and F tmp = (tcread & 0x0000FFF0) >> 4; if (tmp & 0x0800) tmp |= 0xF000; // sign-extend // tmp = Amb deg C decimal datum->ambDecimalC = tmp; datum->ambC = tmp / 16; datum->ambF = ((tmp * 9) / 5 + (32*16)) / 16; // Fault information datum->faultBits = tcread & 0x00000007; } dubnet, t0mpr1c3, bluehash and 2 others 5 Quote Link to post Share on other sites
bluehash 1,581 Posted December 29, 2013 Author Share Posted December 29, 2013 Very thoughtful gift.Love the enclosure. spirilis 1 Quote Link to post Share on other sites
PTB 27 Posted December 30, 2013 Share Posted December 30, 2013 Very cool. Now I'm hungry. spirilis 1 Quote Link to post Share on other sites
t0mpr1c3 91 Posted January 2, 2014 Share Posted January 2, 2014 Nice project Eric. I am not so handy with the wood, about the best I can do is chuck it on a fire and burn marshmallows. How are you interfacing the Linux server with the NRF24L01? Quote Link to post Share on other sites
igor 163 Posted January 6, 2014 Share Posted January 6, 2014 Be aware that the contest has been extended until the end of January 2014 (see updates on the thread on 43oh forum). Also, be sure to use the thread on 43oh to make your submissions (at least according to the leading article, submitting it in this thread may not count, or at least may make it more of a headache for the forum maintainers.) Quote Link to post Share on other sites
bluehash 1,581 Posted January 6, 2014 Author Share Posted January 6, 2014 Be aware that the contest has been extended until the end of January 2014 (see updates on the thread on 43oh forum). Also, be sure to use the thread on 43oh to make your submissions (at least according to the leading article, submitting it in this thread may not count, or at least may make it more of a headache for the forum maintainers.) Thanks igor. I'm keeping track of them. Also changed the date. Quote Link to post Share on other sites
PTB 27 Posted January 15, 2014 Share Posted January 15, 2014 And here's my entry. Its a tool for measuring lag and duration of off-camera flashes and setting timing delays between up to 8 flashes.http://forum.stellarisiti.com/topic/1815-stellaris-launchpad-camera-flash-timer-and-measurement-tool/ Bit of a work in progress... but its getting there.CheersPTB Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.