QDEC в AtXmega

Аватара пользователя
Ev3658
Новичок
Сообщения: 35
Зарегистрирован: 13 фев 2017, 16:08
Репутация: 29
Настоящее имя: Евгений
Контактная информация:

QDEC в AtXmega

Сообщение Ev3658 »

Вдруг кому пригодится городить что-то на любом языке счёт линеек/энкодеров в микроконтроллере серии Xmega поддерживающие аппаратный счёт квадратурного сигнала.
На картинке инициализация аппаратной части на счёт и на выход в ноль.
Xmega Qdec (3364 просмотра) <a class='original' href='./download/file.php?id=197488&sid=b357e137731e3ee858b21c36e3c5cc16&mode=view' target=_blank>Загрузить оригинал (325.85 КБ)</a>
Xmega Qdec
То-есть движение осями на аппаратном уровне при помощи импульсов на частотник.
Импульсы задаются тоже внешними таймерами.

К сожалению счётчик в Xmega 16 битный, аппаратно не получается сложить два таймера в один счётный таймер, всё остальное работает без использования центрального процессора.
То-есть задаёте длину, даёте такты и аппаратно создаются импульсы для перемещения на нужное пространство.
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: QDEC в AtXmega

Сообщение Duhas »

Ev3658 писал(а): 21 авг 2021, 01:48 К сожалению счётчик в Xmega 16 битный, аппаратно не получается сложить два таймера в один счётный таймер,
можно, но с ограничениями
Аватара пользователя
Ev3658
Новичок
Сообщения: 35
Зарегистрирован: 13 фев 2017, 16:08
Репутация: 29
Настоящее имя: Евгений
Контактная информация:

Re: QDEC в AtXmega

Сообщение Ev3658 »

Duhas писал(а): 21 авг 2021, 11:41
Ev3658 писал(а): 21 авг 2021, 01:48 К сожалению счётчик в Xmega 16 битный, аппаратно не получается сложить два таймера в один счётный таймер,
можно, но с ограничениями
Как раз и есть ограничение "задействовать центральный процессор" в нарисованной аппаратной реализаци.
Когда изучал этот QDEC в Xmega, искал помощи на иностранных языках, к сожалению немного не разбираюсь в них и соорудил такую картинку:
Quad.JPG (3311 просмотров) <a class='original' href='./download/file.php?id=197521&sid=b357e137731e3ee858b21c36e3c5cc16&mode=view' target=_blank>Загрузить оригинал (54.58 КБ)</a>
Это и есть прерывание, занимающее шину данных и т.п., если уместить в 16 битные таймеры, то можно создать небольшое пространство.

Примерно оптическая линейка 20-30см. без проблем и блин как точно!!! 0.005мм. (китайская)
Энкодер на двигателе тоже не проблема, проверял QDEC на двигателе с энкодером 2500 (10 000 импульсов QDEC за 1 оборот) на скорости 2500 оборотов и ошибок небыло.

Так-же реализовал Алгоритм Брезенхэма в Xmega, который просто озадачивал таймеры на нужные отрезки синхронно и аппаратно как на картинке.

Если интересует, вот код Bascom AVR:
(для просмотра содержимого нажмите на ссылку)
$regfile = "xm256a3def.dat"
$crystal = 33177600
$hwstack = 200
$swstack = 128
$framesize = 235

$lib "xmega.lib" : $external _xmegafix_clear : $external _xmegafix_rol_r1014


Config Osc = Enabled , Extosc = Enabled , Pllosc = Enabled , _
Range = 2mhz_9mhz , Startup = Xtal_1kclk , Pllsource = Extclock , Pllmul = 9 , Plldiv2 = Disabled , 32khzosc = Disabled ', 32khzpowermode = Normal
Config Sysclock = Pll , Prescalea = 1 , Prescalebc = 1_1
Config Priority = Static , Vector = Application , Lo = Enabled , Med = Enabled , Hi = Enabled

