راه اندازی تایمرکانتر در ATtiny26
از پاپیروس
پرش به ناوبریپرش به جستجو
Makefile
MCU=attiny26
FUSE_L=0xe1
FUSE_H=0x17
F_CPU=1000000
CC=avr-gcc
LD=avr-ld
OBJCOPY=avr-objcopy
SIZE=avr-size
AVRDUDE=avrdude
CFLAGS=-std=c99 -Wall -g -Os -mmcu=${MCU} -DF_CPU=${F_CPU} -I.
TARGET=main
CPUNAME=at26
DATE=`(date +%F_%T)| sed 's/://g' | sed 's/-//g'`
SRCS = main-c.c
all:
${CC} ${CFLAGS} -o bin/${TARGET}.o ${SRCS}
${LD} -o bin/${TARGET}.elf bin/${TARGET}.o
${OBJCOPY} -j .text -j .data -O ihex bin/${TARGET}.o bin/${TARGET}.hex
${SIZE} -C --mcu=${MCU} bin/${TARGET}.elf
flash:
${AVRDUDE} -p ${MCU} -c usbasp -B10 -U flash:w:bin/${TARGET}.hex:i -F -P usb
readfb:
avrdude -c usbasp -p ${MCU} -U lfuse:r:fusebits/lf-${CPUNAME}-${DATE}.hex:h -U hfuse:r:fusebits/hf-${CPUNAME}-${DATE}.hex:h -U efuse:r:fusebits/ef-${CPUNAME}-${DATE}.hex:h
clean:
rm -f *.c~ bin/*.o bin/*.elf bin/*.hex
fuse:
$(AVRDUDE) -p ${MCU} -c usbasp -B10 -U hfuse:w:${FUSE_H}:m -U lfuse:w:${FUSE_L}:m
راهاندازی تایمر/کانتر صفر
تایمر صفر
شماتیک
کد برنامه (فایل main.c)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
volatile char myvar = 150; //it could be from 0 to 255
ISR(TIMER0_OVF0_vect)
{
PORTA ^= (1 << PA7); //toggle LED on PA7 (pin 11 of ATtiny26)
TIFR |=( 1<<TOV0); //reset flag. it seems it's not needed
TCNT0 = myvar; //setting initial value of timer. if ignore, timer/counter start from 0 to 255. if set to myvar, it starts from myvar to 255
}
static inline void initTC0(void) {
TCCR0 |= (1<<CS02) | (0<<CS01) | (1<<CS00); //prescaler CK/1024
TIMSK |= (1<<TOIE0); //enable TIMER0_OVF0_vect interrupt
TCNT0 = myvar; //setting initial value of timer. if ignore, timer/counter start from 0 to 255. if set to myvar, it starts from myvar to 255
}
int main(void)
{
initTC0();
DDRA |= (1<<PA7); //set PA7 as output
sei();
while(1){
}
}
کانتر صفر
شماتیک
کد برنامه (فایل main.c)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
volatile char myvar = 251; //it could be from 0 to 255
ISR(TIMER0_OVF0_vect)
{
PORTA ^= (1 << PA7); //toggle LED on PA7 (pin 11 of ATtiny26)
TIFR |=( 1<<TOV0); //reset flag. it seems it's not needed
TCNT0 = myvar; //setting initial value of timer. if ignore, timer/counter start from 0 to 255. if set to myvar, it starts from myvar to 255
}
static inline void initTC0(void) {
TCCR0 |= (1<<CS02) | (1<<CS01) | (1<<CS00); //set clock source as: External Pin T0 (pin 9 of ATtiny26) on rising edge. in order to set on falling edge, change (1<<CS00) to (0<<CS00)
TIMSK |= (1<<TOIE0); //enable TIMER0_OVF0_vect interrupt
TCNT0 = myvar; //setting initial value of timer. if ignore, timer/counter start from 0 to 255. if set to myvar, it starts from myvar to 255
}
int main(void)
{
initTC0();
DDRA |= (1<<PA7) | (1<<PA6); //set PA7 and PA6 as output. PA7 is for demonstrating LED as over follow action and PA6 is for demonstrating LED as input external clock on T0 (pin 9 of ATtiny26)
DDRB &= ~(1 << PB6); //set T0 (pin 9 of ATtiny26) as input
PORTB|= (1 << PB6); //set T0 (pin 9 of ATtiny26) pull-up
sei();
while(1){
PORTA ^= (1 << PA6); //toggle LED on PA6 (pin 12 of ATtiny26) in order to create external clock
_delay_ms(100); //wait for 100 miliseconds
}
}
راهاندازی تایمر/کانتر یک
منبع کلاک می تواند کلاک CPU سیستم (CK) یا کلاک پرسرعت ۶۴ مگاهرتزی درونی (PCK) باشد. البته هر کدام که انتخاب شود با استفاده از prescaler میتوان به فرکانس مورد نظر رسید. یرای استفاده از PCK کافیست مد asynchronous فعال گردد. بعد از فعال شدن این مد، کلاک مورد استفاده تایمر/کانتر شماره یک از CK به PCK تغییر پیدا میکند.
فعال کردن مد asynchronous
PLLCSR |= (1<<PLLE); //enable PLL
while ( ((PLLCSR & (1 << PLOCK)) == 0) ){ //wait for PLL lock
}
PLLCSR |= (1<<PCKE); //enable PCK
در صورت نیاز برای برگشت به CK میتوان:
- از
PLLCSR &= ~(1<<PLLE);استفاده کرد. در این حالت برای برگشت به PCK، باید قطعه کد بالا را مجددا به کار برد. - یا از
PLLCSR &= ~(1<<PCKE);استفاده کرد. در این حالت برای برگشت به PCK، فقط کافیست ازPLLCSR |= (1<<PCKE);استفاده شود.
حالتی که فقط از overfollow استفاده میکنیم. (مقایسهگرهای A و B استفاده نمیشوند)
شماتیک
کد برنامه (فایل main.c)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
ISR(TIMER1_OVF1_vect)
{
PORTA ^= (1 << PA7); //toggle LED on PA7 (pin 11 of ATtiny26)
TIFR |=( 1<<TOV1); //reset flag. it seems it's not needed
}
static inline void initTC1(void) {
PLLCSR |= (1<<PLLE); //enable PLL
while ( ((PLLCSR & (1 << PLOCK)) == 0) ){ //wait for PLL lock
}
PLLCSR |= (1<<PCKE); //enable PCK
TCCR1B |= (1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10); //prescaler CK/16384 or PCK/16384
TCCR1B |= (1<<CTC1); //enable CTC1
TIMSK |= (1<<TOIE1); //enable TIMER1 Over follow interrupt
OCR1C = 0x7E; //maximum value of Timer1. this option works only if CTC1 bit set. otherwise timer/counter counts to 0xFF and after next clock over follow occurred.
}
int main(void)
{
initTC1();
DDRA |= (1<<PA7); //set PA7 as output
sei();
while(1){
}
}
حالتی که از مقایسهگرهای A و B استفاده میکنیم. (از overfollow استفاده نمیشود.)
شماتیک
کد برنامه (فایل main.c)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
ISR(TIMER1_CMPA_vect)
{
//do everything you want;
}
ISR(TIMER1_CMPB_vect)
{
//do everything you want
}
static inline void initTC1(void) {
TCCR1A |= (0<<COM1A1) | (1<<COM1A0); //toggle OC1A (PB1 or pin 2 of ATtiny26)
TCCR1A |= (0<<COM1B1) | (1<<COM1B0); //toggle OC1B (PB3 or pin 4 of ATtiny26)
TCCR1B |= (1<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10); //prescaler setting: CK/16384 or PCK/16384
TCCR1B |= (1<<CTC1); //enable CTC1
TIMSK |= (1<<OCF1A); // Timer/Counter1 Compare Match 1A
TIMSK |= (1<<OCF1B); // Timer/Counter1 Compare Match 1B
OCR1A = 0x1E; //compare value for comparator A
OCR1B = 0x22; //compare value for comparator B
OCR1C = 0x3F; //maximum value of Timer1. this option works only if CTC1 bit set. otherwise timer/counter counts to 0xFF and after next clock over follow occurred.
}
int main(void)
{
initTC1();
DDRB |= (1<<PB1) | (1<<PB3); //set OC1A and OC1B (PB1 and PB3) as output
sei();
while(1){
}
}
با نوشتن TCCR1A |= (1<<FOC1A); (یا متناظر آن FOC1B) میتوان فارغ از مقدار تایمر روی پین OC1A (یا OC1B) اثر گذاشت (شرایط compare match را ایجاد کرد). البته تحت هیچ شرایطی با این کار وقفهای تحریک نخواهد شد.
راهاندازی PWM
شماتیک
کد برنامه (فایل main.c)
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
static inline void initTC1(void) {
TCCR1A |= (1<<PWM1A); //enable PWM A
TCCR1A |= (0<<COM1A1) | (1<<COM1A0); //set OC1A and ~OC1A as output pin for PWM
TCCR1B |= (0<<CS13) | (1<<CS12) | (1<<CS11) | (1<<CS10); //prescaler setting: CK/64 or PCK/64
TCCR1B |= (1<<CTC1); //enable CTC1
OCR1A = 0x10; //compare value for comparator A
OCR1C = 0xFE; //maximum value of Timer1. this option works only if CTC1 bit set. otherwise timer/counter counts to 0xFF and after next clock over follow occurred.
PLLCSR |= (1<<PLLE); //enable PLL
while ( ((PLLCSR & (1 << PLOCK)) == 0) ){ //wait for PLL lock
}
PLLCSR |= (1<<PCKE); //enable PCK
}
int main(void)
{
initTC1();
DDRB |= (1<<PB1) | (1<<PB0); //set OC1A and ~OC1A (PB1 and PB0) as output
sei();
while(1){
}
}