Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Дисплеи и индикация » Вывод данных на LCD / Самопроизвольное изменение переменной


Вывод данных на LCD / Самопроизвольное изменение переменной

Сообщений 1 страница 12 из 12

1

Всем доброго времени суток!

сотел бы найти совета, по поводу «явления» с которым мне пришлось столкнуться. Большим специалистом в области программирования микроконтроллеров себя не считаю, хотя и усиленно изучаю этот предмет. Это все и заставляет обратится к совету более опытных людей.

Путем поиска удалось локализовать проблему до нескольких строчек кода, но не удается самостоятельно понять первопричину проблемы.

Проблема проявляется в повторном выводе данных на LCD либо в COM-порт. Поясню, вместо положенных 1234 при выводе данных получается что-то проде этого: 7?:481234
Причем изкажения данных не посят постоянных характер. Первоначально возникло подозрение что данные по непонятным причинам неправильно передаются уже в функцию, чтобы проверить это добавил две строчки в код. Это строки с комментариями. Этим я пытался однозначно задать значение переменной и для контроля вывести тоже самое как на LCD, так и COM-порт.
Данные в обоих случаях выводятся с искажениями. Скриншоты прилагаются.

Проблемный участок кода:

Код:
Sub LCD_Ausgabe (byval Ausgabe as Word , byval V_Pos as Byte)
Ausgabe = 1234                 'добавленно для тестирования
print Ausgabe                     'добавленно для тестирования
Locate V_Pos , 9
Lcd Ausgabe ;
End SUB

Хотелось бы узнать мнение опытных людей, в чем причина подобного поведения и как с этим бороться?

http://uploads.ru/t/H/u/y/HuyO9.jpg
http://uploads.ru/t/b/s/5/bs5nM.jpg

А здесь код целиком, если в нем возникнет необходимость:
Код программы

0

2

1 Не слишком часто происходят прерывания?
2 Зачем такой огород? Нужно ПРОСТО считать прерывания по фронтам импульсов энкодера. Это всего 20-30 команд ассемблера.
и обязательно немножко поддавливать дребезг энкодера RС-цепочкой (пост. врем. 1 мс). Где-то здесь на сайте я ранее выкладывал код.

0

3

1. Я подсоединял энкодер к осциллографу и крутил как мог, получалось, что частота следования импульсов около 900 Гц, именно поэтому выбрана такая частота опроса энкодера.  Он у меня на один тактильный щелчок выдает четыре изменения состояния.

2. Может и проще можно сделать, но на ассембере я пора не решаюсь писать. Что касается дребезга, то RC цепочки добавлю позже. Меня пока другое сильнее мучает.

3. Немного изменил код вызываемой функии. Переменная Ausgabe которой передаются значения с энкодера пока НЕ используется. Сделанно исключительно для однозначного определения проблемного места кода. На LCD и СОМ-порт передаю значение переменной TEST. Оно НЕ изменяется и НИГДЕ больше не используется в программе. Как результат при любом вызове функции должно выдаваться только 1234. А вместо этого периодически выскакивает непонятно откуда взявшийся мусор. Видно на приложенных изображениях.

Код:
Sub LCD_Ausgabe(byval Ausgabe as Word , byval V_Pos as Byte)
local TEST as Word                              'добавленно для тестирования  
TEST = 1234                                       'добавленно для тестирования
print TEST                                           'добавленно для тестирования
Locate V_Pos , 9
Lcd TEST ;
End SUB

если изменить код следующим образом, то проблема исчезает:

Код:
Sub LCD_Ausgabe(byval Ausgabe as Word , byval V_Pos as Byte)
print 1234                                            'добавленно для тестирования
Locate V_Pos , 9
Lcd 1234 ;                                            'добавленно для тестирования
End SUB

такое ощущение, что что-то по время исполнения программы залезает в переменую и изменяет ее значение...  :canthearyou:

0

4

Попробуйте увеличить  эти параметры:
$hwstack = 32                                               ' default use 32 for the hardware stack
$swstack = 10                                               ' default use 10 for the SW stack
$framesize = 40                                             ' default use 40 for the frame space

