МК и энкодер.

Дисплеи, датчики и прочие функциональные узлы, управляемые МК.
Ответить
Прорезались зубы
Сообщения: 247
Зарегистрирован: Вс ноя 06, 2011 16:59:31

Сообщение asd81 »

приветствую. не могу найти простенький проект мк с энкодером для cvavr, с целью изучения(поиграться светодиодами или что нибудь в том плане). то что находил ни как не хочет работать или компилироваться. поделитесь пожалуйста у кого имеется или дайте ссылку. спасибо.
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.

Сообщение da-nie »

Покажу работу с прецизионным энкодером ЛИР-120 на AVR. Но только это WinAVR будет. ;)

Контроллер - Atmega8L-8PU с кварцем на 8 МГц. Угол отправляется по RS232 на компьютер.
Спойлер
//----------------------------------------------------------------------------------------------------
//частота контроллера
//----------------------------------------------------------------------------------------------------
#define F_CPU 8000000UL

#define bool unsigned char
#define true 1
#define false 0

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//скорость передачи данных UART, бит/с
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
#define UART_SPEED 19200UL

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//макроопределения
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

#define UA_DDR DDRC
#define UA_PORT PORTC
#define UA_PIN PINC
#define UA 5

#define UB_DDR DDRC
#define UB_PORT PORTC
#define UB_PIN PINC
#define UB 4

#define UR_DDR DDRC
#define UR_PORT PORTC
#define UR_PIN PINC
#define UR 3


//----------------------------------------------------------------------------------------------------
//библиотеки
//----------------------------------------------------------------------------------------------------
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
//----------------------------------------------------------------------------------------------------
//глобальные переменные
//----------------------------------------------------------------------------------------------------


