МК - Моторчик - Фотопрерыватель
|
|
Участник
8 сообщений
Мужчина
|
Имеется: - средство разработки TE-Mini168 (ATmega168) - драйвер L293D - щелевой фотопрерыватель BITR9707 (DINT-5200) - программатор KIT BM9010 USB - электродвигатель F280-23100 9.0V (моторчик, на конце прикреплена типа шторка вида X, для датчика) - AVR Studio 5.0 - MathLab - Proteus 7 Professional
Необходимо: - все это дело собрать - написать прошивку: входные данные - для оборотов моторчика, выходные данные - данные с датчика - соединить с MathLab: нужно в зависимости от получаемых данных с датчика, управлять оборотами двигателя
P.S.: Пока что в ISIS запускал простейшую прошивку, написанную мною (впервые этим заниматься начал). Но чувствую что сам не справлюсь, особенно с MathLab. Как связать с MathLab вообще не понял.
Не до конца еще собран, т.к. пока что на стадии написания прошивки, а ее работу проверяю в эмуляторе ISIS. Сейчас вот пытаюсь разобраться с ШИМ сигналом от МК к драйверу. Кто-нибудь может помочь с кодом?
ISIS.zip
(38.4 Kb)
·
AVR.zip
(13.2 Kb)
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
nightmare когда читал на сайтах и форумах про UART, наткнулся на ссылку для генерации кода (AVR/Си) =) Там выбрал свой МК (ATmega168) и галочкой включил usarts, поставил Baudrate=9600, на что он выдал:
Code #include <avr/io.h> #include <avr/interrupt.h> #define RAMSTART 0x0100 #define RAMSIZE (RAMEND-RAMSTART+1) #define nop() asm volatile ("nop") #define sleep() asm volatile ("nop")
unsigned char usart0_read() { while (!(UCSRA & (1<<RXC))) ; return UDR; } void usart0_write(unsigned char data) { while (!(UCSRA & (1<<UDRE))) ; UDR = data; }
int main() { // usart '0' // settings: 9600 8-n-1 // real baud = 9615 // error = 0.15624999999999112% UCSRA = 0; UCSRB = (1<<RXEN)|(1<<TXEN); UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); UBRRH = 0; UBRRL = 103;
// --- main loop --- sei(); for (;;) sleep(); // ... add your application code here return 0; }
|
|
|
|
|
Начальная группа
1798 сообщений
Мужчина
|
Похоже, лишнего правда нагенерило немного.
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
Quote (nightmare) Похоже, лишнего правда нагенерило немного. на все случаи использования мб) либо мне стоило изменить еще какие-то параметры...
|
|
|
|
|
Начальная группа
1798 сообщений
Мужчина
|
Не пробовали еще байты через UART отправлять?
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
Неа, из того что я понял, разбирая примеры и читая в инете про UART, вот:
Рассчитываем UBBR = XTAL / (16 * baudrate) - 1 = 10000000 / (16 * 9600) - 1 = 64,104166666 XTAL - рабочая тактовая частота контроллера rate - выбрал 9600, вродь норм самый умножаем на 16, а не на 8 в формуле, тк не включаем ускорение - U2X
Поехали, после библиотек пишем: Code #define buffer_MAX 16 // длина буфера char buffer[buffer_MAX] = "0123456789ABCDEF"; // то что в буфере uint8_t buffer_index=0;
// Использовать будем буфер допустим, далее пишем:
ISR (USART_UDRE_vect) // прерывание по опустошению буфера { buffer_index++; // увеличиваем индекс if(buffer_index == buffer_MAX) // проверка на то, ввели ли весь индекс { UCSRB &=~(1<<UDRIE); // UDRIE - сигнализирует о том, готов ли UDR к приему нового байту, тут проверка на это } else { UDR = buffer[buffer_index]; // когда что-то читаем с UDR - мы берем данные с пк, когда записываем в него, UDR отправляет, как в данном случае } }
int main(void) { #define baudrate 9600L #define bauddivider (F_CPU/(16*baudrate)-1) #define HI(x) ((x)>>8) #define LO(x) ((x)& 0xFF)
// Инициализация стандартна:
// UBRRL:UBRRH - скорость UBRRL = LO(bauddivider); // т.к. расчитали ранее, то можно записать тут просто = 64; UBRRH = HI(bauddivider); // а тут = 0; UCSRA = 0; // завершение приема и передачи, ставим - 0, тк нам этого не над UCSRB = 1<<RXEN|1<<TXEN|0<<RXCIE|0<<TXCIE; // выставляем флаги: RXEN и TXEN - разрешают прием и передачу, RXC и TXC - флаги завершения передачи и прием UCSRC = 1<<URSEL|1<<UCSZ0|1<<UCSZ1;
// и в конце, после всех настроек (ну типа свои еще какие-то):
sei(); // разрешаем прерывания.
buffer_index=0; // сбрасываем индекс UDR = buffer[0]; // отправляем первый байт UCSRB|=(1<<UDRIE); // Разрешаем прерывание UDRE
while(1) { // тут свое... } } А для своего не могу понять что и как отправлять, принимать тоже... А примеры эти понял вроде...
Добавлено (27.11.2011, 21:34) ---------------------------------------------
Пользуясь кодами и т.д. с инета, у меня либо Proteus ISIS зависал, либо ШИМ переставал работать нормально... В итоге в даташите нашел как более правильно настроить и теперь вроде как все нормально... Написал в коде "эхо", чтобы набрал в терминале чтот, а он тебе в обратку... В Proteus ISIS нашел Virtual Terminal, подключил его RXD и TXD ножки, но что-либо писать в терминал не выходит.. Поэтому даже не знаю как мне проверить... Думал сначала проверю работает ли вообще, патом буду отправлять данные с оптопары и принимать данные для управления ШИМом...
Вот код: Code #define F_CPU 1000000UL //частота мк #include <avr/io.h> // общая библиотека #include <avr/iom168.h> // atmega168 #include <util/delay.h> // для паузы: _delay_ms(1); #include <avr/interrupt.h> //Библиотека прерываний
//Перечисляем прототипы функций void USART_Init(unsigned int ubrr); //Функция инициализации модуля USART unsigned char USART_Receive(void); //Функция приема данных по протоколу USART void USART_Transmit(unsigned char data); //Функция передачи данных по протоколу USART
unsigned int counter = 0;
#define IN1 PB0 #define IN2 PB3 #define LED PD4
ISR(INT0_vect) { counter++; // счетчик оборотов if(counter == 250) { PORTB &= ~(1<<IN1); // стоп PORTD |= (1<<LED); // после остановки загорается лампочка } }
int main(void) { // "0" на ножку PD0 - обороты увеличиваются, на ножку PD1 - обороты уменьшаются unsigned int i=0;
// порты ввода-вывода: PORTB = 0x00; DDRB = (1 << PB1)|(1<<PB0)|(1<<PB3); PORTD = (1 << PD0)|(1 << PD1); DDRD = (1<<PD4);
// ШИМ, режим FAST PWM: TCCR1A = (1 << COM1A1)|(0 << COM1A0)|(1 << WGM11)|(0 << WGM10); TCCR1B = (1 << WGM13)|(1 << WGM12)|(0 << CS12)|(0 << CS11)|(1 << CS10); TCNT1 = 0x00; // начальная установка счетчика ICR1 = 0xFF; // задаем период ШИМ = 255 OCR1A = 0x00; // начальный коэффициент заполнения ШИМ
//Прерывание INT0 EICRA = (1<<ISC00); EIMSK = (1<<INT0);
PORTB |= (1<<IN1);
USART_Init (64); // Рассчитываем UBBR = XTAL / (16 * baudrate) - 1 = 10000000 / (16 * 9600) - 1 = 64,104166666
sei(); // основной цикл: while(1) { USART_Transmit (USART_Receive()); //Отправка принятого символа назад if ( (PIND & ( 1 << PD0 )) == 0) //если кнопка "больше" нажата { if (i < 254) { i++; OCR1A = i; _delay_ms(10); } }
if (( PIND & (1 << PD1)) == 0) //если кнопка "меньше" нажата { if (i > 0) { i--; OCR1A = i; _delay_ms(10); } } } }
void USART_Init(unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; UCSR0B = (1<<RXEN0)|(1<<TXEN0); UCSR0C = (1<<USBS0)|(3<<UCSZ00); }
unsigned char USART_Receive( void ) { while ( !(UCSR0A & (1<<RXC0)) ); return UDR0; }
void USART_Transmit( unsigned char data ) { while ( !( UCSR0A & (1<<UDRE0)) ); UDR0 = data; } Добавлено (27.11.2011, 22:35) --------------------------------------------- В одной книжке нашел, там обороты вот так вычисляют:
Code unsigned int PreviousTime; unsigned int CurrentTime, T;
INTERRUPT(SIG_INPUT_CAPTURE1) { // вычисляем текушее значение времени замера CurrentTime=(256*ICR1H)+ICR1L; // проверяем, было ли переполнение значения // если нет, то определяем период Т со времени предыдущего замера if (CurrentTime>PreviousTime) T = CurrentTime - PreviousTime; // если было переполнение, то определяем период Т с коррекцией else T = 0xFFFF - CurrentTime + PreviousTime; // сохраняем в буфер buffer форматированную строку, содержащую // значение скорости вращения вала двигателя // нужно подключить библиотеку <string.g> // spintf(buffer, "%06u",(unsigned long)60E6 / (unsigned long)T);
// насколько я понял все хранится в T. ее и нужно переправить... // либо отформатировать T и отправлять значение хранящееся в buffer...
PreviousTime = CurrentTime; // делаем текущий замер "предыдущим" }
|
|
|
|
|
Начальная группа
1798 сообщений
Мужчина
|
Quote #define F_CPU 1000000UL //частота мк Quote USART_Init (64); // Рассчитываем UBBR = XTAL / (16 * baudrate) - 1 = 10000000 / (16 * 9600) - 1 = 64,104166666 Так какая всё таки частота? 1 Мгц или 10 Мгц? Прототипы функций не влом лепить?))
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
Quote (nightmare) Так какая всё таки частота? 1 Мгц или 10 Мгц? Прототипы функций не влом лепить?)) ой, точно =) пересчитаю все для 8 Мгц наверное =) не) пусть будут прототипы))
|
|
|
|
|
Начальная группа
1798 сообщений
Мужчина
|
Проверил в протеусе - для 8Мгц работает. Code #define F_CPU 8000000UL //частота мк #define BAUD 9600 #define MYUBRR F_CPU/16/BAUD-1
#include <avr/io.h> // общая библиотека #include <avr/iom168.h> // atmega168 #include <util/delay.h> // для паузы: _delay_ms(1); #include <avr/interrupt.h> //Библиотека прерываний //Перечисляем прототипы функций void USART_Init(unsigned int ubrr); //Функция инициализации модуля USART unsigned char USART_Receive(void); //Функция приема данных по протоколу USART void USART_Transmit(unsigned char data); //Функция передачи данных по протоколу USART unsigned int counter = 0; #define IN1 PB0 #define IN2 PB3 #define LED PD4 ISR(INT0_vect) { counter++; // счетчик оборотов if(counter == 250) { PORTB &= ~(1<<IN1); // стоп PORTD |= (1<<LED); // после остановки загорается лампочка } } void _USART_Init( unsigned int ubrr) { /*Set baud rate */ UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; //Enable receiver and transmitter */ UCSR0B = (1<<RXEN0)|(1<<TXEN0); /* Set frame format: 8data, 2stop bit */ UCSR0C = (1<<USBS0)|(3<<UCSZ00); } int main(void) { // "0" на ножку PD0 - обороты увеличиваются, на ножку PD1 - обороты уменьшаются unsigned int i=0; // порты ввода-вывода: PORTB = 0x00; DDRB = (1 << PB1)|(1<<PB0)|(1<<PB3); PORTD = (1 << PD0)|(1 << PD1); DDRD = (1<<PD4); // ШИМ, режим FAST PWM: TCCR1A = (1 << COM1A1)|(0 << COM1A0)|(1 << WGM11)|(0 << WGM10); TCCR1B = (1 << WGM13)|(1 << WGM12)|(0 << CS12)|(0 << CS11)|(1 << CS10); TCNT1 = 0x00; // начальная установка счетчика ICR1 = 0xFF; // задаем период ШИМ = 255 OCR1A = 0x00; // начальный коэффициент заполнения ШИМ //Прерывание INT0 EICRA = (1<<ISC00); EIMSK = (1<<INT0); PORTB |= (1<<IN1); USART_Init (MYUBRR); sei(); // основной цикл: while(1) { USART_Transmit (USART_Receive()); //Отправка принятого символа назад if ( (PIND & ( 1 << PD0 )) == 0) //если кнопка "больше" нажата { if (i < 254) { i++; OCR1A = i; _delay_ms(10); } } if (( PIND & (1 << PD1)) == 0) //если кнопка "меньше" нажата { if (i > 0) { i--; OCR1A = i; _delay_ms(10); } } } } void USART_Init(unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; UCSR0B = (1<<RXEN0)|(1<<TXEN0); UCSR0C = (1<<USBS0)|(3<<UCSZ00); } unsigned char USART_Receive( void ) { while ( !(UCSR0A & (1<<RXC0)) ); return UDR0; } void USART_Transmit( unsigned char data ) { while ( !( UCSR0A & (1<<UDRE0)) ); UDR0 = data; }
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
Quote (nightmare) Проверил в протеусе - для 8Мгц работает. с такой частотой или и uart тоже работает?
|
|
|
|
|
БЛОГГЕР
340 сообщений
Мужчина
|
Если ошибусь, поправте пожалуйста, но UART лучше работает когда частота передачи кратна тактовой частоте МК (сейчас даже источник не скажу, от куда вычитал)
|
|
|
|
|
Начальная группа
1798 сообщений
Мужчина
|
Quote с такой частотой или и uart тоже работает? UART тоже работает. Терминал нужно крест накрест подключать. RX к TX, TX к RX.
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
Quote (nightmare) UART тоже работает. Терминал нужно крест накрест подключать. RX к TX, TX к RX. Здорово, что работает) Пробовал, видимо настройка МК в Proteus не правильная у меня.. или фьюзов... или в AVR Studio при создании hex файла мне тож фьюзы менять нужно было... Кстати, у TE-MINI168 свой кварц вродь как же есть) на 16 вродь) и по 22 пкф конденсаторы... Надеюсь что это так и фьюзы не нужно будет настраивать, страшно заблокировать мк...
Код в итоге вот такой будет наверное, но проблема возникла с ICR1H.. он используется в ШИМе и для нахождения частоты оборотов через оптопару.. И он один, хотя в даташите и пишут ICRnH, будто бы можно другой еще взять =( Находил другие примеры, коды для тахометров и частометров, но там опять тот же ICR1... Code #define F_CPU 8000000UL //частота мк #define BAUD 9600 #define MYUBRR F_CPU/16/BAUD-1 #include <avr/io.h> // общая библиотека #include <avr/iom168.h> // atmega168 #include <util/delay.h> // для паузы: _delay_ms(1); #include <avr/interrupt.h> //Библиотека прерываний //Перечисляем прототипы функций void USART_Init(unsigned int ubrr); //Функция инициализации модуля USART unsigned char USART_Receive(void); //Функция приема данных по протоколу USART void USART_Transmit(unsigned char data); //Функция передачи данных по протоколу USART unsigned int counter = 0; #define IN1 PB0 #define IN2 PB3
unsigned int PreviousTime, CurrentTime, T, X; INTERRUPT(SIG_INPUT_CAPTURE1) { // вычисляем текушее значение времени замера CurrentTime=(256*ICR1H)+ICR1L; // проверяем, было ли переполнение значения // если нет, то определяем период Т со времени предыдущего замера if (CurrentTime>PreviousTime) T = CurrentTime - PreviousTime; // если было переполнение, то определяем период Т с коррекцией else T = 0xFFFF - CurrentTime + PreviousTime; // по идее все хранится в T. ее и нужно переправить. PreviousTime = CurrentTime; // делаем текущий замер "предыдущим" } void _USART_Init( unsigned int ubrr) { /*Set baud rate */ UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; //Enable receiver and transmitter */ UCSR0B = (1<<RXEN0)|(1<<TXEN0); /* Set frame format: 8data, 2stop bit */ UCSR0C = (1<<USBS0)|(3<<UCSZ00); } int main(void) { // порты ввода-вывода: PORTB = 0x00; DDRB = (1 << PB1)|(1<<PB0)|(1<<PB3);
// ШИМ, режим FAST PWM: TCCR1A = (1 << COM1A1)|(0 << COM1A0)|(1 << WGM11)|(0 << WGM10); TCCR1B = (1 << WGM13)|(1 << WGM12)|(0 << CS12)|(0 << CS11)|(1 << CS10); TCNT1 = 0x00; // начальная установка счетчика ICR1 = 0xFF; // задаем период ШИМ = 255 OCR1A = 0x00; // начальный коэффициент заполнения ШИМ //Прерывание INT0 EICRA = (1<<ISC00); EIMSK = (1<<INT0); PORTB |= (1<<IN1); USART_Init (MYUBRR); sei(); // основной цикл: while(1) { X=USART_Receive(); if ((X>0) & (X<254)) { OCR1A = X; USART_Transmit (T); } } } void USART_Init(unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; UCSR0B = (1<<RXEN0)|(1<<TXEN0); UCSR0C = (1<<USBS0)|(3<<UCSZ00); } unsigned char USART_Receive( void ) { while ( !(UCSR0A & (1<<RXC0)) ); return UDR0; } void USART_Transmit( unsigned char data ) { while ( !( UCSR0A & (1<<UDRE0)) ); UDR0 = data; }
Сделал бы как Вы писали, но так и не разобрался, в комментариях все написал... Code ISR(INT0_vect) { // нужен ICP (в него сбрасывается содержимое регистра TCNTx, в нем хранится текущее число тиков таймера) и таймер тикает дальше до переполнения // Теория: сохраняем в temp=ICP, на следующем импульсе считаем разницу d=ICP-temp // зная частоту, с которой тикает таймер, можно подсчитать время одного тика t (вот этот момент не ясен...) // Можно подсчитать частоту как f=1/T (об/сек), а период T=d*t // temp,f,T,d,t как unsigned int объявить? }
Купил резисторы по 150 Ом, по мощности самые слабые... Вот так собираюсь соединять (ой, на рисунке нарисовал как 100 случайно): ножку PB0 как вход еще наверное надо в коде описать..
|
|
|
|
|
Начальная группа
1798 сообщений
Мужчина
|
Ага, как вход. Можно еще как вход с подтяжкой внутренним резистором к плюсу, тогда можно попробовать убрать резистор на 100 Ом и подключить фототранзистор к минусу питания и PB0. Как время будет - напишу программу, всё равно собрался частотомер делать, а там период аналогичным способом измерять.
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
кстати забыл в коде еще и выходы на драйвер L293D написать... PD0 и PD1 не буду использовать, как ранее, там все таки TXD и RXD...
|
|
|
|
|
Участник
16 сообщений
Мужчина
|
Надеюсь, что конечный код:
Code #define F_CPU 8000000UL //частота мк #define BAUD 9600 #define MYUBRR F_CPU/16/BAUD-1 #include <avr/io.h> // общая библиотека #include <avr/iom168.h> // atmega168 #include <util/delay.h> // для паузы: _delay_ms(1); #include <avr/interrupt.h> //Библиотека прерываний //Перечисляем прототипы функций void USART_Init(unsigned int ubrr); //Функция инициализации модуля USART unsigned char USART_Receive(void); //Функция приема данных по протоколу USART void USART_Transmit(unsigned char data); //Функция передачи данных по протоколу USART unsigned int counter = 0; #define IN1 PB2 #define IN2 PB3 #define LED PD4 unsigned int PreviousTime, CurrentTime, T, X; ISR(SIG_INPUT_CAPTURE1) { // вычисляем текушее значение времени замера CurrentTime=(256*ICR1H)+ICR1L; // проверяем, было ли переполнение значения // если нет, то определяем период Т со времени предыдущего замера if (CurrentTime>PreviousTime) T = CurrentTime - PreviousTime; // если было переполнение, то определяем период Т с коррекцией else T = 0xFFFF - CurrentTime + PreviousTime; // по идее все хранится в T. ее и нужно переправить. PreviousTime = CurrentTime; // делаем текущий замер "предыдущим" } void _USART_Init( unsigned int ubrr) { /*Set baud rate */ UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; //Enable receiver and transmitter */ UCSR0B = (1<<RXEN0)|(1<<TXEN0); /* Set frame format: 8data, 2stop bit */ UCSR0C = (1<<USBS0)|(3<<UCSZ00); } int main(void) { unsigned int i=0; // порты ввода-вывода: PORTB = 0x00; DDRB = (1 << PB1)|(1<<PB2)|(1<<PB3); PORTD = (1 << PD0)|(1 << PD1); DDRD = (1<<PD4); // ШИМ, режим FAST PWM: TCCR1A = (1 << COM1A1)|(0 << COM1A0)|(1 << WGM11)|(0 << WGM10); TCCR1B = (1 << WGM13)|(1 << WGM12)|(0 << CS12)|(0 << CS11)|(1 << CS10); TCNT1 = 0x00; // начальная установка счетчика ICR1 = 0xFF; // задаем период ШИМ = 255 OCR1A = 0x00; // начальный коэффициент заполнения ШИМ PORTB |= (1<<IN1); TIMSK1 = (1<<ICIE1); USART_Init (MYUBRR); sei();
while(1) { X=USART_Receive(); if ((X>0) & (X<254)) { OCR1A = X; USART_Transmit (T); USART_Transmit(T>>8); } } } void USART_Init(unsigned int ubrr) { UBRR0H = (unsigned char)(ubrr>>8); UBRR0L = (unsigned char)ubrr; UCSR0B = (1<<RXEN0)|(1<<TXEN0); UCSR0C = (1<<USBS0)|(3<<UCSZ00); } unsigned char USART_Receive( void ) { while ( !(UCSR0A & (1<<RXC0)) ); return UDR0; } void USART_Transmit( unsigned char data ) { while ( !( UCSR0A & (1<<UDRE0)) ); UDR0 = data; }
motor.rar
(68.4 Kb)
|
|
|
|
|