Меня интересует какая тактовая будет от МК если тактовый генератор на 4мгц.
Если память не изменяет мне то AVR изменяет состояние порта за 2такта и еще ~ 2такта теряется на циклы.
по подсчетам F SPI = ~1мгц.
Код: Выделить всё
;-------------------------------------------------------------------------------
; Перекодировка и вывод данных на индикаторы
; Первым идёт последний бит большого индикатора
; Направление данных | Адреса в буфере
; |
; >-----------> |
; | |
; ^-----------< | 08 09 0A 0B 0C 0D
; | |
; >-----------^ | 00 01 02 03 04 05 06 07
;-------------------------------------------------------------------------------
print:
; первые 6 байт читаем без инверсии, остальные инвертируем
ldi r16,14 ; Счетчик байт
ldiX display_buf+14 ; В X адрес буфера индикаторов (на конец)
lds r19,point_maskH ; Берём маски точек
lds r20,point_maskL
pr0:
ld r17,-X ; Читаем байт и декрементируем указатель X
ldi2Z digits ; В Z указатель на таблицу перекодировки
add16Z r17 ; Смещение по таблице перекодировки
lpm r17,Z ; Читаем "рисунок" символа
mov r21,r19 ; Накладываем маску с точками
andi r21,0b10000000
or r17,r21
cpi r16,9 ; Прошли 6 символов?
brcc pr1
com r17 ; Если да - инвертируем
pr1:
ldi r18,8 ; Счетчик битов
pr2:
cbi ds_port,ds_bit ; Линию данных в 0
rol r17 ; Бит в C
brcc pr3 ; Если бит = 0 перепрыгиваем
sbi ds_port,ds_bit ; Иначе линию в 1
pr3:
push_sh_cp ; Сдвиговый импульс
dec r18
brne pr2 ; Не прошло 8 бит? Зацикливаем
rol r20 ; Сдвигаем временные регистры с масками
rol r19 ; с учётом переноса
dec r16 ; Не прошло 14 байт? Зацикливаем
brne pr0
push_st_cp ; Все данные прошли, дёргаем защёлку
ret
Код: Выделить всё
#define Enc PINC.3 // ВХОД енкодера
// INT1
interrupt [EXT_INT1 void ext_int1_isr(void) // прерывание от ЭНКОДЕРА
{
if (Enc==0)
{
if (Enc==0)
{
ваш код (у меня if(OCR0<235) {OCR0+=1;} )
}
}
if (Enc==1)
{
if (Enc==1)
{
ваш код ( у меня if(OCR0>2) {OCR0-=1;})
}
}
}
Код: Выделить всё
sbi sh_cp_port,sh_cp_bit #Выставили бит на порт
nop #Пропустили такт
cbi sh_cp_port,sh_cp_bit #Сняли бит
Код: Выделить всё
//Глобальные переменные
volatile static char EncValue = 0; /*значение увеличения\уменьшения енкодера*/
//обработка прерывания, частота вызова 1000 Гц. (или циклический вызов из основной программы)
#define EncoderPort PINC /*порт чтения енкодера*/
#define EncoderPin0 (1<<3) /*пины чтения енкодера*/
#define EncoderPin1 (1<<4) /*пины чтения енкодера*/
#define EncLockCntrMax 3 /*количество циклов опроса для фиксации шага енкодера (2-10) */
void encoder (void)
{
static unsigned char EncLockCntr0 = 0; //счетчик защелки канала 0
static unsigned char EncLockCntr1 = 0; //счетчик защелки канала 1
static unsigned char EncFlags = 0; //байт флагов
#define bEncLock0 (1<<0) /*бит защелки фазы 0 енкодера*/
#define bEncLock1 (1<<1) /*бит защелки фазы 1 енкодера*/
//обработка фазы 1
if (EncoderPort & EncoderPin0){ //контакт разомкнут (лог 1)?
if (EncLockCntr0 < EncLockCntrMax) //защелка досчитала?
EncLockCntr0 ++; //инкремент защелки
else
EncFlags |= bEncLock0; //установить бит защелки
}
else{ //контакт разомкнут
if (EncLockCntr0) //защелка обнулилась?
EncLockCntr0 --; //декремент защелки
else
if (EncFlags & bEncLock0){
EncFlags &= ~bEncLock0; //сбросить бит защелки
if (~EncFlags & bEncLock1) //если второй канал уже обнулен, обновить значение глобального счетчика
EncValue --;
}
}
//обработка фазы 2
if (EncoderPort & EncoderPin1){ //контакт разомкнут (лог 1)?
if (EncLockCntr1 < EncLockCntrMax) //защелка досчитала?
EncLockCntr1 ++; //инкремент защелки
else
EncFlags |= bEncLock1; //установить бит защелки
}
else{ //контакт разомкнут
if (EncLockCntr1) //защелка обнулилась?
EncLockCntr1 --; //декремент защелки
else
if (EncFlags & bEncLock1){
EncFlags &= ~bEncLock1; //сбросить бит защелки
if (~EncFlags & bEncLock0) //если второй канал уже обнулен, обновить значение глобального счетчика
EncValue ++;
}
}
} Код: Выделить всё
#define ENC_A RB0
#define ENC_B RB1
extern void EncoderScan(void);
extern signed int Enc_Get_Val(void);
Код: Выделить всё
#include "enc.h"
static char EncState;
static volatile signed int EncValRet=0;
/***********************************************************/
void EncoderScan(void){
char New = (char)(ENC_A) + ((char)ENC_B<<1);
switch(EncState){
case 0:
if(New == 2) EncValRet++;
if(New == 1) EncValRet--;
break;
case 1:
if(New == 0) EncValRet++;
if(New == 3) EncValRet--;
break;
case 2:
if(New == 3) EncValRet++;
if(New == 0) EncValRet--;
break;
case 3:
if(New == 1) EncValRet++;
if(New == 2) EncValRet--;
break;
}
EncState = New; // Записываем новое значение
}
/***********************************************************/
signed int Enc_Get_Val(void){
signed int ret;
ret = EncValRet;
EncValRet=0;
return ret;
}
ketrosi писал(а):У меня так сделано (CVAVR)
энкодер подключеный одним выводом на INT1, другой вывод Enc (пин необходимого вам порта настроенный на ввод)Код: Выделить всё
#define Enc PINC.3 // ВХОД енкодера // INT1 interrupt [EXT_INT1 void ext_int1_isr(void) // прерывание от ЭНКОДЕРА { if (Enc==0) { if (Enc==0) { ваш код (у меня if(OCR0<235) {OCR0+=1;} ) } } if (Enc==1) { if (Enc==1) { ваш код ( у меня if(OCR0>2) {OCR0-=1;}) } } }
защита от дребезга имеется в виде конденсаторов на 0,1 и еще програмная.
INT0 можно задействовать на кнопку энкодера или подключить еще один энкодер при необходимости.
Код: Выделить всё
if (enc && flags_enc) // ловим импульс
{
if(enc1) // вправо
{
right();
}
else // влево
{
left();
}
flags_enc=0;
}
if(!(enc)) flags_enc=1; // сбрасываем флаг
Спасибо Вам большое за измерения!ploop писал(а):Измерил. Идут посылки по 8 бит с небольшими паузами (пауза из-за условий для инверсии, смотрите код). Между группами, после того, как передадутся 112 бит, паузы довольно большие (10-20 мс). Выглядит так (ch1 - такт, ch2 - данные):
Реализовано так:Код: Выделить всё
sbi sh_cp_port,sh_cp_bit #Выставили бит на порт nop #Пропустили такт cbi sh_cp_port,sh_cp_bit #Сняли бит
ketrosi писал(а):ketrosi писал(а):У меня так сделано (CVAVR)
энкодер подключеный одним выводом на INT1, другой вывод Enc (пин необходимого вам порта настроенный на ввод)Код: Выделить всё
#define Enc PINC.3 // ВХОД енкодера // INT1 interrupt [EXT_INT1 void ext_int1_isr(void) // прерывание от ЭНКОДЕРА { if (Enc==0) { if (Enc==0) { ваш код (у меня if(OCR0<235) {OCR0+=1;} ) } } if (Enc==1) { if (Enc==1) { ваш код ( у меня if(OCR0>2) {OCR0-=1;}) } } }
защита от дребезга имеется в виде конденсаторов на 0,1 и еще програмная.
INT0 можно задействовать на кнопку энкодера или подключить еще один энкодер при необходимости.
также можно обрабатывать прерыванием INT1 еще и кнопку подключив ее через диод ко входу INT1 и
прямым подключением ко входу нужного порта.
Таким образом одно прерывание обрабатывает один энкодер (кнопку и крутилку), и упрощается сама программа.
Много чего можно обслуживать по одному прерыванию используя диоды по схеме монтажное или.
срабатывает прерывание , в нем проверяются пины портов, определяется по какому произошла сработка, далее выполняются нужные действия.
Спасибо!
Входы подтяните резисторами на минус питания. Так как КМОП микросхемы. Полевые транзисторы управляются электрическим полем, потому ловят малейшую статику.Gerik_PP писал(а):...
Браво!!! Особенно радует то, что решение без временных задержек. Спасибо, Леонид Иванович!ploop писал(а):Да дребезг программно нормально отсекается. Если сами не придумаете, вот алгоритм Леонида Ивановича, раскомментирован до нельзя...Спойлер
Код: Выделить всё
//---------------------------------------------------------------------------- //Модуль поддержки энкодера //Энкодер подключается к портам ENC_F1 (фаза 1) и ENC_F2 (фаза 2). //Для подавления дребезга используется анализ двух последовательных //состояний. Это позволяет обойтись без временных задержек. //Функция Encoder_Init() должна вызываться один раз в начале программы. //Функция Encoder_Exe() должна вызываться в основном цикле. //При повороте энкодера на шаг вправо или влево вызываются функции //To_Do_Step_Up() и To_Do_Step_Dn() соответственно. .....