Well, last week I got several packages of parts with lots of sets of ten. I got ten 8pin sockets, ten CR2032 batteries and ten battery holders, and most importantly ten attiny85 MCUs. I figure I can use this set of parts for a bunch of small projects, but my first project is to make a tiny bot! I've already got some tiny pager motors, and some ir emitters I can use as light sensors.
Of course my first problem was figuring out how to program these little things. I've been using Arduino relatives up until now, so I don't have a proper chip programmer. I'd read in a few places though that an Arduino could be used to program other 8bit AVR chips. It turns out most of the posts I found about this are out of date though. Luckly there is an example 'sketch' included with the Arduino environment that lets the Arduino act as an ISP, and the comments at the top of the file had all the information I needed to wire it up!
With that sorted my second problem was: figuring out how to program it! Programming a raw AVR chip isn't simple like the Arduino, there is no hand holding. I'm not that comfortable with C, so I at least wanted an IDE. I'm on a new Macbook pro though, so I couldn't even use the standard (Windows only) IDE. It wasn't hard to install the AVR crosspack for OSX and get Eclipse setup with the AVR plugin. From there I found a blinking LED tutorial somewhere, and read some tutorials in the AVR-Freaks forum. It is kind of a wierd way to work, but I'm starting to understand how to talk to these things. (BTW I had to specify a bitrate for AVRdude before it would work, but setting the bitrate with the avr plugin seemed buggy)
So after getting a light to blink I started working on the most basic thing I would need to get a bot working: using PWM to run a motor. This is where things got really tricky. All the tutorials I could find were doing the pulsing manually by playing with timers and interrupts, and the datasheet was just a bunch of nonsense acronyms and no clear example of the steps to get working PWM... Well, after hours of searching and reading on the internet, and reading the datasheet backward and forward I finally figured out the magic incantations used to run hardware PWM!
Here are some pictures of my setup:
Red and Black for power, Orange/Blue for ISP programming, White for ISP signal LEDs.
I got the motor driver "design" from the project here, which is incidentally about the same as what I want to make. It is just a transistor acting as a switch driven by a data pin, and a snubber diode. This only allows motor control in one direction, but my design still has one free data pin, so if I were clever I could probably find a way to switch the motor connections?
Here is my code:
#include <avr/io.h>
#include <util/delay.h>
// I haven't decided about these yet...
#define bit_get(p,m) ((p) & (m))
#define bit_set(p,m) ((p) |= (m))
#define bit_clear(p,m) ((p) &= ~(m))
#define bit_flip(p,m) ((p) ^= (m))
#define BIT(x) (0x01 << (x))
#define MOTOR PB4
void delay_ms(uint16_t ms){
// _delay_ms is limited, and requires a const arg for optimal code generation
// The maximal possible delay is 262.14 ms / F_CPU in MHz. (approx. 32 at 8MHz)
int i;
if (ms <= 32){
_delay_ms(ms);
return;
}
ms = ms/32; // note rounding error!
for (i=0;i<32;i++){
_delay_ms(ms);
}
}
void setup_pwm(void){
// Do all the bit twiddling magic to activate hardware PWM (only using pwmb for this test)
int i;
// First setup the pll (Fast Peripheral Clock)
PLLCSR = BIT(PLLE);
_delay_ms(0.1); // Datasheet
for (i=0;i<255;i++) { // timeout at 256 trys
if (~bit_get(PLLCSR, 0x01)) { // Wait for the PLOCK bit to be set
break;
}
}
PLLCSR = BIT(PCKE);
// Set clock rate prescaler for 250kHz (From datasheet)
TCCR1 = 0x01;
// Setup timer1b for PWM on pb4
GTCCR = BIT(PWM1B) | BIT(COM1B1);
// Set the Output Compare Register for 50% duty cycle
OCR1B = BIT(7);
}
int main(void){
int i;
// Set clock full speed
CLKPR = BIT(CLKPCE);
CLKPR = BIT(CLKPS0);
// Set port b to output
DDRB = BIT(MOTOR);
setup_pwm();
for (;;){
for (i=0;i<255;i++){
// Change the PWM duty cycle
OCR1B = i;
// delay for a while
delay_ms(5);
}
for (i=255;i>0;i--){
// Change the PWM duty cycle
OCR1B = i;
// delay for a while
delay_ms(5);
}
// pause for a moment
DDRB = 0x00;
delay_ms(500);
DDRB = BIT(MOTOR);
}
return (1); // should never happen
}
It may not be the best code around, but like I said - I couldn't find any decent examples!
Next I'll try to get some ADC readings with my irLEDs!