Вдруг поможет.

0

5

1 У тебя импульсный энкодер. С ним работать еще легче (затем он и придуман). Нужно только одно внешнее прерывание по любой ножке.
2 Схема: пин приема сигнала - резистор 10 к подтяжка на +5 В - конденсатор 0.1 мкФ на корпус  - резистор 100 Ом последовательно с контактом, общий провод энкодера на корпус
3 Код:
' обработка внешнего прерывания 0 - двухфазного енкодера
'ПРЕРЫВАНИЕ ПРОИСХОДИТ ПО СПАДУ НА ВХОДЕ P_CHA. ЗАТЕМ ПРОГРАММА ИНТЕГРИРУЕТ
' (ФИЛЬТРУЕТ) ЭТОТ УРОВЕНЬ, ДОЖИДАЯСЬ НАДЕЖНОГО УСТАНОВЛЕНИЯ "0". В МОМЕНТ
'ФИКСАЦИИ "0" НА ЛИНИИ P_cha РЕГИСТРИРУЕТСЯ УРОВЕНЬ P_chb , ПО КОТОРОМУ И
'ОПРЕДЕЛЯЕТСЯ НАПРАВЛЕНИЕ ВРАЩЕНИЯ
Int0_0:
    Inc R31                             'УРОВЕНЬ ВЫСОКИЙ - ОТКАТ СЧЕТЧИКА
    Cpi R31 , 45                        'это Con_irt*1.5
    Brne Int0_1                         'ЕСЛИ ЖДЕМ СЛИШКОМ ДОЛГО - ВЫХОД
    Rjmp Int0_e
'---------
'ВНЕШНЕЕ ПРЕРЫВАНИЕ ОТ ЦИФРОВОЙ РУЧКИ
Int0_int:
$asm
    Push R31                            'сохраним регистры
    In R31 , Sreg
    Push R31
'-----
    Ldi R31 , 30                        'ПОСТОЯНАЯ ИНТЕГРИРОВАНИЯ
Int0_1:
    Sbic Pind , 2
    Rjmp Int0_15                        'ЕСЛИ НА НОЖКЕ "1"
    Dec R31                             'ПОКА НЕ ОБНУЛИЛСЯ СЧЕТЧИК ЖДЕМ
    Brne Int0_1                         'УСТАНОВЛЕНИЯ НИЗКОГО УРОВНЯ
    Rjmp Int0_2
'-----
Int0_15:
    Inc R31                             'УВЕЛИЧИВАЕМ СЧЕТЧИК
    Cpi R31 , 60                        'ЕСЛИ НА "1" УСТАНОВЛЕНА СЛИШКОМ ДОЛГО
    Brne Int0_e                         'НА ВЫХОД
    Rjmp Int0_1
'---------------------------------------------
'ПРОГРАММА РАСЧИТАНА НА КОДОВЫЙ ПЕРЕКЛЮЧАТЕЛЬ
'С НОРМАЛЬНО РАЗОМКНУТЫМИ КОНТАКТАМИ, ЗАМЫКАЮЩИМИСЯ
'ТОЛЬКО В МОМЕНТ ЩЕЛЧКА. ЭТО ОЧЕНЬ УПРОЩАЕТ ЗАДАЧУ
'---------------------------------------------
'      |<----- ВРАЩЕНИЕ ВЛЕВО (ИЛИ НАОБОРОТ, В ЗАВИСИМОСТИ ОТ МОНТАЖА)
'chA---     ---------     ------ ОПРЕДЕЛЕНИЕ НАПРАВЛЕНИЯ
'      ¦   ¦  chA    ¦   ¦      ВРАЩЕНИЯ ЦИФРОВОГО КОДЕРА
'       ---           ---      ОСНОВАНО НА АНАЛИЗЕ СОСТОЯНИЯ
'chB-----  |  ---------     ---- КАНАЛА "B" В МОМЕНТ ЗАМЫКАНИЯ
'      | ¦ | ¦  chB    ¦   ¦    (ЩЕЛЧКА) В КАНАЛЕ "A"
'      |  ---           ---
'      |   |<------ ВРАЩЕНИЕ ВПРАВО
'---------------------------------------------
Int0_2:
'ОБРАБОТКА ИЗМЕНЕНИЯ УРОВНЯ
'---------
    Sbis Pind , 3                       
    Rjmp Int0_3                         'ОПРЕДЕЛИМ НАПРАВЛЕНИЕ ВРАЩЕНИЯ
