I did this purely for the fun of it, and am aware there are many ways to accomplish the same thing. I was playing Counter Strike Source (you should buy it and play with me, name “swharden”) and my fingers are really cold from the winter weather, and wondered if I could have a button help with the rapid firing of pistols. I mentioned it on the microphone, and one of the players (“{Ẋpli¢it} shadow”) said I should go for it. Because it was a fun little project, I documented it so I could share it. Check out the cool photos and video!

There’s a summary of the project in video form. Some details of the project are below…rapidfire_mouse_mod (1)

Here you can see the original circuit board in the mouse. The microchip on the bottom right of the image seems to do the data processing, so I investigated it a bit and found the pin that the left-click button goes to.rapidfire_mouse_mod (2)

Here’s the underside. It helped me identify good locations to grab +5V and GND solder points.rapidfire_mouse_mod (3)

This is the microcontroller I decided to use for the project. It’s an ATTiny25, $1.33 USD (10+ quantity from Mouser), and has a built in 8MHz oscillator (which can run at 1MHz thanks to the DIV/8 clock prescaler.rapidfire_mouse_mod (4)

I slap the chip in the homebrew development board (a glorified AVR-ISP mkII) and it’s ready for programming. Code and schematics are at the bottom.rapidfire_mouse_mod (5)

After programming, I glued the microchip upside-down in the mouse case and soldered wires directly to the pins. I used small (about 28AWG) magnet wire because it’s a lot easier than stripping wires. Just heat the tip with a soldering iron, the coating melts away, and you can stick it wherever you need to with a dab of solder. Not too many people use this method, but I recommend you try it at least once! It can be very useful at times, and is about as cheap as you can get. (eBay has good prices)rapidfire_mouse_mod (6)

BIG PROBLEM! It didn’t work *AT ALL*. Why? Didn’t know… I checked the o-scope and saw everything seemed to be working fine. It turns out that 50 clicks per second was too fast to register, and when I reduced the speed to 25 clicks per second it worked fine. Unfortunately I had to add extra wires to allow myself to program the chip while it was in the mouse – a major pain that complicated the project more than I wished!

rapidfire_mouse_mod (7)

Here’s a good view of the transistor. Simply put, when the microcontroller sends power to the “base” pin of the 2n2222 transistor, the “collector” is drained through the “emitter”, and the transistor acts like a switch. It’s shorting the pin, just like would happen if you physically pressed the left click mouse button. When the mouse microchip is positive (+5V), it’s “no click”, but when it goes to ground (shorted by the click button), a click is detected. I biased the “base” pin toward ground by connecting it to GND through a high value resistor. This makes sure it doesn’t accidentally fire when it’s not supposed to.

rapidfire_mouse_mod (8)

Here you can clearly see the programmer pins I added. This lets me quickly access the chip and reprogram it if I decide to add/modify functionality.

rapidfire_mouse_mod (9)

When it’s all said and done, it’s surprisingly slick and functional. I’m using it right now to write my blog, and the button isn’t really in the way. I think it’s one of those el-cheapo buttons you get in a pack of 10 from RadioShack, but I would highly recommend eBay as RadioShack is ridiculously overpriced on components.

rapidfire_mouse_mod (10)

There’s the schematic. Grabbing 5v and GND from a usb mouse is trivial. Heck, most of the circuity/code is trivial! Now that I think about it, this represents are really great starter project for anyone interested in microcontrollers.

ATtiny25-45-85V

Use this diagram of the pin functions for reference.

Remember there’s more than one way to skin a cat! For example, if you don’t want to program a microcontroller, a 555 timer is a simple method and there are tutorials out there demonstrating how to do this. I chose a microcontroller because I can precisely control the rate of firing and the duration. If you decide to do something similar, send me photos and I’d be happy to share them on the site! I love doing tangible projects, however silly they are.

And finally, the code!

#define F_CPU 1000000UL	// frequency (20MHz)
#include <avr/io.h>
#include <util/delay.h>



void on(){
	PORTB |= 1 << PB3; //led
	PORTB |= 1 << PB2; //heater
	}
void off(){
	PORTB &= ~( 1 << PB3 );//led
	PORTB &= ~( 1 << PB2 );//heater
	}


void main() {
	DDRB |= (1<<PB3)|(1<<PB2);
	int ticks;

	for (;;) { //FOREVER
		while ((PINB & _BV(PB4))==0) {} // NOT PRESSED, DO NOTHING
		for(ticks=0;ticks<125;ticks++) // CLICK FOR 5 seconds
			{
			on();_delay_ms(20);off();_delay_ms(20);
			} // CLICK TAKES 1/50'th second
	}
}




Now that I’ve finished my 6-channel data logger (previous post), it’s time to put it to the test! I’m using a handful of LM335 temperature sensors to measure temperature, and a 20 Ohm resistor to act as a heater. When 1A of current passes through it, it gets quite toasty! First, I’ll make some temperature probes…IMG_4581IMG_4588

UPDATE: Those photos show a partially completed sensor. Obviously the third wire is required between the resistor and the LM335 to allow for measurement! Here’s a more completed sensor before the shrink tube was massaged over the electrical elements:IMG_4591

Then I mounted the sensors on a block of steel with the heater on one side. This way I can use one temperature to measure the heater temperature, and the other to measure the temperature of the metal chassis. I then put the whole thing in a small Styrofoam box. IMG_4606IMG_4615

When I fire the heater, that sucker gets pretty darn hot. In 40 minutes it got almost 250F (!) at which time I pulled the plug on the heater and watched the whole thing cool. Notice how the metal chassis lags behind the temperature of the heater. I guess it’s a bit of a “thermal low-pass filter”. Also, yes, I’m aware I spelled chassis incorrectly in the graphs.howhotquicktest

But how do we use this to build a thermo-stable crystal oven for a MEPT (radio transmitter)? I tried a lot of code, simply “if it’s too cold, turn heater on / if it’s too hot, turn heater off” but because the chassis always swung behind the heater, and even the heater itself had a bit of a delay in heating up, the results were always slowly oscillating temperatures around 10F every 20 min. That’s worse than no heater! My best luck was a program to hold temperature stable at 100F with the following rules:
1.) If heater > 155F, turn heater off (prevent fire)
2.) If chassis < 100F, turn heater on
3.) if (heater-target) > (target-chassis), turn heater offheaterworks

