Задание 3. Примеры для ATtiny2313 ("Бегущие огни")

Задание 3. Примеры для ATtiny2313 ("Бегущие огни")

Сообщение ZuykovAV MEPhI » 20 ноя 2011, 22:54

Автомат 8-ми канального «бегущего огня» (по мотивам 5-го задания раздела «Первые шаги»)

Порядок действий:

1. Собрать схему.
2. Разобрать примеры.
3. Выполнить задание.

1. Схема:
Изображения принципиальной схемы в теме нет, но её надо собрать на макетке, учитывая разницу между мк ATtiny13 и ATtiny 2313. Как и в схеме с ATtiny13 для ATtiny2313 необходимо подвести линии питания и от программатора (GND, сигналы MOSI, Reset, SCK, МISO), подключить индикацию (был один светодиод, здесь восемь) и кнопки (была одна кнопка, здесь две). 8 светодиодов шкалы (из 10-ти) анодными выводами подключаются к 8-ми выводам МК ( PORTB, разряды PB0-PB7, крайний левый светодиод - разряд PB7), а со стороны катодов через сопротивления 1 кОм подключаются к GND (земле). Две кнопки подключаются к входам INT0 и INT1.

Если используется программатор STK200/300, то на него (через шлейф и соединительные разъёмы) ещё необходимо подать питающее напряжение +5 вольт (линия VCC).

Рекомендуемое расположение заданий на маленькой макетке. Слева расположены детали схемы с мк ATtiny13, а справа – детали схемы с мк ATtiny2313. В следующем задание используются оба микроконтроллера.

Изображение

2. Примеры:
На примерах последовательно создается 8-ми канальный реверсивный «бегущий огонь», работающий в режимах Счёт/Сдвиг.
Две кнопки переключают режим и направление. Тактирование выполняется от таймера МК. Рабочая частота МК - 500 кГц (4000000/8).

3. Задание: (выполняется после примеров)
Продолжите работу над созданием устройства. Оно должно работать с автоматической сменой: режимов работы Счёт/Сдвиг, направлением движения, с разными вариантами начальной установки в режиме Сдвиг (аналогично 5-му заданию). Тактирование нужно сделать от внешнего генератора (2-го или 7-го задания). Схема тактового генератора собирается (или устанавливается как модуль -*) в центральной пустой зоне макетки.

(*) - Внимание ! Схему тактового генератора 7-го задания ("Первые шаги") для установки на макетке можно спаять (кто умеет). Печатную плату можно получить на занятиях. Для варианта печатной платы с выводными элементами используются ранее полученные детали.
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 20 ноя 2011, 23:08

Пример 1. Проверка индикатора на PORTB.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

#include <avr/io.h>           

int main(void) {
  PORTA = 0b11111111; // Могут использоваться A0, A1. A2 - Reset
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111; // Могут использоваться D0-D6
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111; // PB0-PB7 - через сопротивления 1 кОм к анодам индикатора
  DDRB  = 0b11111111;
      
  while (1) {};
}
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 20 ноя 2011, 23:14

Пример 2. Проверка кнопок на INT0 и INT1.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

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

SIGNAL(SIG_INTERRUPT0) {         
  if (bit_is_set(PIND,PD2)) PORTB = 0b11111111; else PORTB = 0b00000000;
}       

SIGNAL(SIG_INTERRUPT1) { 
  if (bit_is_set(PIND,PD3)) PORTB = 0b11111111; else PORTB = 0b00000000; 
}     

int main(void) {
  PORTA = 0b11111111;
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111;
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111;
  DDRB  = 0b11111111;

  GIMSK = 0b11000000;  // Разрешение прерываний INT0 и INT1
  MCUCR = 0b00000101;  // при любом перепаде

  sei();

  while (1) {};
}
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 20 ноя 2011, 23:45

Пример 3. Тактирование от таймера.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

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

// =====TIM0=====
#define TIM0_ON   TCCR0A = 0x00; TCCR0B =0x05; TIMSK |= 0b00000010  // Делитель на 1024 и прерывание по переполнению
#define TCNT_ON   TCNT0 = 0x100-125
#define TIM0_OFF  TCCR0B = 0x00; TIMSK &= 0b11111101                // Таймер выключён

SIGNAL(SIG_OVERFLOW0) {
  TCNT_ON;
  PORTB ^= 0b11111111;
}