'---------
'ВРАЩЕНИЯ ВЛЕВО (УМЕНЬШЕНИЕ)
    Lds R31 , {r_cdec}                  'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВЛЕВО
    Inc R31
    Sts {r_cdec} , R31
    Rjmp Int0_4
'---------
Int0_3:
'ВРАЩЕНИЯ ВПРАВО (УВЕЛИЧЕНИЕ)
    Lds R31 , {r_cinc}                  'УВЕЛИЧИМ СЧЕТЧИК ЩЕЛЧКОВ ВПРАВО
    Inc R31
    Sts {r_cinc} , R31
Int0_4:
    Ldi R31 , &HFF
    Sts {edat} , R31                    'поставить признак "НОВЫЕ ДАННЫЕ ЕНКОДЕРА"
'---------
Int0_e:
    Pop R31
    Out Sreg , R31
    Pop R31
    Reti
$end Asm
Return

0

6

Civil написал(а):

Попробуйте увеличить  эти параметры:
$hwstack = 32                                               ' default use 32 for the hardware stack
$swstack = 10                                               ' default use 10 for the SW stack
$framesize = 40                                             ' default use 40 for the frame space

Сразу же после обнаружения своего глюка я изменил эти значения на приведенные ниже, но это не помогло.

$hwstack = 100
$swstack = 100
$framesize = 50

0

7

Добрый вечер,

Буду писать по пунктам, так легче задавать вопросы и отвечать на них...

1. Что значит импульсный энкодер? Погуглив я не выяснил для себя разницу между обычным энкодером и импульсным энкодером.
2. Правильно я понял схему подключения? Изображение для одного пина прилагается.
3. Код обработки энкодера пока не менял. Меня смущает тот факт, что ты делаешь упор на изменении логики обработки энкодера. Даже если она не самая оптимальная, я сознательно выбирал вариант без использования прерывания для обработки      (хотел познакомится в деталях с этим вариантом, потом сделаю на прерывании), работать то должно. И работает, только наблюдается для меня необъяснимый глюк, в виде того, что значание хранящееся в переменной периодически самостоятельно изменятся. Мне бы хотелсь этот момент понять, чтобы понять на какие грабли я наступил и стараться обойти их в будущем...

http://uploads.ru/t/k/s/v/ksv1D.jpg

0

8

1 да, схема правильная. 100 ом нужно чтобы не выжигать контакт энкодера. постоянная времени именно такая! Без подавления дребезга с механическим энкодером работать невозможно! ( всегда наблюдается многократное срабатывание при медленном вращении)
2 в импульсном энкодере (например, ECWJ от Bourns) замыкания происходят только в момент щелчка, а в статическом (обычно это оптические) - замыкается или размыкается только один из контактов. Поэтому для обработки сигналов статического энкодера нужно применять два прерывания по изменению уровня или четыре (два по спаду, два по фронту с параллеливанием попарно ножек).
3 без прерывания использовать энкодер нельзя! или не остается время на остальные задачи, или пропускаешь щелчки

0

9

У меня PEC16-4220F-S0024.
Я им управляю так:

Код:
$regfile = "m16def.dat"                                     'подключаем файл заголовков для контроллера ATbanned6
$crystal = 8000000                                          'частота кварцевого генератора

$baud = 9600                                                'настройка скорости передачи RS-232
$hwstack = 32                                               'аппаратный стек
$swstack = 10                                               'програмный стек
$framesize = 40                                             'размер фрейма