What a great job! That thing is practically stable in 20 minutes. The advantage of this over an analog method is that I can set the temperature in software (or provide an interface to change temperature) and my readings are analytical, such that they can be conveyed in a radio message. Again, my best results came when I implemented rule 3 in the code above. More experiments to come!





While working to perfect my temperature-controlled manned experimental propagation transmitter (MEPT), I developed the need to accurately measure temperature inside my Styrofoam enclosure (to assess drift) and compare it to external temperature (to assess insulation effects). I accomplished this utilizing the 8 ADC channels of the ATMega48 and used its in-chip USART capabilities to send this data to a PC for logging. I chose the ATMega48 over the ATTiny2313 (which has USART but no ADCs) and the ATTiny44a (which has ADCs but no USART). From when I see, no ATTiny series ATMEL AVR has both! Lucky for me, the ATMega48 is cheap at $2.84 USD. Here’s my basic circuit idea: IMG_4559

EDIT: the SCHEMATIC1 : PAGE1voltage reference diagram is wrong at the bottom involving the zener diode. Reference the picture to the right for the CORRECT way to use such a diode as a voltage reference. (stupid me!)

MULTIPLE SENSORS – Although in this demonstration post I only show a single sensor, it’s possible to easily have 8 sensors in use simultaneously since the ATMega48 has 8 ADC pins, and even more (infinitely) if you want to design a clever way to switch between them.

LM335 Temperature Sensor – selected because it’s pretty cheap (< $1) and quantitative. In other words, every 10mV drop in voltage corresponds to a change of 1ºC. If I wanted to be even cheaper, I would use thermistors (<$0.10) which are more qualitative, but can be calibrated I guess. Notes on power stability - The output of the sensor is measured with the ADC (analog to digital converter) of the microcontroller. The ADC has a 10-bit resolution, so readings are from 0 to 2^10 (1024). AREF and AVCC can be selected as a voltage reference to set what the maximum value (1024) should be. If the ADC value is 1V (for example) and AREF is 1V, the reading will be 1024. If AREF becomes 5V, the reading will be 1024/5. Make sense? If AREF is fluctuating like crazy, the same ADC voltage will be read as differing vales which is not what we want, therefore care should be taken to ensure AREF is ripple-free and constant. Although I did it by adding a few capacitors to the lines of the power supply (not very precise), a better way would be to use a zener diode (perhaps 4.1V?) as a voltage reference.IMG_4575

Here is my circuit. I’m clocking the chip at 9.21MHz which works well for 19200 baud for serial communication. Refer to my other MAX232 posts for a more detailed explanation of how I chose this value. The temperature sensor (blurry) is toward the camera, and the max232 is near the back. Is that an eyelash on the right? Gross!logger

The data is read by a Python script which watches the serial port for data and averages 10 ADC values together to produce a value with one more significant digit. This was my way of overcoming continuously-fluctuating values.
IMG_4564

Here you can see me testing the device by placing an ice cube on the temperature sensor. I had to be careful to try to avoid getting water in the electrical connections. I noticed that when I pressed the ice against the sensor firmly, it cooled at a rate different than if I simply left the ice near it.

NOTICE THE PROGRAMMER in the background (slightly blurry). The orange wires connect the AVR programmer to my circuit, and after the final code is completed and loaded onto the microcontroller these orange wires will be cut away.lm335 microcontroller graph annotated

Here is some actual data from the device. The LM335 readout is in Kelvin, such that 3.00V implies 300K = 80ºF = 27ºC (room temperature). The data is smooth until I touch it with the soldering iron (spike), then it gets cool again and I touch it with a cold piece of metal (wimpy dip), then later I put an ice cube on it (bigger dip). Pretty good huh? Remember, 0.01V change = 1ºC change. The bottom of the dip is about 2.8V = 280K = 44ºF = 7ºC. If I left the cube on longer, I imagine it would reach 0ºC (273K, or 2.73V).

For everyone’s reference, here’s the pinout diagram of the ATMega48:atmega48pinout