'===================== Порты первого частотника
Error1 Alias Pind.5 'Вход ошибки
Config Error1 = Input
Config Xpin = Portd.5 , Outpull = Pullup

Pozicia1 Alias Pind.4 'Вход сигнала выхода на позицию
Config Pozicia1 = Input
Config Xpin = Portd.4 , Outpull = Pullup

On1 Alias Portd.7 'Включить часттник
Config On1 = Output

Reset1 Alias Portd.6 'Сброс ошибки в частотнике
Config Reset1 = Output

Rev1 Alias Porte.0 'Направление вращения
Config Rev1 = Output

Puls1 Alias Porte.1 'Выход импульсов перемещения
Config Puls1 = Output

'Входы квадратурной дешифрации
Config Pina.0 = Input 'A
Config Pina.1 = Input 'B
Config Pina.2 = Input 'Z
Config Xpin = Pina.0 , Sense = Rising 'Контроль входа на обнаружение падающего фронта
Config Xpin = Pina.1 , Sense = Rising 'Контроль входа на обнаружение падающего фронта
Config Xpin = Pina.2 , Sense = Both 'Контроль входа на обнаружение падающего фронта
'===================== Порты второго частотника
Error2 Alias Pinb.1
Config Error1 = Input
Config Xpin = Portb.1 , Outpull = Pullup

Pozicia2 Alias Pinb.0
Config Pozicia2 = Input
Config Xpin = Portb.0 , Outpull = Pullup

On2 Alias Portb.3 'Включить часттник
Config On2 = Output

Reset2 Alias Portb.2 'Сброс ошибки в частотнике
Config Reset2 = Output

Rev2 Alias Portd.0 'Направление вращения
Config Rev2 = Output

Puls2 Alias Portd.1 'Выход импульсов перемещения
Config Puls2 = Output

'Входы квадратурной дешифрации
Config Porta.3 = Input 'A
Config Porta.4 = Input 'B
Config Porta.5 = Input 'Z
Config Xpin = Porta.3 , Sense = Rising 'Контроль входа на обнаружение падающего фронта
Config Xpin = Porta.4 , Sense = Rising 'Контроль входа на обнаружение падающего фронта
Config Xpin = Porta.5 , Sense = Both 'Контроль входа на обнаружение падающего фронта
'===================== Энкодер шпинделя
'Входы квадратурной дешифрации
Config Portc.5 = Input 'A
Config Portc.6 = Input 'B
Config Portc.7 = Input 'Z

'===================== Настройка UART
Config Com7 = 115200 , Mode = Asynchroneous , Parity = None , Stopbits = 1 , Databits = 8
Config Portf.2 = Input 'RX
Config Portf.3 = Output 'TX
Open "COM7:" For Binary As #1
On Usartf0_rxc Serialinput
Enable Usartf0_rxc
Dim S As String * 21
Dim B As Byte
Dim Priem As Bit




Dim Takt1 As Byte
Dim Takt2 As Byte

Dim Pzsm1 As Byte
Dim Pzsm2 As Byte

Dim En1 As Byte
Dim En2 As Byte


'===================== Каналы событий
'квадратурной дешифрации
Config Event_system = Dummy , Mux0 = Porta.0 , Qd0 = Enabled , Digflt0 = 2
Config Event_system = Dummy , Mux2 = Porta.3 , Qd2 = Enabled , Digflt2 = 2
Config Event_system = Dummy , Mux4 = Portc.5 , Qd4 = Enabled , Digflt4 = 2

'Тактовое событие
Config Event_system = Dummy , Mux1 = Tcf0_ovf 'Общий такт перемещения
Config Event_system = Dummy , Mux3 = Tce0_ccb 'Счёт импульсов перемещения 1
Config Event_system = Dummy , Mux5 = Tcd0_ccb 'Счёт импульсов перемещения 2
'===================== Таймеры квадратурной дешифрации