'настраиваем ЖКИ
Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.5 , Db6 = Portb.6 , Db7 = Portb.7 , E = Portb.3 , Rs = Portb.2
Config Lcd = 16 * 2                                         'ЖКИ 2 строки по 16 символов
Cursor Off                                                  'выключить курсор

'VALCODER________________________    выводы енкодера(валкодера)
Config Pind.3 = Input                                       'Valcoder A INT1
Valcod_a Alias Pind.3
Config Pina.4 = Input                                       'Valcoder B
Valcod_b Alias Pina.4
Set Portd.3
Set Porta.4

'объявляем переменные
Dim Valcod_param As Byte
Dim Valcod_cange As Bit

Config Int1 = Falling                                       'настраиваем внешнее прерывание INT1 на срабатывание при изменении из "1" в "0"
On Int1 Valcoder_change                                     'подпрограмма обработка прерывания Valcoder_change
Enable Int1                                                 'разрешаем работу прерывания  INT1
Enable Interrupts                                           'разрешаем глобальные прерывания

Cls                                                         'очищаем экран ЖКИ
Locate 1 , 10                                               'задаем позицию курсора
Lcd "Enc=" ; Valcod_param                                   'выводим переменную изменения значения енкодера(валкодера)

Do                                                          'начало цикла

If Valcod_cange = 1 Then                                    'если битовая переменна Valcod_cange = 1 (крутили енкодер(валкодер)
                       Locate 1 , 14                        'то задаем позицию курсора
                       Lcd Valcod_param ; "  "              'выводим переменную изменения значения енкодера(валкодера)
                       Reset Valcod_cange                   'сбрасываем битовую переменную Valcod_cange
                       Sound Buzer , 10 , 500               'генерим звук
End If

Loop                                                        'замыкаем цикл


Valcoder_change:                                            'подпрограмма обработки прерывания INT1
'*******************************************************************************
If Valcod_b = 1 Then                                        'если на линии B лог "1"
                  If Valcod_param <> 255 Then Incr Valcod_param       'то если  переменная Valcod_param не достигла значения 255 увеличиваем ее на 1
                Else                                        'если на линии B лог "0"
                  If Valcod_param <> 0 Then Decr Valcod_param       'то если  переменная Valcod_param не достигла значения 0 уменьшаем ее на 1
End If
Set Valcod_cange                                            'выставляем битовую переменную Valcod_cange
Return                                                      'возврат из подпрогрммы

End                                                         'конец программы

0

10

BRODJAGA
У меня был похожий случай. Портилась Byte-переменная. Причина была примерно в следующем:

Dim Var1 As String * 4
Dim Var2 As Byte

И случилось так, что при фузинговании переменной Var1, её длина становилась 5, а не 4. И переменная Var2 портилась.
Проверь, мало ли ...

0

11

Из за недостатка времени пришлось немного отвлечься от своего «проекта».
Но некоторые новые детали все же удалось выяснить.
А именно:

В первоначальной версии программы опрос энкодера следует с частотой порядка 1000Гц. Время обработки/опроса занимает около 13мкс (замерял осциллографом), т.е вроде как на остальную часто программы остается порядка 900 мкс. Но беда в том, что процедура вывода на LCD занимает много больше времени (около 15 мс). Теперь я понимаю о чем говорил мне „dmm“. Выясненное не объясняет полностью причины возникновения проблемы с изменениями данных в переменной, но практическим путем удалось также выяснить, что если при заходе в процедуру отвечающую за вывод данных на LCD отключить временно обработку прерываний, и включить снова лишь при выходе из процедуры, то подобного эффекта самопроизвольного изменения данных не наблюдается.

Буду переделывать опрос энкодера как посоветовал «мах».

Кстати вопрос к SIvan:
Мне не знаком термин фузингование переменной. Пытался поиском найти ответ, но не удалось. Можно пояснить, что имеется ввиду?

0

12

Функция Fusing. Преобразование числа в строковую переменную с форматированием.

0


Вы здесь » Программирование ATMEL в BASCOM. » Дисплеи и индикация » Вывод данных на LCD / Самопроизвольное изменение переменной