Finally, the code to record live data:

import socket
import sys
import serial

ser = serial.Serial('COM1', 19200, timeout=1)
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)

chunk=""
i=0
data = ser.readline()
while True:
    i+=1
    data = ser.readline()
    data=data.replace("n","")
    data=data.replace("r","")
    data="["+data[:-1]+"]"
    data=eval(data)
    val=sum(data)/float(len(data))
    print i,data,val
    chunk=chunk+"%.01f,"%val
    if i==100:
        print "nSAVING"
        i=0
        f=open("data.txt","a")
        f.write(chunk)
        f.close()
        chunk=""

and the code to PLOT the data file:

import matplotlib.pyplot as plt
import numpy

def smoothTriangle(data,degree,dropVals=False):
        """performs moving triangle smoothing with a variable degree."""
        """note that if dropVals is False, output length will be identical
        to input length, but with copies of data at the flanking regions"""
        triangle=numpy.array(range(degree)+[degree]+range(degree)[::-1])+1
        smoothed=[]
        for i in range(degree,len(data)-degree*2):
                point=data[i:i+len(triangle)]*triangle
                smoothed.append(sum(point)/sum(triangle))
        if dropVals: return smoothed
        smoothed=[smoothed[0]]*(degree+degree/2)+smoothed
        while len(smoothed)<len(data):smoothed.append(smoothed[-1])
        return smooth


print "loading..."
f=open("data.txt")
raw="["+f.read()+"]"
f.close()
data=eval(raw)

print "converting..."
data=numpy.array(data)
data=data/1024.0*5 #10-bit resolution, 5V max

print "graphing"
plt.plot(data)

plt.grid(alpha=.5)
plt.title("ATMega48 LM335 Temperature Sensor")
plt.ylabel("Voltage (V)")
plt.xlabel("Time (5/sec)")
plt.show()

Also, the AVR-GCC code loaded on the ATMega48:





#define F_CPU 9210000UL

#include <avr/io.h>
#include <util/delay.h>

void init_usart(unsigned long);

unsigned int readADC(char times){
	unsigned long avg=0;
	for (char i=0; i<times; i++){
        ADCSRA |= (1<<ADSC); // reset value
        while (ADCSRA & ( 1<<ADSC)) {}; // wait for measurement
		avg=avg+ADC;
	}
	avg=avg/times;
	return avg;
}

int main (void){

    ADMUX = 0b0100101; // AVCC ref on ADC5
    ADCSRA = 0b10000111; //ADC Enable, Manual Trigger, Prescaler 128
	ADCSRB = 0;

	DDRD=255;

	init_usart(19200);
	for(;;){
		for(char j=0;j<10;j++){
			sendNum(readADC(10)>>6); // shift to offset 10bit 16bit
			send(44); // COMMA
			PORTD=255;_delay_ms(10);
			PORTD=0;_delay_ms(10);
			}
		send(10);send(13); // LINE BREAK
		}
	}


void sendNum(unsigned int num){
		char theIntAsString[7];
		int i;
		sprintf( theIntAsString, "%u", num );
		for (i=0; i < strlen(theIntAsString); i++)
		{send(theIntAsString[i]);}
}

void send (unsigned char c){
		while((UCSR0A & (1<<UDRE0)) == 0) {}
		UDR0 = c;
}

void init_usart (unsigned long baud)
{
	/////////////////////////
	//		Baud Generation
	unsigned int UBRR_2x_off;
	unsigned int UBRR_2x_on;
	unsigned long closest_match_2x_off;
	unsigned long closest_match_2x_on;
	unsigned char off_2x_error;
	unsigned char on_2x_error;

	UBRR_2x_off = F_CPU/(16*baud) - 1;
	UBRR_2x_on = F_CPU/(8*baud) - 1;

	closest_match_2x_off = F_CPU/(16*(UBRR_2x_off + 1));
	closest_match_2x_on = F_CPU/(8*(UBRR_2x_on + 1));

	off_2x_error = 255*(closest_match_2x_off/baud - 1);
	if (off_2x_error <0) {off_2x_error *= (-1);}
	on_2x_error = 255*(closest_match_2x_on/baud -1);
	if (on_2x_error <0) {on_2x_error *= (-1);}

	if(baud > F_CPU / 16)
	{
		UBRR0L = 0xff & UBRR_2x_on;
		UBRR0H = 0xff & (UBRR_2x_on>>8);
		UCSR0A |= (1<<U2X0);
	} else {

		if (off_2x_error > on_2x_error)
		{
			UBRR0L = 0xff & UBRR_2x_on;
			UBRR0H = 0xff & (UBRR_2x_on>>8);
			UCSR0A |= (1<<U2X0);
		} else {
			UBRR0L = 0xff & UBRR_2x_off;
			UBRR0H = 0xff & (UBRR_2x_off>>8);
			UCSR0A &= ~(1<<U2X0);
		}
	}
	/////////////////////////
	//	Configuration Registers
	UCSR0B = (0<<RXCIE0) |//We don't want this interrupt
	(0<<TXCIE0) |//We don't want this interrupt
	(0<<UDRIE0) |//We don't want this interrupt
	(1<<RXEN0) |//Enable RX, we wont use it here but it can't hurt
	(1<<TXEN0) |//Enable TX, for Talkin'
	(0<<UCSZ02);//We want 8 data bits so set this low

	UCSR0A |= (0<<U2X0) |//already set up, so don't mess with it
	(0<<MPCM0) ;//We wont need this

	UCSR0C = (0<<UMSEL01) | (0<<UMSEL00) |//We want UART mode
	(0<<UPM01) | (0<<UPM00) |//We want no parity bit
	(0<<USBS0) |//We want only one stop bit
	(1<<UCSZ01) | (1<<UCSZ00) |//We want 8 data bits
	(0<<UCPOL0) ;//This doesn't effect UART mode
}

