# Sample project for ATTINY10 | AVR Freaks
Dear Sir/Madam,

Skip to main content

## Sample project for ATTINY10

Topic locked
Go To Last Post
16 posts / 0 new
Author
Message
tonyctsiu
Level: New Member
Joined: Fri. Jan 2, 2015
Posts: 2 View posts
#1
Posted by tonyctsiu: Fri. Jan 2, 2015 - 10:58 AM
Fivestar widget

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Dear Sir/Madam,

Just would like to know if there is anywhere i can download sample C example projects for Atmel Studio that shows different functionality of the ATTINY10?

Like ADC, IO setting, Timers etc..

I use STK600.

Regards,

Tony Siu

Tony Siu

## Tags:

AVR Microcontrollers, megaAVR and tinyAVR
Last Edited: Sat. Mar 21, 2020 - 09:00 PM
snigelen
Level: Posting Freak
Joined: Thu. Jan 8, 2009
Posts: 1952 View posts
Location: Lund, Sweden
#2
Posted by snigelen: Fri. Jan 2, 2015 - 11:59 AM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Here's a short sample that read the ADC and uses the timer to generate two servo signals proportional to the ADC reading.

    /*
      Read ADC2 (PB2) and output servo signal on PB0 and PB1.
      ATtiny5 or 10 at default 1MHz.
     */

    #include <avr/io.h>

    int main(void)
    {
        // ADC channel 2
        ADMUX = 2;
        // Disable digital input on PB2
        DIDR0 = (1<<ADC2D);
        // Enable ADC, presc 1:8 for 125kHz ADC-clock
        ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);

        // PB0 and 1 output.
        DDRB = (1<<PB0) | (1<<PB1);

        // Timer0 50Hz PWM, 1us tick, mode 14 with ICR0 as TOP.
        ICR0 = 19999; // 1MHz / 50Hz - 1
        // Start with 1.5 ms pulse-width
        OCR0A = OCR0B = 1500;

        // OC0A and OC0B non inverting PWM, mode bit 1
        TCCR0A = (1<<COM0A1) | (1<<COM0B1) | (1<<WGM01);
        // mode bits 2 and 3, presc 1:1
        TCCR0B = (1<<WGM03) | (1<<WGM02) | (1<<CS00);

        while(1)
        {
    	uint8_t i;
    	uint16_t adc4;

    	// Take four ADC samples, add them in adc4
    	for (i = 0, adc4 = 0; i < 4; i++)
    	{
    	    // Start a conversion
    	    ADCSRA |= (1<<ADSC);
    	    // wait until it's finished
    	    while (ADCSRA & (1<<ADSC))
    		; // Nothing
    	    adc4 += ADCL;
    	}

    	// Set PWM to 990 to 2010 ms from ADC.
    	OCR0A = 990 + adc4;
    	// OCR0B "inverted" servo signal
    	OCR0B = 2010 - adc4;
        }
    }

Last Edited: Fri. Jan 2, 2015 - 12:00 PM
snigelen
Level: Posting Freak
Joined: Thu. Jan 8, 2009
Posts: 1952 View posts
Location: Lund, Sweden
#3
Posted by snigelen: Wed. Jan 7, 2015 - 08:23 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Wasn't that useful? Anyway, here's a couple of more examples from my t10/test directory.

Toggle a LED at 1Hz

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

    int main(void)
    {
        // PB2 output
        DDRB = 1<<2;

        while(1)
        {
    	// Toggle PB2
    	PINB = 1<<2;
    	_delay_ms(500);
        }
    }

Short 1Hz flash using the timer

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

    int main(void)
    {
        TCNT0 = 0;
        OCR0A = 0;
        // Start timer, free running with presc. 1:64
        TCCR0B = 1<<CS01 | 1<<CS00;

        DDRB = 1<<2;

        while(1)
        {
    	// Short flash
    	PORTB |= 1<<2;
    	_delay_ms(1);
    	PORTB &= ~(1<<2);

    	// Add one second
    	OCR0A += F_CPU / 64 - 1;
    	// Wait for compare match
    	while(!(TIFR0 & (1<<OCF0A)))
    	    ;
    	// Clear interrupt flag
    	TIFR0 |= 1<<OCF0A;
        }
    }

