Jump to content
43oh

gordon

Members
  • Content Count

    536
  • Joined

  • Last visited

  • Days Won

    13

Reputation Activity

  1. Like
    gordon reacted to bluehash in [ SPAM ] - Spam Hammer Implemented! No More Zombies.   
    Hello 43oher's,
    We've implemented Dangerous Prototypes' Spam Hammer - a spam blocking mod. It had proved itself to be very powerful in the dp forums as well as the phpbb3 forums. The install went well and the databases look fine, so no problems there. This is on a test run - so there will be a report here in this thread in two weeks. Thanks to DP for developing the mod.
     
    FAQ:
    This forum is protected by phpBB3 spam hammer. Here's how our simple anti-spam measures work.
     
    These restrictions only apply to new users. They are removed automatically after your account meets certain criteria. Normal users will never be effected by these restrictions.
     
    Spam poured in after our recent move to a phpBB forum. Captchas, registration questions, and other measures only stopped the stupidest scripts and annoyed everyone. Instead, we stopped spammers from getting what they want - new members can't post links. This method that has stopped 100% of spam so far, and it is totally transparent to most people.
     
    How does it work?
    New user accounts are slightly restricted to deny spammers a place to put a link.
     
    These restrictions only apply to new users. They are removed automatically after your account meets certain criteria. Normal users will never be effected by these restrictions.
     
    1. New users receive an error if they use off-site links in posts or signatures. New users can still link to 43oh.com, and a select set of white-list sites like Google Code, distributors, etc.
    2. New users receive an error if they use certain forbidden words in posts or signatures. The error reports the trigger word to help you find and remove it.
    3. New users receive an error if they enter non-English characters (like Cyrillic).
    4. New users can't save a personal profile. Spammers like to put a URL in the personal profile.
    5. Accounts that don't post within 24 hours of registration are automatically disabled and then purged. We get 100s of zombie spam registrations every day, an automated process cleans them out.
     
    Who is a new user?
    The above restrictions only apply to new users. We are constantly tweaking the definition of a new user to stop spam while not annoying real people. These restrictions currently apply to users who:
    *Have less than 1 post
    *Registered in the last 24 hours
    The restrictions are automatically removed once an account meets these criteria.
     
    Warning!! Extreme honey-pot mode in use!!
    Users with 0 posts will be automatically deleted for certain common spam behaviors:
    *Entering a profile
    *Entering a signature with external links
    *Entering more than 20 links in the first post
     
    Need Help?
    Contact admin AT 43oh . com
  2. Like
    gordon got a reaction from jsolarski in Makefile for MSPGCC   
    Following up on viewtopic.php?f=10&t=1228#p8163, I made some tweaks to the Makefile. It now has simple heuristics to detect whether you are running Windows (I'm not much of a Windows person, so it is kind of a shot in the dark, please test), and if yes, it uses MSP430Flasher for installing.
     
    It is also possible to have only one central instance of this "master" Makefile, with per-project Makefiles only referencing this one, possibly overriding some settings.
     
    Per-project Makefile:

    TARGETMCU := msp430g2211 include ../Makefile
    (I really don't recommend symlinking the master Makefile in project directories, you'll surely shoot yourself in the foot sooner or later.)
     
    Master Makefile:

    TARGETMCU ?= msp430g2231 SRCS ?= main.c CROSS := msp430- CC := $(CROSS)gcc CXX := $(CROSS)g++ OBJDUMP := $(CROSS)objdump OBJCOPY := $(CROSS)objcopy SIZE := $(CROSS)size LD := $(CC) MSPDEBUG := mspdebug MSP430FLASHER := C:\\bin\\MSP430Flasher LDFLAGS := -mmcu=$(TARGETMCU) CFLAGS := -Os -Wall -W -Wextra -Werror -std=gnu99 -g -mmcu=$(TARGETMCU) ifneq ($(WITH_CXX),) CC := $(CXX) LD := $(CC) endif ifeq ($(WITH_CXX),) CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wbad-function-cast CFLAGS += -Werror-implicit-function-declaration -Wdeclaration-after-statement CFLAGS += -Wnested-externs -Wold-style-definition endif CFLAGS += -Wmissing-declarations -Winit-self -Winline -Wredundant-decls CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare -Wformat=2 CFLAGS += -Wfloat-equal -Wmissing-field-initializers CFLAGS += -Wmissing-include-dirs -Wswitch-default -Wpacked CFLAGS += -Wpacked -Wlarger-than-65500 -Wunknown-pragmas CFLAGS += -Wmissing-format-attribute -Wmissing-noreturn CFLAGS += -Wstrict-aliasing=2 -Wswitch-enum -Wundef -Wunreachable-code CFLAGS += -Wunsafe-loop-optimizations -Wwrite-strings -Wcast-align CFLAGS += -Wformat-nonliteral -Wformat-security -Waggregate-return CFLAGS += -fno-common -Wp,-D_FORTIFY_SOURCE=2 CFLAGS += -finline-functions CXXFLAGS := $(CFLAGS) PROG := $(firstword $(SRCS:.c=)) OBJS := $(SRCS:.c=.o) all: $(PROG).elf $(PROG).hex $(PROG).lst %.elf: $(OBJS) $(LD) $(LDFLAGS) -o $(PROG).elf $(OBJS) $(SIZE) $< %.o: %.c $(CC) $(CFLAGS) -c $< %.lst: %.elf $(OBJDUMP) -DS $< > $@ %.hex: %.elf $(OBJCOPY) -O ihex $< $@ clean: -rm -f $(PROG).elf $(PROG).lst $(PROG).hex $(OBJS) install: $(PROG).elf $(PROG).hex ifeq ($(OS),Windows_NT) $(MSP430FLASHER) -n $(TARGETMCU) -e ERASE_MAIN -w $< else $(MSPDEBUG) -n rf2500 "prog $<" endif erase: $(MSPDEBUG) -n rf2500 erase .PHONY: all clean install erase .PRECIOUS: %.o
     
    I don't know what options does MSP430Flasher take, I just sort of guessed.
  3. Like
    gordon got a reaction from Rickta59 in MSP-EXP430FR5739 demo code ported to msp430-gcc   
    "msp430-objcopy -O ihex infile.elf outfile.hex" should do the trick (if MSP430Flasher needs Intel hex as it's input).
  4. Like
    gordon got a reaction from pine in Is this safe to power up?   
    Just push the extra MCU in a piece of antistatic foam or something, and let it float. It is IMHO much safer than this construct where an accident can bend it or something.
     
    Anyhow, as far as I can remember, there's nothing connected to those pins, so as long as you don't put anything to the headers you will probably solder on, it should be safe. Check the LP schematics though.
     
    Edit: I mean check the LP schematics and the PCB layout as well.
  5. Like
    gordon reacted to jsolarski in Makefile for MSPGCC   
    here are the 2 make files I use for mspgcc - for use or comparison
     

    OBJECTS = main.o CC = msp430-gcc CFLAGS =-Os -Wall -g -mmcu=msp430x2011 all : $(OBJECTS) $(CC) $(CFLAGS) $(OBJECTS) -o main.elf %.o : %.c $(CC) $(CFLAGS) -c $< clean: rm -fr $(OBJECTS) main.elf erase: mspdebug rf2500 "erase" upload: mspdebug rf2500 "prog main.elf" size: msp430-size main.elf
     

    CC=msp430-gcc CFLAGS=-Os -Wall -g -mmcu=msp430g2231 OBJS=main.c all: $(OBJS) $(CC) $(CFLAGS) -o main.elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< clean: rm -fr main.elf $(OBJS)
     
     
    very simple and no extra flags
     
    as for all your flags, time to get out the gcc manual lol
  6. Like
    gordon got a reaction from pimmel in Makefile for MSPGCC   
    Rickta59 says this might be of interest to others, so here's the Makefile I've been using for MSPGCC.
     

    TARGETMCU ?= msp430g2211 CROSS := msp430- CC := $(CROSS)gcc CXX := $(CROSS)g++ OBJDUMP := $(CROSS)objdump SIZE := $(CROSS)size LD := $(CC) MSPDEBUG := mspdebug LDFLAGS := -mmcu=$(TARGETMCU) CFLAGS := -Os -Wall -W -Wextra -Werror -g -mmcu=$(TARGETMCU) ifneq ($(WITH_CXX),) CC := $(CXX) LD := $(CC) endif ifneq ($(DEBUG),) ifeq ($(WITH_CXX),) CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wbad-function-cast CFLAGS += -Werror-implicit-function-declaration -Wdeclaration-after-statement CFLAGS += -Wnested-externs -Wold-style-definition CFLAGS += -finline-functions endif CFLAGS += -Wmissing-declarations -Winit-self -Winline -Wredundant-decls CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare -Wformat=2 CFLAGS += -Wfloat-equal -Wmissing-field-initializers CFLAGS += -Wmissing-include-dirs -Wswitch-default -Wpacked CFLAGS += -Wpacked -Wlarger-than-65500 -Wunknown-pragmas CFLAGS += -Wmissing-format-attribute -Wmissing-noreturn CFLAGS += -Wstrict-aliasing=2 -Wswitch-enum -Wundef -Wunreachable-code CFLAGS += -Wunsafe-loop-optimizations -Wwrite-strings -Wcast-align CFLAGS += -Wformat-nonliteral -Wformat-security -Waggregate-return CFLAGS += -fno-common -Wp,-D_FORTIFY_SOURCE=2 endif SRCS := main.c PROG := $(firstword $(SRCS:.c=)) OBJS := $(SRCS:.c=.o) all: $(PROG).elf $(PROG).lst $(PROG).elf: $(OBJS) $(LD) $(LDFLAGS) -o $(PROG).elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< %.lst: %.elf $(OBJDUMP) -DS $< > $@ $(SIZE) $< clean: -rm -f $(PROG).elf $(PROG).lst $(OBJS) install: $(PROG).elf $(MSPDEBUG) -n rf2500 "prog $(PROG).elf"
     
    I don't know what half of the CFLAGs mean anymore (some of them most likely don't even have any real meaning in the MSP430 context), I have collected them during the years, the result is considerably anal about code quality, though.
     
    roxfan notes,
     
    Well, I got used to objdump's output, that's about it.
     
    It's GNU make, don't even try with others, really. Also don't forget to expand spaces to tabs.
  7. Like
    gordon got a reaction from bluehash in Makefile for MSPGCC   
    Rickta59 says this might be of interest to others, so here's the Makefile I've been using for MSPGCC.
     

    TARGETMCU ?= msp430g2211 CROSS := msp430- CC := $(CROSS)gcc CXX := $(CROSS)g++ OBJDUMP := $(CROSS)objdump SIZE := $(CROSS)size LD := $(CC) MSPDEBUG := mspdebug LDFLAGS := -mmcu=$(TARGETMCU) CFLAGS := -Os -Wall -W -Wextra -Werror -g -mmcu=$(TARGETMCU) ifneq ($(WITH_CXX),) CC := $(CXX) LD := $(CC) endif ifneq ($(DEBUG),) ifeq ($(WITH_CXX),) CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wbad-function-cast CFLAGS += -Werror-implicit-function-declaration -Wdeclaration-after-statement CFLAGS += -Wnested-externs -Wold-style-definition CFLAGS += -finline-functions endif CFLAGS += -Wmissing-declarations -Winit-self -Winline -Wredundant-decls CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare -Wformat=2 CFLAGS += -Wfloat-equal -Wmissing-field-initializers CFLAGS += -Wmissing-include-dirs -Wswitch-default -Wpacked CFLAGS += -Wpacked -Wlarger-than-65500 -Wunknown-pragmas CFLAGS += -Wmissing-format-attribute -Wmissing-noreturn CFLAGS += -Wstrict-aliasing=2 -Wswitch-enum -Wundef -Wunreachable-code CFLAGS += -Wunsafe-loop-optimizations -Wwrite-strings -Wcast-align CFLAGS += -Wformat-nonliteral -Wformat-security -Waggregate-return CFLAGS += -fno-common -Wp,-D_FORTIFY_SOURCE=2 endif SRCS := main.c PROG := $(firstword $(SRCS:.c=)) OBJS := $(SRCS:.c=.o) all: $(PROG).elf $(PROG).lst $(PROG).elf: $(OBJS) $(LD) $(LDFLAGS) -o $(PROG).elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< %.lst: %.elf $(OBJDUMP) -DS $< > $@ $(SIZE) $< clean: -rm -f $(PROG).elf $(PROG).lst $(OBJS) install: $(PROG).elf $(MSPDEBUG) -n rf2500 "prog $(PROG).elf"
     
    I don't know what half of the CFLAGs mean anymore (some of them most likely don't even have any real meaning in the MSP430 context), I have collected them during the years, the result is considerably anal about code quality, though.
     
    roxfan notes,
     
    Well, I got used to objdump's output, that's about it.
     
    It's GNU make, don't even try with others, really. Also don't forget to expand spaces to tabs.
  8. Like
    gordon got a reaction from Rickta59 in Makefile for MSPGCC   
    Rickta59 says this might be of interest to others, so here's the Makefile I've been using for MSPGCC.
     

    TARGETMCU ?= msp430g2211 CROSS := msp430- CC := $(CROSS)gcc CXX := $(CROSS)g++ OBJDUMP := $(CROSS)objdump SIZE := $(CROSS)size LD := $(CC) MSPDEBUG := mspdebug LDFLAGS := -mmcu=$(TARGETMCU) CFLAGS := -Os -Wall -W -Wextra -Werror -g -mmcu=$(TARGETMCU) ifneq ($(WITH_CXX),) CC := $(CXX) LD := $(CC) endif ifneq ($(DEBUG),) ifeq ($(WITH_CXX),) CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wbad-function-cast CFLAGS += -Werror-implicit-function-declaration -Wdeclaration-after-statement CFLAGS += -Wnested-externs -Wold-style-definition CFLAGS += -finline-functions endif CFLAGS += -Wmissing-declarations -Winit-self -Winline -Wredundant-decls CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare -Wformat=2 CFLAGS += -Wfloat-equal -Wmissing-field-initializers CFLAGS += -Wmissing-include-dirs -Wswitch-default -Wpacked CFLAGS += -Wpacked -Wlarger-than-65500 -Wunknown-pragmas CFLAGS += -Wmissing-format-attribute -Wmissing-noreturn CFLAGS += -Wstrict-aliasing=2 -Wswitch-enum -Wundef -Wunreachable-code CFLAGS += -Wunsafe-loop-optimizations -Wwrite-strings -Wcast-align CFLAGS += -Wformat-nonliteral -Wformat-security -Waggregate-return CFLAGS += -fno-common -Wp,-D_FORTIFY_SOURCE=2 endif SRCS := main.c PROG := $(firstword $(SRCS:.c=)) OBJS := $(SRCS:.c=.o) all: $(PROG).elf $(PROG).lst $(PROG).elf: $(OBJS) $(LD) $(LDFLAGS) -o $(PROG).elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< %.lst: %.elf $(OBJDUMP) -DS $< > $@ $(SIZE) $< clean: -rm -f $(PROG).elf $(PROG).lst $(OBJS) install: $(PROG).elf $(MSPDEBUG) -n rf2500 "prog $(PROG).elf"
     
    I don't know what half of the CFLAGs mean anymore (some of them most likely don't even have any real meaning in the MSP430 context), I have collected them during the years, the result is considerably anal about code quality, though.
     
    roxfan notes,
     
    Well, I got used to objdump's output, that's about it.
     
    It's GNU make, don't even try with others, really. Also don't forget to expand spaces to tabs.
  9. Like
    gordon got a reaction from jsolarski in Makefile for MSPGCC   
    Rickta59 says this might be of interest to others, so here's the Makefile I've been using for MSPGCC.
     

    TARGETMCU ?= msp430g2211 CROSS := msp430- CC := $(CROSS)gcc CXX := $(CROSS)g++ OBJDUMP := $(CROSS)objdump SIZE := $(CROSS)size LD := $(CC) MSPDEBUG := mspdebug LDFLAGS := -mmcu=$(TARGETMCU) CFLAGS := -Os -Wall -W -Wextra -Werror -g -mmcu=$(TARGETMCU) ifneq ($(WITH_CXX),) CC := $(CXX) LD := $(CC) endif ifneq ($(DEBUG),) ifeq ($(WITH_CXX),) CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wbad-function-cast CFLAGS += -Werror-implicit-function-declaration -Wdeclaration-after-statement CFLAGS += -Wnested-externs -Wold-style-definition CFLAGS += -finline-functions endif CFLAGS += -Wmissing-declarations -Winit-self -Winline -Wredundant-decls CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare -Wformat=2 CFLAGS += -Wfloat-equal -Wmissing-field-initializers CFLAGS += -Wmissing-include-dirs -Wswitch-default -Wpacked CFLAGS += -Wpacked -Wlarger-than-65500 -Wunknown-pragmas CFLAGS += -Wmissing-format-attribute -Wmissing-noreturn CFLAGS += -Wstrict-aliasing=2 -Wswitch-enum -Wundef -Wunreachable-code CFLAGS += -Wunsafe-loop-optimizations -Wwrite-strings -Wcast-align CFLAGS += -Wformat-nonliteral -Wformat-security -Waggregate-return CFLAGS += -fno-common -Wp,-D_FORTIFY_SOURCE=2 endif SRCS := main.c PROG := $(firstword $(SRCS:.c=)) OBJS := $(SRCS:.c=.o) all: $(PROG).elf $(PROG).lst $(PROG).elf: $(OBJS) $(LD) $(LDFLAGS) -o $(PROG).elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< %.lst: %.elf $(OBJDUMP) -DS $< > $@ $(SIZE) $< clean: -rm -f $(PROG).elf $(PROG).lst $(OBJS) install: $(PROG).elf $(MSPDEBUG) -n rf2500 "prog $(PROG).elf"
     
    I don't know what half of the CFLAGs mean anymore (some of them most likely don't even have any real meaning in the MSP430 context), I have collected them during the years, the result is considerably anal about code quality, though.
     
    roxfan notes,
     
    Well, I got used to objdump's output, that's about it.
     
    It's GNU make, don't even try with others, really. Also don't forget to expand spaces to tabs.
  10. Like
    gordon got a reaction from zborgerd in Makefile for MSPGCC   
    Rickta59 says this might be of interest to others, so here's the Makefile I've been using for MSPGCC.
     

    TARGETMCU ?= msp430g2211 CROSS := msp430- CC := $(CROSS)gcc CXX := $(CROSS)g++ OBJDUMP := $(CROSS)objdump SIZE := $(CROSS)size LD := $(CC) MSPDEBUG := mspdebug LDFLAGS := -mmcu=$(TARGETMCU) CFLAGS := -Os -Wall -W -Wextra -Werror -g -mmcu=$(TARGETMCU) ifneq ($(WITH_CXX),) CC := $(CXX) LD := $(CC) endif ifneq ($(DEBUG),) ifeq ($(WITH_CXX),) CFLAGS += -Wstrict-prototypes -Wmissing-prototypes -Wbad-function-cast CFLAGS += -Werror-implicit-function-declaration -Wdeclaration-after-statement CFLAGS += -Wnested-externs -Wold-style-definition CFLAGS += -finline-functions endif CFLAGS += -Wmissing-declarations -Winit-self -Winline -Wredundant-decls CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wsign-compare -Wformat=2 CFLAGS += -Wfloat-equal -Wmissing-field-initializers CFLAGS += -Wmissing-include-dirs -Wswitch-default -Wpacked CFLAGS += -Wpacked -Wlarger-than-65500 -Wunknown-pragmas CFLAGS += -Wmissing-format-attribute -Wmissing-noreturn CFLAGS += -Wstrict-aliasing=2 -Wswitch-enum -Wundef -Wunreachable-code CFLAGS += -Wunsafe-loop-optimizations -Wwrite-strings -Wcast-align CFLAGS += -Wformat-nonliteral -Wformat-security -Waggregate-return CFLAGS += -fno-common -Wp,-D_FORTIFY_SOURCE=2 endif SRCS := main.c PROG := $(firstword $(SRCS:.c=)) OBJS := $(SRCS:.c=.o) all: $(PROG).elf $(PROG).lst $(PROG).elf: $(OBJS) $(LD) $(LDFLAGS) -o $(PROG).elf $(OBJS) %.o: %.c $(CC) $(CFLAGS) -c $< %.lst: %.elf $(OBJDUMP) -DS $< > $@ $(SIZE) $< clean: -rm -f $(PROG).elf $(PROG).lst $(OBJS) install: $(PROG).elf $(MSPDEBUG) -n rf2500 "prog $(PROG).elf"
     
    I don't know what half of the CFLAGs mean anymore (some of them most likely don't even have any real meaning in the MSP430 context), I have collected them during the years, the result is considerably anal about code quality, though.
     
    roxfan notes,
     
    Well, I got used to objdump's output, that's about it.
     
    It's GNU make, don't even try with others, really. Also don't forget to expand spaces to tabs.
  11. Like
    gordon got a reaction from djlorenz in Dmx512 comunication with MSP430 and launchpad   
    viewtopic.php?f=8&t=162
     
    LaunchPad-Compatible Devices
     
    But basically, you can just pretty much get (sample) a 2553 (the biggest of the value line, I think), and be done with it, IMHO .
  12. Like
    gordon reacted to bluehash in Using the Launchpad with a Breadboard   
    Bineman/SimpleAVR( was very active here, hope he comes back) made a cable for it:
    http://www.43oh.com/2010/11/ez430-f2013 ... out-cable/
  13. Like
    gordon got a reaction from MarkoeZ in A Noobs Introduction to MSP430 - Serial RC Car Video Blog   
    This is a shy recommendation as I have not looked very closely at them so basically talking out of my bottom, but you could also look at LED drivers (MAX6957 I got recently). They probably won't do PWM (for microstepping), but otherwise, driven by I2C and loads of (relatively) high- and constant-current outputs. There are also some other tips on the URL above for alternatives.
  14. Like
    gordon got a reaction from jsolarski in openMSP430   
    Probably only marginally interesting, but interesting nevertheless, look what my partner in crime just dug up: openMSP430.
  15. Like
    gordon reacted to zeke in G2553 28pin Prototyping?   
    The other reason for using 45' angles on traces has to do with high speed signals. By high speed I mean really high speed.
     
    So high, we will never see them on a LaunchPad board.
     
    Still, it's good practice to use 45' angles on pcb traces.
     
    Dave Jones' PCB Design Tutorial has some high speed pcb layout guidance on page 19. The whole document is an awesome resource.
  16. Like
    gordon got a reaction from GeekDoc in G2553 28pin Prototyping?   
    The etchant gets under the sharp corners easier and causes bad etching.
     
    I don't really think it is a(ny major) problem with professionally-made PCBs, but it is an issue when you cook Fe2O3 my buttFeCl3 in the kitchen, so I'm guessing in this particular case bringing up the right angles-issue might be just an involuntary reflex .
  17. Like
    gordon got a reaction from nyordanov in Using mspdebug for 2452 - could not write to memory   
    Sorry, I misremembered my samples orderDidn't notice they were on backorder, I got no 2452s (maybe 2-3 weeks or so at best). It works fine with 2553, though, and Rickta59 hinted on IRC that he uses 2452s with mspdebug without problems. Looking again, the "fet: command C_IDENT1 failed" is something I too have every time, and it's probably harmless (hooray consistent opinion), but I can't find where did I read up on this.
     
    Back at square one.
  18. Like
    gordon reacted to RobG in MIDI Light controller   
    Here's the code.
    There is still room for improvement, like making zero crossing detector immune to noise, better handling of small loads like LED lights, and programmable MIDI channel and octave.
     
     

    #include "msp430g2553.h" #define MIDI_IN_PIN BIT1 // MIDI in pin #define ZERO_X_PIN BIT0 // Zero Crossing Detector in pin #define MIDI_RCVD_LED_PIN BIT2 // MIDI message received LED out pin #define P1_OUT_PINS BIT4 + BIT5 + BIT6 + BIT7 // Outputs on P1 void setUp(); char charIndex = 0; // general use index char rxData = 0; // received data char rxByte = 1; // data byte, first or second char channel = 0; // MIDI channel to listen to char status = 0; // Status byte converted to something easy to use char runningStatus = 0; // running status flag char light = 255; // light index char lights[40]; // array of light brightness values (we are only using 10, but 40 or more are possible) char counter = 1; // PWM counter char lightCounter = 0; // used to track lights when setting/sending light on/off int bitCounter = 0; // used for setting parallel lights on/off void main(void) { setUp(); __bis_SR_register(GIE); // enable global while(1) { // main loop lightCounter = 0; // clear light counter bitCounter = 1; // first light on port 2 (P2.0-P2.5) while(lightCounter < 6) { // loop through parallel lights 0-5 if((counter > 8) && (lights[lightCounter] == counter)) {// when value equals PWM counter... (unreliable when below 8) P2OUT |= bitCounter; // turn light on } lightCounter++; // next light P2OUT &= ~bitCounter; // clear output bitCounter <<= 1; // next bit on port 2 } bitCounter = 0x10; // first light on port 1 (P1.4-P1.7) while(lightCounter < 10) { // loop through parallel lights 6-9 if((counter > 8) && (lights[lightCounter] == counter)) {// when value equals PWM counter... (unreliable when below 8) P1OUT |= bitCounter; // turn light on } lightCounter++; // next light P1OUT &= ~bitCounter; // clear output bitCounter <<= 1; // next bit on port 1 } __bis_SR_register(LPM0_bits); // go to sleep and wait for timer } } // increment count up to 64 #pragma vector = TIMER0_A0_VECTOR __interrupt void Timer_A0 (void) { if(counter > 1) { counter--; // decrement PWM counter } __bic_SR_register_on_exit(LPM0_bits); // wake up and update lights } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { counter = 64; // reset counter P1OUT &= ~(P1_OUT_PINS); // clear outputs just in case P2OUT = 0; P1OUT |= MIDI_RCVD_LED_PIN; // MIDI LED off P1IFG = 0; } void setUp() { WDTCTL = WDTPW + WDTHOLD; // disable WDT BCSCTL1 = CALBC1_8MHZ; // 8MHz clock DCOCTL = CALDCO_8MHZ; P1OUT |= MIDI_RCVD_LED_PIN; P1DIR |= MIDI_RCVD_LED_PIN; P1OUT &= ~(P1_OUT_PINS); // port 1, 4 outs P1DIR |= (P1_OUT_PINS); P1SEL = MIDI_IN_PIN; // setup MIDI in pin P1SEL2 = MIDI_IN_PIN; P2SEL &= ~(BIT6|BIT7); // port 2 all out P2OUT = 0; P2DIR = 0xFF; P1DIR &= ~ZERO_X_PIN; // port P1.0 zero crossing detector input P1IES |= ZERO_X_PIN; // high/lo edge P1IFG &= ~ZERO_X_PIN; P1IE |= ZERO_X_PIN; CCTL0 = CCIE; // setup timer CCR0 = 1042; // 130.2us TACTL = TASSEL_2 + MC_1; // SMCLK, upmode UCA0CTL1 |= UCSSEL_2; // setup UART UCA0BR0 = 0x00; UCA0BR1 = 0x01; // 31.25 Kbaud UCA0CTL1 &= ~UCSWRST; IE2 |= UCA0RXIE; charIndex = 0; // clear lights while(charIndex < 40) { lights[charIndex] = 0; charIndex++; } } // this is where the MIDI magic happens #pragma vector=USCIAB0RX_VECTOR __interrupt void USCI0RX_ISR(void) { rxData = UCA0RXBUF; // copy RX buffer to var if(rxData & BIT7) { // is it status? if((rxData & 0xF8) != 0xF8) { // ignore RealTime Category if((rxData & 0x0F) == channel) { // are we listening on this channel status = (rxData >> 4) - 8; // yep, let's set status runningStatus = 1; // expect running status messages for our channel } else { // nope, not our channel runningStatus = 0; // do not process data for other channels } } } else { // it's data byte if(runningStatus) { // process data only for our channel including running status messages if(rxByte == 1) { // is it first data byte? rxByte = 2; // second byte will follow unless... if(status == 4 || status == 5) {// it's Prog Change or Channel Pressure rxByte = 1; // only one data byte expected } else if (status == 0 || status == 1) {// it's Note Off or Note On, select light if(rxData > 59 && rxData < 100) { // check range: 60-99, middle C to ... light = rxData - 60; // offset to start at 0 P1OUT &= ~MIDI_RCVD_LED_PIN; // MIDI LED on } } else if (status == 3) { // it's Controller if(rxData > 0 && rxData < 17) {// check range: 1-16, General Purpose Slider light = rxData - 1; // offset to start at 0 P1OUT &= ~MIDI_RCVD_LED_PIN; // MIDI LED on } else if(rxData == 120 || rxData == 123) {// if it's All Sound Off or All Notes Off... charIndex = 0; while(charIndex < 40) { // clear all lights lights[charIndex] = 0; charIndex++; } } } } else if(rxByte == 2) { // it's second data byte rxByte = 1; // next byte will be first byte if(light == 255 ) // light not in range... return; // and return if(status == 1) { // it's Note On lights[light] = rxData >> 1;// velocity is brightness (divided by 2, 0-64 range) } else if(status == 0) { // it's Note Off lights[light] = 0; // we ignore velocity and just clear the light } else if(status == 3) { // it's Controller if(light < 16) { // are those sliders? lights[light] = rxData >> 1; // yes, we use sliders to control lights 0-15 (divided by 2, 0-64 range) } } light = 255; // set light to not in range } } } }
     

  19. Like
    gordon reacted to rockets4kids in Using the Launchpad with a Breadboard   
    This has been mentioned a few times before but as not too many people know about it I thought I would bring it up again with my particular spin on things.
     
    It is a little known fact that the Launchpad can easily program external chips. In fact, I only programmed a chip in the Launchpad socket itself just a few times before connecting it to an external breadboard.
     
    A picture is worth a thousand words, so here are some of my Launchpad-breadboard setup:
     
    http://imgur.com/a/UA46s#Qmjp7
     

    Very high resolution versions of the image are available through the "Image Options" menu.
     
    Physically, the breadboard is taped (double-sided foam tape) to a piece of scrap plastic. The Launchpad is held in place with a rubber band -- the ones that hold broccoli are perfect.
     
    I didn't have any "proper" connectors, so I simply trimmed (cut and sanded) one of the 10-pin female connectors that comes with the Launchpad. I also didn't have any heat-shrink small enough, so I just "potted" the solder connections with epoxy. It's not pretty, but it works just fine.
     
    To understand what is going on here, it is best to look at the schematic and PCB layout that is included in the Launchpad User's Guide:
     
    http://focus.ti.com/lit/ug/slau318/slau318.pdf
     
    It is important to note that the "Emulation" side is completely separate from the "EXP-MSP430G2" or "target" side. You can actually (physically) cut the board along the dashed line if you want. Aside from power and ground, all of the signals cross the dashed line via the jumper pins. If you remove the jumper pins, you have access to all of the signals required to program an external chip.
     
    It may not be clear in the picture, but the jumpers are hanging off one pin on the target side -- that is the easiest way to keep from losing them when the external programming header is connected.
     
    Many people also seem to be confused about the minimal support circuitry required for the MSP430, so that is definitely worth going over. The schematic in slau318 is nicely split on multiple pages to show G2/target side of things on a single page. This is essentially what you will be building on the breadboard.
     
    Obviously the chip requires power and ground, and these are provided via the Launchpad. The power supply must be properly decoupled for proper operation. This involves a 10 uF cap (electrolytic or tantalum) somewhere on the breadboard and a 0.1 uF (a cheap ceramic is just fine) as close to the MSP430 as possible.
     
    The RST line must be held high with a 47 k resistor. If you wish to reset the chip, just apply a jumper from RST to ground. You could use a switch, but a simple wire works just fine when needed.
     
    I have a watch crystal on XIN-XOUT, but this is not necessary. My xtal requires two 22 pF caps for proper loading, but I have not used these, instead enabling the internal 14 pF caps on the MSP430. The xtal seems to oscillate just fine with the improper loading, but I am certain that it effects the frequency. I don't have a frequency counter, so I don't know how far off it really is. The important thing is that oscillator does not seem to fault even when I touch it with the case ungrounded.
     
    If you don't want to use an xtal, you can use the pins as GPIOs.
     
    It is important to note that the chip is programmed over the TEST/RST lines, *not* the TX/RX serial lines. If you do not need serial communication, TX/RX do not need to be connected to the launchpad, and the pins can be used as GPIOs. Even more important to note is that the TX/RX lines used by the chips with a hardware UART (The 2xx3 chips) are *reversed* from the pins used for software serial! The breadboard in the photograph is populated with a 2553, so TX from the 2553 goes to RX on the jumper block and vice-versa.
     
    The only real "application circuit" here is the LED/resistor on P1.0 -- which happens to match LED1 on the Launchpad.
     
    As you can see, this leaves quite a fair bit of board space to experiment with, even with a small 400 pin breadboard.
     
    These little breadboards can be had for just a little more than two bucks when you get 10 of them, and it's really nice to be able to leave multiple small circuits all wired up at the same time. It's also useful to wire up each board as a discrete function, just like a "shield" on an Arduino. For example, you can wire a 2x16 LCD display for 2-pin serial display, and then easily connect that among multiple other boards.
     
    Hopefully this will be helpful to others just getting started!
  20. Like
    gordon reacted to V0JT4 in Slot Cars Lap Counter/Timer   
    Here is my first project with LaunchPad - Slot Cars Lap Counter/Timer. I wanted to build the lap counter for quite a long time, originally from BCD counter ICs and 7 segment LED display. Some time passed and my friend told me about LaunchPad, it looked like a great opportunity to start with MCUs and make some old ideas reality.


    Main idea was to use character LCD instead of 7seg LED as it gives you much more space to display stuff and I had one lying (from old computer connected to LPT with LCDSmartie). I used great RobG's project and slightly modified it to my needs. As I usually build only two lane circuits, I used custom characters feature of HD44780 to display large digits.

    Car is detected by magnetic Reed switch (extracted from old keyboard) placed under each lane. I needed to use capacitor parallel to switch, otherwise many false interrupts were generated (one car triggering both lanes,...). TimerA is used to track time with interrupt generated 100 times per second. Long and short button press is distinguish by WDT in timer mode with accumulator variable and threshold. Buzzer is connected to TimerA output 1 in PWM mode.

    The construction was fairly simple. I used hot melt glue to attach Reed switch under each lane. You just have to be very careful bending the Reed switch contacts, it's very fragile piece of glass and mine are maybe 30 years old, extracted from computer keyboard.

    Software implements 3 modes, standard N lap race, time attack limited by N laps and free practice with no time or lap limit. You can see it in action in video posted below. It's possible to pause/resume race (short press) and restart race (long press). Buzzer signals start, end and resume of race. To change race mode just hit reset button. I wasn't able to fit in 2K limit by 200B, so I had to use MSP430G2553 I received from great TI sample program. I think without large digits it would easily fit MSP430G2211, maybe even in 4 lane modification.



    EDIT: Good news everyone! I have a new code version, now with possibility to enable big digits or 4 lanes. Without big digits it fits in 2K FLASH devices supplied with LaunchPad in both 2 and 4 lanes modes. In 4 lanes mode buzzer needs to be placed on P2.6 (XIN).
    #include <msp430g2553.h> #include "lcd.h" //#define LANE_4 // uncomment to enable 4 lane mode #ifdef BIG_DIGITS // big digits enabled in lcd.h #undef LANE_4 // are incompatible with 4 lanes #endif // Type definition for simplicity typedef unsigned char u8; typedef char s8; typedef unsigned int u16; typedef int s16; // Pin allocation #define BUTTON BIT3 #define SENS0 BIT4 #define SENS1 BIT5 #define BUZZER BIT6 #ifdef LANE_4 #define SENS2 BIT6 #define SENS3 BIT7 #endif #define LONG_PRESS 10 // N x 30 ms #define MIN_LAP_TIME 100 // N x 1/100 s #ifdef LANE_4 // lane count adjustment #define LANES 4 static const u8 SENS[] = {SENS0, SENS1, SENS2, SENS3}; #else #define LANES 2 static const u8 SENS[] = {SENS0, SENS1}; #endif u8 hold = 0; // Long button press counter u8 lap[LANES]; // Lap number u16 time[LANES]; // Lap time in 1/100 s u16 best[LANES]; // Best Lap time u8 race; // Car did not finish race u8 raceLaps = 0; // Number of laps of race #ifdef BIG_DIGITS u8 bufferT[] = {0, 0, ' ', 0x07, 0x07}; // Number to display top part u8 bufferB[] = {0, 0, '.', 0x06, 0x06}; // Number to display bottom part #else u8 bufferT[] = {0, 0, '.', '0', '0'}; // Number to display #endif #define BEST_MARK 0x8000 // best updated flag, needs redraw #define LAP_MARK 0x80 // lap updated flag, needs redraw // Application states #define STATE_MAIN 0x00 #define STATE_SETUP1 0x10 #define STATE_SETUP2 0x20 #define STATE_READY 0x30 #define STATE_START 0x40 #define STATE_PAUSE 0x50 #define STATE_RACE 0x60 #define STATE_FINISH 0x70 #define STATE_END 0x80 #define WIN1_MASK 0x03 // Race result bits u8 state = STATE_MAIN; // Race modes #define MODE_RACE 0x01 // first to finish wins #define MODE_TIME 0x02 // best lap time wins #define MODE_PRAC 0x03 // infinite practice with best time tracking u8 mode = MODE_RACE; // Race initial screen #ifdef BIG_DIGITS static const char CScreen[] = {'L', ' ', 0x07, 0x07, ' ', 'T', ' ', 0x07, 0x07, ' ', 0x07, 0x07, ' ', 'B', ' ', '_', '_', ' ', '_', '_', 'P', ' ', 0x07, 0x07, ' ', 'M', ' ', 0x07, 0x07, ' ', 0x07, 0x07, ' ', 'S', ' ', '_', '_', ' ', '_', '_', 'A', ' ', 0x06, 0x06, ' ', 'I', ' ', 0x06, 0x06, '.', 0x06, 0x06, ' ', 'E', ' ', ' ', ' ', '.', ' ', ' ', 'S', ' ', 0x06, 0x06, ' ', 'E', ' ', 0x06, 0x06, '.', 0x06, 0x06, ' ', 'T', ' ', ' ', ' ', '.', ' ', ' '}; #else #ifdef LANE_4 static const char CScreen[] = {'L', ' ', '0', '0', ' ', 'T', ' ', '0', '0', '.', '0', '0', ' ', 'B', ' ', '-', '-', '.', '-', '-', 'P', ' ', '0', '0', ' ', 'M', ' ', '0', '0', '.', '0', '0', ' ', 'S', ' ', '-', '-', '.', '-', '-', 'A', ' ', '0', '0', ' ', 'I', ' ', '0', '0', ' ', '0', '0', ' ', 'E', ' ', '-', '-', '.', '-', '-', 'S', ' ', '0', '0', ' ', 'E', ' ', '0', '0', ' ', '0', '0', ' ', 'T', ' ', '-', '-', '.', '-', '-'}; #else static const char CScreen[] = {'L', ' ', '0', '0', ' ', 'T', ' ', '0', '0', '.', '0', '0', ' ', 'B', ' ', '-', '-', '.', '-', '-', 'P', ' ', ' ', ' ', ' ', 'M', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'S', ' ', ' ', ' ', ' ', ' ', ' ', 'A', ' ', '0', '0', ' ', 'I', ' ', '0', '0', '.', '0', '0', ' ', 'E', ' ', '-', '-', '.', '-', '-', 'S', ' ', ' ', ' ', ' ', 'E', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'T', ' ', ' ', ' ', ' ', ' ', ' '}; #endif /* LANE_4 */ #endif /* BIG_DIGITS */ void longDelay(void); void initData(void); void buttonShort(void); void buttonLong(void); void tostr(u16 i); void printL(u8 r, u8 c); void printT(u8 r, u8 c); void newLap(u8 id); // handles all race LCD updates to avoid char placement errors void main(void) { // try to set DCO to 1 MHz if (CALBC1_1MHZ != 0xFF || CALDCO_1MHZ != 0xFF) { BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation } // initialize peripheries // watchdog WDTCTL = WDTPW | WDTHOLD | WDTTMSEL | WDTCNTCL; // Stop+Clear+TimerMode WDT IE1 = WDTIE; // WDT IE // gpio P1 #ifdef LANE_4 P1OUT = SENS0 | SENS1 | SENS2 | SENS3; // pullup P1REN = SENS0 | SENS1 | SENS2 | SENS3; // internal resistor P1IES = BUTTON | SENS0 | SENS1 | SENS2 | SENS3; // Hi/lo edge #else P1OUT = SENS0 | SENS1; // pullup P1REN = SENS0 | SENS1; // internal resistor P1IES = BUTTON | SENS0 | SENS1; // Hi/lo edge #endif P1IFG = 0; // IFG cleared P1IE = BUTTON; // BUTTON interrupt enabled // timerA CCR0 = 9994 - 1; // 1/100s, DCO 1MHz calibration = 244x4096 TACTL = TASSEL_2 + MC_1; // SMCLK, upmode //buzzer #ifdef LANE_4 P2DIR = BUZZER; // P2.6 in 4 lane mode P2SEL = BUZZER; // BUZZER TimeA output #else P1DIR = BUZZER; // P1.6 in 4 lane mode P1SEL = BUZZER; // BUZZER TimeA output #endif CCTL1 = OUTMOD_7; // CCR1 reset/set CCR1 = 0; // Buzzer off // lcd lcdInit(); _enable_interrupts(); // global interupt enable // Setup initial screen lcdString("Select Mode: Time Attack ~ Lap Race Practice"); initData(); while (1) { u8 id; // print updated values for (id = 0; id < LANES; ++id) { if (P1IE & SENS[id]) { // hold after lap tostr(time[id]); // print time printT(id, 7); } if (best[id] & BEST_MARK) { best[id] &= ~BEST_MARK; tostr(best[id]); // print best printT(id, 15); } if (lap[id] & LAP_MARK) { lap[id] &= ~LAP_MARK; tostr(lap[id]); // print lap count printL(id, 2); } } if (state == STATE_READY) { // draw init race screen lcdCommand(LCD_SETDDRAMADDR); lcdDataArray(CScreen, 80); } if (state == STATE_START) { // Sound countdown CCR0 = 4000; // higher frequency for (id = 8; id > 1; id--) { // 3 short+1 long CCR1 ^= 2000; longDelay(); if (id & 1)longDelay(); } longDelay(); CCR1 = 0; CCR0 = 9994 - 1; // resume 1/100s state = STATE_RACE; CCTL0 = CCIE; // start time counting #ifdef LANE_4 P1IFG &= ~(SENS0 | SENS1 | SENS2 | SENS3); P1IE |= SENS0 | SENS1 | SENS2 | SENS3; #else P1IFG &= ~(SENS0 | SENS1); P1IE |= SENS0 | SENS1; #endif } // race ended if ((state & ~WIN1_MASK) == STATE_FINISH) { #ifdef BIG_DIGITS lcdJump((state & WIN1_MASK) << 1, 1); // mark winner on LCD #else lcdJump(state & WIN1_MASK, 1); // mark winner on LCD #endif lcdData(0xFF); CCR1 = 4997; // short beep longDelay(); CCR1 = 0; state = STATE_END; } } } // Delay ~0.2s void longDelay(void) { _delay_cycles(190000); } // Set initial values void initData(void) { u8 id; for (id = 0; id < LANES; ++id) { best[id] = 9999; lap[id] = 0; time[id] = 0; } #ifdef LANE_4 race = SENS0 | SENS1 | SENS2 | SENS3; #else race = SENS0 | SENS1; #endif } // Short button press void buttonShort(void) { switch (state) { case STATE_MAIN: lcdJump(mode, 0); lcdData(' '); switch (mode) { // change race mode case MODE_RACE: mode = MODE_TIME; break; case MODE_TIME: mode = MODE_PRAC; break; case MODE_PRAC: mode = MODE_RACE; break; default: break; } lcdJump(mode, 0); lcdData(0x7E); break; case STATE_SETUP1: raceLaps++; // increase 1st digit if (raceLaps == 10) // overflow raceLaps = 0; LPRINT: tostr(raceLaps); // update LCD #ifdef BIG_DIGITS printL(1, 10); #else printL(2, 10); #endif break; case STATE_SETUP2: raceLaps += 10; // increase 2nd digit if (raceLaps >= 100) // overflow raceLaps -= 100; goto LPRINT; //break; case STATE_RACE: // pause race state = STATE_PAUSE; CCTL0 = 0; #ifdef LANE_4 P1IE &= ~(SENS0 | SENS1 | SENS2 | SENS3); #else P1IE &= ~(SENS0 | SENS1); #endif break; case STATE_READY: // start race case STATE_PAUSE: // resume race state = STATE_START; break; default: break; } } // Long button press void buttonLong() { switch (state) { case STATE_MAIN: // confirm race mode if (mode == MODE_PRAC) { // start practice raceLaps = 127; goto CPRINT; } state = STATE_SETUP1; lcdClear(); lcdString("Set number of laps:"); lcdJump(1, 11); lcdData('_'); #ifdef BIG_DIGITS printL(1, 10); #else printL(2, 10); #endif break; case STATE_SETUP1: // confirm 1st digit state = STATE_SETUP2; lcdJump(1, 11); lcdData(' '); lcdJump(1, 10); lcdData('_'); break; case STATE_PAUSE: // restart race case STATE_RACE: case STATE_END: CCTL0 &= ~CCIE; #ifdef LANE_4 P1IE &= ~(SENS0 | SENS1 | SENS2 | SENS3); #else P1IE &= ~(SENS0 | SENS1); #endif case STATE_SETUP2: // confirm 2nd digit and prepare race CPRINT : state = STATE_READY; raceLaps |= LAP_MARK; // for easier lap[id] comparison in newLap initData(); break; default: break; } } // Print 2 digit number (lap count) void printL(u8 r, u8 c) { #ifdef BIG_DIGITS r <<= 1; lcdJump(r + 1, c); lcdData(bufferB[3]); lcdData(bufferB[4]); #endif lcdJump(r, c); lcdData(bufferT[3]); lcdData(bufferT[4]); } // Print 2.2 digit number (time/best) void printT(u8 r, u8 c) { #ifdef BIG_DIGITS r <<= 1; lcdJump(r + 1, c); lcdDataArray(bufferB, 5); #endif lcdJump(r, c); lcdDataArray(bufferT, 5); } // Convert Interger to 2.2 or 2 digit 2 line size String void tostr(u16 i) { bufferT[4] = i % 10; i /= 10; bufferT[3] = i % 10; i /= 10; bufferT[1] = i % 10; i /= 10; bufferT[0] = i % 10; #ifdef BIG_DIGITS bufferB[4] = numB[bufferT[4]]; bufferT[4] = numT[bufferT[4]]; bufferB[3] = numB[bufferT[3]]; bufferT[3] = numT[bufferT[3]]; bufferB[1] = numB[bufferT[1]]; bufferT[1] = numT[bufferT[1]]; bufferB[0] = numB[bufferT[0]]; bufferT[0] = numT[bufferT[0]]; #else bufferT[4] += '0'; bufferT[3] += '0'; bufferT[1] += '0'; bufferT[0] += '0'; #endif } // New lap service routine void newLap(u8 id) { lap[id]++; // increment lap counter if (lap[id] == 100) lap[id] = 0; // 2 digit overflow lap[id] |= LAP_MARK; // mark for LCD update if (time[id] < best[id]) { // test best lap time best[id] = time[id] | BEST_MARK; // mark for LCD update } time[id] = 0; // reset time counter if (state >= STATE_FINISH) { race &= ~SENS[id]; // race mode looser finish } if (lap[id] == raceLaps) { race &= ~SENS[id]; if (mode == MODE_RACE && state == STATE_RACE) { state = STATE_FINISH | id; // race mode winner finish } else if (mode == MODE_TIME) { if (++state == (STATE_RACE + LANES)) { // time mode all finished u8 bestId = 0; for (id = 1; id < LANES; ++id) { // find best time if (best[id] < best[bestId]) bestId = id; } state = STATE_FINISH | bestId; } } } } // Timer A0 interrupt service routine #ifdef TIMER0_A0_VECTOR #pragma vector=TIMER0_A0_VECTOR #else #pragma vector=TIMERA0_VECTOR #endif __interrupt void Timer_A(void) { u8 id; for (id = 0; id < LANES; ++id) { if (race & SENS[id]) { time[id]++; // increment time counter if (time[id] == MIN_LAP_TIME) { P1IFG &= ~SENS[id]; // SENS IFG cleared P1IE |= SENS[id]; // SENS interrupt enabled } else if (time[0] == 10000) time[id] = 0; // 4 digit overflow } } } // Watchdog Timer interrupt service routine #pragma vector=WDT_VECTOR __interrupt void watchdog_timer(void) { if (hold == LONG_PRESS) { buttonLong(); } else if (P1IN & BUTTON) { buttonShort(); } else { // Button still pressed hold++; return; } P1IE |= BUTTON; // BUTTON interrupt enabled WDTCTL = WDTPW | WDTHOLD | WDTTMSEL | WDTCNTCL; // Stop+Clear+TimerMode WDT hold = 0; } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { u8 id; u8 x = P1IFG & P1IE; // Mask enabled intrrupt flags // BUTTON if (x & BUTTON) { P1IE &= ~BUTTON; // BUTTON interrupt disabled P1IFG &= ~BUTTON; // BUTTON IFG cleared WDTCTL = WDTPW | WDTTMSEL; // Start+TimerMode WDT } else { // SENS for (id = 0; id < LANES; ++id) { if (x & SENS[id]) { P1IE &= ~SENS[id]; // SENS interrupt disabled P1IFG &= ~SENS[id]; // SENS IFG cleared newLap(id); return; } } P1IFG = 0; } }
    Final version code:
    EDIT: Now with possibility to disable large digits (comment #define BIG_DIGITS in lcd.h) so it can fit in 2K FLASH devices.
    EDIT2: Deprecated, replaced by new 2/4 lane version
    #include <msp430g2553.h> #include "lcd.h" // Pin allocation #define BUTTON BIT3 #define SENS0 BIT4 #define SENS1 BIT5 #define BUZZER BIT6 #define LONG_PRESS 10 // N x 30 ms #define MIN_LAP_TIME 100 // N x 1/100 s // Type definition for simplicity typedef unsigned char u8; typedef char s8; typedef unsigned int u16; typedef int s16; u8 hold = 0; // Long button press counter u8 lap[2]; // Lap number u16 time[2]; // Lap time in 1/100 s u16 best[2]; // Best Lap time u8 race[2]; // Car did not finish race u8 raceLaps = 0; // Number of laps of race #ifdef BIG_DIGITS u8 bufferT[] = {0, 0, ' ', 0x07, 0x07}; // Number to display top part u8 bufferB[] = {0, 0, '.', 0x06, 0x06}; // Number to display bottom part #else u8 bufferT[] = {0, 0, '.', '0', '0'}; // Number to display #endif #define BEST_MARK 0x8000 // best updated flag, needs redraw #define LAP_MARK 0x80 // lap updated flag, needs redraw // Application states #define STATE_MAIN 0x00 #define STATE_SETUP1 0x10 #define STATE_SETUP2 0x20 #define STATE_PAUSE 0x30 #define STATE_START 0x40 #define STATE_RACE 0x50 #define STATE_FINISH 0x60 #define STATE_END 0x70 #define WIN1_MARK 0x02 // Race result bit, set if car 1 wins u8 state = STATE_MAIN; // Race modes #define MODE_RACE 0x01 // first to finish wins #define MODE_TIME 0x02 // best lap time wins #define MODE_PRAC 0x03 // infinite practice with best time tracking u8 mode = MODE_RACE; // Race initial screen #ifdef BIG_DIGITS static const char CScreen[] = {'L', ' ', 0x07, 0x07, ' ', 'T', ' ', 0x07, 0x07, ' ', 0x07, 0x07, ' ', 'B', ' ', '_', '_', ' ', '_', '_', 'P', ' ', 0x07, 0x07, ' ', 'M', ' ', 0x07, 0x07, ' ', 0x07, 0x07, ' ', 'S', ' ', '_', '_', ' ', '_', '_', 'A', ' ', 0x06, 0x06, ' ', 'I', ' ', 0x06, 0x06, '.', 0x06, 0x06, ' ', 'E', ' ', ' ', ' ', '.', ' ', ' ', 'S', ' ', 0x06, 0x06, ' ', 'E', ' ', 0x06, 0x06, '.', 0x06, 0x06, ' ', 'T', ' ', ' ', ' ', '.', ' ', ' '}; #else static const char CScreen[] = {'L', ' ', '0', '0', ' ', 'T', ' ', '0', '0', '.', '0', '0', ' ', 'B', ' ', '-', '-', '.', '-', '-', 'P', ' ', '0', '0', ' ', 'M', ' ', '0', '0', '.', '0', '0', ' ', 'S', ' ', '-', '-', '.', '-', '-', 'A', ' ', ' ', ' ', ' ', 'I', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'E', ' ', ' ', ' ', ' ', ' ', ' ', 'S', ' ', ' ', ' ', ' ', 'E', ' ', ' ', ' ', ' ', ' ', ' ', ' ', 'T', ' ', ' ', ' ', ' ', ' ', ' '}; #endif void longDelay(void); void initData(void); void buttonShort(void); void buttonLong(void); void tostr(u16 i); void printL(u8 r, u8 c); void printT(u8 r, u8 c); void newLap(u8 id); // handles all race LCD updates to avoid char placement errors void main(void) { // try to set DCO to 1 MHz if (CALBC1_1MHZ != 0xFF || CALDCO_1MHZ != 0xFF) { BCSCTL1 = CALBC1_1MHZ; // Set range DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation } // initialize peripheries // watchdog WDTCTL = WDTPW | WDTHOLD | WDTTMSEL | WDTCNTCL; // Stop+Clear+TimerMode WDT IE1 = WDTIE; // WDT IE // gpio P1 P1OUT = SENS0 | SENS1; // pullup P1REN = SENS0 | SENS1; // internal resistor P1IES = BUTTON | SENS0 | SENS1; // Hi/lo edge P1IFG = 0; // IFG cleared P1IE = BUTTON; // BUTTON interrupt enabled // timerA CCR0 = 9994 - 1; // 1/100s, DCO 1MHz calibration = 244x4096 TACTL = TASSEL_2 + MC_1; // SMCLK, upmode //buzzer P1DIR = BUZZER; P1SEL = BUZZER; // BUZZER TimeA output CCTL1 = OUTMOD_7; // CCR1 reset/set CCR1 = 0; // Buzzer off // lcd lcdInit(); _enable_interrupts(); // global interupt enable // Setup initial screen lcdString("Select Mode: Time Attack ~ Lap Race Practice"); initData(); while (1) { u8 id = 0; if (P1IE & SENS0) { // hold after lap tostr(time[0]); // print time printT(0, 7); } if (P1IE & SENS1) { // hold after lap tostr(time[1]); // print time printT(2, 7); } // print updated values REPEAT: if (best[id] & BEST_MARK) { best[id] &= ~BEST_MARK; tostr(best[id]); // print time printT(id << 1, 15); } if (lap[id] & LAP_MARK) { lap[id] &= ~LAP_MARK; tostr(lap[id]); // print lap count printL(id << 1, 2); } id = !id; // to update both cars 0/1 if (id) goto REPEAT; if (state == STATE_START) { // Sound countdown CCR0 = 4000; // higher frequency for (id = 8; id > 1; id--) { // 3 short+1 long CCR1 ^= 2000; longDelay(); if (id & 1)longDelay(); } longDelay(); CCR1 = 0; CCR0 = 9994 - 1; // resume 1/100s state = STATE_RACE; CCTL0 = CCIE; // start time counting P1IFG &= ~(SENS0 | SENS1); P1IE |= SENS0 | SENS1; } // race ended if ((state & ~WIN1_MARK) == STATE_FINISH) { lcdJump(state & WIN1_MARK, 1); // mark winner in LCD lcdData(0xFF); CCR1 = 4997; // short beep longDelay(); CCR1 = 0; state = STATE_END; } longDelay(); } } // Delay ~0.2s void longDelay(void) { _delay_cycles(190000); } // Set initial values void initData(void) { best[0] = 9999; best[1] = 9999; lap[0] = 0; lap[1] = 0; time[0] = 0; time[1] = 0; race[0] = 1; race[1] = 1; } // Short button press void buttonShort(void) { switch (state) { case STATE_MAIN: lcdJump(mode, 0); lcdData(' '); switch (mode) { // change race mode case MODE_RACE: mode = MODE_TIME; break; case MODE_TIME: mode = MODE_PRAC; break; case MODE_PRAC: mode = MODE_RACE; break; default: break; } lcdJump(mode, 0); lcdData(0x7E); break; case STATE_SETUP1: raceLaps++; // increase 1st digit if (raceLaps == 10) // overflow raceLaps = 0; LPRINT: tostr(raceLaps); // update LCD printL(1, 10); break; case STATE_SETUP2: raceLaps += 10; // increase 2nd digit if (raceLaps >= 100) // overflow raceLaps -= 100; goto LPRINT; //break; case STATE_RACE: // pause race state = STATE_PAUSE; CCTL0 = 0; P1IE &= ~(SENS0 | SENS1); break; case STATE_PAUSE: // resume race state = STATE_START; break; default: break; } } // Long button press void buttonLong() { switch (state) { case STATE_MAIN: // confirm race mode lcdClear(); if (mode == MODE_PRAC) { // start practice raceLaps = 127; goto CPRINT; } state = STATE_SETUP1; lcdString("Set number of laps:"); printL(1, 10); lcdJump(3, 11); lcdData(0x2D); break; case STATE_SETUP1: // confirm 1st digit state = STATE_SETUP2; lcdJump(3, 11); lcdData(' '); lcdJump(3, 10); lcdData(0x2D); break; case STATE_PAUSE: // restart race case STATE_RACE: case STATE_END: CCTL0 &= ~CCIE; P1IE &= ~(SENS0 | SENS1); case STATE_SETUP2: // confirm 2nd digit and prepare race CPRINT : state = STATE_PAUSE; initData(); lcdCommand(LCD_SETDDRAMADDR); lcdDataArray(CScreen, 80); break; default: break; } } // Print 2 digit number (lap count) void printL(u8 r, u8 c) { lcdJump(r, c); lcdData(bufferT[3]); lcdData(bufferT[4]); #ifdef BIG_DIGITS lcdJump(r + 1, c); lcdData(bufferB[3]); lcdData(bufferB[4]); #endif } // Print 2.2 digit number (time/best) void printT(u8 r, u8 c) { lcdJump(r, c); lcdDataArray(bufferT, 5); #ifdef BIG_DIGITS lcdJump(r + 1, c); lcdDataArray(bufferB, 5); #endif } // Convert Interger to 2.2 or 2 digit 2 line size String void tostr(u16 i) { bufferT[4] = i % 10; i /= 10; bufferT[3] = i % 10; i /= 10; bufferT[1] = i % 10; i /= 10; bufferT[0] = i % 10; #ifdef BIG_DIGITS bufferB[4] = numB[bufferT[4]]; bufferT[4] = numT[bufferT[4]]; bufferB[3] = numB[bufferT[3]]; bufferT[3] = numT[bufferT[3]]; bufferB[1] = numB[bufferT[1]]; bufferT[1] = numT[bufferT[1]]; bufferB[0] = numB[bufferT[0]]; bufferT[0] = numT[bufferT[0]]; #else bufferT[4] += '0'; bufferT[3] += '0'; bufferT[1] += '0'; bufferT[0] += '0'; #endif } // New lap service routine void newLap(u8 id) { lap[id]++; // increment lap counter if (lap[id] == 100) lap[id] = 0; // 2 digit overflow if (time[id] best[id] = time[id] | BEST_MARK; // mark for LCD update } time[id] = 0; // reset time counter if (mode == MODE_RACE && (race[0] ^ race[1])) { race[id] = 0; // race mode looser finish } if (lap[id] == raceLaps) { race[id] = 0; if (mode == MODE_RACE && (race[0] ^ race[1])) { state = STATE_FINISH; // race mode winner finish if (id) state |= WIN1_MARK; } else if (mode == MODE_TIME && !(race[0] | race[1])) { state = STATE_FINISH; // time mode both finished if (best[0] > best[1]) { // time mode select winner state |= WIN1_MARK; } } } lap[id] |= LAP_MARK; // mark for LCD update } // Timer A0 interrupt service routine #ifdef TIMER0_A0_VECTOR #pragma vector=TIMER0_A0_VECTOR #else #pragma vector=TIMERA0_VECTOR #endif __interrupt void Timer_A(void) { if (race[0]) { time[0]++; // increment time counter if (time[0] == MIN_LAP_TIME) { P1IFG &= ~SENS0; // SENS1 IFG cleared P1IE |= SENS0; // SENS1 interrupt enabled } else if (time[0] == 10000) time[0] = 0; // 4 digit overflow } if (race[1]) { time[1]++; // increment time counter if (time[1] == MIN_LAP_TIME) { P1IFG &= ~SENS1; // SENS2 IFG cleared P1IE |= SENS1; // SENS1 interrupt enabled } else if (time[1] == 10000) time[1] = 0; // 4 digit overflow } } // Watchdog Timer interrupt service routine #pragma vector=WDT_VECTOR __interrupt void watchdog_timer(void) { if (hold == LONG_PRESS) { buttonLong(); } else if (P1IN & BUTTON) { buttonShort(); } else { // Button still pressed hold++; return; } P1IE |= BUTTON; // BUTTON interrupt enabled WDTCTL = WDTPW | WDTHOLD | WDTTMSEL | WDTCNTCL; // Stop+Clear+TimerMode WDT hold = 0; } // Port 1 interrupt service routine #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { u8 x = P1IFG & P1IE; // Mask enabled intrrupt flags // BUTTON if (x & BUTTON) { P1IE &= ~BUTTON; // BUTTON interrupt disabled P1IFG &= ~BUTTON; // BUTTON IFG cleared WDTCTL = WDTPW | WDTTMSEL; // Start+TimerMode WDT }// SENS1 else if (x & SENS0) { P1IE &= ~SENS0; // SENS1 interrupt disabled P1IFG &= ~SENS0; // SENS1 IFG cleared newLap(0); }// SENS2 else if (x & SENS1) { P1IE &= ~SENS1; // SENS2 interrupt disabled P1IFG &= ~SENS1; // SENS2 IFG cleared newLap(1); } else P1IFG = 0; }  


    Modified RobG's LCD display code with large digits:
    lcd.h
    // Pin allocation, modify to connected pins! #define LCD_D BIT2 #define LCD_C BIT1 #define LCD_E BIT0 #define BIG_DIGITS // uncomment to enable two line digits, takes ~100B #ifdef BIG_DIGITS // Dual Line digits 0-9 // Top part static const char numT[] = {0x07,0x00,0x01,0x01,0x06,0x03,0x03,0x01,0x05,0x07}; // Bottom part static const char numB[] = {0x06,0x00,0x04,0x02,0x00,0x02,0x05,0x00,0x05,0x02}; #endif void lcdInit(void); void lcdString(const char text[]); void lcdDataArray(const char data[], char length); void lcdClear(); void lcdJump(char row, char colum); void lcdSend(char data, char registerSelect); #define lcdData(data) lcdSend(data, 1) #define lcdCommand(command) lcdSend(command, 0) // commands #define LCD_CLEARDISPLAY 0x01 #define LCD_RETURNHOME 0x02 #define LCD_ENTRYMODESET 0x04 #define LCD_DISPLAYCONTROL 0x08 #define LCD_CURSORSHIFT 0x10 #define LCD_FUNCTIONSET 0x20 #define LCD_SETCGRAMADDR 0x40 #define LCD_SETDDRAMADDR 0x80 // flags for display entry mode #define LCD_ENTRYRIGHT 0x00 #define LCD_ENTRYLEFT 0x02 #define LCD_ENTRYSHIFTINCREMENT 0x01 #define LCD_ENTRYSHIFTDECREMENT 0x00 // flags for display on/off control #define LCD_DISPLAYON 0x04 #define LCD_DISPLAYOFF 0x00 #define LCD_CURSORON 0x02 #define LCD_CURSOROFF 0x00 #define LCD_BLINKON 0x01 #define LCD_BLINKOFF 0x00 // flags for display/cursor shift #define LCD_DISPLAYMOVE 0x08 #define LCD_CURSORMOVE 0x00 #define LCD_MOVERIGHT 0x04 #define LCD_MOVELEFT 0x00 // flags for function set #define LCD_8BITMODE 0x10 #define LCD_4BITMODE 0x00 #define LCD_2LINE 0x08 #define LCD_1LINE 0x00 #define LCD_5x10DOTS 0x04 #define LCD_5x8DOTS 0x00  

    lcd.c
    #include "msp430g2553.h" #include "lcd.h" // Starts of lines for 4x20 LCD static const char Line[] = {0, 0x40, 20, 0x40 + 20}; #ifdef BIG_DIGITS // Definition of custom chars for dual line digits static const char NUMdata[] = {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1f, 0x1f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1f, 0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1f, 0x1f, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}; #endif void lcdInit(void) { _delay_cycles(100000); // initialize pins P1OUT &= ~(LCD_C | LCD_D); P1OUT |= LCD_E; P1DIR |= LCD_E | LCD_C | LCD_D; // initialize display lcdCommand(LCD_FUNCTIONSET | LCD_8BITMODE | LCD_2LINE | LCD_5x8DOTS); lcdCommand(LCD_DISPLAYCONTROL | LCD_DISPLAYON); lcdClear(); #ifdef BIG_DIGITS lcdCommand(LCD_ENTRYMODESET | LCD_ENTRYLEFT); // define 8 custom characters lcdCommand(LCD_SETCGRAMADDR); lcdDataArray(NUMdata, 64); // go to first position lcdCommand(LCD_SETDDRAMADDR); #endif } // Display String ended by 0x00 void lcdString(const char text[]) { int i; for (i = 0; text[i] != 0; i++) { lcdData(text[i]); } } // Send byte array void lcdDataArray(const char data[], char length) { char i; for (i = 0; i < length; i++) { lcdData(data[i]); } } // Bitbang one LDE instruction/data void lcdSend(char data, char registerSelect) { char i; for (i = 0; i < 8; i++) { (data & BIT0) ? (P1OUT |= LCD_D) : (P1OUT &= ~LCD_D); data >>= 1; P1OUT |= LCD_C; P1OUT &= ~LCD_C; } registerSelect ? (P1OUT |= LCD_D) : (P1OUT &= ~LCD_D); P1OUT &= ~LCD_E; P1OUT |= LCD_E; } // Clear display and go to first position void lcdClear() { lcdCommand(LCD_CLEARDISPLAY); _delay_cycles(2000); } // Go to defined position void lcdJump(char row, char colum) { lcdCommand(LCD_SETDDRAMADDR + Line[row] + colum); }  
     




    http://www.youtube.com/watch?v=Fwz0Ui2cySw

    http://www.youtube.com/watch?v=YNLD608ZsAQ


    [id]){>[id]){>
  21. Like
    gordon got a reaction from bluehash in DTMF-Controlled Garage Door Opener [GDO]   
    By some miracle, my project started showing signs of working, so time to show it the light of day .
     
    It is a remotely-controlled garage door opener of sorts. Hook it up to a phone (that is set to auto-answer), call phone, identify and authenticate yourself, and it will (in its current configuration) pulse an output. The outputs may (via a bit of further circuitry) be used to open your garage door, solve the "damn cable modem froze again" situation, you name it. Features include "user accounts" with permissions assigned, protection against your pocket having long chats with your garage door, audible feedback (with plenty of noise), and generous amounts of comments with hopes that it'll be educational to someone (I heard POM was about code sharing, so what the heck ).
     

    It is my second ever MCU project (the first one was Blinky, of course), and it indeed has been a hell of a ride spanning about a month. In case anyone cares, here are a couple of things highlighting what I have learnt during these past couple of weeks:
     
    - Timers are the bread and butter of everything
    - No situation is hopeless enough for a friendly, helpful green LED
    - State machines can get tricky. I thought I was pretty OK with them, but it turns out state machines and ISRs can get quite different from state machines and Unix signal handlers
    - Data sheets good. Use data sheets. Just keep staring at them, they will make sense, eventually.
    - Did I mention timers are the bread and butter of everything?
    - ... and I still don't know jack about them.
     
    Attached to this post is the GDO source and the schematic (there's more to the right, but the forum theme knows better; just view the image in a separate window). I've also attached the HT9170 data sheet for reference.
     

    Credit bits: I re-used gatesphere's '595 handling stuff to a great extent; also Rob's and oPossum's advices have been most influential. I should in fact be making roll calls. Thanks to the whole 43oh lot .
    HT9170.pdf
    gdo_src.c
  22. Like
    gordon got a reaction from bluehash in 2252 or 2452 or did mspdebug lose it for good?   
    Anyone received G2252s recently? I got my samples last week (or maybe the week before), can't find any date code, but the package also has "12D3RRK A" etched on it, whatever this might mean.
     
    Thing is, mspdebug (absolutely bleeding edge, just released 0.16, tripped over it by accident) identifies it as a G2452, and -- on a cursory look -- might as well be right:
     

    $ mspdebug rf2500 --fet-force-id boo MSPDebug version 0.16 - debugging tool for MSP430 MCUs Copyright (C) 2009-2011 Daniel Beer This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Trying to open interface 1 on 046 rf2500: warning: can't detach kernel driver: No data available Initializing FET... FET protocol version is 30066536 Configured for Spy-Bi-Wire Set Vcc: 3000 mV Device ID: 0x2452 fet: unknown device msg28_data: [0x1a bytes] 24 52 00 a0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 89 00 00 00 00 00 00 00 fet: identify failed Trying again... Initializing FET... FET protocol version is 30066536 Configured for Spy-Bi-Wire Sending reset... Set Vcc: 3000 mV Device ID: 0x2452 fet: unknown device msg28_data: [0x1a bytes] 24 52 00 a0 00 00 00 00 00 00 00 00 01 00 00 00 00 00 89 00 00 00 00 00 00 00 fet: identify failed
     
    So, if that msg28_data has any correspondence with the chip type (looking at the other ones, it does), it indeed suggests this is a G2452.
     
    The only difference between the G2252 and the G2452 is 2K flash vs 8K flash.
     
    I was just about to report this as an mspdebug bug, but now it smells fishy. What does your G2252 have to say about this?
  23. Like
    gordon got a reaction from jsolarski in DTMF-Controlled Garage Door Opener [GDO]   
    By some miracle, my project started showing signs of working, so time to show it the light of day .
     
    It is a remotely-controlled garage door opener of sorts. Hook it up to a phone (that is set to auto-answer), call phone, identify and authenticate yourself, and it will (in its current configuration) pulse an output. The outputs may (via a bit of further circuitry) be used to open your garage door, solve the "damn cable modem froze again" situation, you name it. Features include "user accounts" with permissions assigned, protection against your pocket having long chats with your garage door, audible feedback (with plenty of noise), and generous amounts of comments with hopes that it'll be educational to someone (I heard POM was about code sharing, so what the heck ).
     

    It is my second ever MCU project (the first one was Blinky, of course), and it indeed has been a hell of a ride spanning about a month. In case anyone cares, here are a couple of things highlighting what I have learnt during these past couple of weeks:
     
    - Timers are the bread and butter of everything
    - No situation is hopeless enough for a friendly, helpful green LED
    - State machines can get tricky. I thought I was pretty OK with them, but it turns out state machines and ISRs can get quite different from state machines and Unix signal handlers
    - Data sheets good. Use data sheets. Just keep staring at them, they will make sense, eventually.
    - Did I mention timers are the bread and butter of everything?
    - ... and I still don't know jack about them.
     
    Attached to this post is the GDO source and the schematic (there's more to the right, but the forum theme knows better; just view the image in a separate window). I've also attached the HT9170 data sheet for reference.
     

    Credit bits: I re-used gatesphere's '595 handling stuff to a great extent; also Rob's and oPossum's advices have been most influential. I should in fact be making roll calls. Thanks to the whole 43oh lot .
    HT9170.pdf
    gdo_src.c
  24. Like
    gordon got a reaction from nuetron in DTMF-Controlled Garage Door Opener [GDO]   
    By some miracle, my project started showing signs of working, so time to show it the light of day .
     
    It is a remotely-controlled garage door opener of sorts. Hook it up to a phone (that is set to auto-answer), call phone, identify and authenticate yourself, and it will (in its current configuration) pulse an output. The outputs may (via a bit of further circuitry) be used to open your garage door, solve the "damn cable modem froze again" situation, you name it. Features include "user accounts" with permissions assigned, protection against your pocket having long chats with your garage door, audible feedback (with plenty of noise), and generous amounts of comments with hopes that it'll be educational to someone (I heard POM was about code sharing, so what the heck ).
     

    It is my second ever MCU project (the first one was Blinky, of course), and it indeed has been a hell of a ride spanning about a month. In case anyone cares, here are a couple of things highlighting what I have learnt during these past couple of weeks:
     
    - Timers are the bread and butter of everything
    - No situation is hopeless enough for a friendly, helpful green LED
    - State machines can get tricky. I thought I was pretty OK with them, but it turns out state machines and ISRs can get quite different from state machines and Unix signal handlers
    - Data sheets good. Use data sheets. Just keep staring at them, they will make sense, eventually.
    - Did I mention timers are the bread and butter of everything?
    - ... and I still don't know jack about them.
     
    Attached to this post is the GDO source and the schematic (there's more to the right, but the forum theme knows better; just view the image in a separate window). I've also attached the HT9170 data sheet for reference.
     

    Credit bits: I re-used gatesphere's '595 handling stuff to a great extent; also Rob's and oPossum's advices have been most influential. I should in fact be making roll calls. Thanks to the whole 43oh lot .
    HT9170.pdf
    gdo_src.c
  25. Like
    gordon got a reaction from RobG in DTMF-Controlled Garage Door Opener [GDO]   
    By some miracle, my project started showing signs of working, so time to show it the light of day .
     
    It is a remotely-controlled garage door opener of sorts. Hook it up to a phone (that is set to auto-answer), call phone, identify and authenticate yourself, and it will (in its current configuration) pulse an output. The outputs may (via a bit of further circuitry) be used to open your garage door, solve the "damn cable modem froze again" situation, you name it. Features include "user accounts" with permissions assigned, protection against your pocket having long chats with your garage door, audible feedback (with plenty of noise), and generous amounts of comments with hopes that it'll be educational to someone (I heard POM was about code sharing, so what the heck ).
     

    It is my second ever MCU project (the first one was Blinky, of course), and it indeed has been a hell of a ride spanning about a month. In case anyone cares, here are a couple of things highlighting what I have learnt during these past couple of weeks:
     
    - Timers are the bread and butter of everything
    - No situation is hopeless enough for a friendly, helpful green LED
    - State machines can get tricky. I thought I was pretty OK with them, but it turns out state machines and ISRs can get quite different from state machines and Unix signal handlers
    - Data sheets good. Use data sheets. Just keep staring at them, they will make sense, eventually.
    - Did I mention timers are the bread and butter of everything?
    - ... and I still don't know jack about them.
     
    Attached to this post is the GDO source and the schematic (there's more to the right, but the forum theme knows better; just view the image in a separate window). I've also attached the HT9170 data sheet for reference.
     

    Credit bits: I re-used gatesphere's '595 handling stuff to a great extent; also Rob's and oPossum's advices have been most influential. I should in fact be making roll calls. Thanks to the whole 43oh lot .
    HT9170.pdf
    gdo_src.c
×
×
  • Create New...