UPDATE: A day later I added multiple sensors to the device. I calibrated one of them by putting it in a plastic bag and letting it set in ice water, then I calibrated the rest to that one. You can see as my room temperature slowly falls for the night, the open air sensor (red) drops faster than the insulated one in a Styrofoam box. Also, I did a touch of math to convert voltage to kelvin to Fahrenheit. You can also see spikes where it quickly approached 90+ degrees from the heat of my fingers as I handled the sensor. Cool!3traces

UPDATE: a day and a half later, here’s what the fluctuations look like. Notice the cooling of night, the heating of day, and now (near the end of the graph) the scattered rain causes more rapid fluctuations. Also, although one sensor is in an insulated styrofoam box, it still fluctuates considerably. This measurement system is prepped and ready to go for crystal oven tests!insulated3





I’ve been pretty busy lately, but I drip to the hardware store with the XYL produced a PVC enclosure that looked perfect for my ongoing MEPT (manned experimental propagation transmitter) projects. I didn’t want to buy it (it was a little pricey by my standards, at $6 USD, which is about the total cost of the transmitter!) but the wife convinced me and I’m glad she did! I intended it to replace the styrofoam enclosure I had been using, but I wasn’t thinking clearly and drilled holes in the box and mounted screws through them. While electrically this is a wonderful way to add antenna connections, thermally it was a bad idea. The main point of the enclosure was to be temperature stable! Oh well. I put the whole thing in the Styrofoam and as a test, I’m leaving it outside tonight. I can’t wait to see how it goes! Here are some photos of the project.IMG_4526IMG_4534IMG_4547IMG_4548

Update: Even when being housed outdoors when temperature fluctuations vary greatly between day and night, this MEPT is surprisingly stable! When I open the box, it’s very warm inside, so I am thinking that the voltage regulators and the MOSTFETs of the PA are heating the device nicely. Here’s a capture spanning about 2 hours. The vertical height of each “V” is about 10Hz, so I estimate that for this span of time, drift is <1Hz. However, I do believe that long term (day to day) frequency stability is still not optimal, but only time will tell.
qrss_stable

Signal report: briefly, this is my signal in Alaska courtesy of KL7UK. My signal is the V-shaped one near the bottom: KL7UK_alaska





UPDATE: I found a method of PC/microcontroller communication which I feel is simpler, easier, and definitely cheaper than this! It’s not good for everything, but worth looking at. It’s a way to communicate with a PC using your sound card and zero components!

This weekend I had a need, and I met it with parts I had on hand. Simply put, I wanted to assess whether or not my temperature-controlled crystal heater is doing its job in keeping temperature rock-stable. I wanted to measure temperature by measuring the ADC (analog-to-digital) value at the middle of a voltage divider with a resistor and a thermistor. Using a computer to plot this data, I can see if temperature fluctuates as my apartment AC turns on/off, or if it’s perfectly stable (my goal). The problem is that my only MCU (micro-controller unit) with USART (universal asynchronous receiver/transmitter) built-in is an ATTiny2313, which has no ADC capabilities. I had a lot of ATTiny44A chips on hand, so I had to figure out a way to get the data from my an ATTiny44A to an ATTiny2313 then to a MAX232 chip (voltage driver) so it can be sent to a PC’s serial port.

IMG_3919This is my bare-bones solution to easily sending data from ANY microcontroller to a PC’s serial port using 3 pins to send data to an ATTiny2313 which is interpreted, converted to decimal, then sent to my PC’s serial port. I will keep this little board and use it often to peek at variables inside my microcontroller projects in real time, with minimal coding!

Let’s take a look! schematic_fixed2

Above is the bare-bones schematic required to send data from an ATTiny2313 to a PC via a serial port. This schematic is improved and documented better on this page than on my previous post Simple Case AVR/PC Serial Communication via MAX232. Note that I’m designing this to be functional, perhaps not well enough to be used in mission-critical systems. Although some schematics suggest extra capacitors, I found that the only one required is between pins 4 and 5 of the MAX232. The role of the MAX232 chip is to act as a voltage pump and relay the incoming signal at increased voltage which the PC’s serial port can read. It doesn’t actually change the data.

