реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Генератор прямоугольных импульсов на AVR
PhX
сообщение Nov 11 2008, 04:21
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 473
Регистрация: 10-09-06
Из: Тольятти. Самарская обл.
Пользователь №: 20 249



Добрый день, необходимо управлять скоростью вращения шагового двигателя, для этого на плату управления двигателем нужно подавать прямоугольные импульсы с платы микроконтроллера.
Для начала написал это:
Код
#include <avr/io.h>
#include <avr/interrupt.h>

#define Frq 20 //Частота импульсов Гц


// Конфигурирование Timer1
void Timer1_init(void)
{
  TCCR1B |= 0x04; //Частота счета таймера Sclk/256
  TCCR1B |= 0x08; //Вкл CTC
  TCCR1A |= 0x40; //Активировать выход OC1A
  OCR1A = F_CPU/(256*Frq); //Определяем соответствующее значение для Frq
}

void Inter_init(void)
{
  TIMSK = 0x00; //Запрещаем все прерывания
  GIMSK = 0x00; //Запрет внешних прерываний
  cli(); //Общее запрещение прерываний;
}  

// Конфигурирование портов В/В
void Ports_init(void)
{
  DDRB = 0x0F; // PB1 Выход
}

int main (void)
{
  Ports_init();
  Timer1_init();
  Inter_init();
  while(1) {}  
  return 1;
}

Это работает нормально.
Теперь хочу плавно регулировать частоту:
Код
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define Frq 20 //Частота импульсов Гц

//Функция задания частоты
void SetSpeed(const unsigned int w)
{
  OCR1A = (F_CPU/w)>>8;
}

// Конфигурирование Timer1
void Timer1_init(void)
{
  TCCR1B |= 0x04; //Частота счета таймера Sclk/256
  TCCR1B |= 0x08; //Вкл CTC
  TCCR1A |= 0x40; //Активировать выход OC1A
  OCR1A = F_CPU/(256*Frq); //Определяем соответствующее значение для Frq
}

void Inter_init(void)
{
  TIMSK = 0x00; //Запрещаем все прерывания
  GIMSK = 0x00; //Запрет внешних прерываний
  cli(); //Общее запрещение прерываний;
}  

// Конфигурирование портов В/В
void Ports_init(void)
{
  DDRB = 0x0F; // PB1 Выход
}

int main (void)
{
  unsigned int i;
  Ports_init();
  Timer1_init();
  Inter_init();
  while(1)
  {
    while (i<5000)
    {
        SetSpeed(i); i++;
        _delay_ms(10);
    }
    _delay_ms(1000);
    while (i>2)
    {
        SetSpeed(i); i--;
        _delay_ms(10);
    }
  }  
  return 1;
}

Это работает весьма странно... Иногда нормально, а иногда импульсы прекращаются и на ноге OC1A устанавливается 0 или 1. 07.gif Прерывания вроде бы отключены.


--------------------
Если все, то не я...
Go to the top of the page
 
+Quote Post
ARV
сообщение Nov 11 2008, 05:41
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581



...

Сообщение отредактировал ARV - Nov 11 2008, 05:43


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
PhX
сообщение Nov 11 2008, 05:51
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 473
Регистрация: 10-09-06
Из: Тольятти. Самарская обл.
Пользователь №: 20 249



Цитата(ARV @ Nov 11 2008, 09:41) *
...

Эскизы прикрепленных изображений
Прикрепленное изображение
 


--------------------
Если все, то не я...
Go to the top of the page
 
+Quote Post
=GM=
сообщение Nov 11 2008, 09:51
Сообщение #4


Ambidexter
*****

Группа: Свой
Сообщений: 1 589
Регистрация: 22-06-06
Из: Oxford, UK
Пользователь №: 18 282



Цитата(PhX @ Nov 11 2008, 04:21) *
Это работает весьма странно... Иногда нормально, а иногда импульсы прекращаются и на ноге OC1A устанавливается 0 или 1

Возможно, при больших i вы устанавливаете OCR1A = (F_CPU/i)>>8 в 0, при этом CTC не срабатывает.


--------------------
Делай сразу хорошо, плохо само получится
Go to the top of the page
 
+Quote Post
PhX
сообщение Nov 12 2008, 08:04
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 473
Регистрация: 10-09-06
Из: Тольятти. Самарская обл.
Пользователь №: 20 249