Short 1Hz flash using idle mode between flashes

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

    EMPTY_INTERRUPT(TIM0_COMPA_vect)

    int main(void)
    {
        TCNT0 = 0;
        OCR0A = 0;
        // Enable compare match A interrupt
        TIMSK0 = 1<<OCIE0A;
        // Start timer, free running with presc. 1:64
        TCCR0B = 1<<CS01 | 1<<CS00;

        // PB2 output
        DDRB = 1<<2;

        set_sleep_mode(SLEEP_MODE_IDLE);

        sei();

        while(1)
        {
    	// Short flash
    	PORTB |= 1<<2;
    	_delay_ms(1);
    	PORTB &= ~(1<<2);

    	// Add one second
    	OCR0A += F_CPU / 64 - 1;

    	// Idle mode until COMPA interrupt
    	sleep_enable();
    	sleep_cpu();
    	sleep_disable();
        }
    }

Short flash at about 1 Hz, powerdown and wakeup by watchdog interrupt.

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

    // Wake up by WDT interrupt.
    // Don't need to do anything here but (auto-) clearing the interrupt flag.
    EMPTY_INTERRUPT(WDT_vect)

    /*
      Delay in powerdown mode. Wake up by watchdog interrupt.
     */
    void delay_power_down_wdt(uint8_t wdto)
    {
        wdt_reset();
        wdt_enable(wdto);
        WDTCSR |= (1<<WDIE);
        set_sleep_mode(SLEEP_MODE_PWR_DOWN);
        sleep_enable();
        // Make sure interrups are enabled and the I flag is restored
        NONATOMIC_BLOCK(NONATOMIC_RESTORESTATE)
        {
    	sleep_cpu();
    	wdt_disable();
        }
        sleep_disable();
    }

    int main(void)
    {
        DDRB = 1<<2;

        sei();

        while(1)
        {
    	// Short flash
    	PORTB |= 1<<2;
    	_delay_ms(1);
    	PORTB &= ~(1<<2);

    	delay_power_down_wdt(WDTO_1S);
        }
    }

Fade PB0 and PB1 up and down using PWM

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

    int main(void)
    {
        int i;

        // PB0 and PB1 outputs
        DDRB = (1<<PB0) | (1<<PB1);
        // Timer0 in mode 14, fast PWM with ICR0 as top.
        // Enable OC0A and OC0B, lower mode bits
        TCCR0A = (1<<COM0A1) | (1<<COM0B1) | (1<<WGM01);
        // Set top to 1000
        ICR0 = 1000;
        // Start timer with prescaler 1:8 and set upper mode bits
        TCCR0B = (1<<CS01)  | (1<<WGM03) | (1<<WGM02);

        while(1)
        {
    	for (i = 0; i <= 1000; i++)
    	{
    	    OCR0A = i;
    	    OCR0B = 1000-i;
    	    _delay_ms(1);
    	}
    	for (i = 1000; i >= 0; i--)
    	{
    	    OCR0A = i;
    	    OCR0B = 1000-i;
    	    _delay_ms(1);
    	}
        }
    }

Toggle a LED when a button is pressed

    /*
      Button on PB2 to GND, LED on PB0.
      Toggle led when button is pressed.
      Button is debounced using timer interrupt.
     */

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

    // Variable to tell main that the button is pressed (and debounced).
    // Main will clear it after a detected button press.
    volatile uint8_t button_down;

    // Check button state on PB2 and set the button_down variable if a debounced
    // button down press is detected.
    // Call this function about 100 times per second.
    static inline void debounce(void)
    {
        // Counter for number of equal states
        static uint8_t count = 0;
        // Keeps track of current (debounced) state
        static uint8_t button_state = 0;

        // Check if button is high or low for the moment
        uint8_t current_state = (~PINB & (1<<PINB2)) != 0;

        if (current_state != button_state) {
            // Button is about to be pressed or released, increase counter
            count++;
            if (count >= 4) {
                // The button have not bounced for four checks, change state
                button_state = current_state;
                // If the button was pressed (not released), tell main so
                if (current_state != 0) {
    		button_down = 1;
                    count = 0;
                }
            }
        } else {
            // Reset counter
            count = 0;
        }
    }

    // Called at 100Hz
    ISR(TIM0_OVF_vect)
    {
        debounce();
    }

    int main(void)
    {
        // PB0 output
        DDRB = 1<<0;
        // Enable internal pullup on PB2
        PUEB = 1<<2;

        // Timer0 in CTC mode
        TCCR0A = (1<<WGM01) | (1<<WGM00);
        // Set TOP for 100 Hz overflow rate
        OCR0A = F_CPU / 8 / 100 - 1;
        // Enable overflow interrupt
        TIMSK0 = 1<<TOIE0;
        // Start timer with presc 1:8
        TCCR0B = 1<<CS01;
        // Enable global interrupts
        sei();

        while(1)
        {
            if (button_down) {
                // Clear flag
                button_down = 0;
    	    // Toggle PB0
    	    PORTB ^= (1<<0);
            }
        }
    }