UPDATE: in a later project working with an ATMega48 I found that a capacitor was needed between pin 6 and ground - don't know why! If it's not working for you (you're getting garbage) start adding capacitors as shown in this MAX232 circuit

Power supply: Since the thing runs on 5V, we’re golden! Just grab a USB cable, hook up the black (ground) and red (+5V) wires, and you’re good to go! If you want you can add a few capacitors of different values in parallel to the power supply to stabilize fluctuations in voltage, but I’ve been doing just fine without this extra precaution.

Display: The two LEDs are totally optional, but they let me see what’s going on. One of them flashes when the device is waiting for data (to let me know it’s on), and the other one turns on every time a [CLOCK] signal is detected (which is any time data is being sent)

Notes on frequency and crystals. The UBRRL value in the code must be set depending on your micro-controller speed and desired baud rate. I set-up an Excel spreadsheet and did some math determining UBRRL for a combination of different frequencies/rates. The UBRRL values closest to whole numbers are those which should be used to minimize errors. External crystals are often used to increase and stabalize the clock speed of micro-controllers, but I was able to send serial data without a crystal. I set the fuse for “internal 8mhz” clocking, and enabled the “div8” fuse so it actually ran at 1mhz. With these settings at 4800 baud, UBRR [according to the equation UBRR=(freq/(16*baud))-1] is 12.02 (pretty close to 12), so I set UBRRL=12 in the code and it sent data to a PC beautifully without a crystal. However, I had the desire to run the MCU faster to watch for incoming signals. I therefore used a 9.21MHz crystal (I had to set the fuses to enable the external crystal), which can send serial data to a PC reliably at 19200 baud.

Sending data to the ATTiny2313 to be relayed to the PC: Not every MCU has SPI, USI, I2C, TWI, USART, or other “standard” communication methods. If I want to have a Texas Instruments or PIC or PICaxe chip send data to a PC, I have to decipher the datasheet and spend half a day to figure out how (yuk!). Therefore, I developed an ULTRA-SIMPLE protocol of data transfer which can be used by ANY microcontroller. Here’s an example of a sensor microcontroller. Although it’s not shown, there’s a thermistor (or some analog voltage being measured) somewhere. It reads the sensor, then sends its data over the 3 wires [CLOCK], [A], and [B].

Pulling-down the clock: Note that the 100k resistor shown pulling the [CLOCK] line to ground is critical. It doesn’t have to be 100k, it can be virtually any value, it just makes sure that if current is not being sent on the clock line, it quickly goes to 0V. Without this resistor, the clock line might flicker on and off even though no data is being sent.

serial_example

Sending data this way is embarrassingly easy! The [clock] line is almost always low. When [clock] goes high, data is read. When data is read, IMG_3907the ATTiny2313 determines the state of [A] and [B]. If A=0 and B=0, a ZERO is sent. If A=1 and B=0, a ONE is sent. If A=0 and B=1, a SPACE is sent (between values). If A=1 and B=1, a LINE BREAK is sent. Values are sent in binary, and when a space or line break is detected, the binary value is converted to decimal and sent to the PC’s serial port. It’s not dependent on speed, so send data as fast (within reason) or slowly as you want from any microcontroller and it will end-up on your computer screen! It’s that easy!

FLAME ALERT: A lot of people will be mad at me for suggesting this method. There are fancier, faster, and more stable ways to data transfer between micro-controllers, but this works well at moderate speeds (maybe 10 measurements a second?) and I can implement this on any microcontroller in seconds, without puzzling over the datasheet.

BREADBOARDED PROTOTYPE

Remember that I’m powering this entirely from USB power. The layout is simple: ATTiny44A measuring ADC of a thermistor on the left (see the little red thing?) sending data with 3 wires (top 3) to an ATTiny2313 intermediate chip (center), which converts this binary data to decimal and sends it to a MAX232 chip (right) where it gets converted to levels suitable for transmission to a serial port.IMG_3905

IMG_3891

IMG_3899

IMG_3904

IMG_3907

FINAL DEVICE

IMG_3922

IMG_3919

CODE (AVR-GCC)

This is what runs on the ATTiny2313 intermediate chip:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define B PB2
#define A PB1
#define clk PB0
unsigned int times=0;

// THIS RUNS ON THE ATTINY2313
// FUSES SET FOR INTERNAL 8MHZ, DIV/8=TRUE
// LISTENS ON PINS 12 (CLOCK), 13 (DATA), AND 14 (TRANSMIT)
// OUTPUTS TO A MAX232 THEN TO SERIAL PORT
// PC TERMINAL SET TO LISTEN AT 4800 BAUD

int main (void) {
	UBRRL = 29; // value determined for 9.21MHz crystal at 19200 baud
	UCSRB = (1 << RXEN) | (1 << TXEN); // fire-up USART
	UCSRC = (1 << UCSZ1) | (1 << UCSZ0); // fire-up USART
    DDRB=0; // set all of port b to input
	DDRD=255; // set all of port d to output
	char last=255;
	int var=0;
	char pos=0;
	char i=0;
	for(;;){
		while bit_is_clear(PINB,clk){blink();}
		PORTD|=(1<<PD5);PORTD&=~(1<<PD4);
		if (bit_is_set(PINB,A) && bit_is_clear(PINB,B)) {var=(var<<1)+1;}//ONE
		if (bit_is_clear(PINB,A) && bit_is_clear(PINB,B)) {var=(var<<1);}//ZERO
		if (bit_is_clear(PINB,A) && bit_is_set(PINB,B)) {show(var);var=0;send(32);}//SPACE
		if (bit_is_set(PINB,A) && bit_is_set(PINB,B)) {show(var);var=0;send(10);send(13);}//BREAK
		while bit_is_set(PINB,clk){blink();}
		PORTD&=~(1<<PD5);PORTD|=(1<<PD4);
		}
	}
void blink(){
	// just hanging out
	times++;
	if (times==10000){times==0;PORTD|=(1<<PD3);}
	if (times==20000){times==0;PORTD&=~(1<<PD3);times=0;}
	}

unsigned int rev(unsigned int b) {
  unsigned char result = 0;
  while (b) {
    result <<= 1;
    result  |= b % 2;
    b>>= 1;
    }
  return result;
  }

void show(unsigned int val){
	/* SHOW INDIVIDUAL 1s and 0s?
	for (char i=0;i<16;i++){
		if (val&(1<<i)){send(49);}
		else {send(48);}
		}
	send(61);
	*/
	val=rev(val);
	if (val==0) {send(48);}
	else {
		char started=0;
		int div=10000;
		for (char i=0;i<5;i++){
			if (val>div){started=1;}
			if (started){
				send(val/div+48);
				val=val-(val/div)*div;
				}
			div=div/10;
			}
		}
	return;
	}

void send(unsigned char data){
	  while (!(UCSRA & (1 << UDRE))); // wait for buffer to be empty
	  UDR = data; // send that sucker
	}

This is what runs on my ATTiny44a sensor chip. This is what you can replace with ANYTHING, as long as it twiddles the [clock], [a], and [b] pins similarly.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define dtaprt PORTA
#define clk PA1
#define A PA2
#define B PA0
#define delayms 100 // increase to slow it down

void wait(){_delay_ms(delayms);}
void clockNow(){dtaprt|=(1<<clk);wait();dtaprt&=~(1<<clk);wait();}
void sendSpace(){dtaprt=(1<<B);clockNow();}
void sendLine(){dtaprt=(1<<B)|(1<<A);clockNow();}
void sendOne(){dtaprt=(1<<A);clockNow();}
void sendZero(){dtaprt=0;clockNow();}

// TAKE A READING FROM ADC7 AND SEND IT TO SERIAL CHIP

int main (void) {
	DDRA|=(1<<clk);
	DDRA|=(1<<A);
	DDRA|=(1<<B);
	ADMUX = (1<<REFS1)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0); // ADC on ADC7 to 1.1v ref
	ADCSRA = (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2); // enable, prescale
	for(;;){
		int data=ReadADC();
		sendData(data);
		sendSpace();
		sendData(data);
		sendLine();
		_delay_ms(1000);
	}
}

