Jump to content
43oh

jim940

Members
  • Content Count

    68
  • Joined

  • Last visited

  • Days Won

    3

Reputation Activity

  1. Like
    jim940 got a reaction from mprairie in eagle cad library for the msp430g2553?   
    I have a library here too with this footprint if you want ... Including a few other footprints like Aranan's A110L like in the boosterpack, OLED, LCD's etc.
     
    http://www.northernd...les/1 - Jim.lbr
     
    Jim
  2. Like
    jim940 got a reaction from msptest6 in C2k Mini-LaunchPad   
    I was looking at the C2K Launchpad, and was sort of disappointed they didn't go with a board that uses CAN, so decided to possibly make my own.
     
    Any ways, I did not route the LIN ports yet, I should have, but as you can see, there is quite a bit of fudging along to make it all work.
     
    It is more or less pin compatible with the regular C2K LaunchPad, except I'm using the 2 NC pins on the lower right headers to break out the CAN pins. And using a JTAG port for programming and debugging.
     

     
    It won't let me upload .brd files so I attached them to my website:
    http://www.northernd.../files/main.brd
    http://www.northernd.../files/main.sch
     
    Dimitri (aka jim940 at 43oh)
    main.brd
    main.sch
  3. Like
    jim940 got a reaction from Automate in C2k Mini-LaunchPad   
    I was looking at the C2K Launchpad, and was sort of disappointed they didn't go with a board that uses CAN, so decided to possibly make my own.
     
    Any ways, I did not route the LIN ports yet, I should have, but as you can see, there is quite a bit of fudging along to make it all work.
     
    It is more or less pin compatible with the regular C2K LaunchPad, except I'm using the 2 NC pins on the lower right headers to break out the CAN pins. And using a JTAG port for programming and debugging.
     

     
    It won't let me upload .brd files so I attached them to my website:
    http://www.northernd.../files/main.brd
    http://www.northernd.../files/main.sch
     
    Dimitri (aka jim940 at 43oh)
    main.brd
    main.sch
  4. Like
    jim940 got a reaction from NullColaShip in OBD-II (On-Board Diagnostic) project idea   
    I just realized I forgot the "u" in forums. :oops:
     
    Anyways, I know more about the CAN Bus now then any other network protocol, spent a entire semester at my college studying it (first Semester of Project Design) so that when I did my project the next semester (Semester 2 we are supposed to build and make work the project) I was decently well versed in it:
     
    http://www.northerndtool.com/bionx
     
    Its Arduino I know, (don't kill me), but that is what I was asked to work with, so that is what I did. :shh:
     
    One thing that confused me as I learned about it, knowing the OSI model, is that technically the CAN Bus forgets about that style of operation. For example, for layer 1, connector types etc should be specified, instead, the higher OSI layers that are implemented on top of the CAN Bus Specifications (such as OBD-II) specify the connectors themselves, and while the OSI model relies heavily on the addressing of the node you wish to speak to, the CAN Bus system, is designed so that each and every node will get the same packets and will use the Message ID as a means to detect whether or not the data is useful to them.
     
    Say you have a home monitoring system running on the CAN Bus, you have a master home controller, a secondary back up controller, and a dozen temperature probes, a couple thermostats, a humidity sensor, oxygen sensor, a couple of smoke sensors and a dozen door sensors.
     
    You'd assign the smoke sensors, lower message ID's, to give them priority, as the CAN Bus will detect "on the fly" if there is a collision, and the lower the message ID bits, the higher priority it gains and wins out arbitration. As in the case of a fire, you want the data to always reach your main controller. So each message ID will be unique to the sensor itself and not its address, instead its what the smoke sensor will use to broadcast its data.
     

     
    Now, your worried about a B&E, so the next lowest set of ID's will go to your door sensors, followed by your oxygen sensor, humidity sensor, thermostats and temperature probes etc. or your own unique priorities.
     
    Since it doesn't rely on a messaging format such as IP routing in your home, BOTH your main controller and your back up controller will receive every packet from every sensor, however, while your programming the main controller regularly, your back up controller is programmed as a watch dog, so that, you'll have code such as, if (Temperature_probe1 < setpoint) && (main_con !sending_messages) then take over the bus and assume the main controller is "dead". And since all the probes, scattered throughout the house can be "dumb", and not actually know who they are sending the packages to, you can have any combination of back up systems in place that will allow your system to survive any number of failures. So any back up "master" nodes, just need to listen as my above example for the sensors (dumb devices) sending requests and the "master" nodes responses. If the master node is not responding, and the back up takes over, the furnace wouldn't know the difference between a packet from the master node, or from the back up master, it will just do what its told, and the system will not be compromised cause of a single (or multiple) failures.
     
    This is one of the reasons why, one of the neat things that the CAN Bus is being used for, beyond the typical industrial automation and automotive sectors, is aerospace, for both planes and space bound satellites, due to its redundancy which doesn't require human intervention to correct itself when properly implemented.
     
    Jim
  5. Like
    jim940 reacted to oPossum in CAN Booster Pack   
    Quick route of PCB...
     
    - Ground plane
    - Short traces for xtal
    - Thicker traces for power
    - Room for more stuff
    booster.brd
    booster.sch

  6. Like
    jim940 got a reaction from bluehash in CAN Booster Pack   
    On Second thought ... in case you don't want to be wasting power.
     

    Booster.brd
  7. Like
    jim940 got a reaction from bluehash in CAN Booster Pack   
    Well this is the minimalist version, the LaunchCAN still needs to be finalized in my head. None the less this one is probably what would interest people the most.
     

     
    If you catch any errors let me know.
     
    Pins currently used:
    1 - CAN Bus Interrupt Pin
    7 - UCB0 CLK
    14 - UCB0 SIMO
    15 - UCB0 SOMI
    16 - RESET
    18 - STE for MCP2525
    19 - AutoBaud feature of TI SN64HVD235
     
    And the BOM of course:
     

    [*:3u4zlitu]Microchip MCP2515 CAN Controller (MCP2515-E/SO).
    [*:3u4zlitu]TI SN64HVD235 CAN Transceiver (SN65HVD235D).
    [*:3u4zlitu]16Mhz Crystal
    [*:3u4zlitu]2x 22pf Capacitors
    [*:3u4zlitu]0.1uF Capacitor
    [*:3u4zlitu]5x2pin Male Header (conforming to CANopen spec's for DE-9 Connection)
    [*:3u4zlitu]Phoenix 1923898 Socket (CANopen type)
    [*:3u4zlitu]2x 10pin Female Headers
     
    You'd also need a Phoenix 1911994 Terminal block to mate with the socket.
     
    Jim
    Booster.brd
  8. Like
    jim940 got a reaction from SugarAddict in $4.30 LCD Booster - Sold Out   
    I apparently got a $5 American bill behind the LCD screen. :!!!:
     
    Jim
  9. Like
    jim940 reacted to mctouch in The Terminal - 43oh OLED Booster Pack   
    In case anybody is having trouble with changing the solder jumpers to switch the board to support the g2553.
     
    SJ4 -> change to VDD (pulls BS0 high for 4 wire SPI)
    SJ3 -> change to P1.7 (moves SDIN to USCI SIMO)
    SJ6 -> change to P2.2 (moves D/C to GPIO)
     

     
    this should help...
  10. Like
    jim940 reacted to bluehash in LaunchCAN?   
    Looks good Jim.
    Will there be an issue of the board rocking due to the LP being underneath at an offset. Just some thing to think about.
  11. Like
    jim940 got a reaction from dubnet in LaunchCAN?   
    Sorry I am pretty bad at coming up with catchy names.
     
    Anyways, my proposal at the moment involves a "double" booster size of 100x50mm. Which will allow it to sit nicely in a 1455C case from Hammond as well. It will have properly broken out headers for LaunchPad Booster packs.
     
    Anyways some of the initial specifications I want on the board:
     

    [*:vili5prf]TI MSP430G2553 TSSOP-28 (or using headers to a LP) (might need something "bigger"?)
    [*:vili5prf]Microchip MCP2515 CAN Bus Controller aka "SPI<->CAN Bridge"
    [*:vili5prf]TI SN65HVD235 CAN Transceiver w/Auto-Baud Loop Back checking
    [*:vili5prf]Bluehash's OLED display
    [*:vili5prf]Anaren CC110L Module
    [*:vili5prf]TI TCA8418 I2C Keypad Controller attached to a 4x3 or 4x4 Button Keypad
    [*:vili5prf]TI TCA6408A I/O Expander attached to 8 Status LED's for CAN Bus and system information
    [*:vili5prf]National LM34910 Switching Regulator
    [*:vili5prf]CANOpen DE-9 Connector (NOT compatible with SPF's OBD-II cable)
    [*:vili5prf]Phoenix M12 CAN Connector
     
    One thing you guys may be able to help me with, is how to use 2 power sources and have the system automatically switch from one to the other without user intervention. Never tried anything like that before. Currently in my head, the National LM34910 will provide approximately 3.3V at 500mA with a input range of 10 to 26V making it compatible with both 12V CAN Bus networks (automotive) and 24V CAN Bus networks (Industrial stuff), however a battery back up would provide for power using a TPS780 which will allow the MSP430 to power itself from 3.3V to 2.2V due to the selection pins when there is no power applied to the CAN Bus connectors.
     
    I might need something bigger then a G2553, however, my CANBus code when I did it on a Arduino was only 4.5K, and nearly 1.5K is automatically taken up by the bootloader when you write your program onto the Arduino, so it might just fit on a mere 16kB, but I am not sure at the moment. Might need a bigger chip, and I feel I would not have the memory space required to implement a SD Card storage on the G2553 at all. Any suggestions are welcomed.
     
    But there you have it a little do it all industrial interface board. I'll post schematics and pictures of the PCBs in due time.
     
    Jim
  12. Like
    jim940 got a reaction from bluehash in LaunchCAN?   
    Sorry I am pretty bad at coming up with catchy names.
     
    Anyways, my proposal at the moment involves a "double" booster size of 100x50mm. Which will allow it to sit nicely in a 1455C case from Hammond as well. It will have properly broken out headers for LaunchPad Booster packs.
     
    Anyways some of the initial specifications I want on the board:
     

    [*:vili5prf]TI MSP430G2553 TSSOP-28 (or using headers to a LP) (might need something "bigger"?)
    [*:vili5prf]Microchip MCP2515 CAN Bus Controller aka "SPI<->CAN Bridge"
    [*:vili5prf]TI SN65HVD235 CAN Transceiver w/Auto-Baud Loop Back checking
    [*:vili5prf]Bluehash's OLED display
    [*:vili5prf]Anaren CC110L Module
    [*:vili5prf]TI TCA8418 I2C Keypad Controller attached to a 4x3 or 4x4 Button Keypad
    [*:vili5prf]TI TCA6408A I/O Expander attached to 8 Status LED's for CAN Bus and system information
    [*:vili5prf]National LM34910 Switching Regulator
    [*:vili5prf]CANOpen DE-9 Connector (NOT compatible with SPF's OBD-II cable)
    [*:vili5prf]Phoenix M12 CAN Connector
     
    One thing you guys may be able to help me with, is how to use 2 power sources and have the system automatically switch from one to the other without user intervention. Never tried anything like that before. Currently in my head, the National LM34910 will provide approximately 3.3V at 500mA with a input range of 10 to 26V making it compatible with both 12V CAN Bus networks (automotive) and 24V CAN Bus networks (Industrial stuff), however a battery back up would provide for power using a TPS780 which will allow the MSP430 to power itself from 3.3V to 2.2V due to the selection pins when there is no power applied to the CAN Bus connectors.
     
    I might need something bigger then a G2553, however, my CANBus code when I did it on a Arduino was only 4.5K, and nearly 1.5K is automatically taken up by the bootloader when you write your program onto the Arduino, so it might just fit on a mere 16kB, but I am not sure at the moment. Might need a bigger chip, and I feel I would not have the memory space required to implement a SD Card storage on the G2553 at all. Any suggestions are welcomed.
     
    But there you have it a little do it all industrial interface board. I'll post schematics and pictures of the PCBs in due time.
     
    Jim
  13. Like
    jim940 got a reaction from GeekDoc in LaunchCAN?   
    Sorry I am pretty bad at coming up with catchy names.
     
    Anyways, my proposal at the moment involves a "double" booster size of 100x50mm. Which will allow it to sit nicely in a 1455C case from Hammond as well. It will have properly broken out headers for LaunchPad Booster packs.
     
    Anyways some of the initial specifications I want on the board:
     

    [*:vili5prf]TI MSP430G2553 TSSOP-28 (or using headers to a LP) (might need something "bigger"?)
    [*:vili5prf]Microchip MCP2515 CAN Bus Controller aka "SPI<->CAN Bridge"
    [*:vili5prf]TI SN65HVD235 CAN Transceiver w/Auto-Baud Loop Back checking
    [*:vili5prf]Bluehash's OLED display
    [*:vili5prf]Anaren CC110L Module
    [*:vili5prf]TI TCA8418 I2C Keypad Controller attached to a 4x3 or 4x4 Button Keypad
    [*:vili5prf]TI TCA6408A I/O Expander attached to 8 Status LED's for CAN Bus and system information
    [*:vili5prf]National LM34910 Switching Regulator
    [*:vili5prf]CANOpen DE-9 Connector (NOT compatible with SPF's OBD-II cable)
    [*:vili5prf]Phoenix M12 CAN Connector
     
    One thing you guys may be able to help me with, is how to use 2 power sources and have the system automatically switch from one to the other without user intervention. Never tried anything like that before. Currently in my head, the National LM34910 will provide approximately 3.3V at 500mA with a input range of 10 to 26V making it compatible with both 12V CAN Bus networks (automotive) and 24V CAN Bus networks (Industrial stuff), however a battery back up would provide for power using a TPS780 which will allow the MSP430 to power itself from 3.3V to 2.2V due to the selection pins when there is no power applied to the CAN Bus connectors.
     
    I might need something bigger then a G2553, however, my CANBus code when I did it on a Arduino was only 4.5K, and nearly 1.5K is automatically taken up by the bootloader when you write your program onto the Arduino, so it might just fit on a mere 16kB, but I am not sure at the moment. Might need a bigger chip, and I feel I would not have the memory space required to implement a SD Card storage on the G2553 at all. Any suggestions are welcomed.
     
    But there you have it a little do it all industrial interface board. I'll post schematics and pictures of the PCBs in due time.
     
    Jim
  14. Like
    jim940 reacted to oPossum in RTTTL (Ring Tone Text Transfer Language) Player   
    Plays ringtones in the RTTTL format. That is a text string for simple monophonic music.
     
    The parser is very simple and does not attempt strict compliance with the specification. It should properly play strings that are written to spec.
     
    The output is a sine wave constructed using 48 kHz PWM on P1.6 that should be low pass filtered by a simple R/C filter.
     
    Code was tested on G2553 - not sure if this will fit in the 2K chips - it should work if it fits.
     


     

    #include #include // // RTTTL spec: http://www.mobilefish.com/tutorials/rtttl/rtttl_quickguide_specification.html // static const long int phase_limit = 48048 * 1000; // Phase accumulator limit, sample rate * 1/resolution static volatile long int pi = 0; // Phase increment (frequency in millihertz) static volatile unsigned note_timer = 0; // Note timer, decrements 48048 times per second static int isnote(char c) // Get note index, or 128 for pause { // // A B C D E F G H( static const int note_map[8] = { 9, 11, 0, 2, 4, 5, 7, 11 }; // MIDI note value if(c >= 'a' && c <= 'h') return note_map[c - 'a']; // Lower case note if(c >= 'A' && c <= 'H') return note_map[c - 'A']; // Upper case note if(c == 'p' || c == 'P') return 128; // Pause return -1; // Invalid, return -1 } static void play_note(unsigned n, unsigned d) // Play note { // n: MIDI note value // d: duration in units of 1/48048 second // static const unsigned note_spacing = 480; // 10 ms between notes static const unsigned long midi_notes[12] = { // MIDI upper 12 notes 6644875L, // 116 G# 9 7040000L, // 117 A 9 7458620L, // 118 A# 9 7902133L, // 119 B 9 8372018L, // 120 C 10 8869844L, // 121 C# 10 9397273L, // 122 D 10 9956063L, // 123 D# 10 10548082L, // 124 E 10 11175303L, // 125 F 10 11839822L, // 126 F# 10 12543854L // 127 G 10 }; // long f; // if(n > 127) { // Invalid note value is pause f = 0; // Frequency = 0 } else { // unsigned o = 10; n += 4; // Init octave, adjust note while(n >= 12) n -= 12, --o; // Normalize note, adjust octave f = midi_notes[n]; // Get frequency while(o) f >>= 1, --o; // Adjust frequency for octave } // while(note_timer); // Wait for current note to finish // pi = 0; // Silence between notes note_timer = note_spacing; // while(note_timer); // // if(d > note_spacing) d -= note_spacing; // Adjust note duration for note spacing note_timer = d; // Setup note time pi = f - phase_limit; // Play note } void play(const char *s) // Play RTTTL string { // unsigned state = 0; // Initial state char c, d; // Char from string, default specifier unsigned bpm = 63; // Beats (quarter notes) per minute unsigned default_duration = 4; // Default note duration (fraction of a whole note) unsigned default_octave = 5; // Default octave long unsigned dot; // Numerator for note clock count calculation, adjusted for dot notation unsigned duration = 0; // Note duration int note; // Note index 0 to 11 int octave; // Octave 0 to 9 // do { // c = *s++; // Get a char from RTTTL string if(c > 0 && c <= 32) continue; // Ingore whitespace and control chars switch(state) { // case 0: // - Skip name if(c == ':') ++state; // Toss chars until ':' break; // case 1: // - Parse defaults state1: // if(c == ':') { // End of default section, begin parsing notes state = 4; // } else if(isalpha(c)) { // Default designator - allow any alpha d = c; // Save it state = 2; // Verify assignment character } else { // state = 1; // Invalid char, stay in this state } // break; // case 2: // - Default assignment char, must be '=' if(c == '=') { // note = 0; // Init default ++state; // Parse default value } else goto state1; // Invalid char, start over break; // case 3: // - Parse and assign default value if(isdigit(c)) { // Update default note = note * 10 + (c - '0'); // } else if(c == ',' || c == ':') { // End of default, assign to variable switch(d) { // case 'b': // Default BPM case 'B': // bpm = note; // break; // case 'o': // Default octave case 'O': // default_octave = note; // break; // case 'd': // Default note duration case 'D': // default_duration = note;// break; // } // state = (c == ':') ? 4 : 1; // Get next default or begin parsing notes } else goto state1; // Invalid char, start over break; // case 4: // - Parse note dot = 48048L * 60 * 4; // Setup defaults for this note duration = default_duration; // octave = default_octave; // note = 0; // if(isdigit(c)) { // May begin with duration duration = c - '0'; // Init duration ++state; // May be more than one digit, continue in next state } else if((note = isnote(c)) >= 0) {// May begin with note state = 6; // Got note, parse modifiers and octave } // break; // case 5: // - Parse duration if(isdigit(c)) { // Numeric digit, update duration duration = duration * 10 + (c -'0'); } else if((note = isnote(c)) >= 0) {// Got note, parse modifiers and octave ++state; // } else { // Invlid char, start over state = 4; // } // break; // case 6: // - Parse modifiers and octave if(c == ',' || c == 0) { // End of note, play it play_note((octave + 1) * 12 + note, dot / (duration * bpm)); state = 4; // Next note } else if(c == '#') { // Sharp, increment note value ++note; // } else if(c == 'b') { // Flat, decrement note value --note; // } else if(c == '.') { // Dotted note, extend length by 50% dot += (dot >> 1); // } else if(isdigit(c)) { // Octave, 0 to 9 allowed, should be 4 to 7 octave = c - '0'; // } // break; // // } // } while(c); // End of string while(note_timer); // Wait for last note to finish pi = 0; // Silence } static const signed char sine[734] = { // 8 bit signed sine wave samples 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 73, 74, 75, 76, 77, 78, 79, 80, 80, 81, 82, 83, 84, 85, 85, 86, 87, 88, 89, 89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99, 100, 101, 101, 102, 103, 103, 104, 105, 105, 106, 106, 107, 108, 108, 109, 109, 110, 110, 111, 111, 112, 113, 113, 114, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 118, 119, 119, 120, 120, 120, 121, 121, 121, 122, 122, 122, 122, 123, 123, 123, 124, 124, 124, 124, 124, 125, 125, 125, 125, 125, 126, 126, 126, 126, 126, 126, 126, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 127, 126, 126, 126, 126, 126, 126, 126, 126, 125, 125, 125, 125, 125, 124, 124, 124, 124, 123, 123, 123, 123, 122, 122, 122, 121, 121, 121, 120, 120, 120, 119, 119, 119, 118, 118, 117, 117, 117, 116, 116, 115, 115, 114, 114, 113, 113, 112, 112, 111, 111, 110, 110, 109, 109, 108, 107, 107, 106, 106, 105, 104, 104, 103, 102, 102, 101, 101, 100, 99, 99, 98, 97, 96, 96, 95, 94, 94, 93, 92, 91, 91, 90, 89, 88, 87, 87, 86, 85, 84, 83, 83, 82, 81, 80, 79, 78, 77, 77, 76, 75, 74, 73, 72, 71, 70, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -15, -16, -17, -18, -19, -20, -21, -22, -23, -24, -25, -26, -27, -29, -30, -31, -32, -33, -34, -35, -36, -37, -38, -39, -40, -41, -42, -43, -44, -45, -46, -47, -48, -49, -50, -51, -52, -53, -54, -55, -56, -57, -58, -59, -60, -61, -62, -63, -64, -65, -66, -67, -68, -68, -69, -70, -71, -72, -73, -74, -75, -76, -76, -77, -78, -79, -80, -81, -82, -82, -83, -84, -85, -86, -86, -87, -88, -89, -90, -90, -91, -92, -93, -93, -94, -95, -96, -96, -97, -98, -98, -99, -100, -100, -101, -102, -102, -103, -104, -104, -105, -106, -106, -107, -107, -108, -108, -109, -110, -110, -111, -111, -112, -112, -113, -113, -114, -114, -115, -115, -116, -116, -116, -117, -117, -118, -118, -119, -119, -119, -120, -120, -120, -121, -121, -121, -122, -122, -122, -123, -123, -123, -123, -124, -124, -124, -124, -125, -125, -125, -125, -125, -126, -126, -126, -126, -126, -126, -126, -126, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -126, -126, -126, -126, -126, -126, -126, -125, -125, -125, -125, -125, -125, -124, -124, -124, -124, -123, -123, -123, -123, -122, -122, -122, -121, -121, -121, -120, -120, -120, -119, -119, -118, -118, -118, -117, -117, -116, -116, -115, -115, -115, -114, -114, -113, -113, -112, -112, -111, -111, -110, -109, -109, -108, -108, -107, -107, -106, -105, -105, -104, -103, -103, -102, -102, -101, -100, -100, -99, -98, -98, -97, -96, -95, -95, -94, -93, -92, -92, -91, -90, -89, -89, -88, -87, -86, -85, -85, -84, -83, -82, -81, -81, -80, -79, -78, -77, -76, -75, -75, -74, -73, -72, -71, -70, -69, -68, -67, -66, -65, -64, -64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49, -48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -3, -2, -1, 0 }; #pragma vector = TIMER0_A1_VECTOR // Timer A0 Overflow interrupt __interrupt void timer0_a1_isr(void) // { // static long int pa = 0; // Phase accumulator static unsigned sample = 200; // PWM sample // TACCR1 = sample; // Output previous PWM sample // volatile unsigned z = TAIV; // Clear interrupt flag // sample = 200 - sine[pa >> 16]; // Get next PWM value // if((pa += pi) < 0) pa += phase_limit; // Update phase accumulator // if(note_timer) --note_timer; // Decrement note timer } // static const char * const tunes[] = { "StWars:d=4,o=5,b=180:8f,8f,8f,2a#.,2f.6,8d#6,8d6,8c6,2a#.6,f.6,8d#6,8d6,8c6,2a#.6,f.6,8d#6,8d6,8d#6,2c6,p,8f,8f,8f,2a#.,2f.6,8d#6,8d6,8c6,2a#.6,f.6,8d#6,8d6,8c6,2a#.6,f.6,8d#6,8d6,8d#6,2c6", "axelf:d=4,o=5,b=160:f#,8a.,8f#,16f#,8a#,8f#,8e,f#,8c.6,8f#,16f#,8d6,8c#6,8a,8f#,8c#6,8f#6,16f#,8e,16e,8c#,8g#,f#.", "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c", "Mission:d=4,o=6,b=100:32d,32d#,32d,32d#,32d,32d#,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16g,8p,16g,8p,16a#,16p,16c,16p,16g,8p,16g,8p,16f,16p,16f#,16p,16a#,16g,2d,32p,16a#,16g,2c#,32p,16a#,16g,2c,16p,16a#5,16c", "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5", "Greensleaves:d=4,o=5,b=140:g,2a#,c6,d.6,8d#6,d6,2c6,a,f.,8g,a,2a#,g,g.,8f,g,2a,f,2d,g,2a#,c6,d.6,8e6,d6,2c6,a,f.,8g,a,a#.,8a,g,f#.,8e,f#,2g", 0 }; void main(void) { WDTCTL = WDTPW | WDTHOLD; // Disable watchdog reset DCOCTL = 0; // Run at 16 MHz BCSCTL1 = CALBC1_16MHZ; // DCOCTL = CALDCO_16MHZ; // // P1DIR = BIT6; // Enable PWM output on P1.6 P1SEL = BIT6; // // TACTL = TASSEL_2 | MC_1 | TAIE; // Timer A config: SMCLK, count up, ovrflow int enabled TACCR0 = 332; // Setup Timer A period for 48.048 kHz TACCR1 = 200; // Setup Timer A compare to "DAC" zero value TACCTL1 = OUTMOD_7; // Setup Timer A reset/set output mode // _EINT(); // Enable interrupts // const char * const *t; // for(; for(t = tunes; *t; ++t) { // Iterate all ring tones play(*t); // Play it note_timer = 48048; // Wait a second before next while(note_timer); // } // }
  15. Like
    jim940 got a reaction from gordon in OBD-II (On-Board Diagnostic) project idea   
    I just realized I forgot the "u" in forums. :oops:
     
    Anyways, I know more about the CAN Bus now then any other network protocol, spent a entire semester at my college studying it (first Semester of Project Design) so that when I did my project the next semester (Semester 2 we are supposed to build and make work the project) I was decently well versed in it:
     
    http://www.northerndtool.com/bionx
     
    Its Arduino I know, (don't kill me), but that is what I was asked to work with, so that is what I did. :shh:
     
    One thing that confused me as I learned about it, knowing the OSI model, is that technically the CAN Bus forgets about that style of operation. For example, for layer 1, connector types etc should be specified, instead, the higher OSI layers that are implemented on top of the CAN Bus Specifications (such as OBD-II) specify the connectors themselves, and while the OSI model relies heavily on the addressing of the node you wish to speak to, the CAN Bus system, is designed so that each and every node will get the same packets and will use the Message ID as a means to detect whether or not the data is useful to them.
     
    Say you have a home monitoring system running on the CAN Bus, you have a master home controller, a secondary back up controller, and a dozen temperature probes, a couple thermostats, a humidity sensor, oxygen sensor, a couple of smoke sensors and a dozen door sensors.
     
    You'd assign the smoke sensors, lower message ID's, to give them priority, as the CAN Bus will detect "on the fly" if there is a collision, and the lower the message ID bits, the higher priority it gains and wins out arbitration. As in the case of a fire, you want the data to always reach your main controller. So each message ID will be unique to the sensor itself and not its address, instead its what the smoke sensor will use to broadcast its data.
     

     
    Now, your worried about a B&E, so the next lowest set of ID's will go to your door sensors, followed by your oxygen sensor, humidity sensor, thermostats and temperature probes etc. or your own unique priorities.
     
    Since it doesn't rely on a messaging format such as IP routing in your home, BOTH your main controller and your back up controller will receive every packet from every sensor, however, while your programming the main controller regularly, your back up controller is programmed as a watch dog, so that, you'll have code such as, if (Temperature_probe1 < setpoint) && (main_con !sending_messages) then take over the bus and assume the main controller is "dead". And since all the probes, scattered throughout the house can be "dumb", and not actually know who they are sending the packages to, you can have any combination of back up systems in place that will allow your system to survive any number of failures. So any back up "master" nodes, just need to listen as my above example for the sensors (dumb devices) sending requests and the "master" nodes responses. If the master node is not responding, and the back up takes over, the furnace wouldn't know the difference between a packet from the master node, or from the back up master, it will just do what its told, and the system will not be compromised cause of a single (or multiple) failures.
     
    This is one of the reasons why, one of the neat things that the CAN Bus is being used for, beyond the typical industrial automation and automotive sectors, is aerospace, for both planes and space bound satellites, due to its redundancy which doesn't require human intervention to correct itself when properly implemented.
     
    Jim
  16. Like
    jim940 got a reaction from bluehash in OBD-II (On-Board Diagnostic) project idea   
    Yes and no, its a lot like a UART with a buffer, typically your stuck with 2-4 messages in the buffer at most with the CAN controllers I've seen. But programming wise, you check the buffer using a interrupt routine when the buffer flags a message is incoming. Even the external MCP2515 SPI<->CAN Bus has a additional pin to be connected to what ever uC's interrupt pin to flag that there is a message.
     
    So, similar to a lot of the MSP430 projects I see around here implementing the power modes, a interrupt routine that wakes up due to the CAN Bus Interrupt, would allow relatively low power, and all the routine would have to do is check with a if or case statement if the message is one the controller wants, if so use the data and then clear the interrupt, otherwise just clear the interrupt and go back to sleep. More or less its the same as any UART interrupt routine because of the way it was designed.
     
    Typically, a CAN Bus doesn't bombard the network all the time with useless data (trying to send files/large hunks of data over it), only packets of the specific preprocessed data as required.
     
    So your thermometer in my previous example isn't blasting away messages as fast as it can, instead you may get it to broadcast only once a minute or more (due to the time it takes to actually change the room temperature in the first place), freeing up a large portion of the Bus, and at the same time, your not sending uncalibrated temperature or other data to the master, your sending something it can directly work with in a simple math function or if statement, allowing it to not be burdened with the grunt work.
     
    Plus, at 250Kb/s or 500Kb/s with most automotive protocols, data takes a while for it to become available compared to the processing ability of the uC (such as running a MSP430 at 8Mhz or better), especially when unwanted message ID's would just be dropped before the rest of the packet is even read/used in the uC's code. As if you know the contents of the message, you can avoid the CPU time of trying to figure out if the data itself is relevant. Which is one of the benefits of a CAN Bus style message ID, verses a address which requires the local device with the same address to work with the data before realizing if some node is just wasting its time.
     
    Jim
  17. Like
    jim940 got a reaction from oPossum in OBD-II (On-Board Diagnostic) project idea   
    I just realized I forgot the "u" in forums. :oops:
     
    Anyways, I know more about the CAN Bus now then any other network protocol, spent a entire semester at my college studying it (first Semester of Project Design) so that when I did my project the next semester (Semester 2 we are supposed to build and make work the project) I was decently well versed in it:
     
    http://www.northerndtool.com/bionx
     
    Its Arduino I know, (don't kill me), but that is what I was asked to work with, so that is what I did. :shh:
     
    One thing that confused me as I learned about it, knowing the OSI model, is that technically the CAN Bus forgets about that style of operation. For example, for layer 1, connector types etc should be specified, instead, the higher OSI layers that are implemented on top of the CAN Bus Specifications (such as OBD-II) specify the connectors themselves, and while the OSI model relies heavily on the addressing of the node you wish to speak to, the CAN Bus system, is designed so that each and every node will get the same packets and will use the Message ID as a means to detect whether or not the data is useful to them.
     
    Say you have a home monitoring system running on the CAN Bus, you have a master home controller, a secondary back up controller, and a dozen temperature probes, a couple thermostats, a humidity sensor, oxygen sensor, a couple of smoke sensors and a dozen door sensors.
     
    You'd assign the smoke sensors, lower message ID's, to give them priority, as the CAN Bus will detect "on the fly" if there is a collision, and the lower the message ID bits, the higher priority it gains and wins out arbitration. As in the case of a fire, you want the data to always reach your main controller. So each message ID will be unique to the sensor itself and not its address, instead its what the smoke sensor will use to broadcast its data.
     

     
    Now, your worried about a B&E, so the next lowest set of ID's will go to your door sensors, followed by your oxygen sensor, humidity sensor, thermostats and temperature probes etc. or your own unique priorities.
     
    Since it doesn't rely on a messaging format such as IP routing in your home, BOTH your main controller and your back up controller will receive every packet from every sensor, however, while your programming the main controller regularly, your back up controller is programmed as a watch dog, so that, you'll have code such as, if (Temperature_probe1 < setpoint) && (main_con !sending_messages) then take over the bus and assume the main controller is "dead". And since all the probes, scattered throughout the house can be "dumb", and not actually know who they are sending the packages to, you can have any combination of back up systems in place that will allow your system to survive any number of failures. So any back up "master" nodes, just need to listen as my above example for the sensors (dumb devices) sending requests and the "master" nodes responses. If the master node is not responding, and the back up takes over, the furnace wouldn't know the difference between a packet from the master node, or from the back up master, it will just do what its told, and the system will not be compromised cause of a single (or multiple) failures.
     
    This is one of the reasons why, one of the neat things that the CAN Bus is being used for, beyond the typical industrial automation and automotive sectors, is aerospace, for both planes and space bound satellites, due to its redundancy which doesn't require human intervention to correct itself when properly implemented.
     
    Jim
  18. Like
    jim940 got a reaction from bluehash in OBD-II (On-Board Diagnostic) project idea   
    I just realized I forgot the "u" in forums. :oops:
     
    Anyways, I know more about the CAN Bus now then any other network protocol, spent a entire semester at my college studying it (first Semester of Project Design) so that when I did my project the next semester (Semester 2 we are supposed to build and make work the project) I was decently well versed in it:
     
    http://www.northerndtool.com/bionx
     
    Its Arduino I know, (don't kill me), but that is what I was asked to work with, so that is what I did. :shh:
     
    One thing that confused me as I learned about it, knowing the OSI model, is that technically the CAN Bus forgets about that style of operation. For example, for layer 1, connector types etc should be specified, instead, the higher OSI layers that are implemented on top of the CAN Bus Specifications (such as OBD-II) specify the connectors themselves, and while the OSI model relies heavily on the addressing of the node you wish to speak to, the CAN Bus system, is designed so that each and every node will get the same packets and will use the Message ID as a means to detect whether or not the data is useful to them.
     
    Say you have a home monitoring system running on the CAN Bus, you have a master home controller, a secondary back up controller, and a dozen temperature probes, a couple thermostats, a humidity sensor, oxygen sensor, a couple of smoke sensors and a dozen door sensors.
     
    You'd assign the smoke sensors, lower message ID's, to give them priority, as the CAN Bus will detect "on the fly" if there is a collision, and the lower the message ID bits, the higher priority it gains and wins out arbitration. As in the case of a fire, you want the data to always reach your main controller. So each message ID will be unique to the sensor itself and not its address, instead its what the smoke sensor will use to broadcast its data.
     

     
    Now, your worried about a B&E, so the next lowest set of ID's will go to your door sensors, followed by your oxygen sensor, humidity sensor, thermostats and temperature probes etc. or your own unique priorities.
     
    Since it doesn't rely on a messaging format such as IP routing in your home, BOTH your main controller and your back up controller will receive every packet from every sensor, however, while your programming the main controller regularly, your back up controller is programmed as a watch dog, so that, you'll have code such as, if (Temperature_probe1 < setpoint) && (main_con !sending_messages) then take over the bus and assume the main controller is "dead". And since all the probes, scattered throughout the house can be "dumb", and not actually know who they are sending the packages to, you can have any combination of back up systems in place that will allow your system to survive any number of failures. So any back up "master" nodes, just need to listen as my above example for the sensors (dumb devices) sending requests and the "master" nodes responses. If the master node is not responding, and the back up takes over, the furnace wouldn't know the difference between a packet from the master node, or from the back up master, it will just do what its told, and the system will not be compromised cause of a single (or multiple) failures.
     
    This is one of the reasons why, one of the neat things that the CAN Bus is being used for, beyond the typical industrial automation and automotive sectors, is aerospace, for both planes and space bound satellites, due to its redundancy which doesn't require human intervention to correct itself when properly implemented.
     
    Jim
  19. Like
    jim940 got a reaction from nuetron in OBD-II (On-Board Diagnostic) project idea   
    I just realized I forgot the "u" in forums. :oops:
     
    Anyways, I know more about the CAN Bus now then any other network protocol, spent a entire semester at my college studying it (first Semester of Project Design) so that when I did my project the next semester (Semester 2 we are supposed to build and make work the project) I was decently well versed in it:
     
    http://www.northerndtool.com/bionx
     
    Its Arduino I know, (don't kill me), but that is what I was asked to work with, so that is what I did. :shh:
     
    One thing that confused me as I learned about it, knowing the OSI model, is that technically the CAN Bus forgets about that style of operation. For example, for layer 1, connector types etc should be specified, instead, the higher OSI layers that are implemented on top of the CAN Bus Specifications (such as OBD-II) specify the connectors themselves, and while the OSI model relies heavily on the addressing of the node you wish to speak to, the CAN Bus system, is designed so that each and every node will get the same packets and will use the Message ID as a means to detect whether or not the data is useful to them.
     
    Say you have a home monitoring system running on the CAN Bus, you have a master home controller, a secondary back up controller, and a dozen temperature probes, a couple thermostats, a humidity sensor, oxygen sensor, a couple of smoke sensors and a dozen door sensors.
     
    You'd assign the smoke sensors, lower message ID's, to give them priority, as the CAN Bus will detect "on the fly" if there is a collision, and the lower the message ID bits, the higher priority it gains and wins out arbitration. As in the case of a fire, you want the data to always reach your main controller. So each message ID will be unique to the sensor itself and not its address, instead its what the smoke sensor will use to broadcast its data.
     

     
    Now, your worried about a B&E, so the next lowest set of ID's will go to your door sensors, followed by your oxygen sensor, humidity sensor, thermostats and temperature probes etc. or your own unique priorities.
     
    Since it doesn't rely on a messaging format such as IP routing in your home, BOTH your main controller and your back up controller will receive every packet from every sensor, however, while your programming the main controller regularly, your back up controller is programmed as a watch dog, so that, you'll have code such as, if (Temperature_probe1 < setpoint) && (main_con !sending_messages) then take over the bus and assume the main controller is "dead". And since all the probes, scattered throughout the house can be "dumb", and not actually know who they are sending the packages to, you can have any combination of back up systems in place that will allow your system to survive any number of failures. So any back up "master" nodes, just need to listen as my above example for the sensors (dumb devices) sending requests and the "master" nodes responses. If the master node is not responding, and the back up takes over, the furnace wouldn't know the difference between a packet from the master node, or from the back up master, it will just do what its told, and the system will not be compromised cause of a single (or multiple) failures.
     
    This is one of the reasons why, one of the neat things that the CAN Bus is being used for, beyond the typical industrial automation and automotive sectors, is aerospace, for both planes and space bound satellites, due to its redundancy which doesn't require human intervention to correct itself when properly implemented.
     
    Jim
  20. Like
    jim940 reacted to oPossum in Frequency Counter using Launchpad & Nokia 5110 LCD   
    This is a simple frequency counter with a range of 1 Hz to 16 MHz. It uses the 32 kHz watch crystal so the accuracy is good enough for many applications. Gate time is automatically set to 250 ms or 1 second.
     
    There is no signal conditioning (front end), so it is limited to 3V logic levels signals only! It is intended to be used with digital circuits like another MSP430 or 74HCxx circuits. It is not a substitute for a proper commercial frequency counter.
     
    How a frequency counter works: Fundamentals of Electronic Counters by Agilent
     
    Wiring

     


     
     
    main.c

    #include "msp430g2553.h" #include "lcd.h" static const unsigned long dv[] = { // Base 10 digit weights 10000000, // 8 digit maximum count 1000000, // 100000, // 10000, // 1000, // 100, // 10, // 1, // 0 // }; static void print_freq(unsigned long n) { const unsigned long *dp = dv; unsigned x = 0; unsigned c; unsigned long d; while(n < *dp) { // Skip leading zeros if(*dp == 100000 || *dp == 100) x += 2; // Space between 3 digit groups ++dp; // lcd_pd10(10, x, 2); // Print space x += 10; // } // if(n) { // Non-zero do { // d = *dp++; // Get digit value c = 0; // while(n >= d) ++c, n -= d; // Divide if(d == 100000 || d == 100) x += 2; // Space between 3 digit groups lcd_pd10(c, x, 2); // Print digit x += 10; // } while(!(d & 1)); // Until all digits done } else // lcd_pd10(0, x - 10, 2); // Print zero } static unsigned clock_input = 0; void set_input(void) { const unsigned char z = 0; lcd_pos(0, 4); lcd_send(&z, 84, lcd_data_repeat); switch(clock_input) { default: clock_input = 0; case 0: TACTL = TASSEL_2; lcd_print("Internal 16MHz", 0, 4); break; case 1: TACTL = TASSEL_0; lcd_print("Clock In P1.0", 3, 4); break; #if 0 case 2: // This should always show 32768 TACTL = TASSEL_1; // Something is very wrong if it doesn't lcd_print("Internal 32kHz", 0, 4); break; #endif } } void set_gate(unsigned long f) { if(WDTCTL & WDTIS0) { // 250 ms gate currently in use if(f < 800000) { // Switch to 1 s gate if frequncy is below 800 kHz lcd_print("1 Second Gate", 3, 5); WDTCTL = WDTPW | WDTTMSEL | WDTSSEL; } } else { // 1 s gate currently in use if(f > 900000) { // Switch to 250 ms gate if frequency above 900 kHz lcd_print(" 250 ms Gate ", 3, 5); WDTCTL = WDTPW | WDTTMSEL | WDTSSEL | WDTIS0; } } } void main(void) { unsigned long freq = 12345678L; // Measured frequency // WDTCTL = WDTPW | WDTHOLD; // Disable watchdog reset // DCOCTL = 0; // Run at 16 MHz BCSCTL1 = CALBC1_16MHZ; // DCOCTL = CALDCO_16MHZ; // //BCSCTL3 = XCAP_1; // 6 pF (default) BCSCTL3 = XCAP_2; // 10 pF //BCSCTL3 = XCAP_3; // 12.5 pF // lcd_init(); // Initialize LCD // P1SEL |= BIT0; // Use P1.0 as TimerA input P1SEL2 &= ~BIT0; // P1DIR &= ~BIT0; // P1OUT &= ~BIT0; // Enable pull down resistor to reduce stray counts P1REN |= BIT0; // // WDTCTL = WDTPW | WDTTMSEL | WDTCNTCL | WDTSSEL | WDTIS0; // Use WDT as interval timer // Default to 250 ms gate so that initial call to set_gate() // will switch to 1 s gate and update the LCD // lcd_clear(0); // Clear LCD lcd_print("Frequency", 16, 0); // What it is lcd_print("Counter", 22, 1); // print_freq(freq); // 8 digit frequency set_input(); // Set input and show on LCD set_gate(0); // Set gate time and show on LCD // for(; { // for-ever freq = 0; // Clear frequency TACTL |= TACLR; // Clear TimerA // IFG1 &= ~WDTIFG; // Wait for WDT period to begin while(!(IFG1 & WDTIFG)); // // TACTL |= MC_2; // Start counting - TimerA continuous mode // IFG1 &= ~WDTIFG; // while(!(IFG1 & WDTIFG)) { // While WDT period.. if(TACTL & TAIFG) { // Check for TimerA overflow freq += 0x10000L; // Add 1 to msw of frequency TACTL &= ~TAIFG; // Clear overflow flag } // } // // TACTL &= ~MC_2; // Stop counting - TimerA stop mode if(TACTL & TAIFG) freq += 0x10000L; // Handle TimerA overflow that may have occured between // last check of overflow and stopping TimerA freq |= TAR; // Merge TimerA count with overflow if(WDTCTL & WDTIS0) freq <<= 2; // Multiply by 4 if using 250 ms gate print_freq(freq); // Show on LCD // set_gate(freq); // Adjust gate time if necessary // if(!(P1IN & BIT3)) { // Check if pushbutton down ++clock_input; // Switch clock input set_input(); // } // } // } lcd.h
    typedef enum { lcd_command = 0, // Array of one or more commands lcd_data = 1, // Array of one or more bytes of data lcd_data_repeat = 2 // One byte of data repeated } lcd_cmd_type; void lcd_send(const unsigned char *cmd, unsigned len, const lcd_cmd_type type); void lcd_home(void); void lcd_pos(unsigned char x, unsigned char y); void lcd_clear(unsigned char x); void lcd_init(void); void lcd_print(char *s, unsigned x, unsigned y); void lcd_pd10(unsigned n, unsigned x, unsigned y); lcd.c
    #include "msp430g2553.h" #include "lcd.h" //static const unsigned TXD = BIT1; static const unsigned RXD = BIT2; static const unsigned SWITCH = BIT3; static const unsigned LCD_CLK = BIT5; static const unsigned LCD_BACKLIGHT = BIT6; static const unsigned LCD_DATA = BIT7; static const unsigned LCD_DC = BIT0; // PORT2 static const unsigned LCD_CE = BIT1; // PORT2 void lcd_send(const unsigned char *cmd, unsigned len, const lcd_cmd_type type) { register unsigned mask; P2OUT &= ~LCD_CE; do { mask = 0x0080; do { if(*cmd & mask) { P1OUT &= ~LCD_CLK; P1OUT |= LCD_DATA; } else { P1OUT &= ~(LCD_CLK | LCD_DATA); } P1OUT |= LCD_CLK; mask >>= 1; } while(!(mask & 1)); if(!type) P2OUT &= ~LCD_DC; if(*cmd & mask) { P1OUT &= ~LCD_CLK; P1OUT |= LCD_DATA; } else { P1OUT &= ~(LCD_CLK | LCD_DATA); } P1OUT |= LCD_CLK; P2OUT |= LCD_DC; if(!(type & 2)) ++cmd; } while(--len); P2OUT |= LCD_CE; } static const unsigned char home[] = { 0x40, 0x80 }; void lcd_home(void) { lcd_send(home, sizeof(home), lcd_command); } void lcd_pos(unsigned char x, unsigned char y) { unsigned char c[2]; c[0] = 0x80 | x; c[1] = 0x40 | y; lcd_send(c, sizeof(c), lcd_command); } void lcd_clear(unsigned char x) { lcd_home(); lcd_send(&x, 504, lcd_data_repeat); lcd_home(); } void lcd_init(void) { static const unsigned char init[] = { 0x20 + 0x01, // Function set - extended instructions enabled //0x80 + 64, // Set vop (contrast) 0 - 127 0x80 + 66, // This is better for fast LCD update 0x04 + 0x02, // Temperature control 0x10 + 0x03, // Set bias system 0x20 + 0x00, // Function set - chip active, horizontal addressing, basic instructions 0x08 + 0x04 // Display control - normal mode }; P1REN = RXD | SWITCH; P1DIR = LCD_CLK | LCD_BACKLIGHT | LCD_DATA; P1OUT = LCD_CLK | RXD | SWITCH | LCD_BACKLIGHT; P2REN = 0; P2DIR = LCD_DC | LCD_CE; P2OUT = LCD_CE; __delay_cycles(20000); P2OUT |= LCD_DC; __delay_cycles(20000); lcd_send(init, sizeof(init), lcd_command); } static const unsigned char font6x8[96][5] = { 0x00, 0x00, 0x00, 0x00, 0x00, // 20 32 <space> 0x00, 0x00, 0x5F, 0x00, 0x00, // 21 33 ! 0x00, 0x07, 0x00, 0x07, 0x00, // 22 34 " 0x14, 0x7F, 0x14, 0x7F, 0x14, // 23 35 # 0x24, 0x2A, 0x7F, 0x2A, 0x12, // 24 36 $ 0x23, 0x13, 0x08, 0x64, 0x62, // 25 37 % 0x36, 0x49, 0x56, 0x20, 0x50, // 26 38 & 0x00, 0x08, 0x07, 0x03, 0x00, // 27 39 ' 0x00, 0x1C, 0x22, 0x41, 0x00, // 28 40 ( 0x00, 0x41, 0x22, 0x1C, 0x00, // 29 41 ) 0x2A, 0x1C, 0x7F, 0x1C, 0x2A, // 2A 42 * 0x08, 0x08, 0x3E, 0x08, 0x08, // 2B 43 + 0x00, 0x40, 0x38, 0x18, 0x00, // 2C 44 , 0x08, 0x08, 0x08, 0x08, 0x08, // 2D 45 - 0x00, 0x00, 0x60, 0x60, 0x00, // 2E 46 . 0x20, 0x10, 0x08, 0x04, 0x02, // 2F 47 / 0x3E, 0x51, 0x49, 0x45, 0x3E, // 30 48 0 0x00, 0x42, 0x7F, 0x40, 0x00, // 31 49 1 0x42, 0x61, 0x51, 0x49, 0x46, // 32 50 2 0x21, 0x41, 0x49, 0x4D, 0x33, // 33 51 3 0x18, 0x14, 0x12, 0x7F, 0x10, // 34 52 4 0x27, 0x45, 0x45, 0x45, 0x39, // 35 53 5 0x3C, 0x4A, 0x49, 0x49, 0x30, // 36 54 6 0x41, 0x21, 0x11, 0x09, 0x07, // 37 55 7 0x36, 0x49, 0x49, 0x49, 0x36, // 38 56 8 0x06, 0x49, 0x49, 0x29, 0x1E, // 39 57 9 0x00, 0x00, 0x14, 0x00, 0x00, // 3A 58 : 0x00, 0x00, 0x40, 0x34, 0x00, // 3B 59 ; 0x00, 0x08, 0x14, 0x22, 0x41, // 3C 60 < 0x14, 0x14, 0x14, 0x14, 0x14, // 3D 61 = 0x00, 0x41, 0x22, 0x14, 0x08, // 3E 62 > 0x02, 0x01, 0x51, 0x09, 0x06, // 3F 63 ? 0x3E, 0x41, 0x5D, 0x59, 0x4E, // 40 64 @ 0x7C, 0x12, 0x11, 0x12, 0x7C, // 41 65 A 0x7F, 0x49, 0x49, 0x49, 0x36, // 42 66 B 0x3E, 0x41, 0x41, 0x41, 0x22, // 43 67 C 0x7F, 0x41, 0x41, 0x41, 0x3E, // 44 68 D 0x7F, 0x49, 0x49, 0x49, 0x41, // 45 69 E 0x7F, 0x09, 0x09, 0x09, 0x01, // 46 70 F 0x3E, 0x41, 0x49, 0x49, 0x7A, // 47 71 G 0x7F, 0x08, 0x08, 0x08, 0x7F, // 48 72 H 0x00, 0x41, 0x7F, 0x41, 0x00, // 49 73 I 0x20, 0x40, 0x41, 0x3F, 0x01, // 4A 74 J 0x7F, 0x08, 0x14, 0x22, 0x41, // 4B 75 K 0x7F, 0x40, 0x40, 0x40, 0x40, // 4C 76 L 0x7F, 0x02, 0x1C, 0x02, 0x7F, // 4D 77 M 0x7F, 0x04, 0x08, 0x10, 0x7F, // 4E 78 N 0x3E, 0x41, 0x41, 0x41, 0x3E, // 4F 79 O 0x7F, 0x09, 0x09, 0x09, 0x06, // 50 80 P 0x3E, 0x41, 0x51, 0x21, 0x5E, // 51 81 Q 0x7F, 0x09, 0x19, 0x29, 0x46, // 52 82 R 0x26, 0x49, 0x49, 0x49, 0x32, // 53 83 S 0x01, 0x01, 0x7F, 0x01, 0x01, // 54 84 T 0x3F, 0x40, 0x40, 0x40, 0x3F, // 55 85 U 0x1F, 0x20, 0x40, 0x20, 0x1F, // 56 86 V 0x3F, 0x40, 0x38, 0x40, 0x3F, // 57 87 W 0x63, 0x14, 0x08, 0x14, 0x63, // 58 88 X 0x03, 0x04, 0x78, 0x04, 0x03, // 59 89 Y 0x61, 0x51, 0x49, 0x45, 0x43, // 5A 90 Z 0x00, 0x7F, 0x41, 0x41, 0x41, // 5B 91 [ 0x02, 0x04, 0x08, 0x10, 0x20, // 5C 92 '\' 0x00, 0x41, 0x41, 0x41, 0x7F, // 5D 93 ] 0x04, 0x02, 0x01, 0x02, 0x04, // 5E 94 ^ 0x80, 0x80, 0x80, 0x80, 0x80, // 5F 95 _ 0x00, 0x03, 0x07, 0x08, 0x00, // 60 96 ' 0x20, 0x54, 0x54, 0x54, 0x78, // 61 97 a 0x7F, 0x28, 0x44, 0x44, 0x38, // 62 98 b 0x38, 0x44, 0x44, 0x44, 0x28, // 63 99 c 0x38, 0x44, 0x44, 0x28, 0x7F, // 64 100 d 0x38, 0x54, 0x54, 0x54, 0x18, // 65 101 e 0x00, 0x08, 0x7E, 0x09, 0x02, // 66 102 f 0x18, 0xA4, 0xA4, 0xA4, 0x7C, // 67 103 g 0x7F, 0x08, 0x04, 0x04, 0x78, // 68 104 h 0x00, 0x44, 0x7D, 0x40, 0x00, // 69 105 i 0x00, 0x20, 0x40, 0x40, 0x3D, // 6A 106 j 0x00, 0x7F, 0x10, 0x28, 0x44, // 6B 107 k 0x00, 0x41, 0x7F, 0x40, 0x00, // 6C 108 l 0x7C, 0x04, 0x78, 0x04, 0x78, // 6D 109 m 0x7C, 0x08, 0x04, 0x04, 0x78, // 6E 110 n 0x38, 0x44, 0x44, 0x44, 0x38, // 6F 111 o 0xFC, 0x18, 0x24, 0x24, 0x18, // 70 112 p 0x18, 0x24, 0x24, 0x18, 0xFC, // 71 113 q 0x7C, 0x08, 0x04, 0x04, 0x08, // 72 114 r 0x48, 0x54, 0x54, 0x54, 0x24, // 73 115 s 0x04, 0x04, 0x3F, 0x44, 0x24, // 74 116 t 0x3C, 0x40, 0x40, 0x20, 0x7C, // 75 117 u 0x1C, 0x20, 0x40, 0x20, 0x1C, // 76 118 v 0x3C, 0x40, 0x30, 0x40, 0x3C, // 77 119 w 0x44, 0x28, 0x10, 0x28, 0x44, // 78 120 x 0x4C, 0x90, 0x90, 0x90, 0x7C, // 79 121 y 0x44, 0x64, 0x54, 0x4C, 0x44, // 7A 122 z 0x00, 0x08, 0x36, 0x41, 0x00, // 7B 123 { 0x00, 0x00, 0x77, 0x00, 0x00, // 7C 124 | 0x00, 0x41, 0x36, 0x08, 0x00, // 7D 125 } 0x02, 0x01, 0x02, 0x04, 0x02, // 7E 126 ~ 0x00, 0x06, 0x09, 0x09, 0x06, // 7F 127 degrees }; void lcd_print(char *s, unsigned x, unsigned y) { lcd_pos(x, y); while(*s) { lcd_send(&font6x8[*s - 32][0], 5, lcd_data); lcd_send(&font6x8[0][0], 1, lcd_data); ++s; } } static const unsigned char num10x16[11][9 * 2] = { // Numbers for 10x16 cell 0xF0,0xF8,0x0C,0x04,0x04,0x04,0x0C,0xF8,0xF0, // 0 0x0F,0x1F,0x30,0x20,0x20,0x20,0x30,0x1F,0x0F, 0x00,0x00,0x10,0x10,0xFC,0xFC,0x00,0x00,0x00, // 1 0x00,0x00,0x20,0x20,0x3F,0x3F,0x20,0x20,0x00, 0x18,0x1C,0x04,0x04,0x04,0x04,0x8C,0xF8,0x70, // 2 0x20,0x30,0x38,0x2C,0x26,0x23,0x21,0x20,0x20, 0x18,0x1C,0x04,0x84,0x84,0x84,0xCC,0x78,0x30, // 3 0x18,0x38,0x20,0x20,0x20,0x20,0x31,0x1F,0x0E, 0x00,0x80,0x40,0x20,0x10,0x08,0xFC,0xFC,0x00, // 4 0x03,0x02,0x02,0x02,0x02,0x02,0x3F,0x3F,0x02, 0x00,0x7C,0x7C,0x44,0x44,0x44,0xC4,0x84,0x04, // 5 0x18,0x38,0x20,0x20,0x20,0x20,0x30,0x1F,0x0F, 0xE0,0xF0,0x58,0x4C,0x44,0x44,0xC4,0x84,0x00, // 6 0x0F,0x1F,0x30,0x20,0x20,0x20,0x30,0x1F,0x0F, 0x04,0x04,0x04,0x04,0x04,0xC4,0xF4,0x3C,0x0C, // 7 0x00,0x00,0x30,0x3C,0x0F,0x03,0x00,0x00,0x00, 0x30,0x78,0xCC,0x84,0x84,0x84,0xCC,0x78,0x30, // 8 0x0E,0x1F,0x31,0x20,0x20,0x20,0x31,0x1F,0x0E, 0xF0,0xF8,0x0C,0x04,0x04,0x04,0x0C,0xF8,0xF0, // 9 0x00,0x21,0x23,0x22,0x22,0x32,0x1A,0x0F,0x07, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <space> 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }; void lcd_pd10(unsigned n, unsigned x, unsigned y) // Print 10x16 digit { unsigned char c[2]; c[0] = 0x80 | x; c[1] = 0x40 + y; lcd_send(c, 2, lcd_command); lcd_send(num10x16[n], 9, lcd_data); c[1] = 0x41 + y; lcd_send(c, 2, lcd_command); lcd_send(num10x16[n] + 9, 9, lcd_data); }
  21. Like
    jim940 reacted to RobG in CC2500 Breakout/BoosterPack   
    Here's the tutorial
     


  22. Like
    jim940 reacted to RobG in [S] ProtoPowerSwitch Boosterpack (formerly AC-powered Relay BoosterPack)   
    Actually, "hot" doesn't have anything to do with phase. To simplify, in a properly wired 120V installation, you touch "hot" you create a loop to the ground... and most likely you die. Nothing should happen when you touch "neutral". But don't try it, I have been shocked couple of times when working on 220V and it is not a pleasant experience at all.
  23. Like
    jim940 reacted to infinityis in [S] ProtoPowerSwitch Boosterpack (formerly AC-powered Relay BoosterPack)   
    Larsie, thanks for the link to an enclosure; it should work well for applications like ours provided that the chassis/safety ground exists and care is taken to ensure the metal of the enclosure is tied only to the chassis/safety ground. If the chassis/safety ground wire is not provided or available, a plastic enclosure should be used instead because it is possible for a loose wire internally to contact a metal housing and energize it, whereas a plastic enclosure (like laptop power supply) is insulative and cannot become energized even if a wire comes loose inside. (Edit: nevermind, just realized the description states the enclosure is made out of ABS plastic and not metal, so no need to worry about grounding the enclosure)
     
    And yes, 15-30mA can kill. Again, I recommend plugging into a GFCI outlet when working on something non-isolated from the mains; even though you can still get killed by the 120V, you do gain protection from accidental shorts to other objects/surfaces tied to the earth/chassis/safety ground.
     
    Jim
    Not to be pedantic, but since it affects safety....techically the distinction is not AC vs. DC but isolated vs. non-isolated. A device which provides galvanic isolation (i.e. high impedance) from the mains can safely connect any one (but only one) of it's output wires to the AC chassis/safety ground. For example, if you take the AC mains power and run it through an isolation transformer, then it safe to tie one end of the output to the chassis/safety ground. Same goes for a DC power supply with an isolated output. However, the circuit I use for the transformerless power supply booster pack cannot have anything tied to safety/chassis ground even though it is DC because there is no isolation from the mains.
     
    Just to restate: isolation from the mains is what matters. The chassis ground can be used as a reference for any isolated AC or DC voltages (e.g. AC isolation transformer, DC isolated power supplies, batteries, etc). Anything that is unable "complete the circuit" to send current through the chassis/safety ground during normal operation is ok.
  24. Like
    jim940 got a reaction from larsie in [S] ProtoPowerSwitch Boosterpack (formerly AC-powered Relay BoosterPack)   
    The idea that the "hot" and "neutral" wire are only a North American phenomenon. With zero basis in fact.
     
    Many products come with polarized at the plug connectors but the cable itself can be plugged backwards in the machine (such as laptop power cords to the AC/DC adapter). Or the tons of non-polarized plugs in both North America but the rest of the world that has the "neutral" wire tied into ground none the less, meaning you might never know what is connected to neutral or the "hot" wire as only in North America are polarized plugs defined as some sort of "standard".
     
    Also international regulatory regulations prohibit the use of the neutral and hot wires in the manors sometimes described by people. A laptop or desktop PSU is NOT allowed to treat the hot wire as the "hot" wire, and the neutral wire cannot be treated as the "grounded" wire. Only in a properly installed 3 wire system can you try to use a wire as a ground throughout a building/home, of which many homes due to age do not actually have this ability to use, which again after the direct AC powered circuit (such as AC to DC conversion in a PSU) is still quite illegal to reference your loads to the AC neutral/ground because the wiring in any building is treated as suspect by the regulations.
     
    Anyways this is a pretty interesting read, and a good summery from a respectable source (APC):
     
    http://www.apcdistributors.com/white-pa ... hology.pdf
     
    Jim
  25. Like
    jim940 got a reaction from larsie in Cheap circuit for powering MSP430 from 230V   
    Many cell phone USB chargers and laptop chargers today can switch from 120V/230V without a issue. Cause its cheaper to make one set of internals for everything then not nowadays. Check the back of your chargers, you might have one waiting and available already. World wide all companies do is change the plastic plate that faces the wall with the appropriate plug configuration during manufacture in their last operation so it costs no where near as much as running dedicated lines producing different adapters for different markets. Or in the case of laptop AC Adapters is provide you with a different 3ft length of cable with the appropriate plug attached to that instead of the expensive part (the AC/DC adapter itself).
     
    My Nokia cell phone charger is rated for a input of 100V-240V @ 50-60Hz and outputs 5V DC at 1.2A.
     
    As the examples closest to my desk that will give you your 5V DC and if your really cheap to drop the $5 5V power from the adapter do what oPossum does, use a LED to drop it down to ~3V.
     

     
    Jim
×
×
  • Create New...