//----------------------------------------------------------------------------------------------------
//прототипы функций
//----------------------------------------------------------------------------------------------------
void InitAVR(void);//инициализация контроллера
void SendUARTData(const char *string);//послать по RS232-данные
//----------------------------------------------------------------------------------------------------
//библиотеки
//----------------------------------------------------------------------------------------------------
volatile unsigned short angle=0;
//----------------------------------------------------------------------------------------------------
//основная функция программы
//----------------------------------------------------------------------------------------------------
int main(void)
{
InitAVR();
angle=0;
//настраиваем таймер T0
TCCR0=(0<<CS02)|(0<<CS01)|(1<<CS00);//выбран режим деления тактовых импульсов на 1
TCNT0=200;//начальное значение таймера
TIMSK=(1<<TOIE0);//прерывание по переполнению таймера (таймер T0 восьмибитный)
//разрешаем прерывания
sei();
while(1)
{
//передаём угол
cli();
unsigned short l_angle=angle;
sei();
unsigned long sec=(unsigned long)(((360.0*60.0*60.0)/65536.0)*((double)(l_angle)));
int a=(int)(sec/(60UL*60UL));
sec%=(60UL*60UL);
int m=(int)(sec/(60UL));
sec%=(60UL);
int s=(int)(sec);
char text[100];
sprintf(text,"%03i'%02i'%02i\r\n",a,m,s);
SendUARTData(text);
_delay_ms(10);
}
cli();
return(0);
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//общие функции
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//----------------------------------------------------------------------------------------------------
//инициализация контроллера
//----------------------------------------------------------------------------------------------------
void InitAVR(void)
{
//настраиваем порты
DDRB=0;
DDRD=0;
DDRC=0;

UA_DDR&=0xff^(1<<UA);
UB_DDR&=0xff^(1<<UB);
UR_DDR&=0xff^(1<<UR);
//задаём состояние портов
PORTB=0;
PORTD=0;
PORTC=0;
//настраиваем UART
//устанавливаем режим передачи данных
UCSRB=(1<<RXEN)|(1<<TXEN)|(0<<RXCIE);
//RXCIE=1 и прерывания разрешены (бит I=1 в регистре SREG) : прерывание по завершению приёма по UART разрешено
//TXCIE=1 и прерывания разрешены (бит I=1 в регистре SREG) : прерывание по завершению передачи по UART разрешено
//UDRIE=1 и прерывания разрешены (бит I=1 в регистре SREG) : прерывание по опустошению регистра данных UART разрешено
//RXEN=1 : активация приёмника, вывод D0 становится входом UART.
//TXEN=1 : активация передатчика, вывод D1 становится выходом UART.
//CHR9=1 : длина передаваемой посылки с становится равной 11 бит (9 бит данных + старт-стоповый бит + стоп-бит).
//RXB8-расширенный стоп-бит
//TXB8-расширенный стоп-бит
//вычисляем значение регистра скорости передачи данных
unsigned long speed=F_CPU/(16UL);
speed=(speed/UART_SPEED)-1UL;
UBRRH=(speed>>8)&0xff;
UBRRL=speed&0xFF;
}
//----------------------------------------------------------------------------------------------------
//послать по RS232-данные
//----------------------------------------------------------------------------------------------------
void SendUARTData(const char *string)
{
unsigned char l=strlen(string);
//передаём
for (unsigned char n=0;n<l;n++)
{
while (!(UCSRA&(1<<UDRE)));
UDR=string[n];
}
}
//----------------------------------------------------------------------------------------------------
//обработчик вектора прерывания таймера T0 (8-ми разрядный таймер) по переполнению
//----------------------------------------------------------------------------------------------------
ISR(TIMER0_OVF_vect)
{
TCNT0=100;

static unsigned char ua_last=0;
static unsigned char ub_last=0;

if (UR_PIN&(1<<UR)) angle=0;//сигнал сброса
//считываем значения
unsigned char ua=0;
unsigned char ub=0;
if (UA_PIN&(1<<UA)) ua=1;
if (UB_PIN&(1<<UB)) ub=1;
//фиксируем изменения фронтов
if (ua!=ua_last)
{
if (ua!=ub) angle++;
else angle--;
}
if (ub!=ub_last)
{
if (ua==ub) angle++;
else angle--;
}
ua_last=ua;
ub_last=ub;
}
Поскольку с энкодером лучше работать с помощью таблицы приращений для каждого изменения сигнала, приведу и проект для того же энкодера для PIC24F04KA200:
Спойлер
//----------------------------------------------------------------------------------------------------
//библиотеки
//----------------------------------------------------------------------------------------------------
#include <p24f04ka200.h>

//----------------------------------------------------------------------------------------------------
//биты конфигурации
//----------------------------------------------------------------------------------------------------
//отключаем сторожевой таймер (в последнем байте 5-й бит должен быть сброшен! Иначе будет ошибка чтения из памяти. Делаем & 0xffdf.)
_FWDT(FWDTEN_OFF&0xffdf)
//настраиваем на внешний кварц 8 Мгц
_FOSC(POSCMOD_XT&OSCIOFNC_ON&POSCFREQ_MS&FCKSM_CSECME)
//с поддержкой PLLx4
_FOSCSEL(FNOSC_PRIPLL)

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//макроопределения
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//частота процессора равна половине частоты генератора SYSCLK
#define SYSCLK 32000000UL
//скорость обмена по UART
#define BAUDRATE2 19200UL
//входы и выходы UART
#define UART1_TX_TRIS TRISBbits.TRISB14
#define UART1_RX_TRIS TRISBbits.TRISB15
//входы детектора импульсов
#define UR_TRIS TRISAbits.TRISA4
#define UR_PORT PORTAbits.RA4
#define UR_LAT LATAbits.LATA4
#define UR_CNPU CNPU1bits.CN0PUE
#define UR_CNEN CNEN1bits.CN0IE
#define UR_ADPCFG AD1PCFGbits.PCFG3

#define UB_TRIS TRISBbits.TRISB4
#define UB_PORT PORTBbits.RB4
#define UB_LAT LATBbits.LATB4
#define UB_CNPU CNPU1bits.CN1PUE
#define UB_CNEN CNEN1bits.CN1IE
#define UB_ADPCFG AD1PCFGbits.PCFG2

#define UA_TRIS TRISAbits.TRISA6
#define UA_PORT PORTAbits.RA6
#define UA_LAT LATAbits.LATA6
#define UA_CNPU CNPU1bits.CN8PUE
#define UA_CNEN CNEN1bits.CN8IE

//----------------------------------------------------------------------------------------------------
//глобальные переменные
//----------------------------------------------------------------------------------------------------
volatile unsigned short angle=0;
unsigned char byte_ua_ub_last=0;
signed char DirectTable[16];//приращение направления
//----------------------------------------------------------------------------------------------------
//прототипы функций
//----------------------------------------------------------------------------------------------------
void Delay(void);//задержка
void UART_Transmit(unsigned char *data,short length);//передача по UART
void InitDirectTable(void);//инициализация таблицы приращений
//----------------------------------------------------------------------------------------------------
//основная функция программы
int main(void)
{
InitDirectTable();

//настраиваем порты (1 -порт на вход, 0- порт на выход!)
TRISA=0xffff;
TRISB=0xffff;

//отключаем АЦП от входов (по-умолчанию все входы аналоговые)
//задаём регистр конфигурации входов АЦП
UR_ADPCFG=1;
UB_ADPCFG=1;

TRISB&=(0xffff^(1<<8));
PORTBbits.RB8=0;

UA_TRIS=1;
UB_TRIS=1;
UR_TRIS=1;
//настраиваем UART
UART1_TX_TRIS=0;
UART1_RX_TRIS=1;

U1BRG=(SYSCLK/(8UL*(unsigned long)BAUDRATE2))-1UL;
U1MODE=0;
U1MODEbits.BRGH=1;//с BRGH=0 частота в 4 раза ниже и U1BRG=((SYSCLK/(32*BAUDRATE2)-1);
U1MODEbits.UARTEN=1;
U1STA=0;
U1STAbits.UTXEN=1;
IFS0bits.U1RXIF=0;//сбрасываем флаг приёма

UA_CNPU=0;
UB_CNPU=0;
UR_CNPU=0;

_CNIF=0;//сбрасываем флаг прерывания по CN
_CNIP=7;

UA_CNEN=1;
UB_CNEN=1;
UR_CNEN=1;

_CNIE=1;//включаем прерывания
//запускаем основной цикл

PORTBbits.RB8=1;
unsigned short n;
for(n=0;n<100;n++) Delay();
PORTBbits.RB8=0;

while(1)
{
_CNIE=0;
unsigned short l_angle=angle;
_CNIE=1;
//передаём
unsigned char data[4];
data[0]=(l_angle>>12)&0xff;
data[0]|=0x80;

data[1]=l_angle&0xff;

data[2]=(l_angle>>4)&0xf0;
data[2]|=0x01;

data[3]=data[0]+data[1]+data[2];

UART_Transmit(data,4);
}
return(0);
}
//----------------------------------------------------------------------------------------------------
//задержка
//----------------------------------------------------------------------------------------------------
void Delay(void)
{
unsigned long cnt=10000;
while(cnt!=0) cnt--;
}
//----------------------------------------------------------------------------------------------------
//послать по RS232-данные
//----------------------------------------------------------------------------------------------------
void UART_Transmit(unsigned char *data,short length)
{
short n;
for(n=0;n<length;n++)
{
while(U1STAbits.UTXBF==1);
U1TXREG=data[n];
}
}
//----------------------------------------------------------------------------------------------------
//инициализация таблицы приращений
//----------------------------------------------------------------------------------------------------
void InitDirectTable(void)
{
unsigned char byte;
for(byte=0;byte<16;byte++)
{
unsigned char ua=byte&0b0001;
unsigned char ub=(byte&0b0010)>>1;
unsigned char ua_l=(byte&0b0100)>>2;
unsigned char ub_l=(byte&0b1000)>>3;
DirectTable[byte]=0;
//фиксируем изменения фронтов
if (ua!=ua_l)
{
if (ua!=ub) DirectTable[byte]=1;
else DirectTable[byte]=-1;
}
if (ub!=ub_l)
{
if (ua==ub) DirectTable[byte]=1;
else DirectTable[byte]=-1;
}
}
}
//----------------------------------------------------------------------------------------------------
//прерывание изменения состояния входа
//----------------------------------------------------------------------------------------------------
void __attribute__ ((interrupt,auto_psv)) _CNInterrupt(void)
{
_CNIF=0;//сбрасываем флаг прерывания
//считываем значения
unsigned char byte=0;
if (UA_PORT!=0) byte|=0b0001;
if (UB_PORT!=0) byte|=0b0010;
byte|=(byte_ua_ub_last<<2);
byte_ua_ub_last=byte&0b0011;
angle+=(short)(DirectTable[byte]);
if (UR_PORT!=0) angle=0;//сигнал сброса
}
PIC24 позволяет назначить прерывания по изменения состояния некоторых входов, к которым и подключены линии A, B и R(сброс в 0) энкодера.
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Контактная информация:
Реклама
Прорезались зубы
Сообщения: 247
Зарегистрирован: Вс ноя 06, 2011 16:59:31

Сообщение asd81 »

da-nie, какой winavr посоветуйте скачать?
Друг Кота
Сообщения: 6014
Зарегистрирован: Чт ноя 26, 2009 11:16:50
Откуда: Москва

Сообщение SmarTrunk »

Если имелся в виду обычный энкодер-крутилка с механическими контактами (на 8...24 щелчка на один оборот), а не дорогие оптические энкодеры, то тут уважаемый Ничегонеработает приводил программу на С, с программным подавлением дребезга контактов, который неизбежно будет.
https://radiokot.ru/forum/viewtopic.php ... start=4620
Реклама
Эиком - электронные компоненты и радиодетали
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.

Сообщение da-nie »

da-nie, какой winavr посоветуйте скачать?
Да, собственно, любой. :)
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Контактная информация:
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Чтобы не плодить тем напишу здесь.