void sendData(int data){
	char datalen=16;
	for (char pos=0;pos<datalen;pos++){
		if ((data>>pos)&1){sendOne();}
		else {sendZero();}
		}
	}

int ReadADC()
{
	ADCSRA |= (1<<ADSC); // reset value
	while (ADCSRA & ( 1<<ADSC)); // wait for measurement
	return ADC;
}

UPDATE!!! I found a simpler way to convert binary numbers into strings ready to be sent in ASCII via USART serial port:

void sendNum(unsigned int num){
		char theIntAsString[7];
		int i;
		sprintf( theIntAsString, "%u", num );
		for (i=0; i < strlen(theIntAsString); i++)
		{send(theIntAsString[i]);}
}




Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

So I’m working on building a crystal oven to keep my QRSS MEPT (radio transmitter) at an extremely stable frequency. Even inside a thick Styrofoam box, slight changes in my apartment temperature caused by the AC turning on and off is enough to change the crystal temperature of the transmitter, slightly modifying its oscillation frequency. For a device that vibrates exactly 10,140,070 times a second, even 3 to many or too few vibrations per second is too much. Keeping in the spirit of hacking things together with a minimum of parts, this is what I came up with!

It uses a thermistor, potentiometer, and comparator of a microcontroller (ATTiny44a) to tightly sense and regulate temperature. The heater element is a junk MOSFET I found in an old battery backup system. I simply have pass a ton of current (turned on/off by the gate) to generate heat, transferred into a piece of steel for smooth regulation. One of the unexpected advantages is that the light flickers rapidly near equilibrium, which is great because it has the ability to turn the heater on a little or a lot based upon the averaging effect of the flicker. Here is the code I wrote on the microcontroller to handle the comparator. It couldn’t be simpler!

#include <avr/io.h>
#include <util/delay.h>

int main(void) {
	DDRA=0; // all inputs
	DDRB=255; // all outputs

	while (1){
		if (ACSR & _BV(ACO)) {
			/* AIN0 is more positive than AIN1 right now */
			PORTB|=(1<<PB0);
			PORTB&=~(1<<PB1);

		} else {
	  		/* AIN0 is more negative than AIN1 */
			PORTB|=(1<<PB1);
			PORTB&=~(1<<PB0);
		}

	}
}




Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

One of my microcontroller projects requires me to measure values and transmit then in Morse code. There may be code out there to do this already, but I couldn’t find it. I’m sure there are more elegant and efficient ways to handle the conversion, but this works for me. Hopefully someone will find it useful!