Проблема похоже в том, что когда OCR1A устанавливается ниже текущего значения TCNT1 таймер продолжает долго и упорно считать до FFFF и уже затем до OCR1A...
Можно конечно перед изменением OCR1A изменять TCNT1=0, но мне кажется это не самый лучший путь. Я почти уверен, что задача варьирования частоты прямоугольных импульсов решалась на avr множество раз. Если кто знает, поделитесь решением.


--------------------
Если все, то не я...
Go to the top of the page
 
+Quote Post
GDI
сообщение Nov 12 2008, 09:01
Сообщение #6


Профессионал
*****

Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008



Вообще то регистры OCRx реально перезаписываются в момент переполнения таймера, т.е. они с двойной буферизацией.


--------------------
http://www.embedders.org Блоги разработчиков электроники.
Go to the top of the page
 
+Quote Post
gormih
сообщение Nov 12 2008, 09:10
Сообщение #7


nofb
***

Группа: Свой
Сообщений: 430
Регистрация: 18-05-06
Из: Москва, Зеленоград
Пользователь №: 17 218



Цитата(GDI @ Nov 12 2008, 12:01) *
Вообще то регистры OCRx реально перезаписываются в момент переполнения таймера, т.е. они с двойной буферизацией.

Это всего лишь влияет на фазу.


--------------------
Это не то что вы подумали ...

Go to the top of the page
 
+Quote Post
PhX
сообщение Nov 12 2008, 09:11
Сообщение #8


Местный
***

Группа: Свой
Сообщений: 473
Регистрация: 10-09-06
Из: Тольятти. Самарская обл.
Пользователь №: 20 249



Цитата(GDI @ Nov 12 2008, 13:01) *
Вообще то регистры OCRx реально перезаписываются в момент переполнения таймера, т.е. они с двойной буферизацией.

Вот это как раз то, что нужно! Как же это реализовать?
Видимо строчка вроде:
OCR1A = A;
этого не обеспечивает.


--------------------
Если все, то не я...
Go to the top of the page
 
+Quote Post
GDI
сообщение Nov 12 2008, 09:23
Сообщение #9


Профессионал
*****

Группа: Свой
Сообщений: 1 235
Регистрация: 14-05-05
Из: Санкт-Петербург
Пользователь №: 5 008



Именно это она и обеспечивает, т.е. реальная запись в регистр таймера произойдет только после того как предыдущая фаза будет закончена.

Цитата
Проблема похоже в том, что когда OCR1A устанавливается ниже текущего значения TCNT1 таймер продолжает долго и упорно считать до FFFF и уже затем до OCR1A...

Не будет такого. таймер досчитает до предыдущего значения OCR, и в этот момент произойдет перезапись нового значения в OCR, а таймер обнулится.


--------------------
http://www.embedders.org Блоги разработчиков электроники.
Go to the top of the page
 
+Quote Post
gormih
сообщение Nov 12 2008, 09:28
Сообщение #10


nofb
***

Группа: Свой
Сообщений: 430
Регистрация: 18-05-06
Из: Москва, Зеленоград
Пользователь №: 17 218



Цитата(PhX @ Nov 11 2008, 07:21) *
Это работает весьма странно... Иногда нормально, а иногда импульсы прекращаются и на ноге OC1A устанавливается 0 или 1. 07.gif Прерывания вроде бы отключены.

Иногда и иногда - это когда? Если исходник не меняешь, а эффект наступает случайно - то это не программный сбой.


--------------------
Это не то что вы подумали ...

Go to the top of the page
 
+Quote Post
sansnotfor
сообщение Nov 12 2008, 10:11
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 17
Регистрация: 24-10-08
Пользователь №: 41 157



тоже нужно было генерить меандр, а генератора под рукой не было... вот что пришлось сваять.

Код
.....
unsigned char state_encoder=0;
unsigned int timer_tmp=4000; //начальное значение для OCR1A

void timer_init(void)
{
  TIMSK=(1<<TOIE0)|(1<<OCIE1A);
  TCNT0=TCNT0_const;
  TCCR0=TCCR0_const;  

  TCNT1=0;
  TCCR1A=(0<<COM1A1)|(1<<COM1A0)|(0<<WGM11)|(0<<WGM10);
  TCCR1B=(0<<WGM13)|(0<<WGM12)|(0<<CS12)|(0<<CS11)|(1<<CS10);
  OCR1A=timer_tmp;  
}


....

int main( void )
{
port_init();
Init_Encoder();
timer_init();
asm("sei");  


while(1)
{
if((state_encoder)!=0)
{
   if (state_encoder==0x01) {timer_tmp-=10;}
   else
   {
     if (state_encoder==0xff) {timer_tmp+=10;}
   }
   state_encoder=0;
}
}  


return 0;
}