Tcc1_per = 9999
Tcc0_per = 9999
Config Tcc1 = Normal , Prescale = E0 , Event_source = E0 , Event_action = Qdec , Event_delay = Enabled 'Квадратура двигателя 1
Config Tcc0 = Normal , Prescale = E2 , Event_source = E2 , Event_action = Qdec , Event_delay = Enabled 'Квадратура двигателя 2
Config Tcf1 = Normal , Prescale = E2 , Event_source = E2 , Event_action = Qdec , Event_delay = Enabled

On Tcc1_ovf Enc1:
Enable Tcc1_ovf

On Tcc0_ovf Enc2:
Enable Tcc0_ovf


'===================== Таймер счёта импульсов
Config Tce1 = Normal , Prescale = E3 , Event_source = E3
Config Tcd1 = Normal , Prescale = E5 , Event_source = E5
Tce1_per = 9999 'ограничение счёта импульсов X
Tcd1_per = 9999 'ограничение счёта импульсов Z

'Tce1_cca = 130 'Выход на позицию X в мм.
'Tcd1_cca = 130 'Выход на позицию Z в мм.
'Pzsm1 = 100
'Pzsm2 = 100


'===================== Таймеры импульсов
Config Tce0 = Pwm , Prescale = E1 , Event_source = E1 , Compareb = Enabled
Config Tcd0 = Pwm , Prescale = E1 , Event_source = E1 , Compareb = Enabled
Tce0_ccb = 1
Tcd0_ccb = 1

Tce0_per = 1
Tcd0_per = 1

Tce0_ctrld = 0
Config Tcf0 = Normal , Prescale = Off , Event_delay = Enabled
Tcf0_per = 10


Dim Buff(100) As Byte
Dim Speed(255) As Byte
Dim Napr(255) As Byte
Dim Xmm(255) As Word
Dim Xsm(255) As Byte
Dim Ymm(255) As Word
Dim Ysm(255) As Byte
Dim Tm1 As Byte
Dim Stoptm As Byte

Dim Xvr As Word
Dim Zvr As Word
Dim Vrx As Long
Dim Vrz As Long
Dim Vr As Word

Dim X1 As Byte At Xvr Overlay
Dim X2 As Byte At Xvr + 1 Overlay

Dim Z1 As Byte At Zvr Overlay
Dim Z2 As Byte At Zvr + 1 Overlay

'===================== Тактовый таймер





On Tce1_ovf Pl1
Enable Tce1_ovf
On Tcd1_ovf Pl2
Enable Tcd1_ovf

On Tce1_cca Pz1
Enable Tce1_cca
On Tcd1_cca Pz2
Enable Tcd1_cca


Print #1 , "START"
Dim X As Long

Dim Z As Long
Set On1
Set On2
Set Rev1
Enable Interrupts

Do
Waitms 300
X = En1 * 10000
Z = En2 * 10000
X = X + Tcc1_cnt
Z = Z + Tcc0_cnt
Print #1 , X ; " " ; Z
'Print #1 , En1 ; " " ; Tcc1_cnt ; " " ; En2 ; " " ; Tcc0_cnt
'Print #1 , Takt1 ; " " ; Takt2


Loop


Serialinput:

B = Usartf0_data

If Tm1 > 0 Then
If Tm1 = 9 And B = 127 Then
Rev1 = Buff(2).0
Rev2 = Buff(2).1
X2 = Buff(3) 'Выход на позицию X в мм.
X1 = Buff(4) 'Выход на позицию X в мм.


Pzsm1 = Buff(5)

Z2 = Buff(6) 'Выход на позицию Z в мм.
Z1 = Buff(7) 'Выход на позицию Z в мм.

Pzsm2 = Buff(8)

Vrx = Pzsm1 * 10000
Vrx = Vrx + Xvr
Vrz = Pzsm2 * 10000
Vrz = Vrz + Zvr

If Vrx > Vrz Then
Tce0_per = 2 'Делитель X
Vr = Vrx Mod Vrz
Print #1 , Vrx ; " " ; Vrz ; " " ; Vr
Vrx = Vrx / Vrz
'Vr = Vr / Vrx
Vrx = Vrx * 3
'Vr = Vr / Vrx
'Vr = Vr + Vrx
Tcd0_per = Vrx + 2 'Делитель Z
Tce0_ccb = 1
Tcd0_ccb = Vrx / 2
Elseif Vrx < Vrz Then
Tcd0_per = 2
Vr = Vrz Mod Vrx