binary_to_Morse
#include <stdio.h>

//Morse code numbers from 0 to 9
char * array [10] = {"-----",".----","..---","...--","....-",
	 ".....","-....","--...","---..","----."};

void beep(char v){
	// beep (or print) Morse code as necessary
	printf("%s ",array[v]);
}

void send(int l){
	// convert a number into Morse code
	char d=0;int t=0;int val=0;
	for (t=100000;t>0;t=t/10){ //number of digits here
		if (l>t){d=l/t;beep(d);l-=d*t;}else{beep(0);}
	}
	printf("n");
}

void main(){
	// program starts here
	int l=0b1111111111; //sample number (maximum 10-bit)
	printf("%d ",l);send(l);
	l=0b11010001100101100011; //larger sample number
	printf("%d ",l);send(l);
}




Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

SUMMARY: A small group of high school students taking an AP class for college credit launched a high-altitude weather balloon with a small payload. In addition to a video transmitter and GPS transmitter, they decided to include a simple transmitter built from scratch. This is the story of the project, with emphasis on the simple transmitter’s design, construction, implementation, and reception (which surprised me, being detected ~200 miles away and lasting the entire duration of the flight!) [sample.ogg]

6/16/2010 – TRACKING

I’m impressed how well the transmitter/receiver worked! For only a few milliwatts, I was able to track that thing all the way from takeoff to landing in Gainesville, FL a few hundred miles away.

ANALYSIS: the text on the image describes most if it, but one of the most interesting features is the “multipathing” during the final moments of the descent, where the single carrier signal splits into two. I believe this is due to two Doppler shifts: (1) as the distance between the falling transmitter and the receiver is decreasing, producing a slight in increase in frequency, and (2) a signal reflected off of a layer of the atmosphere above the craft (the ionosphere?) before it gets to the receiver, the distance of which is increasing as the craft falls, producing a decrease in frequency. I’ll bet I can mathematically work backwards and determine how high the craft was, how fast it was falling, and/or how high the layer of the reflecting material is – but that’s more work than this dental student is prepared to do before his morning coffee!

HERE IS SOME AUDIO of some of the strongest signals I received. Pretty good for a few milliwatts a hundred miles away! [beeps.ogg]

6/16/2010 – THE FLIGHT


The design team
Walking the balloon to its launch destination at NASA with an awesome rocket (Saturn 1B – identified by Lee, KU4OS) in the background.
The team again, getting ready for launch. I’ve been informed that the reason their hands are up is to prevent the balloon from tilting over too much. I’d imagine that a brush with a grass blade could be bad news for the project!


Last minute checks – you can see the transmitter and battery holders for it taped to the Styrofoam.
The transmitter in its final position

Note the coil of yellow wire. That serves as a rudimentary “ground” for the antenna’s signal to push off of. I wasn’t very clear on my instructions on how to make it. I meant that it should be a huge coil wrapped around the entire payload (as large as it can be), which would have probably produced a better signal, but since I was able to capture the signal during the whole flight it turned out to be a non-issue.

The antenna can be seen dropping down as a yellow wire beneath the payload. (arrow)
Launch! Look how fast that balloon is rising!
It’s out of our hands now. When I got the text message that it launched, I held my breath. I was skeptical that the transmitter would even work!
One of the students listening to my transmitter with QRSS VD software (score!)
Video capture from an on-board camera was also attempted (900MHz), but from what I hear it didn’t function well for very long.

6/15/2010 – IMPROVED BUILD

Here you can see me (center arrow) showing the students how to receive the Morse code signal sent from the small transmitter (left arrow) using a laptop running QRSS VD (my software) analyzing audio from and an Icom706 mkII radio receiver attached to a dipole (right arrow).

I amped-up the output of the oscillator using an octal buffer chip (74HC240) with some decent results. I’m pleased! It’s not perfect (it’s noisy as heck) but it should be functional for a 2 hour flight.

Closeup of the transmitter showing the oscillator at 29.4912 MHz, the Atmel ATTiny44a AVR microcontroller (left chip), octal buffer 74HC240 (right chip), and some status lights which blink as the code is executed.

This is my desk where I work from home. Note the styrofoam box in the background – that’s where my low-power transmitter lives (the one that’s spotted around the world). All I needed to build this device was a soldering iron.

Although I had a radio, it is not capable of receiving 29MHz so I was unable to test the transmitter from home. I had to take it to the university to assess its transmitting capabilities.

I connected the leads to the output of the transmitter, shorted by a 39ohm resistor. By measuring the peak-to-peak voltage of the signal going into a resistor, we can measure its power.

Here’s the test setup. The transmitter is on the blue pad on the right, and the waveform can be seen on the oscilloscope on the upper left.

With the amplifier off, the output power is just that of the oscillator. Although the wave should look like a sine wave, it’s noisy, and simply does not. While this is unacceptable if our goal is a clean radio signal with maximum efficiency, this is good enough to be heard at our target frequency. The PPV (peak-to-peak voltage) as seen on the screen is about 100mV. Since I’m using a x10 probe, this value should be multiplied by 10 = 1V. 1V PPV into 39 ohms is about 3 milliwatts! ((1/(2*2^.5))^2/39*1000=3.2). For the math, see this post

