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
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
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; } }
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); } } }
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 } }
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.
Thanks.. I think I will use the full size chip for development first.
[The two extra copies of this post have been deleted. Ross]
I like tiny 10s because they're tiny and cheap. Annoying that you can't program them with a 3v supply though.
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
}
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
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.
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.
The simulator may be helpful here to see if WDT is setup correctly.
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")
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...
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