//опрос энкодера
#pragma vector=TIMER0_OVF_vect
__interrupt void timer0_ovf_my(void)
{
  TCNT0=TCNT0_const;
  state_encoder=Read_Encoder();
  
}


#pragma vector=TIMER1_COMPA_vect
__interrupt void timer1_compa_my(void)
{
  TCNT1=0;
  OCR1A=timer_tmp;  
}


значение для timer_tmp устанавливается энкодером в основном цикле программы, а обновление OCR1A происходит в прерывании таймера1. прямоугольный сигнал генерится на выводе PD5(OC1A)
Go to the top of the page
 
+Quote Post
МП41
сообщение Nov 12 2008, 14:11
Сообщение #12


4 синих кубика
****

Группа: Участник
Сообщений: 526
Регистрация: 19-09-08
Из: полупроводника, металла и стекла
Пользователь №: 40 326



При записи в регистры Таймера1, например, в OCR1A, есть ньюансы. Эти ньюансы описаны в даташите, указан порядок заполнения старшего и младшего байтов регистра, правда это для ассемблера, а Си вроде как должен знать эту особенность (так написано). Я на асме писал в регистры не в том порядке и долго не мог добиться, чтобы срабатывало прерывание по совпадению, хотя в AVRStudio всё пошагово отрабатывалось как надо. Кстати, в Proteus'е тоже ерунду показывало, точно как на макете было, покуда не учёл этот ньюанс. Казалось бы мелочь, а времени потерял вагон.


--------------------
p-n-p-p-n-p-n-n-p-n-p структура однако очень эффективна
Go to the top of the page
 
+Quote Post
PhX
сообщение Nov 12 2008, 15:12
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 473
Регистрация: 10-09-06
Из: Тольятти. Самарская обл.
Пользователь №: 20 249



Вообщем GDI был прав, но почему-то поправил пост... 05.gif Постеснялся наверное...
Код
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define Frq 10 //×åñòîòà ïåðåêëþ÷åíèÿ Ãö

void SetSpeed(uint16_t w)
{
    uint8_t sreg;
    sreg = SREG;
    cli();
    OCR1A = (F_CPU>>3)/w;
    SREG = sreg;
}
// Êîíôèãóðèðîâàíèå Timer1
void Timer1_init(void)
{
  TCCR1B |= 0x02; //×àñòîòà ñ÷åòà òàéìåðà Sclk/256
  TCCR1B |= 0x18; //Âêë fast PWM
  TCCR1A |= 0x03; //ñ 50% ïðîäîëæèòåëüíîñòüþ öèêëà
  TCCR1A |= 0x40; //Àêòèâèðîâàòü âûõîä OC1A
  OCR1A = (F_CPU>>3)/Frq; //Îïðåäåëÿåì ñîîòâåòñòâóþùåå çíà÷åíèå äëÿ Frq
}

void Inter_init(void)
{
  TIMSK = 0x00; //Çàïðåùàåì âñå ïðåðûâàíèÿ
  GIMSK = 0x00; //Çàïðåò âíåøíèõ ïðåðûâàíèé
  cli(); //Îáùåå çàïðåùåíèå ïðåðûâàíèé;
}  

// Êîíôèãóðèðîâàíèå ïîðòîâ Â/Â
void Ports_init(void)
{
  DDRB = 0x0F; // PB1 Âûõîä
}

int main(void)
{
  uint16_t i=10;
  Ports_init();
  Timer1_init();
  Inter_init();
  while(1)
  {
      for (i=10; i<10000; i=i+10)
      {
      SetSpeed(i);
      _delay_ms(20);
      }
      for (; i>10; i=i-10)
    {
      SetSpeed(i);
      _delay_ms(20);
    }
  }  
  return 1;
}

А вот решение проблемы:
Эскизы прикрепленных изображений
Прикрепленное изображение
 


--------------------
Если все, то не я...
Go to the top of the page
 
+Quote Post
Roger
сообщение Nov 14 2008, 21:18
Сообщение #14


Участник
*

Группа: Участник
Сообщений: 69
Регистрация: 27-06-06
Пользователь №: 18 383



От себя могу добавить что програматор запустился под вистой с драйверами выложеными несколько странци назад, единственно с прошивкой была, нет protoss, а выложенной ранее. вроде так на стр 5, mail.hex.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 14:03
Рейтинг@Mail.ru


Страница сгенерированна за 0.01498 секунд с 7
ELECTRONIX ©2004-2016