With the amplifier, the output is much more powerful. At 600mV peak-to-peak with a 10x probe (actually 6V peak-to-peak, expected because that’s the voltage of the 4xAAA battery supply we’re using) into 39 ohms we get 115 millivolts! (6/(2*2^.5))^2/39*1000=115.38.

Notes about power: First of all, the actual power output isn’t 115mW. The reason is that the math equations I used work only for pure sine waves. Since our transmitter has multiple waves in it, less than that power is going to produce our primary signal. It’s possible that only 50mW are going to our 29MHz signal, so the power output assessment is somewhat qualitative. Something significant however is the difference between the measured power with and without the amplifier. The 6x increase in peak-to-peak voltage results in a 36x (6^2) increase in power, which is very beneficial. I’m glad I added this amplifier! A 36 times increase in power will certainly help.

6/14/2010 – THE BUILD

Last week I spoke with a student in the UF aerospace engineering department who told me he was working with a group of high school students to add a payload to a high-altitude balloon being launched at (and tracked by) NASA. We tossed around a few ideas about what to put on it, and we decided it was worth a try to add a transmitter. I’ll slowly add to this post as the project unfolds, but with only 2 days to prepare (wow!) I picked a simplistic design which should be extremely easy to understand by everyone. Here’s the schematic:

The code is as simple as it gets. It sends some Morse code (“go gators”), then a long tone (about 15 seconds) which I hope can be measured QRSS style. I commented virtually every line so it should be easy to understand how the program works.

#include <avr /io.h>
#include <util /delay.h>

char call[]={2,2,1,0,2,2,2,0,0,2,2,1,0,1,2,0,2,0,2,2,2,0,1,2,1,0,1,1,1,0,0};
// 0 for space, 1 for dit, 2 for dah


void sleep(){
  _delay_ms(100); // sleep for a while
  PORTA^=(1<<PA1); // "flip" the state of the TICK light
}

void ON(){
 PORTB=255; // turn on transmitter
 PORTA|=(1<<PA3); // turn on the ON light
 PORTA&=~(1<<PA2); // turn off the ON light
}

void OFF(){
 PORTB=0; // turn off transmitter
 PORTA|=(1<<PA2); // turn on the OFF light
 PORTA&=~(1<<PA3); // turn off the OFF light
}

void ID(){
        for (char i=0;i<sizeof(call);i++){
                if (call[i]==0){OFF();} // space
                if (call[i]==1){ON();} // dot
                if (call[i]==2){ON();sleep();sleep();} // dash
    sleep();OFF();sleep();sleep(); // between letters
        }
}

void tone(){
 ON(); // turn on the transmitter
 for (char i=0;i<200;i++){ // do this a lot of times
  sleep();
 }
 OFF();sleep();sleep();sleep(); // a little pause
}

int main(void) // PROGRAM STARTS HERE
{
    DDRB = 255; // set all of port B to output
 DDRA = 255; // set all of port A to output
 PORTA = 1; // turn on POWER light

 while (1){ // loop forever
  ID(); // send morse code ID
  tone(); // send a long beep
 }
}

I’m now wondering if I should further amplify this signal’s output power. Perhaps a 74HC240 can handle 9V? … or maybe it would be better to use 4 AAA batteries in series to give me about 6V. [ponders] this is the schematic I’m thinking of building.

UPDATE

This story was featured on Hack-A-Day! Way to go everyone!





Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

This page documents the progress of my MEPT (manned experimental propagation transmitter) endeavors. If you have questions, feel free to E-mail me! My contact information can be found by clicking the link on the right navigation menu.

The Soup-Can Transmitter

The Signal

The Spots

Florida – 288.3 miles away (W4HBK) May 22, 2010

Massachusetts – 1,075.5 miles away (W1BW) May 27, 2010

Belgium – 4,496.3 miles away (ON5EX) May 27, 2010

Germany- 4,869.2 miles away (DL4MGM) May 28, 2010

Essex – 4,356.4 miles away (G6AVK) May 28, 2010

New Zealand – 8,077.6 miles away (ZL2IK) May 29, 2010





Warning: This post is several years old and the author has marked it as poor quality (compared to more recent posts). It has been left intact for historical reasons, but but its content (and code) may be inaccurate or poorly written.

Haray! I’m making awesome progress with my QRSS transmitter design. Because my current transmitter (previous few posts) was randomly freezing-up (likely due to the oscillator stopping its oscillating due to being overloaded) so I moved the oscillator from in-chip to an external oscillator. It’s been made small enough to fit in an Altoids tin, and I already tested it with the solar panel and it works! Awesome! Here are some photos. Again, when I perfect the design I’ll post final schematics.

Sticking out are wires for power and an antenna on each side. The goal is to hang the device between two trees by its own antenna. That’s my new chip development board. I made it with what I needed on it. It’s so convenient! It uses 5v of power from the USB port too! Altogether I’ve tested the device and confirmed it transmits radio when the solar panel is illuminated. I’m thinking of making it more effective by adding more panels… but that’s it for now!