SIGNAL(SIG_INTERRUPT0) { 
  if (bit_is_clear(PIND,PD2)) { TIM0_OFF; PORTB = 0b11111111; } else { TIM0_ON; } 
}       

SIGNAL(SIG_INTERRUPT1) { 
  if (bit_is_clear(PIND,PD3)) { TIM0_OFF; PORTB = 0b00000000; } else { TIM0_ON; }   
}       

int main(void) {
  PORTA = 0b11111111;
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111;
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111;
  DDRB  = 0b11111111;
      
  GIMSK = 0b11000000;
  MCUCR = 0b00000101;
   
  TIM0_ON;
  TCNT_ON;

  sei();

  while (1) {};
}

Используется прерывание по переполнению.
500000 / 1024 = 488 Гц или 1 / 488 = 0.002 с - время одного такта.
0-й таймер 8-ми разрядный - это 256 циклов (0xFF), у него переполнение - это 0x100.
Пусть тактирование будет через 0.25 с, значит, в регистр TCNT0 надо записать число 0.25/0.002 = 125 (TCNT0=0x100-125)
и разрешить прерывание по переполнению для таймера 0: TIMSK |= 0x02.

Дополнительно, тема для работы с таймером : Таймер в микроконтроллере AVR ATtiny2313.
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 20 ноя 2011, 23:57

Пример 4. Режим сдвига.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

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

// =====TIM0=====
#define TIM0_ON   TCCR0A = 0x00; TCCR0B =0x05; TIMSK |= 0b00000010  // Делитель на 1024 и прерывание по переполнению
#define TCNT_ON   TCNT0 = 0x100-125
#define TIM0_OFF  TCCR0B = 0x00; TIMSK &= 0b11111101                // Таймер выключён

unsigned char nu = 0b10000000; // начальная установка сдвига
unsigned char reg;             // сдвиговый регистр
unsigned char c = 0;           // такт сдвига
unsigned char u;               //

void bo (void) { // режим сдвига
  if (c == 0) reg=nu;
  else {
    if (reg & 0x01) u=1; else u=0;
    reg>>=1;
    if (u==1) reg|=0x80;
  }
}

SIGNAL(SIG_OVERFLOW0) {
  TCNT_ON;
  bo();       // режим сдвига
  PORTB=reg;  // вывод
  c=c+1;      // на следующий такт
}

SIGNAL(SIG_INTERRUPT0) { 
  if (bit_is_clear(PIND,PD2)) { TIM0_OFF; PORTB = 0b11111111; } else { TIM0_ON; }
}       