Vrx = Vrz / Vrx
Vrx = Vrx * 3
Tce0_per = Vrx + 2 'Делитель X
Tce0_ccb = Vrx / 2
Tcd0_ccb = 1
Else
Tce0_per = 2 'Делитель X
Tcd0_per = 2 'Делитель Z
Tce0_ccb = 1
Tcd0_ccb = 1
End If
Tm1 = 0

Tce1_cca = Xvr
Tcd1_cca = Zvr
Stoptm = 0
Config Tce0 = Pwm , Prescale = E1 , Event_source = E1 , Compareb = Enabled
Config Tcd0 = Pwm , Prescale = E1 , Event_source = E1 , Compareb = Enabled

Tcf0_per = Buff(1) * 8
Config Tcf0 = Normal , Prescale = 4
'Tcf0_ctrla = 8

'Priem = 1
Print #1 , Buff(1) ; ",Xmm:" ; Tce1_cca ; ",Xcm:" ; Pzsm1 ; ",Zmm:" ; Tcd1_cca ; ",Zcm:" ; Pzsm2 ; ",DX:" ; Tce0_per ; ",DZ:" ; Tcd0_per
'Print #1 , Vrx ; " " ; Vrz ; " PX:" ; Tce0_per ; " PZ:" ; Tcd0_per
Elseif Tm1 = 21 And B = 128 Then
Tcf0_per = Buff(20) * 8
Tm1 = 0
Else
Buff(tm1) = B
Incr Tm1
End If

Else
Select Case B
Case 126 : Tm1 = 1
Case 125 : Tm1 = 20
End Select

End If
Return

Pl1:
Incr Takt1
Return
Pl2:
Incr Takt2
Return

Pz1:
If Takt1 => Pzsm1 Then
If Stoptm = 1 Then
Gosub Stoped:
Else
'Print #1 , "X STOP"
Tce0_ctrla = 0
Stoptm = 1
End If
End If

Return

Pz2:
'Print #1 , "Y" ; Takt2 ; " =>" ; Pzsm2
If Takt2 => Pzsm2 Then
If Stoptm = 1 Then
Gosub Stoped:
Else
Tcd0_ctrla = 0

Stoptm = 1
End If
End If
Return

Stoped:

Tcf0_ctrla = 0
Tce0_ctrla = 0
Tcd0_ctrla = 0
Print #1 , Takt1 ; " " ; Tce1_cnt ; " " ; Takt2 ; " " ; Tcd1_cnt
Takt1 = 0

Tce0_cnt = Takt1
Tcd0_cnt = Takt1
Tce1_cnt = Takt1
Tcd1_cnt = Takt1
Takt2 = Takt1
'Print #1 , "STOP"
Return

Enc1:
If Tcc1_ctrlfset.0 = 0 Then
Incr En1
Else
Decr En1
End If
'Tcc1_intflags.0 = 0
Return

Enc2:
If Tcc0_ctrlfset.0 = 0 Then
Incr En2
Else
Decr En2
End If
'Tcc0_intflags.0 = 0
Return
Само собой он требует отладки. Я даже стойку замутил простую))))
Аппаратная часть может позволить создать простое устройство и даже с VGA выходом (даже с внутренней памятью):
Duhas
Мастер
Сообщения: 1949
Зарегистрирован: 10 окт 2015, 23:25
Репутация: 284
Настоящее имя: Андрей
Откуда: Красноярск
Контактная информация:

Re: QDEC в AtXmega

Сообщение Duhas »

ограничение не с ЦП связано, а с тем что не дифференцируется переполнение в + и -, соответственно закаскадировать таймеры через EVSYS можно, но только в +
Ответить

Вернуться в «Оффтоп»