Пропорциональное управление на МК с нуля
| |
uwrtey | Дата: Вторник, 19.03.2013, 10:08 | Сообщение # 151 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| да, в главном цикле я накосячил...
не успеваю за своими мыслями......
|
|
| |
uwrtey | Дата: Вторник, 19.03.2013, 12:30 | Сообщение # 152 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| наверно как то так. ( я сейчас на работе, сосредоточится не могу )
не успеваю за своими мыслями......
|
|
| |
ВитГо | Дата: Вторник, 19.03.2013, 13:55 | Сообщение # 153 |
Полковник
Группа: Администраторы
Сообщений: 2422
Статус: Offline
| нет, так тоже не правильно: Код
cicle:
ldi Temp6, 0 ; счетчик отправленных каналов ( фаза передачи )
ldi Temp7, 3 ; только что отправили синхроимпульс ( или это запуск МК )
loop_wait_2: ; цикл вывода PPM
cpi Temp6, 5 ; отправили синхроимпульс ??? brne loop_wait_2 ; если нет, то циклимся
loop_wait_3: ; цикл опроса каналов АЦП
cpi Temp5, 3 ; прочитали все три канала ? brne loop_wait_3 ; если нет, то циклимся
Rjmp cicle
у тебя должно быть одно прерывание по ocr !
для работы этого прерывания заводи переменные: ch_count - количество каналов для передачи (или ты завтра, когда будешь делать 5ти канальную аппу - будешь все с нуля переписывать?) curr_ch - номер текущего канала ch_phase - фаза передачи (канальный импульс или пауза в 300 мкс) pack_len - общая длительность пакета ppm (бывает 20 а бывает 22,5 или даже 25 мс) ну и конечно массив для хранения длительностей каналов
вот это ты должен настроить в main своей программы (то есть при старте) после настроек портов, дисплеев и так далее..
после этого ты должен включить прерывания и включить процесс генерации далее - захват данных с ацп и генерация сигнала ппм должны происходить автоматически в прерывании ocr ! без какого либо участия главной программы - поверь в ней ты найдешь чем заняться (и таймер полета считать, и на дисплее положение ручек рисовать, ну а в будущем микшированием заниматься)
соответственно в прерывании сразу проверяем фазу передачи (ch_phase) - если например =0 то значит переходим на передачу паузы в 300 мкс, и для следующего вызова (когда нужно будет передавать импульс) устанавливаем ch_phase = 1 и выходим из прерывания ! пусть дальше работает программа в main, для передачи сейчас ничего делать не нужно ! (все уже сделали, пауза передается)
если же ch_phase = 1 - значит нужно передавать импульс ! для этого на будущее устанавливаем ch_phase=0 (потом паузу передавать будем), и берем номер канала для передачи curr_ch и количество каналов всего ch_count - если curr_ch<ch_count то читаем значение канала из памяти и отправляем в ocr, если равны - то читаем значение паузы и отправляем в ocr причем если отправили канал - то вычитаем его значение из длительности всей пачки (первоначально это pack_len) - таким образом после передачи всех каналов у нас будет известна общая длительность паузы.. далее, если передали все каналы и передаем паузу - то сбрасываем все переменные для передачи паузы перед нулевым каналом.. в том числе сбрасываем длительность паузы по значению pack_len - чтобы в новой пачке начать отсчет паузы заново ну и в простом варианте здесь же можно читать все каналы АЦП (это плохой вариант, но он простой) либо читать АЦП после передачи соответствующего канала (то есть когда передали канал, запускаем преобразование АЦП, и потом значение с АЦП забираем когда передаем паузу)...
вот где то такой алгоритм должен быть
поскольку вся работа в прерывании - то при входе в прерывание нужно сохранять все регистры (которые потрешь в работе) а на выходе их нужно восстановить - иначе не будет работать основная программа
сейчас попробуй набросать каркас процедуры прерывания без чтения значений ацп..
вообще начни с начала: селектор фазы импульс\пауза селектор канал\пауза пакета и так далее.. таким образом и подойдешь уже к ацп....
цель : написать прерывание которое работает полностью отдельно от основной программы !!!
если это сделаешь - то вот тебе и многозадачность в передатчике :-) вернее двузадачность.. но в принципе на прерываниях можно делать сколько угодно таких задач (лишь бы производительности хватило)
Виталий (аka ВитГо)
|
|
| |
uwrtey | Дата: Среда, 20.03.2013, 13:20 | Сообщение # 154 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
|
переменные так заводить ?
.set ch_count=2 ; - количество каналов для передачи .set curr_ch=0 ;- номер текущего канала .set ch_phase=0 ;- фаза передачи (канальный импульс или пауза в 300 мкс) .set pack_len=40000 ;- общая длительность пакета ppm (длительность в "тиках таймера")
или переменные в РОН сделать?
.def ch_count=R22 ; указатель отправленного канала .def curr_ch=R23 ;- номер текущего канала .def ch_phase=R24 ;- фаза передачи (канальный импульс или пауза в 300 мкс) .def pack_len=R25 ;- общая длительность пакета ppm (длительность в "тиках таймера")
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Среда, 20.03.2013, 22:02 |
|
| |
ВитГо | Дата: Среда, 20.03.2013, 15:23 | Сообщение # 155 |
Полковник
Группа: Администраторы
Сообщений: 2422
Статус: Offline
| нет в регистрах точно не делать !! ведь тогда их нельзя будет использовать в основной программе !!
Виталий (аka ВитГо)
|
|
| |
uwrtey | Дата: Среда, 20.03.2013, 22:20 | Сообщение # 156 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| я не работал с переменными типа .SET ...=..., гугл особо не помог... так что тут туплю.... можно ли с переменными такого типа работать как с РОН ?
например:
.set curr_ch=0___________________; номер текущего канала .... .... INC curr_ch_____________________; увеличиваем номер канала ADC для чтения / так можно делать???
????
или такую переменную можно изменить только с помощью .set ?
например:
.set curr_ch=0_____________________; номер текущего канала ...... ...... .set curr_ch=1_____________________; номер текущего канала
________________________________________________________
Цитата (ВитГо) у тебя должно быть одно прерывание по ocr ! всмысле? прерывания по АЦП не должно быть?
видимо АЦП устроен аппаратно и процессор ему не нужен ( как с ШИМ ) ?
вижу два варианта: 1) можно генерировать АЦП по таймеру 2) можно генерировать АЦП вручную при входе в прерывание по таймеру ( скорее всего этот вариант )
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Четверг, 21.03.2013, 01:22 |
|
| |
uwrtey | Дата: Четверг, 21.03.2013, 01:21 | Сообщение # 157 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| Лучше я сразу покажу, что наделал - пока я совсем далеко не ушел.. ( а то сейчас наделаю делов... )
Виталий, посмотри пожалуйста, это Ты хотел увидеть ? и правильно ли я работаю с переменными ?
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Четверг, 21.03.2013, 02:15 |
|
| |
ВитГо | Дата: Четверг, 21.03.2013, 11:44 | Сообщение # 158 |
Полковник
Группа: Администраторы
Сообщений: 2422
Статус: Offline
| неа, у тебя прямо си какой то :-)))
переменная это ячейка ОЗУ
ch_count: .byte 1
соответственно читаем переменную LDS R16, ch_count
потом работаем с ней как с регистром R16
и в когда нужно сохраняем опять в ячейку памяти STS ch_count, R16
конечно можно использовать и другие регистры (не только R16)
Виталий (аka ВитГо)
|
|
| |
uwrtey | Дата: Четверг, 21.03.2013, 13:30 | Сообщение # 159 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| ясно, спасибо информацию взял тут , так и знал, что как то не так
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Четверг, 21.03.2013, 22:02 |
|
| |
uwrtey | Дата: Четверг, 21.03.2013, 23:56 | Сообщение # 160 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| Виталий, я постоянно путаюсь при работе с метками. А если быть точнее, то путаюсь я в том, что не знаю работаю я с данными, содержащимися по адресу метки, или с адресом этой метки...
Цитата LDI Загрузить константу
LDS Прямая загрузка
LD Косвенная загрузка например:
здесь в регистровую пару загрузится адрес метки
Код key_buff: .byte 1________________; зарезервируем 1 байт в ОЗУ
______________________________; загружаем адрес метки (key_buff) находящейся в ОЗУ в регистровую пару "Z" ___ldi ZL,low (key_buff)__________; младший байт адреса ___ldi ZH,high(key_buff)__________; старший байт адреса
а вот ниже в регистровую пару сразу загрузим значение из константы
Код .EQU ImpLen=0xCE4_________;константа
___LDI XH ,high(ImpLen)______; загрузим значение из константы ___LDI XL,low(ImpLen)________;
почему такая разница?
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Пятница, 22.03.2013, 01:20 |
|
| |
uwrtey | Дата: Пятница, 22.03.2013, 05:44 | Сообщение # 161 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| ну вот, исправил переменные.
осталось написать: 1) Проверку количества отправленных каналов. И если три канала отправлено, то отправлять синхроимпульс 2) Вычисление длины синхроимпульса
Добавлено (22.03.2013, 05:44) --------------------------------------------- Виталий, а можно вместо
Код ldi YL, low(ADC_len) ; загружаем в "Y" адрес метки "ADC_len" ldi YH, High(ADC_len) ;
ld XL, Y+ ; загружаем в "X" данные из адреса находящегося в "Y" ld XH, Y+ ;
сделать вот так
Код lds XL, ADC_len ; загружаем в "X" данные из метки "ADC_len" lds XH, ADC_len+1 ;
???
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Пятница, 22.03.2013, 21:39 |
|
| |
ВитГо | Дата: Пятница, 22.03.2013, 07:42 | Сообщение # 162 |
Полковник
Группа: Администраторы
Сообщений: 2422
Статус: Offline
| просто если LDI - то ты загружаешь в регистр число ! это может быть константа, а может быть адрес указанный в виде метки (это же тоже число)
а если LDS - то ты загружаешь в регистр содержимое ОЗУ по указанному адресу (константе) причем это может быть и метка и вручную заданная константа..
ну и по LD - ты загружаешь в регистр значение из содержимого ОЗУ адрес которого указан в регистровой паре (X, Y, Z)
ну и для чтения flash есть команда LPM - это чтение в регистр содержимого флеша, адрес всегда в регистре Z
поэтому вместо Цитата (uwrtey) Код
ldi YL, low(ADC_len) ; загружаем в "Y" адрес метки "ADC_len" ldi YH, High(ADC_len) ;
ld XL, Y+ ; загружаем в "X" данные из адреса находящегося в "Y" ld XH, Y+ ;
конечно можно
Цитата (uwrtey) Код
lds XL, ADC_len ; загружаем в "Y" адрес метки "ADC_len" lds XH, ADC_len+1 ;
Виталий (аka ВитГо)
|
|
| |
uwrtey | Дата: Пятница, 22.03.2013, 09:39 | Сообщение # 163 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| ок. Это радует. Значит в моей голове по тихоньку начинает наводится порядок.
Цитата если LDS - то ты загружаешь в регистр содержимое ОЗУ по указанному адресу (константе) причем это может быть и метка и вручную заданная константа.. с меткой понятно, а как это "в ручную заданная константа"? Ты имел ввиду, что можно указывать не только метку, но и просто адрес ОЗУ в виде числа...???
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Пятница, 22.03.2013, 21:40 |
|
| |
ВитГо | Дата: Пятница, 22.03.2013, 23:44 | Сообщение # 164 |
Полковник
Группа: Администраторы
Сообщений: 2422
Статус: Offline
| Цитата (uwrtey) с меткой понятно, а как это "в ручную заданная константа"? Ты имел ввиду, что можно указывать не только метку, но и просто адрес ОЗУ в виде числа...???
конечно ! разверни смысл метки - это же просто число ! а число может быть и константой ! поэтому ничто тебе не мешает задавать адреса вручную.. просто так голову сломаешь все помнить и метками проще (особенно когда между двумя переменными воткнешь третью) - компилятор все сам рассчитывает но иногда и вручную можно это делать
Виталий (аka ВитГо)
|
|
| |
uwrtey | Дата: Суббота, 23.03.2013, 00:24 | Сообщение # 165 |
Генерал-майор
Группа: Администраторы
Сообщений: 3270
Статус: Offline
| ну вот, я что-то сделал, но еще не проверял...
не успеваю за своими мыслями......
Сообщение отредактировал uwrtey - Суббота, 23.03.2013, 00:46 |
|
| |
|