SIGNAL(SIG_INTERRUPT1) { 
  if (bit_is_clear(PIND,PD3)) { TIM0_OFF; PORTB = 0b00000000; } else { TIM0_ON; }   


int main(void) {
  PORTA = 0b11111111;
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111;
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111;
  DDRB  = 0b11111111;
      
  GIMSK = 0b11000000;
  MCUCR = 0b00000101;
   
  TIM0_ON;
  TCNT_ON;

  sei();

  while (1) {};
}


Внимание !

В итоговом задании темы (в конце 8-го Примера) предлагается оптимизировать (уменьшить) код режима "Сдвиг" и поэтому размышлять над оптимизацией кода можно уже начиная с этого примера.
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 22 ноя 2011, 23:57

Пример 5. Изменение направления и управление от кнопки.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

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

// =====TIM0=====
#define TIM0_ON   TCCR0A = 0x00; TCCR0B =0x05; TIMSK |= 0b00000010  // Делитель на 1024 и прерывание по переполнению
#define TCNT_ON   TCNT0 = 0x100-125
#define TIM0_OFF  TCCR0B = 0x00; TIMSK &= 0b11111101                // Таймер выключён

unsigned char nu = 0b10000000; // начальная установка сдвига
unsigned char reg;             // сдвиговый регистр
unsigned char c = 0;           // такт сдвига
unsigned char u;               //
char rl=1;                     // направление 1-(8-->1); 0-(8<--1)

void bo (void) { // режим сдвига
  if (c == 0) reg=nu;
  else {
    if (rl==0) {
      if (reg&0x80) u=1; else u=0;
      reg<<=1;
      if (u==1) reg|=0x01;
    }
    else {
      if (reg&0x01) u=1; else u=0;
      reg>>=1;
      if (u==1) reg|=0x80;
    }
  }
}

SIGNAL(SIG_OVERFLOW0) {
  TCNT_ON;
  bo();       // режим сдвига
  PORTB=reg;  // вывод
  c=c+1;      // на следующий такт
}

SIGNAL(SIG_INTERRUPT0) { 
  if (bit_is_clear(PIND,PD2)) rl=0; else rl=1; 
}       

SIGNAL(SIG_INTERRUPT1) { 
  if (bit_is_clear(PIND,PD3)) { TIM0_OFF; PORTB = 0b00000000; } else { TIM0_ON; }   


int main(void) {
  PORTA = 0b11111111;
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111;
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111;
  DDRB  = 0b11111111;
      
  GIMSK = 0b11000000;
  MCUCR = 0b00000101;
   
  TIM0_ON;
  TCNT_ON;

  sei();

  while (1) {};
}
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 23 ноя 2011, 00:04

Пример 6. Режим счёта.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

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

// =====TIM0=====
#define TIM0_ON   TCCR0A = 0x00; TCCR0B =0x05; TIMSK |= 0b00000010  // Делитель на 1024 и прерывание по переполнению
#define TCNT_ON   TCNT0 = 0x100-125
#define TIM0_OFF  TCCR0B = 0x00; TIMSK &= 0b11111101                // Таймер выключён

unsigned char nu = 0b10000000; // начальная установка сдвига
unsigned char reg;             // сдвиговый регистр
unsigned char c = 0;           // такт сдвига
unsigned char u;               //
char rl=1;                     // направление 1-(8-->1); 0-(8<--1)

void bs (void) { // режим счёта
  if (c==0) reg=0b00000000;
  else {
    if (rl==0) {
      if ((reg&128)==0) { reg<<=1; reg|=0x01; } else reg<<=1;
    }
    else {
      if ((reg&1)==0) { reg>>=1; reg|=0x80; } else reg>>=1;
    }
  }
}

SIGNAL(SIG_OVERFLOW0) {
  TCNT_ON;
  bs();       // режим счёта
  PORTB=reg;  // вывод
  c=c+1;      // на следующий такт
}

SIGNAL(SIG_INTERRUPT0) { 
  if (bit_is_clear(PIND,PD2)) rl=0; else rl=1; 
}       

SIGNAL(SIG_INTERRUPT1) {       
  if (bit_is_clear(PIND,PD3)) { TIM0_OFF; PORTB = 0b00000000; } else { TIM0_ON; }   


int main(void) {
  PORTA = 0b11111111;
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111;
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111;
  DDRB  = 0b11111111;
      
  GIMSK = 0b11000000;
  MCUCR = 0b00000101;
   
  TIM0_ON;
  TCNT_ON;

  sei();

  while (1) {};
}
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 23 ноя 2011, 09:24

Пример 7. Переключение режимов Счёт/Сдвиг от кнопки.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

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

// =====TIM0=====
#define TIM0_ON   TCCR0A = 0x00; TCCR0B =0x05; TIMSK |= 0b00000010  // Делитель на 1024 и прерывание по переполнению
#define TCNT_ON   TCNT0 = 0x100-125
#define TIM0_OFF  TCCR0B = 0x00; TIMSK &= 0b11111101                // Таймер выключён

unsigned char nu = 0b10000000; // начальная установка сдвига
unsigned char reg;             // сдвиговый регистр
unsigned char c = 0;           // такт сдвига
unsigned char u;               //
char rl=1;                     // направление 1-(8-->1); 0-(8<--1)
char ss=1;                     // выбор режима

void bo (void) { // режим сдвига
  if (c == 0) reg=nu;
  else {
    if (rl==0) {
      if (reg&0x80) u=1; else u=0;
      reg<<=1;
      if (u==1) reg|=0x01;
    }
    else {
      if (reg&0x01) u=1; else u=0;
      reg>>=1;
      if (u==1) reg|=0x80;
    }
  }
}

void bs (void) { // режим счёта
  if (c==0) reg=0b00000000;
  else {
    if (rl==0) {
      if ((reg&128)==0) { reg<<=1; reg|=0x01; } else reg<<=1;
    }
    else {
      if ((reg&1)==0) { reg>>=1; reg|=0x80; } else reg>>=1;
    }
  }
}

SIGNAL(SIG_OVERFLOW0) {
  TCNT_ON;
  if (ss==0) bs();
  else bo();
  PORTB=reg;  // вывод
  c=c+1;      // на следующий такт
}

SIGNAL(SIG_INTERRUPT0) { 
  if (bit_is_clear(PIND,PD2)) rl=0; else rl=1; 
}       

SIGNAL(SIG_INTERRUPT1) { 
  if (bit_is_set(PIND,PD3)) ss=1; else { ss=0; c=0; }


int main(void) {
  PORTA = 0b11111111;
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111;
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111;
  DDRB  = 0b11111111;
      
  GIMSK = 0b11000000;
  MCUCR = 0b00000101;
   
  TIM0_ON;
  TCNT_ON;

  sei();

  while (1) {};
}

Обратите внимание !
При работе режима Счёт на индикаторе могут быть состояния 00000000 и 11111111. Если в это время включить режим Сдвиг, то эти состояния так и остаются на индикаторе и всё останавливается. Следующий пример исправляет эту ситуацию.
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52

Re: Задание 2. Примеры для ATtiny2313

Сообщение ZuykovAV MEPhI » 23 ноя 2011, 09:30

Пример 8. Устранение сбоя при переключении с Счёта на Сдвиг.

Код: выделить все
//мк ATtiny2313
//F_CPU = 4000000/8=500000

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

// =====TIM0=====
#define TIM0_ON   TCCR0A = 0x00; TCCR0B =0x05; TIMSK |= 0b00000010  // Делитель на 1024 и прерывание по переполнению
#define TCNT_ON   TCNT0 = 0x100-125
#define TIM0_OFF  TCCR0B = 0x00; TIMSK &= 0b11111101                // Таймер выключён

unsigned char nu = 0b10000000; // начальная установка сдвига
unsigned char reg;             // сдвиговый регистр
unsigned char c = 0;           // такт сдвига
unsigned char u;               //
char rl=1;                     // направление 1-(8-->1); 0-(8<--1)
char ss=1;                     // выбор режима

void bo (void) { // режим сдвига
  if (c == 0) reg=nu;
  else {
    if (rl==0) {
      if (reg&0x80) u=1; else u=0;
      reg<<=1;
      if (u==1) reg|=0x01;
    }
    else {
      if (reg&0x01) u=1; else u=0;
      reg>>=1;
      if (u==1) reg|=0x80;
    }
  }
}

void bs (void) { // режим счёта
  if (c==0) reg=0b00000000;
  else {
    if (rl==0) {
      if ((reg&128)==0) { reg<<=1; reg|=0x01; } else reg<<=1;
    }
    else {
      if ((reg&1)==0) { reg>>=1; reg|=0x80; } else reg>>=1;
    }
  }
}

SIGNAL(SIG_OVERFLOW0) {
  TCNT_ON;
  if (ss==0) bs();
  else bo();
  PORTB=reg;  // вывод
  c=c+1;      // на следующий такт
}

SIGNAL(SIG_INTERRUPT0) { 
  if (bit_is_clear(PIND,PD2)) rl=0; else rl=1; 
}       

SIGNAL(SIG_INTERRUPT1) { 
  if (bit_is_set(PIND,PD3)) {
    ss=1;
    if (reg==0) { reg=0x80; c=0; }
    if (reg==255) reg=0xFE;
  }
  else { ss=0; c=0; } 


int main(void) {
  PORTA = 0b11111111;
  DDRA  = 0b00000000;
   
  PORTD = 0b11111111;
  DDRD  = 0b00000000;
   
  PORTB = 0b11111111;
  DDRB  = 0b11111111;
      
  GIMSK = 0b11000000;
  MCUCR = 0b00000101;
   
  TIM0_ON;
  TCNT_ON;

  sei();

  while (1) {};
}

Задание (выполняется после примеров).
Продолжите работу над созданием устройства. Оно должно работать с автоматической сменой: режимов работы Счёт/Сдвиг, направлением движения, с разными вариантами начальной установки в режиме Сдвиг (аналогично 5-ому заданию "Первые шаги"). Тактирование нужно сделать от внешнего генератора (2-го или 7-го задания "Первые шаги"). Также предлагается оптимизировать код в режиме "Сдвиг".
ZuykovAV MEPhI
 
Сообщений: 110
Зарегистрирован: 06 мар 2011, 15:52


Вернуться в Микроконтроллеры - Задания и примеры

Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 5