Torby
Level: 10k+ Postman
Joined: Tue. Nov 11, 2003
Posts: 10276 View posts
Location: Bartlesville Oklahoma USA
#4
Posted by Torby: Wed. Jan 7, 2015 - 09:23 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Here's one I played with a while ago. The anode of a yellow LED is hooked to a 100 ohm resistor to PB0, the cathode to ground. (This is the opposite of the traditional way to hook an LED.) Every minute or so, the program reads the voltage across the LED to decide if it's dark. If it is dark, it blinks like a firefly.

I was curious how long one of these would last on 2 AA batteries: About a month till a storm knocks it off the balcony railing, it smashes on the sidewalk below and the landlady sweeps up the debris and throws it away.

Uses ADC, Timer and Watchdog.

    /*
     * Firefly02.c
     *
     * Created: 4/21/2013 4:30:21 PM
     *  Author: Tom
     */

    #include <avr/interrupt.h>
    #include <avr/io.h>
    #include <avr/sleep.h>
    #define F_CPU 1000000UL  // 1 MHz
    #include<util/delay.h>

    int IsDark(void)
    {
    	DDRB = 1 ;
    	PORTB = PORTB & ~(1);
    	_delay_ms(20);
    	DDRB = 0 ;  // go to high impedance.
    	ADMUX = 0;  // Read v across LED
    	ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
    	ADCSRA |= (1<<ADSC);
    	while ((ADCSRA & (1<<ADIF))==0)
    	{

    	}
    	ADCSRA = (1<<ADIF);
    	if (ADCL < 5) return 1;
    	return 0;
    }

    ISR(TIM0_OVF_vect)
    {
    	if ((TCCR0A & (1<<WGM00))==0) // Sleeping
    	{

    	}
    	else  // Blinking
    	{
    		OCR0A = OCR0A-1 ;
    	}
    }

    ISR(WDT_vect)
    {

    }

    int main(void)
    {
    	DIDR0 = 0xf;
    	sei();
        while(1)
        {
            if (IsDark()!=0)
    		{
    			DDRB = 1;
    			TCCR0B = 0;
    			TCCR0A = (1<<COM0A1) | (1<<WGM00);
    			TCCR0B = (1<<WGM02) | (1<<CS01);
    			OCR0A = 255 ;
    			TIMSK0 = (1<<TOIE0) ;
    			while (OCR0A>0)
    			{

    			}
    			TCNT0 = 0;
    			PORTB = 0 ;
    			DDRB = 0;
    			TCCR0B = 0;
    		}
    		for(uint8_t i = 0; i<8; i++)
    		{
    			// Set watch dog timer for about 8 seconds
    			WDTCSR = (1<<WDIE) | (1<<WDP3) | (1<<WDP0) ;
    			set_sleep_mode(SLEEP_MODE_PWR_DOWN);
    			sleep_enable();
    			sleep_cpu();
    		}
    		WDTCSR = 0 ;  // Disable watch dog
        }
    }

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut.

clawson
Level: Moderator
Joined: Mon. Jul 18, 2005
Posts: 98629 View posts
Location: (using avr-gcc in) Finchingfield, Essex, England
#5
Posted by clawson: Thu. Jan 8, 2015 - 12:09 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Just to note that there articles about timers and ADC in the tutorial forum here. Admittedly not for Tiny10 but on the whole a lot of these peripherals are very similar across the AVRs and the general techniques can be applied to all though you may need to determine the odd change in bit or register names between devices.

But the point is that the use of an ADC is fairly common in general: you init a voltage reference, you init a prescale value to run the ADC at a "sensible" speed, you actually enable the ADC then you set some "start" bit and either keep watching it or wait for an interrupt indication to show completion then you read the results register. That's true for pretty much all AVRs, Tiny10 included so don't limit yourself to only trying to find details about Tiny10 alone. In fact few people (except those using them in industrial quantities) choose to use Tiny 4,5,9,10,20,40 - the so called "brain dead" AVRs - because their only true features are low cost and small package size. "hobbyists" pick more fully featured AVRs to start with like Tiny2313 (previously), Tiny1634, Mega48/88/168, Mega164/324/644/1284 and so on.

tonyctsiu
Level: New Member
Joined: Fri. Jan 2, 2015
Posts: 2 View posts
#6
Posted by tonyctsiu: Sun. Jan 11, 2015 - 11:35 AM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Thanks.. I think I will use the full size chip for development first.

