Основу брал здесь
Огромное СПАСИБО dmm!
Программирование ATMEL в BASCOM. |
Привет, Гость! Войдите или зарегистрируйтесь.
Вы здесь » Программирование ATMEL в BASCOM. » Примеры применения в среде Баском » Исследование энкодера
Основу брал здесь
Огромное СПАСИБО dmm!
Понадобилось 2 энкодера с кнопками на валу, может кому пригодится.
Обработка по прерываниям PCINT0 и PCINT2, кнопки переключают скорость регулировки х1, х10
Симуляция + исходник + фото + видео - скачать
В симуляции второй вывод кнопки энкодера висит в воздухе потому, что кнопка подключена в схему обработки дребезга (кнопки работают синхронно!)
$map ' Получаем карту распределения памяти компилятором Bascom
$regfile = "m328pdef.dat" ' http://www.atmel.com/images/Atmel-8272- … asheet.pdf
$crystal = 8000000 ' 1 МГц
$framesize = 64 ' Размер области используемой и необходимой для преобразований
$hwstack = 64 ' Размер аппаратного стека
$swstack = 64 ' Размер программного стека$baud = 38400
'Ucsr0a.1 = 1 ' Baud = Baud * 2'===============================================================================
' Настройка МК для работы с LCD на базе контроллера hd44780
' Обратите внимание, библиотеки не используются, выводы могут быть любые
'===============================================================================
Config Lcdpin = Pin , Rs = Portc.0 , E = Portc.1 , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5
Config Lcd = 20 * 4 ' Используемый LCD
Initlcd ' Инициализируем LCD
Waitms 50 ' Ждем пока все запустится
Cursor Off Noblink ' Выключаем неморгающий курсор
' Cursor On Noblink ' Включаем неморгающий курсор
' Cursor Blink ' Включаем моргающий курсор
' Upperline 1 строка, Lowerline 2 строка, Thirdline 3 строка, Fourthline 4 строка - один из вариантов перехода на строку
Cls ' Чистим экран, на всякий случай'===============================================================================
' Конфигурация МК для работы с энкодерами
'==============================================================================='-----------------------------------------
'Конфигурация МК для работы с энкодером 1
'-----------------------------------------
Encoder_1_port_1 Alias Pinb
Encoder_1_pin_1 Alias 0Encoder_1_port_2 Alias Pinb
Encoder_1_pin_2 Alias 1Config Pinb.2 = Input : Set Portb.2
Key_encoder_1_port Alias Pinb
Key_encoder_1_pin Alias 2Dim Кольцевое_нажатие_1 As Byte
On Pcint0 Обработка_прерывания_pcint0 Nosave ' Подпрограмма обработки прерывания PCINT0
Pcmsk0 = &B_0000_0101 'PCINT0 (PINB.0); PCINT2 (PINB.2)Dim Счетчик_энкодера_1_влево As Byte
Dim Счетчик_энкодера_1_вправо As Byte
Dim Флаг_обновить_lcd_1 As Byte
Dim Флаг_данные_энкодера_1 As Byte
Dim Направление_вращения_энкодера_1 As Byte
Dim Переменная_integer_1 As Integer
Dim Переменная_str_1 As String * 10'-----------------------------------------
'Конфигурация МК для работы с энкодером 2
'-----------------------------------------
Encoder_2_port_1 Alias Pind
Encoder_2_pin_1 Alias 5Encoder_2_port_2 Alias Pind
Encoder_2_pin_2 Alias 6Config Pind.7 = Input : Set Portd.7
Key_encoder_2_port Alias Pind
Key_encoder_2_pin Alias 7Dim Кольцевое_нажатие_2 As Byte
On Pcint2 Обработка_прерывания_pcint2 Nosave ' Подпрограмма обработки прерывания PCINT2
Pcmsk2 = &B_1010_0000 'PCINT21 (PIND.5); PCINT23 (PIND.7)Dim Флаг_обновить_lcd_2 As Byte
Dim Флаг_данные_энкодера_2 As Byte
Dim Счетчик_энкодера_2_влево As Byte
Dim Счетчик_энкодера_2_вправо As Byte
Dim Направление_вращения_энкодера_2 As Byte
Dim Переменная_integer_2 As Integer
Dim Переменная_str_2 As String * 10Locate 1 , 1
Lcd "Encoder 1"
Locate 2 , 1
Lcd " 0"
Locate 3 , 1
Lcd "Encoder 2"
Locate 4 , 1
Lcd " 0"'-------------- Разрешаем работу необходимых прерываний ----------------------
Enable Pcint0
Enable Pcint2
'------------ Разрешаем работу всех включенных прерываний --------------------
Enable Interrupts
'===============================================================================
Главный_цикл:
'===============================================================================If Флаг_данные_энкодера_1 <> 0 Then
Gosub Обработка_данных_энкодера
Флаг_данные_энкодера_1 = 0
Goto Главный_цикл
End IfIf Флаг_данные_энкодера_2 <> 0 Then
Gosub Обработка_данных_энкодера
Флаг_данные_энкодера_2 = 0
Goto Главный_цикл
End IfIf Флаг_обновить_lcd_1 <> 0 Then
Переменная_str_1 = Str(переменная_integer_1)
Переменная_str_1 = Format(переменная_str_1 , "+ 0")If Переменная_integer_1 = 0 Then
Mid(переменная_str_1 , 5 , 1) = " "
End IfLocate 2 , 1
Lcd Переменная_str_1Флаг_обновить_lcd_1 = 0
Goto Главный_цикл
End IfIf Флаг_обновить_lcd_2 <> 0 Then
Переменная_str_2 = Str(переменная_integer_2)
Переменная_str_2 = Format(переменная_str_2 , "+ 0")If Переменная_integer_2 = 0 Then
Mid(переменная_str_2 , 5 , 1) = " "
End IfLocate 4 , 1
Lcd Переменная_str_2Флаг_обновить_lcd_2 = 0
Goto Главный_цикл
End IfIdle
'===============================================================================
Goto Главный_цикл
End
'==============================================================================='===============================================================================
Обработка_данных_энкодера:
'-------------------------------------------------------------------------------
If Счетчик_энкодера_1_вправо <> 0 Then
If Кольцевое_нажатие_1 = 0 Then
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
Elseif Кольцевое_нажатие_1 = 1 Then
Счетчик_энкодера_1_вправо = Счетчик_энкодера_1_вправо * 10
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
End If
Счетчик_энкодера_1_вправо = 0
Флаг_обновить_lcd_1 = 1
End IfIf Счетчик_энкодера_1_влево <> 0 Then
If Кольцевое_нажатие_1 = 0 Then
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
Elseif Кольцевое_нажатие_1 = 1 Then
Счетчик_энкодера_1_влево = Счетчик_энкодера_1_влево * 10
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
End If
Счетчик_энкодера_1_влево = 0
Флаг_обновить_lcd_1 = 1
End If'----------------------------------
If Счетчик_энкодера_2_вправо <> 0 Then
If Кольцевое_нажатие_2 = 0 Then
Переменная_integer_2 = Переменная_integer_2 + Счетчик_энкодера_2_вправо
Elseif Кольцевое_нажатие_2 = 1 Then
Счетчик_энкодера_2_вправо = Счетчик_энкодера_2_вправо * 10
Переменная_integer_2 = Переменная_integer_2 + Счетчик_энкодера_2_вправо
End If
Счетчик_энкодера_2_вправо = 0
Флаг_обновить_lcd_2 = 1
End IfIf Счетчик_энкодера_2_влево <> 0 Then
If Кольцевое_нажатие_2 = 0 Then
Переменная_integer_2 = Переменная_integer_2 - Счетчик_энкодера_2_влево
Elseif Кольцевое_нажатие_2 = 1 Then
Счетчик_энкодера_2_влево = Счетчик_энкодера_2_влево * 10
Переменная_integer_2 = Переменная_integer_2 - Счетчик_энкодера_2_влево
End If
Счетчик_энкодера_2_влево = 0
Флаг_обновить_lcd_2 = 1
End If
'-------------------------------------------------------------------------------
Return
'==============================================================================='-------------------------------------------------------------------------------
'ОБРАБОТКА ВНЕШНЕГО ПРЕРЫВАНИЯ 0 - ОТ ДВУХФАЗНОГО ИМПУЛЬСНОГО ЕНКОДЕРА
'ПРЕРЫВАНИЕ ПРОИСХОДИТ ПО СПАДУ НА ВХОДЕ P_CHA. ЗАТЕМ ПРОГРАММА ИНТЕГРИРУЕТ
' (ФИЛЬТРУЕТ) ЭТОТ УРОВЕНЬ, ДОЖИДАЯСЬ НАДЕЖНОГО УСТАНОВЛЕНИЯ "0". В МОМЕНТ
'ФИКСАЦИИ "0" НА ЛИНИИ P_cha РЕГИСТРИРУЕТСЯ УРОВЕНЬ P_chb , ПО КОТОРОМУ И
'ОПРЕДЕЛЯЕТСЯ НАПРАВЛЕНИЕ ВРАЩЕНИЯ. П/П РАБОТАЕТ ТАКЖЕ ПРИ ИСПОЛЬЗОВАНИИ
'ПРЕРЫВАНИЯ ОТ ЛЮБОГО ИЗМЕНЕНИЯ УРОВНЯ. НА СПАД СРАБАТЫВАЕТ, ФРОНТ ИГНОРИРУЕТ
'-------------------------------------------------------------------------------
Const Con_irt = 5 '30 'КОНСТАНТА ИНТЕГРИРОВАНИЯ УРОВНЯ НА ВХОДЕ
Const Conirt1 = Con_irt * 1.5 'ПОЛТОРЫ КОНСТАНТЫ ИНТЕГРИРОВАНИЯ
Const Conirt2 = Con_irt * 2 'ДВЕ КОНСТАНТЫ ИНТЕГРИРОВАНИЯPcint0_0:
!Inc R31 'УРОВЕНЬ ВЫСОКИЙ - ОТКАТ СЧЕТЧИКА
!Cpi R31 , Conirt1 'это Con_irt*1.5
!Brne pcint0_1 'ЕСЛИ ЖДЕМ СЛИШКОМ ДОЛГО - ВЫХОД
!Rjmp Выход_pcint0'ВНЕШНЕЕ ПРЕРЫВАНИЕ ОТ ЦИФРОВОЙ РУЧКИ
Обработка_прерывания_pcint0:
!Push R31 'сохраним регистры
!In R31 , Sreg
!Push R31!Sbic Key_encoder_1_port, Key_encoder_1_pin ' Пропустить если бит в порту очищен
!rjmp Прерывание_энкодера_1!lds R31 , {Кольцевое_нажатие_1}
!inc R31
!andi R31 , &B_1111_1101
!sts {Кольцевое_нажатие_1} , R31
!Rjmp Выход_pcint0Прерывание_энкодера_1:
'ИНТЕГРИРУЮЩИЙ ФИЛЬТР (ФНЧ) ВХОДНОГО УРОВНЯ
!Ldi R31 , Con_irt 'ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ В СЧЕТЧИК
Pcint0_1:
!Sbic Encoder_1_port_1 , Encoder_1_pin_1 'ПРОВЕРИМ УРОВЕНЬ НА ВЫВОДЕ
!Rjmp pcint0_15 'ЕСЛИ НА НОЖКЕ "1" - ПЕРЕХОД
!Dec R31 'ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ
!Brne pcint0_1 'МНОГОКРАТНОГО ПОДТВЕРЖДЕНИЯ НИЗКОГО УРОВНЯ
!Rjmp pcint0_2'ЕСЛИ УРОВНЬ ВЫСОКИЙ
Pcint0_15:
!Inc R31 'УВЕЛИЧИВАЕМ СЧЕТЧИК
!Cpi R31 , Conirt2 'ЕСЛИ НА "1" УСТАНОВЛЕНА СЛИШКОМ ДОЛГО
!Brne Выход_pcint0 'НА ВЫХОД
!Rjmp pcint0_1
'---------------------------------------------
'ПРОГРАММА РАСЧИТАНА НА КОДОВЫЙ ПЕРЕКЛЮЧАТЕЛЬ
'С НОРМАЛЬНО РАЗОМКНУТЫМИ КОНТАКТАМИ, ЗАМЫКАЮЩИМИСЯ
'ТОЛЬКО В МОМЕНТ ЩЕЛЧКА. ЭТО ОЧЕНЬ УПРОЩАЕТ ЗАДАЧУ
'---------------------------------------------
' |<----- ВРАЩЕНИЕ ВЛЕВО (ИЛИ НАОБОРОТ, В ЗАВИСИМОСТИ ОТ МОНТАЖА)
'chA--- --------- ------ ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ
' ¦ ¦ chA ¦ ¦ ВРАЩЕНИЯ ЦИФРОВОГО КОДЕРА
' --- --- ОСНОВАНО НА АНАЛИЗЕ СОСТОЯНИЯ
'chB----- | --------- ---- КАНАЛА "B" В МОМЕНТ ЗАМЫКАНИЯ
' | ¦ | ¦ chB ¦ ¦ (ЩЕЛЧКА) В КАНАЛЕ "A"
' | --- ---
' | |<------ ВРАЩЕНИЕ ВПРАВО
'---------------------------------------------
Pcint0_2:
'ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ!Sbis Encoder_1_port_2 , Encoder_1_pin_2
!Rjmp pcint0_3 'ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ'ВРАЩЕНИЯ ВЛЕВО (УМЕНЬШЕНИЕ)
!Lds R31 , {Счетчик_энкодера_1_влево} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО
!Inc R31
!Sts {Счетчик_энкодера_1_влево} , R31
!Rjmp pcint0_4Pcint0_3:
'ВРАЩЕНИЯ ВПРАВО (УВЕЛИЧЕНИЕ)
!Lds R31 , {Счетчик_энкодера_1_вправо} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО
!Inc R31
!Sts {Счетчик_энкодера_1_вправо} , R31
Pcint0_4:
!Ldi R31 , 1
!Sts {Флаг_данные_энкодера_1} , R31 'поставить признак "НОВЫЕ ДАННЫЕ ЕНКОДЕРА"Выход_pcint0:
!Pop R31
!Out Sreg , R31
!Pop R31!Reti
'-------------------------------------------------------------------------------
Return
'==============================================================================='-------------------------------------------------------------------------------
'ОБРАБОТКА ВНЕШНЕГО ПРЕРЫВАНИЯ 0 - ОТ ДВУХФАЗНОГО ИМПУЛЬСНОГО ЕНКОДЕРА
'ПРЕРЫВАНИЕ ПРОИСХОДИТ ПО СПАДУ НА ВХОДЕ P_CHA. ЗАТЕМ ПРОГРАММА ИНТЕГРИРУЕТ
' (ФИЛЬТРУЕТ) ЭТОТ УРОВЕНЬ, ДОЖИДАЯСЬ НАДЕЖНОГО УСТАНОВЛЕНИЯ "0". В МОМЕНТ
'ФИКСАЦИИ "0" НА ЛИНИИ P_cha РЕГИСТРИРУЕТСЯ УРОВЕНЬ P_chb , ПО КОТОРОМУ И
'ОПРЕДЕЛЯЕТСЯ НАПРАВЛЕНИЕ ВРАЩЕНИЯ. П/П РАБОТАЕТ ТАКЖЕ ПРИ ИСПОЛЬЗОВАНИИ
'ПРЕРЫВАНИЯ ОТ ЛЮБОГО ИЗМЕНЕНИЯ УРОВНЯ. НА СПАД СРАБАТЫВАЕТ, ФРОНТ ИГНОРИРУЕТ
'-------------------------------------------------------------------------------
' Const Con_irt_2 = 30 'КОНСТАНТА ИНТЕГРИРОВАНИЯ УРОВНЯ НА ВХОДЕ
' Const Conirt1_2 = Con_irt_2 * 1.5 'ПОЛТОРЫ КОНСТАНТЫ ИНТЕГРИРОВАНИЯ
' Const Conirt2_2 = Con_irt_2 * 2 'ДВЕ КОНСТАНТЫ ИНТЕГРИРОВАНИЯPcint2_0:
!Inc R31 'УРОВЕНЬ ВЫСОКИЙ - ОТКАТ СЧЕТЧИКА
!Cpi R31 , Conirt1 'это Con_irt*1.5
!Brne Pcint2_1 'ЕСЛИ ЖДЕМ СЛИШКОМ ДОЛГО - ВЫХОД
!Rjmp Выход_pcint2'ВНЕШНЕЕ ПРЕРЫВАНИЕ ОТ ЦИФРОВОЙ РУЧКИ
Обработка_прерывания_pcint2:
!Push R31 'сохраним регистры
!In R31 , Sreg
!Push R31!Sbic Key_encoder_2_port, Key_encoder_2_pin ' Пропустить если бит в порту очищен
!rjmp Прерывание_энкодера_2!lds R31 , {Кольцевое_нажатие_2}
!inc R31
!andi R31 , &B_1111_1101
!sts {Кольцевое_нажатие_2} , R31
!Rjmp Выход_pcint2Прерывание_энкодера_2:
'ИНТЕГРИРУЮЩИЙ ФИЛЬТР (ФНЧ) ВХОДНОГО УРОВНЯ
!Ldi R31 , Con_irt 'ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ В СЧЕТЧИК
Pcint2_1:
!Sbic Encoder_2_port_1 , Encoder_2_pin_1 'ПРОВЕРИМ УРОВЕНЬ НА ВЫВОДЕ
!Rjmp Pcint2_15 'ЕСЛИ НА НОЖКЕ "1" - ПЕРЕХОД
!Dec R31 'ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ
!Brne Pcint2_1 'МНОГОКРАТНОГО ПОДТВЕРЖДЕНИЯ НИЗКОГО УРОВНЯ
!Rjmp Pcint2_2'ЕСЛИ УРОВНЬ ВЫСОКИЙ
Pcint2_15:
!Inc R31 'УВЕЛИЧИВАЕМ СЧЕТЧИК
!Cpi R31 , Conirt2 'ЕСЛИ НА "1" УСТАНОВЛЕНА СЛИШКОМ ДОЛГО
!Brne Выход_pcint2 'НА ВЫХОД
!Rjmp Pcint2_1
'---------------------------------------------
'ПРОГРАММА РАСЧИТАНА НА КОДОВЫЙ ПЕРЕКЛЮЧАТЕЛЬ
'С НОРМАЛЬНО РАЗОМКНУТЫМИ КОНТАКТАМИ, ЗАМЫКАЮЩИМИСЯ
'ТОЛЬКО В МОМЕНТ ЩЕЛЧКА. ЭТО ОЧЕНЬ УПРОЩАЕТ ЗАДАЧУ
'---------------------------------------------
' |<----- ВРАЩЕНИЕ ВЛЕВО (ИЛИ НАОБОРОТ, В ЗАВИСИМОСТИ ОТ МОНТАЖА)
'chA--- --------- ------ ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ
' ¦ ¦ chA ¦ ¦ ВРАЩЕНИЯ ЦИФРОВОГО КОДЕРА
' --- --- ОСНОВАНО НА АНАЛИЗЕ СОСТОЯНИЯ
'chB----- | --------- ---- КАНАЛА "B" В МОМЕНТ ЗАМЫКАНИЯ
' | ¦ | ¦ chB ¦ ¦ (ЩЕЛЧКА) В КАНАЛЕ "A"
' | --- ---
' | |<------ ВРАЩЕНИЕ ВПРАВО
'---------------------------------------------
Pcint2_2:
'ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ!Sbis Encoder_2_port_2 , Encoder_2_pin_2
!Rjmp Pcint2_3 'ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ'ВРАЩЕНИЯ ВЛЕВО (УМЕНЬШЕНИЕ)
!Lds R31 , {Счетчик_энкодера_2_влево} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО
!Inc R31
!Sts {Счетчик_энкодера_2_влево} , R31
!Rjmp Pcint2_4Pcint2_3:
'ВРАЩЕНИЯ ВПРАВО (УВЕЛИЧЕНИЕ)
!Lds R31 , {Счетчик_энкодера_2_вправо} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО
!Inc R31
!Sts {Счетчик_энкодера_2_вправо} , R31
Pcint2_4:
!Ldi R31 , 1
!Sts {Флаг_данные_энкодера_2} , R31 'поставить признак "НОВЫЕ ДАННЫЕ ЕНКОДЕРА"Выход_pcint2:
!Pop R31
!Out Sreg , R31
!Pop R31!Reti
'-------------------------------------------------------------------------------
Return
'===============================================================================
Энкодер + кнопка на валу (короткое + длинное нажатия), использовано прерывание PCINT0 + TIMER2.
Для чего нужен TIMER2, чтобы не было задержек в прерываниях
Короткие нажатия - меняется множитель incr и decr энкодера (х1; х10; х100)
Длинное нажатие - в примере реализована полуперезагрузка МК (Rjmp 0), в реальной конструкции, так делать, крайне нежелательно (неполная инициализация МК).
$map ' Получаем карту распределения памяти компилятором Bascom
$regfile = "m328pdef.dat" ' http://www.atmel.com/images/Atmel-8272- … asheet.pdf
$crystal = 8000000 ' 1 МГц
$framesize = 64 ' Размер области используемой и необходимой для преобразований
$hwstack = 64 ' Размер аппаратного стека
$swstack = 64 ' Размер программного стека' $baud = 38400
'Ucsr0a.1 = 1 ' Baud = Baud * 2'===============================================================================
' Настройка МК для работы с LCD на базе контроллера hd44780
' Обратите внимание, библиотеки не используются, выводы могут быть любые
'===============================================================================
Config Lcdpin = Pin , Rs = Portc.0 , E = Portc.1 , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5
Config Lcd = 20 * 4 ' Используемый LCD
Initlcd ' Инициализируем LCD
Waitms 50 ' Ждем пока все запустится
Cursor Off Noblink ' Выключаем неморгающий курсор
' Cursor On Noblink ' Включаем неморгающий курсор
' Cursor Blink ' Включаем моргающий курсор
' Upperline 1 строка, Lowerline 2 строка, Thirdline 3 строка, Fourthline 4 строка - один из вариантов перехода на строку
Cls ' Чистим экран, на всякий случай'===============================================================================
' Конфигурация МК для работы с энкодерами
'===============================================================================
Prescale_1024 Alias &B_0000_0111Config Timer2 = Timer , Prescale = 1024 , Clear Timer = 0 ' 16,384 ms при частоте МК 8МГц
Stop Timer2
Timer2 = 0
On Timer2 Обработка_прерывания_timer2 Nosave'-----------------------------------------
'Конфигурация МК для работы с энкодером 1
'-----------------------------------------
Config Pinb.0 = Input : Set Portb.0
Encoder_1_port_1 Alias Pinb
Encoder_1_pin_1 Alias 0Config Pinb.1 = Input : Set Portb.1
Encoder_1_port_2 Alias Pinb
Encoder_1_pin_2 Alias 1Config Pinb.2 = Input : Set Portb.2
Key_encoder_1_port Alias Pinb
Key_encoder_1_pin Alias 2
Set_isr_key_encoder Alias &B_0000_0100
Reset_isr_key_encoder Alias &B_1111_1011On Pcint0 Обработка_прерывания_pcint0 Nosave ' Подпрограмма обработки прерывания PCINT0
Pcmsk0 = &B_0000_0101 'PCINT0 (PINB.0) - один из боковых выводов энкодера + вывод кнопки (PCINT2 (PINB.2))
Enable_pcint0 Alias &B_0000_0001
Disable_pcint0 Alias &B_1111_1110Dim Count As Byte ' Временная переменная, в релизе удалить
Dim Val_byte As Byte ' Временная переменная, в релизе удалить
Dim Long_press As Byte ' Временная переменная, в релизе удалить
Dim Short_press As Byte ' Временная переменная, в релизе удалить
Dim Флаг_обновить_lcd_1 As Byte ' Временная переменная, в релизе удалить
Dim Кольцевое_нажатие_1 As Byte ' Временная переменная, в релизе удалить
Dim Счетчик_длины_нажатий As Byte
Dim Флаг_данные_энкодера_1 As Byte ' Временная переменная, в релизе удалить
Dim Флаг_реакция_на_кнопки As Byte ' Временная переменная, в релизе удалить
Dim Переменная_integer_1 As Integer
Dim Счетчик_энкодера_1_влево As Byte
Dim Счетчик_энкодера_1_вправо As Byte
Dim Длинное_нажатие_энкодер_1 As Byte
Dim Уровень_кнопки_энкодера_1 As Byte : Уровень_кнопки_энкодера_1 = 255
Dim Короткое_нажатие_энкодер_1 As Byte
Dim Флаг_направл_кольц_нажатия As ByteDim Short_press_str As String * 5
Dim Переменная_str_1 As String * 10'Начальное заполнение экрана
Locate 1 , 1
Lcd "Short_press " ; " x1"
Locate 2 , 1
Lcd "Encoder 1 " ; " 0"
Locate 3 , 1
Lcd " "'-------------- Разрешаем работу необходимых прерываний ----------------------
Pcifr.pcif0 = 1 : Enable Pcint0 ' Сброс флаг прерывания и разрешение прерывания, иначе получается сразу +1 от энкодера
Enable Timer2
'------------ Разрешаем работу всех включенных прерываний --------------------
Enable Interrupts
'===============================================================================
Главный_цикл:
'===============================================================================If Флаг_данные_энкодера_1 <> 0 Then
Gosub Обработка_данных_энкодера
Флаг_данные_энкодера_1 = 0
Goto Главный_цикл
End IfIf Флаг_обновить_lcd_1 <> 0 Then
Переменная_str_1 = Str(переменная_integer_1)
Переменная_str_1 = Format(переменная_str_1 , "+ 0")
If Переменная_integer_1 = 0 Then
Mid(переменная_str_1 , 5 , 1) = " "
End If
Locate 2 , 13
Lcd Переменная_str_1
Флаг_обновить_lcd_1 = 0
Goto Главный_цикл
End IfIf Флаг_реакция_на_кнопки <> 0 Then
If Короткое_нажатие_энкодер_1 <> 0 Then
Incr Short_press
Short_press_str = Str(short_press)
Short_press_str = Format(short_press_str , " 0")If Флаг_направл_кольц_нажатия = 0 Then
Incr Кольцевое_нажатие_1
If Кольцевое_нажатие_1 > 1 Then
Флаг_направл_кольц_нажатия = 1
End If
Else
Decr Кольцевое_нажатие_1
If Кольцевое_нажатие_1 = 0 Then
Флаг_направл_кольц_нажатия = 0
End If
End IfIf Кольцевое_нажатие_1 = 0 Then
Locate 1 , 15
Lcd " x1"
Elseif Кольцевое_нажатие_1 = 1 Then
Locate 1 , 15
Lcd " x10"
Elseif Кольцевое_нажатие_1 = 2 Then
Locate 1 , 15
Lcd "x100"
End If
Короткое_нажатие_энкодер_1 = 0
End IfIf Длинное_нажатие_энкодер_1 <> 0 Then
Incr Long_press
For Val_byte = 1 To 5
Locate 1 , 1
Lcd " Save, or "
Locate 2 , 1
Lcd " Goto menu, or "
Locate 3 , 1
Lcd " Goto config "
Locate 4 , 1
Lcd " "
Waitms 500
Locate 1 , 1
Lcd " "
Locate 2 , 1
Lcd " "
Locate 3 , 1
Lcd " "
Waitms 250
Next Val_byte
Locate 1 , 1
Lcd " "
Locate 2 , 1
Lcd " Reboot "
Locate 3 , 1
Lcd " "
Locate 4 , 1
Lcd " "
Waitms 1000
Длинное_нажатие_энкодер_1 = 0'Reset Program
!jmp $00Enable Pcint0 ' После реакции на длинное нажатие кнопки энкодера, обязательно включаем прерывания!!!
End If
Count = 0
Флаг_реакция_на_кнопки = 0
Goto Главный_цикл
End If' Idle
'===============================================================================
Goto Главный_цикл
End
'==============================================================================='===============================================================================
Обработка_данных_энкодера:
'-------------------------------------------------------------------------------
If Счетчик_энкодера_1_вправо <> 0 Then
If Кольцевое_нажатие_1 = 0 Then
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
Elseif Кольцевое_нажатие_1 = 1 Then
Счетчик_энкодера_1_вправо = Счетчик_энкодера_1_вправо * 10
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
Elseif Кольцевое_нажатие_1 = 2 Then
Счетчик_энкодера_1_вправо = Счетчик_энкодера_1_вправо * 100
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
End If
Счетчик_энкодера_1_вправо = 0
Флаг_обновить_lcd_1 = 1
End IfIf Счетчик_энкодера_1_влево <> 0 Then
If Кольцевое_нажатие_1 = 0 Then
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
Elseif Кольцевое_нажатие_1 = 1 Then
Счетчик_энкодера_1_влево = Счетчик_энкодера_1_влево * 10
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
Elseif Кольцевое_нажатие_1 = 2 Then
Счетчик_энкодера_1_влево = Счетчик_энкодера_1_влево * 100
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
End If
Счетчик_энкодера_1_влево = 0
Флаг_обновить_lcd_1 = 1
End If
'-------------------------------------------------------------------------------
Return
'==============================================================================='===============================================================================
Const Const_time_long_press_button = 40 ' Время выдержки длинного нажатия
Const Const_time_short_press_button = 10 ' Время выдержки короткого нажатия
'===============================================================================
Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------
!push R31
!in R31 , sreg
!push R31'Если кнопка нажата
!SBIc Key_encoder_1_port , Key_encoder_1_pin ' Пропустить если бит в порту очищен
!rjmp Обработка_прерывания_timer2_1!lds R31 , {Счетчик_длины_нажатий}
!inc R31
!sts {Счетчик_длины_нажатий} , R31
!cpi R31 , Const_time_long_press_button ' Время выдержки длинного нажатия
!BRLO Выход_прерывания_timer2 ' Перейти если меньше!ldi R31 , 1
!sts {Длинное_нажатие_энкодер_1} , R31
!ldi R31 , 0
!sts {Короткое_нажатие_энкодер_1} , R31'Disable Pcint0
!lds R31 , Pcicr
!andi R31 , Disable_pcint0 '&B_1111_1110
!sts Pcicr , R31'Pcmsk0.2 = 0
!lds R31 , Pcmsk0
!andi R31 , Reset_isr_key_encoder '&B_1111_1011 ' Выключаем обработку прерывания с вывода PINB.2
!sts Pcmsk0 , R31
!rjmp Обработка_прерывания_timer2_6
!rjmp Выход_прерывания_timer2Обработка_прерывания_timer2_1:
!lds R31 , {Счетчик_длины_нажатий}
!cpi R31 , Const_time_short_press_button ' Время выдержки короткого нажатия
!BRSH Обработка_прерывания_timer2_5!ldi R31 , 1
!sts {Короткое_нажатие_энкодер_1} , R31
!rjmp Обработка_прерывания_timer2_5'============================
Выход_прерывания_timer2:
!pop R31
!out Sreg , R31
!pop R31!reti
'============================Обработка_прерывания_timer2_5:
!lds R31 , Pcmsk0
!ori R31 , Set_isr_key_encoder ' Включаем обработку прерывания с вывода PINB.2
!sts Pcmsk0 , R31Обработка_прерывания_timer2_6:
'Stop TIMER2
!lds R31 , TCCR2B
!andi R31 , &B_1111_1000
!sts TCCR2B , R31
!lds R31 , {Счетчик_длины_нажатий}
!sts {Count} , R31
!ldi R31 , 0
!sts {Счетчик_длины_нажатий} , R31
'TIMER2 = 0
!sts tcnt2 , R31
!ldi R31 , 1
!sts {Флаг_реакция_на_кнопки} , R31
!rjmp Выход_прерывания_timer2
'==============================================================================='===============================================================================
'ОБРАБОТКА ВНЕШНЕГО ПРЕРЫВАНИЯ 0 - ОТ ДВУХФАЗНОГО ИМПУЛЬСНОГО ЕНКОДЕРА
'ПРЕРЫВАНИЕ ПРОИСХОДИТ ПО СПАДУ НА ВХОДЕ P_CHA. ЗАТЕМ ПРОГРАММА ИНТЕГРИРУЕТ
' (ФИЛЬТРУЕТ) ЭТОТ УРОВЕНЬ, ДОЖИДАЯСЬ НАДЕЖНОГО УСТАНОВЛЕНИЯ "0". В МОМЕНТ
'ФИКСАЦИИ "0" НА ЛИНИИ P_cha РЕГИСТРИРУЕТСЯ УРОВЕНЬ P_chb , ПО КОТОРОМУ И
'ОПРЕДЕЛЯЕТСЯ НАПРАВЛЕНИЕ ВРАЩЕНИЯ. П/П РАБОТАЕТ ТАКЖЕ ПРИ ИСПОЛЬЗОВАНИИ
'ПРЕРЫВАНИЯ ОТ ЛЮБОГО ИЗМЕНЕНИЯ УРОВНЯ. НА СПАД СРАБАТЫВАЕТ, ФРОНТ ИГНОРИРУЕТ
'===============================================================================
Const Con_irt = 5 'КОНСТАНТА ИНТЕГРИРОВАНИЯ УРОВНЯ НА ВХОДЕ
Const Conirt1 = Con_irt * 1.5 'ПОЛТОРЫ КОНСТАНТЫ ИНТЕГРИРОВАНИЯ
Const Conirt2 = Con_irt * 2 'ДВЕ КОНСТАНТЫ ИНТЕГРИРОВАНИЯ
'===============================================================================
Pcint0_0:
!Inc R31 'УРОВЕНЬ ВЫСОКИЙ - ОТКАТ СЧЕТЧИКА
!Cpi R31 , Conirt1 'это Con_irt*1.5
!Brne pcint0_1 'ЕСЛИ ЖДЕМ СЛИШКОМ ДОЛГО - ВЫХОД
!Rjmp Выход_pcint0'===============================================================================
Обработка_прерывания_pcint0: 'ВНЕШНЕЕ ПРЕРЫВАНИЕ ОТ ЦИФРОВОЙ РУЧКИ
'===============================================================================
!push R31
!in R31 , sreg
!push R31'Если прерывание было от кнопки
!Sbic Key_encoder_1_port, Key_encoder_1_pin ' Пропустить если бит в порту очищен
!rjmp Прерывание_энкодера_1!ldi R31 , 0
!sts {Уровень_кнопки_энкодера_1} , R31
'Start TIMER2
!lds R31 , TCCR2B
!andi R31 , &B_1111_1000
!ori R31 , Prescale_1024 '&B_0000_0111 ' Выставляем Prescale = 1024, тем самым запуская TIMER2 (аналог "Start Timer2")
!sts TCCR2B , R31
'Pcmsk0.2 = 0
!lds R31 , Pcmsk0
!andi R31 , Reset_isr_key_encoder ' Выключаем обработку прерывания с вывода PINB.2
!sts Pcmsk0 , R31
!rjmp Выход_pcint0Прерывание_энкодера_1:
'ИНТЕГРИРУЮЩИЙ ФИЛЬТР (ФНЧ) ВХОДНОГО УРОВНЯ
!Ldi R31 , Con_irt 'ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ В СЧЕТЧИК
Pcint0_1:
!Sbic Encoder_1_port_1 , Encoder_1_pin_1 'ПРОВЕРИМ УРОВЕНЬ НА ВЫВОДЕ
!Rjmp pcint0_15 'ЕСЛИ НА НОЖКЕ "1" - ПЕРЕХОД
!Dec R31 'ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ
!Brne pcint0_1 'МНОГОКРАТНОГО ПОДТВЕРЖДЕНИЯ НИЗКОГО УРОВНЯ
!Rjmp pcint0_2'ЕСЛИ УРОВНЬ ВЫСОКИЙ
Pcint0_15:
!Inc R31 'УВЕЛИЧИВАЕМ СЧЕТЧИК
!Cpi R31 , Conirt2 'ЕСЛИ НА "1" УСТАНОВЛЕНА СЛИШКОМ ДОЛГО
!Brne Выход_pcint0 'НА ВЫХОД
!Rjmp pcint0_1
'----------------------------------------------------------------
'ПРОГРАММА РАСЧИТАНА НА КОДОВЫЙ ПЕРЕКЛЮЧАТЕЛЬ
'С НОРМАЛЬНО РАЗОМКНУТЫМИ КОНТАКТАМИ, ЗАМЫКАЮЩИМИСЯ
'ТОЛЬКО В МОМЕНТ ЩЕЛЧКА. ЭТО ОЧЕНЬ УПРОЩАЕТ ЗАДАЧУ
'----------------------------------------------------------------
'|<----- ВРАЩЕНИЕ ВЛЕВО (ИЛИ НАОБОРОТ, В ЗАВИСИМОСТИ ОТ МОНТАЖА)
'chA--- --------- ------ ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ
' ¦ ¦ chA ¦ ¦ ВРАЩЕНИЯ ЦИФРОВОГО КОДЕРА
' --- --- ОСНОВАНО НА АНАЛИЗЕ СОСТОЯНИЯ
'chB----- | --------- ---- КАНАЛА "B" В МОМЕНТ ЗАМЫКАНИЯ
' | ¦ | ¦ chB ¦ ¦ (ЩЕЛЧКА) В КАНАЛЕ "A"
' | --- ---
' | |<------ ВРАЩЕНИЕ ВПРАВО
'----------------------------------------------------------------
Pcint0_2:
'ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ
!Sbis Encoder_1_port_2 , Encoder_1_pin_2
!Rjmp pcint0_3 'ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ'ВРАЩЕНИЯ ВЛЕВО (УМЕНЬШЕНИЕ)
!Lds R31 , {Счетчик_энкодера_1_влево} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО
!Inc R31
!Sts {Счетчик_энкодера_1_влево} , R31
!Rjmp pcint0_4Pcint0_3:
'ВРАЩЕНИЯ ВПРАВО (УВЕЛИЧЕНИЕ)
!Lds R31 , {Счетчик_энкодера_1_вправо} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО
!Inc R31
!Sts {Счетчик_энкодера_1_вправо} , R31
Pcint0_4:
!Ldi R31 , 1
!Sts {Флаг_данные_энкодера_1} , R31 'поставить признак "НОВЫЕ ДАННЫЕ ЕНКОДЕРА"Выход_pcint0:
!pop R31
!out sreg , R31
!pop R31!reti
'-------------------------------------------------------------------------------
Return
'===============================================================================
$map ' Получаем карту распределения памяти компилятором Bascom
$regfile = "m328pdef.dat" ' http://www.atmel.com/images/Atmel-8272- … asheet.pdf
$crystal = 8000000 ' 1 МГц
$framesize = 64 ' Размер области используемой и необходимой для преобразований
$hwstack = 64 ' Размер аппаратного стека
$swstack = 64 ' Размер программного стека' $baud = 38400
'Ucsr0a.1 = 1 ' Baud = Baud * 2'===============================================================================
' Настройка МК для работы с LCD на базе контроллера hd44780
' Обратите внимание, библиотеки не используются, выводы могут быть любые
'===============================================================================
Config Lcdpin = Pin , Rs = Portc.0 , E = Portc.1 , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5
Config Lcd = 20 * 4 ' Используемый LCD
Initlcd ' Инициализируем LCD
Waitms 50 ' Ждем пока все запустится
Cursor Off Noblink ' Выключаем неморгающий курсор
' Cursor On Noblink ' Включаем неморгающий курсор
' Cursor Blink ' Включаем моргающий курсор
' Upperline 1 строка, Lowerline 2 строка, Thirdline 3 строка, Fourthline 4 строка - один из вариантов перехода на строку
Cls ' Чистим экран, на всякий случай'===============================================================================
' Конфигурация МК для работы с энкодерами
'===============================================================================
Config Timer2 = Timer , Prescale = 1024 , Clear Timer = 0 ' 16,384 ms при частоте МК 8МГц
Stop Timer2
Timer2 = 0
On Timer2 Обработка_прерывания_timer2'-----------------------------------------
'Конфигурация МК для работы с энкодером 1
'-----------------------------------------
Config Pinb.0 = Input : Set Portb.0
Encoder_1_port_1 Alias Pinb
Encoder_1_pin_1 Alias 0Config Pinb.1 = Input : Set Portb.1
Encoder_1_port_2 Alias Pinb
Encoder_1_pin_2 Alias 1Config Pinb.2 = Input : Set Portb.2
Key_encoder_1_port Alias Pinb
Key_encoder_1_pin Alias 2On Pcint0 Обработка_прерывания_pcint0 ' Подпрограмма обработки прерывания PCINT0
Pcmsk0 = &B_0000_0101 'PCINT0 (PINB.0) - один из боковых выводов энкодера + вывод кнопки (PCINT2 (PINB.2))Dim Count As Byte ' Временная переменная, в релизе удалить
Dim Val_byte As Byte ' Временная переменная, в релизе удалить
Dim Long_press As Byte ' Временная переменная, в релизе удалить
Dim Short_press As Byte ' Временная переменная, в релизе удалить
Dim Флаг_обновить_lcd_1 As Byte ' Временная переменная, в релизе удалить
Dim Кольцевое_нажатие_1 As Byte ' Временная переменная, в релизе удалить
Dim Счетчик_длины_нажатий As Byte
Dim Флаг_данные_энкодера_1 As Byte ' Временная переменная, в релизе удалить
Dim Флаг_реакция_на_кнопки As Byte ' Временная переменная, в релизе удалить
Dim Переменная_integer_1 As Integer
Dim Счетчик_энкодера_1_влево As Byte
Dim Счетчик_энкодера_1_вправо As Byte
Dim Длинное_нажатие_энкодер_1 As Byte
Dim Уровень_кнопки_энкодера_1 As Byte : Уровень_кнопки_энкодера_1 = 255
Dim Короткое_нажатие_энкодер_1 As Byte
Dim Флаг_направл_кольц_нажатия As ByteDim Short_press_str As String * 5
Dim Переменная_str_1 As String * 10'Начальное заполнение экрана
Locate 1 , 1
Lcd "Short_press " ; " x1"
Locate 2 , 1
Lcd "Encoder 1 " ; " 0"
Locate 3 , 1
Lcd " "'-------------- Разрешаем работу необходимых прерываний ----------------------
Pcifr.pcif0 = 1 : Enable Pcint0 ' Сброс флаг прерывания и разрешение прерывания, иначе получается сразу +1 от энкодера
Enable Timer2
'------------ Разрешаем работу всех включенных прерываний --------------------
Enable Interrupts
'===============================================================================
Главный_цикл:
'===============================================================================If Флаг_данные_энкодера_1 <> 0 Then
Gosub Обработка_данных_энкодера
Флаг_данные_энкодера_1 = 0
Goto Главный_цикл
End IfIf Флаг_обновить_lcd_1 <> 0 Then
Переменная_str_1 = Str(переменная_integer_1)
Переменная_str_1 = Format(переменная_str_1 , "+ 0")
If Переменная_integer_1 = 0 Then
Mid(переменная_str_1 , 5 , 1) = " "
End If
Locate 2 , 13
Lcd Переменная_str_1
Флаг_обновить_lcd_1 = 0
Goto Главный_цикл
End IfIf Флаг_реакция_на_кнопки <> 0 Then
If Короткое_нажатие_энкодер_1 <> 0 Then
Incr Short_press
Short_press_str = Str(short_press)
Short_press_str = Format(short_press_str , " 0")If Флаг_направл_кольц_нажатия = 0 Then
Incr Кольцевое_нажатие_1
If Кольцевое_нажатие_1 > 1 Then
Флаг_направл_кольц_нажатия = 1
End If
Else
Decr Кольцевое_нажатие_1
If Кольцевое_нажатие_1 = 0 Then
Флаг_направл_кольц_нажатия = 0
End If
End IfIf Кольцевое_нажатие_1 = 0 Then
Locate 1 , 15
Lcd " x1"
Elseif Кольцевое_нажатие_1 = 1 Then
Locate 1 , 15
Lcd " x10"
Elseif Кольцевое_нажатие_1 = 2 Then
Locate 1 , 15
Lcd "x100"
End If
Короткое_нажатие_энкодер_1 = 0
End IfIf Длинное_нажатие_энкодер_1 <> 0 Then
Incr Long_press
For Val_byte = 1 To 5
Locate 1 , 1
Lcd " Save, or "
Locate 2 , 1
Lcd " Goto menu, or "
Locate 3 , 1
Lcd " Goto config "
Locate 4 , 1
Lcd " "
Waitms 500
Locate 1 , 1
Lcd " "
Locate 2 , 1
Lcd " "
Locate 3 , 1
Lcd " "
Waitms 250
Next Val_byte
Locate 1 , 1
Lcd " "
Locate 2 , 1
Lcd " Reboot "
Locate 3 , 1
Lcd " "
Locate 4 , 1
Lcd " "
Waitms 1000
Длинное_нажатие_энкодер_1 = 0'Reset Program
!jmp $00Enable Pcint0 ' После реакции на длинное нажатие кнопки энкодера, обязательно включаем прерывания!!!
End If
Count = 0
Флаг_реакция_на_кнопки = 0
Goto Главный_цикл
End IfIdle
'===============================================================================
Goto Главный_цикл
End
'==============================================================================='===============================================================================
Обработка_данных_энкодера:
'-------------------------------------------------------------------------------
If Счетчик_энкодера_1_вправо <> 0 Then
If Кольцевое_нажатие_1 = 0 Then
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
Elseif Кольцевое_нажатие_1 = 1 Then
Счетчик_энкодера_1_вправо = Счетчик_энкодера_1_вправо * 10
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
Elseif Кольцевое_нажатие_1 = 2 Then
Счетчик_энкодера_1_вправо = Счетчик_энкодера_1_вправо * 100
Переменная_integer_1 = Переменная_integer_1 + Счетчик_энкодера_1_вправо
End If
Счетчик_энкодера_1_вправо = 0
Флаг_обновить_lcd_1 = 1
End IfIf Счетчик_энкодера_1_влево <> 0 Then
If Кольцевое_нажатие_1 = 0 Then
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
Elseif Кольцевое_нажатие_1 = 1 Then
Счетчик_энкодера_1_влево = Счетчик_энкодера_1_влево * 10
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
Elseif Кольцевое_нажатие_1 = 2 Then
Счетчик_энкодера_1_влево = Счетчик_энкодера_1_влево * 100
Переменная_integer_1 = Переменная_integer_1 - Счетчик_энкодера_1_влево
End If
Счетчик_энкодера_1_влево = 0
Флаг_обновить_lcd_1 = 1
End If
'-------------------------------------------------------------------------------
Return
'==============================================================================='===============================================================================
Обработка_прерывания_timer2:
'-------------------------------------------------------------------------------
If Pinb.2 = 0 Then
Incr Счетчик_длины_нажатийIf Счетчик_длины_нажатий > 25 Then
Gosub Обработка_прерывания_timer2_2
Длинное_нажатие_энкодер_1 = 1
Короткое_нажатие_энкодер_1 = 0
Disable Pcint0
Pcmsk0.2 = 0 ' Выключаем обработку прерывания с вывода PINB.2
End IfElse
If Счетчик_длины_нажатий < 10 Then
Короткое_нажатие_энкодер_1 = 1
End IfGosub Обработка_прерывания_timer2_1
End IfВыход_прерывания_timer2:
'-------------------------------------------------------------------------------
Return
'===============================================================================
Обработка_прерывания_timer2_1:
'-------------------------------------------------------------------------------
Pcmsk0.2 = 1 ' Включаем обработку прерывания с вывода PINB.2Обработка_прерывания_timer2_2:
Stop Timer2
Timer2 = 0
Count = Счетчик_длины_нажатий
Счетчик_длины_нажатий = 0
Флаг_реакция_на_кнопки = 1
'-------------------------------------------------------------------------------
Return
'==============================================================================='-------------------------------------------------------------------------------
'ОБРАБОТКА ВНЕШНЕГО ПРЕРЫВАНИЯ 0 - ОТ ДВУХФАЗНОГО ИМПУЛЬСНОГО ЕНКОДЕРА
'ПРЕРЫВАНИЕ ПРОИСХОДИТ ПО СПАДУ НА ВХОДЕ P_CHA. ЗАТЕМ ПРОГРАММА ИНТЕГРИРУЕТ
' (ФИЛЬТРУЕТ) ЭТОТ УРОВЕНЬ, ДОЖИДАЯСЬ НАДЕЖНОГО УСТАНОВЛЕНИЯ "0". В МОМЕНТ
'ФИКСАЦИИ "0" НА ЛИНИИ P_cha РЕГИСТРИРУЕТСЯ УРОВЕНЬ P_chb , ПО КОТОРОМУ И
'ОПРЕДЕЛЯЕТСЯ НАПРАВЛЕНИЕ ВРАЩЕНИЯ. П/П РАБОТАЕТ ТАКЖЕ ПРИ ИСПОЛЬЗОВАНИИ
'ПРЕРЫВАНИЯ ОТ ЛЮБОГО ИЗМЕНЕНИЯ УРОВНЯ. НА СПАД СРАБАТЫВАЕТ, ФРОНТ ИГНОРИРУЕТ
'-------------------------------------------------------------------------------
Const Con_irt = 5 '30 'КОНСТАНТА ИНТЕГРИРОВАНИЯ УРОВНЯ НА ВХОДЕ
Const Conirt1 = Con_irt * 1.5 'ПОЛТОРЫ КОНСТАНТЫ ИНТЕГРИРОВАНИЯ
Const Conirt2 = Con_irt * 2 'ДВЕ КОНСТАНТЫ ИНТЕГРИРОВАНИЯPcint0_0:
!Inc R31 'УРОВЕНЬ ВЫСОКИЙ - ОТКАТ СЧЕТЧИКА
!Cpi R31 , Conirt1 'это Con_irt*1.5
!Brne pcint0_1 'ЕСЛИ ЖДЕМ СЛИШКОМ ДОЛГО - ВЫХОД
!Rjmp Выход_pcint0'ВНЕШНЕЕ ПРЕРЫВАНИЕ ОТ ЦИФРОВОЙ РУЧКИ
Обработка_прерывания_pcint0:
If Pinb.2 = 0 ThenУровень_кнопки_энкодера_1 = 0
Start Timer2
Pcmsk0.2 = 0 ' Выключаем обработку прерывания с вывода PINB.2Else
Прерывание_энкодера_1:
'ИНТЕГРИРУЮЩИЙ ФИЛЬТР (ФНЧ) ВХОДНОГО УРОВНЯ
!Ldi R31 , Con_irt 'ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ В СЧЕТЧИК
Pcint0_1:
!Sbic Encoder_1_port_1 , Encoder_1_pin_1 'ПРОВЕРИМ УРОВЕНЬ НА ВЫВОДЕ
!Rjmp pcint0_15 'ЕСЛИ НА НОЖКЕ "1" - ПЕРЕХОД
!Dec R31 'ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ
!Brne pcint0_1 'МНОГОКРАТНОГО ПОДТВЕРЖДЕНИЯ НИЗКОГО УРОВНЯ
!Rjmp pcint0_2'ЕСЛИ УРОВНЬ ВЫСОКИЙ
Pcint0_15:
!Inc R31 'УВЕЛИЧИВАЕМ СЧЕТЧИК
!Cpi R31 , Conirt2 'ЕСЛИ НА "1" УСТАНОВЛЕНА СЛИШКОМ ДОЛГО
!Brne Выход_pcint0 'НА ВЫХОД
!Rjmp pcint0_1
'---------------------------------------------
'ПРОГРАММА РАСЧИТАНА НА КОДОВЫЙ ПЕРЕКЛЮЧАТЕЛЬ
'С НОРМАЛЬНО РАЗОМКНУТЫМИ КОНТАКТАМИ, ЗАМЫКАЮЩИМИСЯ
'ТОЛЬКО В МОМЕНТ ЩЕЛЧКА. ЭТО ОЧЕНЬ УПРОЩАЕТ ЗАДАЧУ
'---------------------------------------------
' |<----- ВРАЩЕНИЕ ВЛЕВО (ИЛИ НАОБОРОТ, В ЗАВИСИМОСТИ ОТ МОНТАЖА)
'chA--- --------- ------ ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ
' ¦ ¦ chA ¦ ¦ ВРАЩЕНИЯ ЦИФРОВОГО КОДЕРА
' --- --- ОСНОВАНО НА АНАЛИЗЕ СОСТОЯНИЯ
'chB----- | --------- ---- КАНАЛА "B" В МОМЕНТ ЗАМЫКАНИЯ
' | ¦ | ¦ chB ¦ ¦ (ЩЕЛЧКА) В КАНАЛЕ "A"
' | --- ---
' | |<------ ВРАЩЕНИЕ ВПРАВО
'---------------------------------------------
Pcint0_2:
'ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ
!Sbis Encoder_1_port_2 , Encoder_1_pin_2
!Rjmp pcint0_3 'ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ'ВРАЩЕНИЯ ВЛЕВО (УМЕНЬШЕНИЕ)
!Lds R31 , {Счетчик_энкодера_1_влево} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО
!Inc R31
!Sts {Счетчик_энкодера_1_влево} , R31
!Rjmp pcint0_4Pcint0_3:
'ВРАЩЕНИЯ ВПРАВО (УВЕЛИЧЕНИЕ)
!Lds R31 , {Счетчик_энкодера_1_вправо} 'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО
!Inc R31
!Sts {Счетчик_энкодера_1_вправо} , R31
Pcint0_4:
!Ldi R31 , 1
!Sts {Флаг_данные_энкодера_1} , R31 'поставить признак "НОВЫЕ ДАННЫЕ ЕНКОДЕРА"End If ' If Pinb.2 = 0 Then
Выход_pcint0:
'-------------------------------------------------------------------------------
Return
'===============================================================================
Симуляция (Протеус 7.10 sr0) + исходники (ASM; Bascom 2.0.7.1) + фото + видео - скачать
+4 - ничего себе, такая популярная тема, а я думал никто и не заметит.
Ещё вариант работы с энкодером, используется 1 таймер.
Мне нравится больше всех остальных. Работают даже убитые в хлам. Обвязка не нужна.
Симуляция (Протеус 7.10) + исходник (Bascom 2.0.7.1) - скачать, для форумчан из Украины качать через VPN, или пишите, закину на mail.
в процессе вращения в переменной "Direction" получаете +1 или -1, т.е., повернули вправо, повернули влево.
Если ±1 мало, умножаете на 2, 3, 4, ... 100, получаете шаг вращения 2, 3, 4, ...100переменная "Direction", обязательно Integer
Prev_encoder_value_int - предыдущее значение вашей переменной
Encoder_value_int - текущее значениедля работы энкодера нужно прерывание по таймеру (антидребезг), написано на ASM для максимального быстродействия, можно использовать в обработчике 7-seg развёртки
в основном цикле нужен только этот кусочек:
If Encoder_value_int <> Prev_encoder_value_int Then
Prev_encoder_value_int = Encoder_value_int
End Ifглавное, чтобы туда попадать, хоть изредка
Эти константы не трогать, это автомат текущего состояния энкодера
Const State_0 = 0
Const State_a = 1
Const State_b = 2
Const State_ab = 3Направление вращения, есть энкодеры с реверсом.
Почему именно переменная, чтобы можно было менять из менюшки
Значение 0 или 1
Dim Enc_reverse As Byte : Enc_reverse = 1 'Переменная для хранения значения реверсивности энкодера (китайский вариант)
Настройка для других выводов МК,
'===============================================================================
' Н А С Т Р О Й К А Э Н К О Д Е Р А
'===============================================================================
Encoder_pin Alias Pind 'используемый порт
Encoder_ab Alias &B_0000_1100 'используемые выводы
Config Pind.2 = Input : Portd.2 = 1
Config Pind.3 = Input : Portd.3 = 1
Const State_0 = 0
Const State_a = &B_0000_0100
Const State_b = &B_0000_1000
Const State_ab = &B_0000_1100
'===============================================================================
' Н А С Т Р О Й К А Э Н К О Д Е Р А
'===============================================================================
Encoder_pin Alias Pinb 'используемый порт
Encoder_ab Alias &B_1100_0000 'используемые выводы
Config Pinb.6 = Input : Portb.6 = 1
Config Pinb.7 = Input : Portb.7 = 1
Const State_0 = 0
Const State_a = &B_0100_0000
Const State_b = &B_1000_0000
Const State_ab = &B_1100_0000
Вы здесь » Программирование ATMEL в BASCOM. » Примеры применения в среде Баском » Исследование энкодера