Есть такое вот чудо https://www.bluetooth.org/tpg/RefNotes/ ... sheet1.pdf. На борту контроллер 51-го семейства. Надо прокрутить к нему энкодер. Беда в том, что прерывания по портам, в дурном скрипте от bluegiga, можно установить или по возрастающему, или по спадающему фронту.
Сделал так: один вывод энкодера на прерывание по спаду. В обработчике щупаем вторую ногу и если 1, то +1, если 0, то -1.
Беда в том, что при вращении в сторону -1 переменная достигает опустошения явно за меньшее количество счелчков чем в противоположную сторону.

У кого-то есть алгоритм обработки для подобных условий?
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.

Сообщение da-nie »

А вы инвертор поставьте на другое внешнее прерывание (если у вас их несколько, конечно). И будут попеременно приходить по спаду и по нарастанию в разные прерывания.
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Это решение невозможно, нет свободных пинов. Все расписано.
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.

Сообщение da-nie »

Тогда выбрасывайте внешнее прерывание и либо постоянно отслеживайте в цикле изменения состояния входов, либо периодически по таймеру.
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 672
Зарегистрирован: Ср фев 29, 2012 01:58:32
Откуда: Харьков, Украина

Сообщение eess9 »

Я тоже склоняюсь к прерыванию таймера. Только частоту опроса выбрать надо. Как думаете раз в 5мс щупать состояние пинов не редко?
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.

Сообщение da-nie »

А вы исходите из скорости вращения и числа импульсов за оборот. Вот и узнаете, как часто приходят эти самые импульсы. :)
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Контактная информация:
Ответить

Вернуться в «Периферия»