[The two extra copies of this post have been deleted. Ross]

Tony Siu

Last Edited: Sun. Jan 11, 2015 - 11:39 AM
Torby
Level: 10k+ Postman
Joined: Tue. Nov 11, 2003
Posts: 10276 View posts
Location: Bartlesville Oklahoma USA
#7
Posted by Torby: Sun. Jan 11, 2015 - 12:47 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

I like tiny 10s because they're tiny and cheap. Annoying that you can't program them with a 3v supply though.

If you don't know my whole story, keep your mouth shut.

If you know my whole story, you're an accomplice. Keep your mouth shut.

dadams8355
Level: New Member
Joined: Mon. Mar 5, 2018
Posts: 17 View posts
#8
Posted by dadams8355: Fri. Apr 6, 2018 - 07:15 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Hello,

I am trying to do the following.

Sleep for 1 minute.

Flash an LED.

then go back to sleep.

For some reason, My code does not wake up after the sleep_cpu(); command. does anyone have any idea's. I am using an ATtiny 5 on the STK600 Dev system.

*

* ModuleJunctionBoxV1.c

*

* Created: 4/4/2018 2:01:01 PM

* Author : Dave Adams Se-Kure Controls Inc.

* Description:

* This Module will wake up every X Seconds, Flash the LED and Check the Battery Voltage.

*/

#define F_CPU 1000000UL // 1MHz

#include <avr/io.h>

#include <util/delay.h>

#include <avr/sleep.h>

#include <avr/wdt.h>

#include <avr/interrupt.h>

#include "MJBGlobals.h"

int main(void)

{

sysint();

adcint();

wdt_disable();

HORN_OFF;

LED_OFF;

while(1)

{

for(uint8_t i = 0; i<8; i++)

{

// Set watch dog timer for about 8 seconds

WDTCSR = (1<<WDIE) | (1<<WDP3) | (1<<WDP0) ;

set_sleep_mode(SLEEP_MODE_PWR_DOWN);

sleep_enable();

sleep_cpu();

}

WDTCSR = 0 ; // Disable watch dog

led_flash();

}

}

/*

* Function: sysint

*

* Created: 4/4/2018 2:01:01 PM

* Author : Dave Adams Se-Kure Controls Inc.

* Description:

* This function sets up the main processor ports

*/

void sysint(void)

{

CLKMSR = 0x00; // Set up internal 8MHz Clock

DDRB = 0x03; // PB3 = INPUT

// PB2 = INPUT

// PB1 = OUTPUT

// PB0 = OUTPUT

PUEB = 0; // Turn off week pullups

}

/*

* Function: adcint

*

* Created: 4/4/2018 2:01:01 PM

* Author : Dave Adams Se-Kure Controls Inc.

* Description:

* This function initializes ADC2

*/

void adcint(void)

