Сб июл 23, 2016 20:33:14
Сб июл 23, 2016 21:00:24
BOB51 писал(а):На АВРке подобного соорудить будет весьма напряжно даже под ассемблером - а как "прикладная микруха" ПИК вполне может пригодиться...
Вт июл 26, 2016 10:27:45
Вт ноя 15, 2016 09:10:36
.include "m8def.inc" ; ATMega8
; внутренний RC генератор 1 МГц
; R14, R15 - счетчик энкодера
...
;------ настройка Таймера0 ------
ldi R16, 2 ; предделитель = 8, интервал срабатывания Таймера0 2048 мкс
out TCCR0, R16
...
;--- прерывание по Таймеру0 ---
timer0:
push R16 ; сохраним регистр, который использует прерывание
in R16, SREG ; сохраним SREG
push R16 ; сохраним SREG
; канал A энкодера - порт D0
; канал B энкодера - порт D1
in new_state_enc, PinD
andi new_state_enc, 3
cp old_state_enc, new_state_enc ; если состояние не поменялось, то выходим
breq nothing
cpi new_state_enc, 0 ; если состояние поменялось, выбираем подходящий вариант
breq case0
cpi new_state_enc, 1
breq case1
cpi new_state_enc, 2
breq case2
cpi new_state_enc, 3
breq case3
rjmp nothing ; блокировка на всякий случай, хотя до этой команды никогда не должно дойти
case0:
cpi old_state_enc, 1
breq Iref_plus
cpi old_state_enc, 2
breq Iref_minus
rjmp nothing ; блокировка на случай ошибочной комбинации состояний энкодера
case1:
cpi old_state_enc, 3
breq Iref_plus
cpi old_state_enc, 0
breq Iref_minus
rjmp nothing ; блокировка на случай ошибочной комбинации состояний энкодера
case2:
cpi old_state_enc, 0
breq Iref_plus
cpi old_state_enc, 3
breq Iref_minus
rjmp nothing ; блокировка на случай ошибочной комбинации состояний энкодера
case3:
cpi old_state_enc, 2
breq Iref_plus
cpi old_state_enc, 1
breq Iref_minus
rjmp nothing ; блокировка на случай ошибочной комбинации состояний энкодера
Iref_plus:
mov old_state_enc, new_state_enc ; копируем в темп1 новое состояние выводов
inc R14
brne no_0_R14
inc R15
no_0_R14:
rjmp nothing
Iref_minus:
mov old_state_enc, new_state_enc ; копируем в темп1 новое состояние выводов
ldi R16, 1
sub R14, R16
brcc no_R14
sbc R15, R31
no_R14:
nothing:
pop R16 ; восстановим SREG
out SREG, R16 ; восстановим SREG
pop R16 ; восстановим регистр, который использует прерывание
reti
...
;--- это делается в основном цикле программы с интервалом 0,1 секунды ---
;--- обработка результата вращения энкодера ---
ldi R16, par_Iref ; подставим номер параметра "задание тока"
rcall get_parametr ; получим в R21:R20 параметр
add R20, R14
adc R21, R15
cp R20, R31
cpc R21, R31
brpl no_Iref_min
mov R20, R31
mov R21, R31
no_Iref_min:
ldi R16, low(500)
ldi R17, high(500)
cp R16, R20
cpc R17, R21
brcc no_Iref_max
mov R20, R16
mov R21, R17
no_Iref_max:
ldi R30, spisok_par + (par_Iref<<1)
st Z+, R20
st Z, R21
clr R14 ; очищаем регистры счетчика энкодера (приращение к параметру)
clr R15
...
Вт ноя 15, 2016 09:21:05
Вт ноя 15, 2016 09:22:28
Вт ноя 15, 2016 09:23:32
фу таким бытьStarichok51 писал(а):тексты на С я даже читать отказываюсь
Вт ноя 15, 2016 09:33:59
Возможно Вы перед разрешением прерывания не сбрасывали флаг прерывания. Если Вы определяли направление вращения по фронту, то прерывание "дребезжания" спада следует игнорировать, чего Вы скорее всего не делали.Starichok51 писал(а):в обработке прерывания я сразу же запрещал это прерывание и запускал таймер, которой через некоторое время опять разрешал это внешнее прерывание. прерывание по таймеру отключало этот таймер.
в общем, по внешнему прерыванию у меня вообще ничего не получилось.
Вт ноя 15, 2016 09:34:30
#ifndef _ENCODER_
#define _ENCODER_ 1
/*********************************************************************
Модуль программной поддержки контактного квадратурного энкодера
типа РЕС16 и аналогичных (без использования прерываний)
Copyright 2008 © ARV Research.
Внимание! Вы можете использовать данный модуль по своему усмотрению
в любых проектах. При любой публикации ваших проектов, использующих
этот модуль, следует указать ссылку на сайт http://arv.radioliga.com
Требуется компилятор WinAVR
**********************************************************************/
#define ENC_MAX_SPEED 100 /* максимальная "скорость" вращения энкодера */
#define ENC_BIG_STEP 98 /* "большой" шаг при быстром вращении */
#define ENC_FAST_ROTATE 90 /* константа "быстрого" вращения */
#define ENC_A_PIN 3 /* номер линии порта для сигнала А энкодера */
#define ENC_B_PIN 6 /* номер линии порта для сигнала B энкодера */
#define ENC_A_PORT PIND /* порт, к которому подключен сигнал А энкодера */
#define ENC_B_PORT PINB /* порт, к которому подключен сигнал B энкодера */
#define ENC_A_UP (ENC_A_PORT & (1<<ENC_A_PIN))
#define ENC_B_UP (ENC_B_PORT & (1<<ENC_B_PIN))
#define ENC_A_DN (!ENC_A_UP)
#define ENC_B_DN (!ENC_B_UP)
#define rotate_fast(x) (x > ENC_FAST_ROTATE)
#define DDR(x) (*(&x + 1))
#define PORT(x) (*(&x + 2))
/*
Использование модуля элементарно: в начале программы следует вызвать
функцию enc_init(), которая настроит нужные порты ввода-вывода.
Затем в основном цикле в нужном месте можно обратиться либо к
функции enc_rotate(), которая вернет значение, соответствующее направлению
вращения энкодера, либо функцию enc_delta(), которая кроме направления
возвратит и условную величину скорости вращения.
enc_rotate() позволяет использовать энкодер, как 2 кнопки "+1" и "-1"
enc_delta() уже может заменить 4 кнопки "+1", "+100", "-1" и "-100".
Функция способна отличать "рывки туда-сюда" от простого вращения в
одном направлении.
Нажатие встроенной кнопки энкодера НЕ ОБРАБАТЫВАЕТСЯ
*/
// инициализирует порты, к которым подключен энкодер
void enc_init(void);
/* возвращает направление и скорость вращения энкодера
параметр speed - указатель на переменную, в которую возвращается
условная скорость вращения (число от 0 до 100)
возвращает:
-1 - вращение влево (против часовой стрелки)
0 - нет вращения
1 - вращение вправо (по часовой стрелке)
ВНИМАНИЕ! функция выполняется достаточно длительное время:
максимально (при остановленном энкодере) ENC_MAX_SPEED миллисекунд,
при вращении возвращает управление раньше
*/
signed char enc_rotate(unsigned char * speed);
/* возвращает приращение энкодера:
1 или -1 при медленном вращении,
0 - при остановленном
ENC_BIG_STEP или -ENC_BIG_STEP при быстром вращении
ВНИМАНИЕ!!! Функция выполняется долго!!!
при быстром вращении возвращает управление только ПОСЛЕ ОСТАНОВКИ энкодера!
остановкой считается, если в течение 2*ENC_MAX_SPEED миллисекунд не было импульсов
с энкодера.
*/
signed char enc_delta(void);
#endif
/*********************************************************************
Модуль программной поддержки контактного квадратурного энкодера
типа РЕС16 и аналогичных (без использования прерываний)
Copyright 2008 © ARV Research.
Внимание! Вы можете использовать данный модуль по своему усмотрению
в любых проектах. При любой публикации ваших проектов, использующих
этот модуль, следует указать ссылку на сайт http://arv.radioliga.com
Требуется компилятор WinAVR
**********************************************************************/
#include <avr/io.h>
#include <util/delay.h>
#include "encoder.h"
signed char enc_rotate(unsigned char *speed){
/* возвращает направление и скорость вращения энкодера
параметр speed - указатель на переменную, в которую возвращается
условная скорость вращения (число от 0 до 100)
возвращает:
-1 - вращение влево (против часовой стрелки)
0 - нет вращения
1 - вращение вправо (по часовой стрелке)
ВНИМАНИЕ! функция выполняется достаточно длительное время:
максимально (при остановленном энкодере) ENC_MAX_SPEED миллисекунд,
при вращении возвращает управление раньше
*/
char stage = 0;
for(*speed = ENC_MAX_SPEED; (*speed) > 0; (*speed)--){
switch(stage){
case 0:
if(EN_A_DN || ENC_B_DN) stage++;
break;
case 1:
if(ENC_A_UP || ENC_B_UP) break;
_delay_us(100);
if(ENC_A_DN && ENC_B_DN) stage++;
break;
case 2:
if(ENC_A_UP) return 1;
else if(ENC_B_UP) return -1;
}
_delay_ms(1);
}
return 0;
}
signed char enc_delta(void){
/* возвращает приращение энкодера:
1 или -1 при медленном вращении,
0 - при остановленном
ENC_BIG_STEP или -ENC_BIG_STEP при быстром вращении
ВНИМАНИЕ!!! Функция выполняется долго!!!
при быстром вращении возвращает управление только ПОСЛЕ ОСТАНОВКИ энкодера!
остановкой считается, если в течение 2*ENC_MAX_SPEED миллисекунд не было импульсов
с энкодера.
*/
signed char d;
unsigned char w;
d = enc_rotate(&w);
if(rotate_fast(w)){
if((d == enc_rotate(&w)) && rotate_fast(w)){
d *= ~ENC_BIG_STEP;
while(enc_rotate(&w)) _delay_ms(1);
}
}
return d;
}
void enc_init(void){
// инициализирует порты, к которым подключен энкодер
DDR(ENC_A_PORT) &= ~(1 << ENC_A_PIN);
DDR(ENC_B_PORT) &= ~(1 << ENC_B_PIN);
PORT(ENC_A_PORT) |= 1 << ENC_A_PIN;
PORT(ENC_B_PORT) |= 1 << ENC_B_PIN;
}
Вт ноя 15, 2016 11:12:24
какие дефайны тебя интересуют?akl писал(а):Был бы интересен текст с дефайнами.
страха перд С у меня нет. для компа я пишу на С++ (Мелкософтовская вижл студия).Demiurg писал(а):Отказ от си - банальный страх перед кажущейся сложностью.
да, я про его сброс даже не подумал. видимо, прерывание запрещено, а флаг все равно устанавливается.Z_h_e писал(а):Возможно Вы перед разрешением прерывания не сбрасывали флаг прерывания.
Вт ноя 15, 2016 11:19:20
Вт ноя 15, 2016 11:32:21
Уже не интересуют. Твой текст с исправлениями.Starichok51 писал(а):какие дефайны тебя интересуют?
Вт ноя 15, 2016 13:50:50
спасибо, но принять твои исправления не представляется возможным, так как регистры R18 и R19 уже заняты под другие цели и у меня не осталось свободных регистров, допускающих работу с непосредственным операндом.akl писал(а):Твой текст с исправлениями.
Вт ноя 15, 2016 15:23:31
Вт ноя 15, 2016 16:29:09
Вт ноя 15, 2016 18:36:18
Starichok51 писал(а):...
Вт ноя 15, 2016 21:22:57
Ср ноя 16, 2016 07:15:19
Ср ноя 16, 2016 11:12:05
ты абсолютно прав. у меня нет сложных проектов. и для моих домашних нужд и не нужны сложные проекты.Demiurg писал(а):я могу сказать одно - ваши проекты относительно простые.
Ср ноя 16, 2016 12:14:08