{

ADMUX = 2; //ADC Channel 2

DIDR0 = (1<<ADC2D); // Disable Digital Input on PB2

ADCSRA = (0<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Disable ADC, presc 1:8 for 125kHz ADC-clock

}

/*

* Function: readadc

*

* Created: 4/4/2018 2:01:01 PM

* Author : Dave Adams Se-Kure Controls Inc.

* Description:

* This function enables the ADC, Starts the ADC and then takes 4 readings.

*/

/*void readadc(void)

{

uint8_t i;

uint16_t adc4;

ADCSRA = (1<<ADEN); // Enable the ADC

PRR = (0<<PRADC); // Turning on the ADC

// Take four ADC samples, add them in adc4

for (i = 0, adc4 = 0; i < 4; i++)

{

ADCSRA |= (1<<ADSC); // Start a conversion

while (ADCSRA & (1<<ADSC)) // wait until it's finished

; // Nothing

adc4 += ADCL;

}

}*/

void led_flash(void)

{

LED_ON; // Turn LED On

_delay_ms(100); // Wait 100 ms

LED_OFF; // Turn LED Off

_delay_ms(100); // Wait 100 ms

}

## Attachment(s):

MJBGlobals.h
main.c
ki0bk
Level: Raving Lunatic
Joined: Mon. Sep 8, 2014
Posts: 6615 View posts
Location: Olathe KS
#9
Posted by ki0bk: Fri. Apr 6, 2018 - 07:43 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

I don't think your WDT is being disabled as it requires a timed sequence to disable, gcc should have a built in for this.

I'm not a gcc user so maybe another freak will jump in with the correct incantation.

Jim

dadams8355
Level: New Member
Joined: Mon. Mar 5, 2018
Posts: 17 View posts
#10
Posted by dadams8355: Fri. Apr 6, 2018 - 07:54 PM (Reply to #9)

- 1
- 2
- 3
- 4
- 5

Total votes: 0

What happens it the processor enters into sleep with the sleep_cpu(); instruction and it never exits this instruction. If I put a LED_OFF; instruction right after the sleep_cpu instruction, the LED never turns off.

theusch
Level: 10k+ Postman
Joined: Mon. Feb 19, 2001
Posts: 39665 View posts
Location: Wisconsin USA
#11
Posted by theusch: Fri. Apr 6, 2018 - 07:59 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 1

As mentioned, others that have experience with this family may need to help. But with a quick glance ...

-- learn how to use the Code <> tags on the formatting toolbar. It makes source code much easier to understand. Practice with editing your post, or make another.

-- I cannot tell whether the WDIE is taking effect; I suspect that the sequence is not correct. I don't think that the built-in GCC functions are very good at watchdog interrupt.

-- ...but even if it does, there is a WDIE and no ISR for it.

-- "WDTCSR = 0 ; // Disable watch dog" won't turn off the watchdog, will it? But a moot point as I don't think the watchdog is enabled anyway.

> 10.3.2.1. Safety Level 1
> In this mode, the Watchdog Timer is initially disabled, but can be enabled by writing the WDE bit to one
> without any restriction. A special sequence is needed when disabling an enabled Watchdog Timer. To
> disable an enabled Watchdog Timer, the following procedure must be followed:
> 1. Write the signature for change enable of protected I/O registers to register CCP
> 2. Within four instruction cycles, in the same operation, write WDE and WDP bits

-- I don't see any WDE in your code? I guess that is OK in interrupt mode, so you might be closer than we think.

-- I don't see any SEI in your code.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

ki0bk
Level: Raving Lunatic
Joined: Mon. Sep 8, 2014
Posts: 6615 View posts
Location: Olathe KS
#12
Posted by ki0bk: Fri. Apr 6, 2018 - 08:00 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

The simulator may be helpful here to see if WDT is setup correctly.

theusch
Level: 10k+ Postman
Joined: Mon. Feb 19, 2001
Posts: 39665 View posts
Location: Wisconsin USA
#13
Posted by theusch: Fri. Apr 6, 2018 - 08:05 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

The CodeVisionAVR Wizard code is below. Note several things:

-- CCP register handling

-- Global interrupts turned on after setup

-- Clear of WDIF (though I don't really know what that might be for -- cascading events?

There is also a corresponding empty ISR.

    // Watchdog Timer initialization
    // Watchdog Timer Prescaler: OSC/1024k
    // Watchdog timeout action: Interrupt
    #asm("wdr")
    CCP=0xd8;
    WDTCSR=(1<<WDIF) | (1<<WDIE) | (1<<WDP3) | (0<<WDE) | (0<<WDP2) | (0<<WDP1) | (1<<WDP0);
    // Globally enable interrupts
    #asm("sei")

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

toybuilder
Level: New Member
Joined: Wed. Dec 4, 2013
Posts: 2 View posts
#14
Posted by toybuilder: Sun. Dec 30, 2018 - 07:49 AM (Reply to #7)

- 1
- 2
- 3
- 4
- 5

Total votes: 0

Torby, thank you for making the comment. I was pulling my hair out tonight because I Had missed that detail while reading over the programming section on the datasheet and AtmelStudio doesn't warn you (at least with the AtmelICE)... As soon as I changed my rail to 5V, it just worked...

Lidas
Level: Rookie
Joined: Wed. Jan 8, 2020
Posts: 37 View posts
#15
Posted by Lidas: Sat. Mar 21, 2020 - 12:05 PM

- 1
- 2
- 3
- 4
- 5

Total votes: 0

hello and congratulations for the projects you have published, interested in trying this little cip, I tried to program it with one of your projects but I can't give me this error

Error. “Verifying Flash…Failed! address=0×0000 expected=0×0a actual=oxff

use avr studio 7 and as AVR ISP mk2 programmer

awneil
Level: 10k+ Postman
Joined: Fri. Jul 1, 2005
Posts: 17855 View posts
Location: Basingstoke, Hampshire, UK
#16
Posted by awneil: Sat. Mar 21, 2020 - 01:51 PM (Reply to #15)

- 1
- 2
- 3
- 4
- 5

Total votes: 0

You already have your own thread on this:

https://www.avrfreaks.net/forum/...

Top Tips:

1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
4. Difference between a crystal, and a crystal oscillator: https://www.avrfreaks.net/comment...
5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...

Jump To
Topic locked