Chertenok.ru - все о программировании
Вход  |  Регистрация  |  Поиск 
Праздник
Завтра :

День взятия турецкой крепости Измаил русскими войсками под командованием А.В. Суворова (1790)


Микроконтроллеры - изучение и программирование (личный опыт)


Новая тема  Ответить  Печать Предыдущая тема  Следующая тема

Нравится это повествование?
да
100%
 100%  [ 4 ]
нет
0%
 0%  [ 0 ]
Всего голосов : 4
Кто проголосовал:

Автор Сообщение
cybermerlin
Гость







СообщениеСр, 27-Сен-2006 16:14    Заголовок сообщения: Микроконтроллеры - изучение и программирование (личный опыт)
Цитата

Цитата:
Если есть замечания или вопросы в личное сообщение мне отсылайте, я отвечу и может вставлю здесь в текст

началось все так - http://forum.chertenok.ru/viewtopic.php?t=5903
со своей стороны сцылки по МК
http://www.gaw.ru
http://www.radiokot.ru/forum
http://avr123.nm.ru -- здесь все с использованием Си написано.
Этого впринципе за глаза Хватит

Для начала освойте системы счисления и их приведения между собой.
**********ВСТАВИТЬ о СИСТЕМАХ СЧИСЛЕНИЯ*********************
начал я изучение всей этой темы с азов, а именно что такое микроконтроллеры и какие они бывают и для чего они вообще нужны-то.
скачал книжецу ... блин сейчас найду ее... (ушел ... пришелл через 20 минут...
уффф долго искал
название такое курс лекций "Микропроцессоры"
собственно это сайтик, но очень хорош, его распечатал и читал обязательно в бумажном виде чтоб всегда перед глазами ИМЕТЬ ( http://www.sibsutis.ru/~mavr/MP/contMP.htm )
затем наткнулся на форум электронщиков http://www.radiokot.ru/forum
там обязательно зарегился и начал общаться с умными людьми
оттуда меня переадресовали на местную обучалку
http://radiokot.ru/start ну, а дальше пошли вопросы и их стало превеликое множество

СЛУШАЙ я прям книгу напишу так (типа Заметки идиота радиотехника-прогера) гыгы

там мне кто-то очень умный предложил забуриться в Gaw.ru, а там у меня и времени не хватать стало, ибо обилие информации поглащает и стал я на работе сидеть до 10 часов и домой приходил и сидел до 2 ночи
-------------------------
ну сегодня приступил непосредственно к написанию программы и продолжаю изучать по-шагово.
ЗАДАЧА - снимать показания о нажатых кнопка и положениях тумглеров
для получения качественного результата необходимо учесть состояние ДРЕБЕЗГА манипуляторов (кнопок, тумглеров, переключателей..)
Дребезг - состояние манипулятора, проявляемое во время нажатия или отпускания кнопки.
отражается это ввиде частой смены показателей состояния кнопки (нажата/отпущена) (за период времени удержания кнопки в каком-то положении, например когда вы нажали и держите первые 10-15 мс МОЖЕТ наблюдаться состояние дребезга, т.е. как будто кнопка сама нажимается и отпускается с характерной ей частотой, тоже самое наблюдается и при отпускании! кнопки) (длительность дребезга у каждого манипулятора разная чаще всего встречается 5-15 мс, но у некоторых примерно до 100 мс может доходить (или 200 мс :)
вот примерный код ПОКА:
asm:
  1.  
  2. .include "C:\SPAWN\proging\avr\tavrasm\appnotes\m162def.inc"
  3.  
  4. .def     Temp0=R16      ;переименование РОН   -моя прихоть
  5. .def     Temp1=R17
  6. .def     Temp2=R18
  7. .def     Temp3=R19
  8. .def     Temp4=R20
  9.  
  10. .cseg         ;начало программного сегмента
  11. .org 0      ;начальный адрес 0
  12.  
  13. ldi Temp0,RamEnd        ;инициализация стека for work in the RCALL
  14. out SPL,Temp0
  15.                         ;ссылки на прерывания
  16. rjmp Reset
  17. rjmp INT0addr
  18. rjmp INT1addr
  19. rjmp INT2addr
  20. rjmp PCINT0addr  ;Pin Change Interrupt Request 0
  21. rjmp PCINT1addr
  22. rjmp TIMER3CAPTaddr
  23. rjmp TIMER3COMPAaddr
  24. rjmp TIMER3COMPBaddr
  25. rjmp TIMER3OVFaddr
  26. rjmp TIMER2COMPaddr
  27. rjmp TIMER2OVFaddr
  28. rjmp TIMER1CAPTaddr
  29. rjmp TIMER1COMPAaddr
  30. rjmp TIMER1COMPBaddr
  31. rjmp TIMER1OVFaddr
  32. rjmp TIMER0COMPaddr
  33. rjmp TIMER0OVFaddr
  34. rjmp SPISTCaddr
  35. rjmp USART0RXCaddr
  36. rjmp USART1RXCaddr
  37. rjmp USART0UDREaddr
  38. rjmp USART1UDREaddr
  39. rjmp USART0TXCaddr
  40. rjmp USART1TXCaddr
  41. rjmp EE_RDYaddr
  42. rjmp ANA_CMPaddr
  43. rjmp SPM_RDYaddr
  44.  
  45.  
  46. ;Reset:
  47. INT0addr:
  48. INT1addr:
  49. INT2addr:
  50. PCINT0addr:
  51. PCINT1addr:
  52. TIMER3CAPTaddr:
  53. TIMER3COMPAaddr:
  54. TIMER3COMPBaddr:
  55. TIMER3OVFaddr:
  56. TIMER2COMPaddr:
  57. TIMER2OVFaddr:
  58. TIMER1CAPTaddr:
  59. TIMER1COMPAaddr:
  60. TIMER1COMPBaddr:
  61. TIMER1OVFaddr:
  62. TIMER0COMPaddr:
  63. TIMER0OVFaddr:
  64. SPISTCaddr:
  65. USART0RXCaddr:
  66. USART1RXCaddr:
  67. USART0UDREaddr:
  68. USART1UDREaddr:
  69. USART0TXCaddr:
  70. USART1TXCaddr:
  71. EE_RDYaddr:
  72. ANA_CMPaddr:
  73. SPM_RDYaddr:
  74.           reti
  75.  
  76. Reset:    ;START
  77. ldi TIMSK, 0b01000000
  78. ldi Temp0, 0b1111000    ;настройка каналов порта В
  79. out DDRB,Temp0
  80.  
  81. Work_Key:
  82. rcall Delay
  83. cpi Temp0,0b1000000     ;сравнение с конечным после двигов
  84. breq Reset
  85. lsl Temp0
  86. rjmp Work_Key
  87.                         ;занимаемся клавиатурой
  88. Daley:
  89. ldi Temp0,0b0001000     ;присвоение константы
  90. out PortB,Temp0         ;вывод на индикацию
  91. ldi Temp1,0
  92. Loop:
  93. dec Temp1
  94. ret
  95.  
  96.  
  97.         ERASED--опрос клавиатуры после второй единицы
  98. Init:
  99. ldi Temp0,0
  100. ldi Temp1,0
  101.  
  102. OPROS:
  103. cpi btn,1
  104. breq work
  105.  
  106. work:
  107. inc Temp0
  108. rcall daley
  109. rjmp opros
  110. nop
  111.  
  112. Delay:
  113. ldi temp2,0
  114. ldi temp3,0
  115. Loop:
  116. dec temp2
  117. brne loop
  118. dec temp3
  119. brne Loop
  120. ret
  121.  


планируется чтобы опрос был по прерыванию таймера
------------------------------------
Цитата:
Хочу добавить, здесь рассматривается программирование микроконтроллера ATmega162, относится к AVR-микроконтроллерам, и команды используемые в них отличаются от команд просто Ассемблера, которые используется для ПК
когда разберемся с этой задачей займемся перенастройкой оборудования имеющегося у нас в ПК и периферии, а также кое чего спаяем САМИ. такчто терпение товарищи

теперь продолжим:
Так вот есть не много способов решения проблемы Дребезга и помех (проскакивающих "иголочек" как выражаются некоторые специалисты)
один способ:
(выполняется в 4 шага)
1) использовать прерывания при изменении состояния на входе
2) перед обработкой ждать 30 мс
3) сделать штук 10-14 статических выборок каждые 5 мс
4) на основании статистики делать вывод
второй способ:
по таймеру опрашивать каждые 50 мс клавиатуру
(между прочем вариант хороший, но есть возможность попадания на период дребезга, тогда ждать еще 50 мс и снова опросить эту кнопку и если результат тот же значить кнопка нажата, но остается очень сильный варинат что может проскочить иголочка, т.е. для качественного результата этот вариант не подходит)
третий способ:
опрашивать скажем 31 раз клавиатуру каждые 5 мс и на основе среднеарифметического сделать вывод кнопка нажата или нет.
(этот вариант очень хороший, но если человек нажимает очень часто на кнопку это может быть похоже на состояние дребезга!!!

есть способ снизить весь этот геморрой комплексным решением -- в аппаратной части поставить фильтры на входе порта (резистор-конденсатор-резистор -вроде этого)
НО я работаю только с программной частью, будем надеяться, с аппаратной частью ребята из электро отдела разберутся. тогда зациклимся на решении программной части

Будем использовать первый способ.

asm:
  1.  
  2. ; это предварительные наметки
  3.  
  4.     ;--опрос клавиатуры после второй единицы
  5. Init:
  6. ldi Temp0,0
  7. ldi Temp1,0
  8.  
  9. OPROS:
  10. cpi btn,1
  11. breq work
  12.  
  13. work:
  14. inc Temp0
  15. rcall daley
  16. rjmp opros
  17. nop
  18.  
  19. Delay:
  20. ldi temp2,0
  21. ldi temp3,0
  22. Loop:
  23. dec temp2
  24. brne loop
  25. dec temp3
  26. brne Loop
  27. ret
  28.  


Последний раз редактировалось: cybermerlin (Чт, 26-Окт-2006 12:49), всего редактировалось 5 раз(а)
В начало
cybermerlin
Гость







СообщениеЧт, 28-Сен-2006 10:19 
Цитата

сегодня разбираюсь с кварцем и таймером, т.к. мы привязаны к таймеру
на моем чипе их аж 3 (ATmega162)
кварц у меня 8МГц - период 125 нс. Как рассчитать?
(1/8МГц)*(10^(-6)) (расписал так чтоб понятней было
Максимальное значение таймера: 2^16 = 65535
почему степень 16? потому что мы используем таймер с 16-bitной разрядностью
вычислим, за сколько досчитает до конца таймер при тактовой частоте равной частоте кварца: 125 нс * 65536 = 8,2 мс.
мы используем Timer/Counter1 скинул бы сюда картинку но... объема недостаточно будет в итоге смотрите в ДатаШите на странице 104
у этого мультиплексора регистр TCCR1B есть
сначала нам надо задать какое прерывание мы будем использовать спомощью регистра маски прерываний TIMSK. Так как нам нужен компаратор (сравниватель-сравнивает число которое ему мы зададим с текущим значением таймера и если будет совпадение, таймер выдаст прерывание на выполнение подпрограммы, которую мы напишем). Компаратор в этом регистре стоит в шестом бите, т.е. мы должны в 6 бит вставить единичку:
asm:
  1. ldi TIMSK,0b01000000

ПОКА ЗАЙМЕМСЯ ОПРОСОМ кнопок которые у нас на матрице подключены,
т.е. которые расположены в виде таблицы состоящей из строк и столбцов
у нас 6 строк и 4 столбца, получается 24 ячейки, но кнопок 23, значит последняя 6,4 у нас без кнопки и ее опрашивать не будем
так какой период нам надо задать опроса, чтоб у нас кнопки были опрошены раз в 30 мс????
выяснили, что нам подойдет коэффициент деления 8
из таблицы узнаем какие биты мы должны выставить в регистр TCCR1B
Этот регистр - контрольный регистр таймера нашего, чтобы выбрать для таймера необходимый источник тактового сигнала, необходимо записать его адрес в соответствующие биты регистра TCCR1B, а именно в биты cs12-cd10 (2-0 биты).

cs12
cs11
cs10
Description
0
0
1
(clkI/O)/1
0
1
0
(clkI/O)/8
0
1
1
(clkI/O)/64

значит нам нужно (clkI/O)/8, тогда пишем в код
asm:
  1. ldi TCCR1B,0b00000010

вычислим значение, с которым будет сравнивать компаратор текущее состояние таймера,его мы загрузим в OCR1A.
мы выяснили, что тактовая частота таймера в 8 раз меньше частоты кварца, значит период в 8 раз больше 125 нс* 8 = 1 мкс. Нам нужно чтобы опрос клавы происходил каждые 30 мс. Считаем количество тактовых импульсов, которое пройдет за это время:
30 мс/ 1 мкс = 30 000 имп. (т.е. 30 мс равны 30 000 тактам)
это число загрузим в OCR1A. Но этот регистр - составной. Состоит из двух 8-битных регистров. Поэтому, сначала нужно преобразовать это число в шестнадцатеричную систему и загрузить старшие и младшие разряды в соответствующие регистры: OCR1AH и OCR1AL
30 000(10) = 7530(16)
OCR1AH = 0x75
OCR1AL = 0x30
Цитата:
забыл - напрямую в регистр (кроме РОН- регистра общего назначения) значение запихивать нельзя!!
для этого мы делаем так
asm:
  1.  
  2. Reset:      ;START
  3. ldi Temp0,0b01000000
  4. out TIMSK,Temp0  ;разрешить прерывание компаратора
  5. ldi Temp0,0b00000010
  6. out TCCR1B,Temp0        ;тактовый сигнал = CK/8
  7.  
  8. ldi Temp0,0x75    ;инициализация компаратора
  9. out OCR1AH,Temp0
  10. ldi Temp0,0x30
  11. out OCR1AL,Temp0
  12.  
  13. ldi Temp0,RamEnd        ;инициализация стека for work in the RCALL
  14. out SPL,Temp0
  15.  
  16. ldi Temp0,0b1111000     ;настройка каналов порта В на выдачу данных
  17. out DDRB,Temp0
  18. ldi Temp0,0b0000000     ;настройка каналов порта A на получение данных
  19. out DDRA,Temp0
  20.  
  21. eor Temp0,Temp0  ;обнуление таймера
  22. out TCNT1H,Temp0
  23. out TCNT1L,Temp0
  24.  
  25. sei
  26.  
В начало
cybermerlin
Гость







СообщениеПт, 29-Сен-2006 16:22 
Цитата

немного прервемся...
создаю значит код программы, почти все готово, но......
возникли два серьезных для меня вопроса:
1. Как выяснить в Ассемблере что больше Temp5 или Temp4 ??
2. как выяснить побитно, какой бит содержит "1" в РОНе ??
..............................(решение выложу позже, когда узнаю его :) )
В начало
cybermerlin
Гость







СообщениеПн, 02-Окт-2006 12:34 
Цитата

ответ на первый вопрос выглядит так!!!!!
собственно теперь предоставляю почти весь код программы анализирующей данные на портах
asm:
  1.  
  2. ldi Temp0,0     ;значения порта В
  3. ldi Temp1,0     ;значения порта А
  4. ldi Temp2,0     ;счетчик ОПРОСОВ !!!порта А!!!
  5. ldi Temp3,0     ;ЗАПАСКА
  6. ldi Temp4,0     ; !!!Хранение НОЛЕЙ порта А!!!
  7. ldi Temp5,0     ; !!!Хранение ЕДИНИЦ порта А!!!
  8. ldi Temp6,0     ;ЗАПАСКА
  9.  
  10. ;Out PortB,Temp0
  11.  
  12.  
  13.  
  14. Start:
  15.         in Temp1,PinA
  16.         cpse Temp1,0    ;данные есть?? в порту А
  17.         rjmp Not_Zero   ;если НЕ НОЛЬ в порту А
  18.         rjmp Zero       ;если НОЛЬ в порту А
  19.  ret
  20.         Opros_1:
  21.                 cpse Temp2,0    ;ОПРОС первый?
  22.                 rcall Opros_2   ; если ОПРОС не первый          --переход
  23.                 inc Temp2       ; если ОПРОС первый        увеличиваем счетчик ОПРОСОВ
  24.                 rcall Delay     ;-----задержка
  25.          ret
  26.         Not_Zero:       ; ---==// поступили данные на входе ПОРТА *А* \\==---
  27.                 inc Temp5       ;увеличим счетчик ЕДИНИЦ
  28.                 rcall Opros_1
  29.                 rjmp Start                        ;--go to Start--
  30.         Zero:      ; ---==// нет данных на входе ПОРТА *А* \\==---
  31.                 inc Temp4
  32.                 rcall Compare_T45       ;проверяем, если у нас были ЕДИНИЦЫ - РеСтарт!!!
  33.                 rcall Opros_1
  34.                 rjmp Start                        ;--go to Start--
  35.         Opros_2:
  36.                 cpse Temp2,1    ;ОПРОС второй?
  37.                 rcall Shag_PB   ; ОПРОС третий!!      --переход
  38.          ret
  39.         Shag_PB:
  40.                 cpi Temp0,0          ;здесь мы пытаемся начать работу с Портом В
  41.                 breq Temp0_Step  ;присвоить Порту В 0b0001000 & Go to !!!-Start-!!!
  42.                 cpse Temp1,0        ;в порту А   ПУСТО??
  43.                 ;ВСТАВИТЬ ИДЕНТИФИКАЦИЮ  ;идентифицируем нажатую кнопушку
  44.                 rcall Temp0_Step        ;в Порту А данных нет --проверяем следующий столбец
  45.          ret
  46. ;*************************************************
  47. ;ИДЕНТИФИКАЦИЯ ПЕРЕМЕННЫХ нолЕВЫХ и единиц
  48.           Identifer:        ;производим идентификацию нажатых кнопок из МАТРИЦЫ
  49.                 lsr Temp0
  50.                 ;*******************************
  51.                 ;insert this F.... Cod!!!
  52.                
  53.                 ;*************end***************
  54.                 ;GOTO ---==EXIT==---
  55. ;**************-конец идентификации-**************
  56. ;*************************************************
  57. ;СРАВНЕНИЕ ПЕРЕМЕННЫХ нолЕВЫХ и единиц
  58.         Compare_T45:        ;уходит на СТАРТ, если НОЛей ((1) или (2 и 1-единица))
  59.                 cp Temp4,Temp5    ;--это у нас для все остальных подпрограмм
  60.                 breq Clr_S
  61.                 cpi Temp5,1     ;ЭТО у нас для если все НОЛики и 1 иголочка!!!
  62.                 breq Clr_S
  63.          ret
  64.           Clr_S:
  65.                 rcall Clear_S
  66.                 Rcall Delay
  67.                 rjmp Start
  68. ;**************-конец сравнения-******************
  69.         Clear_s:                                ;Clear RON 4,5,2
  70.                 ldi Temp4,0   ;в НОЛЬ --счетчик "нулей"
  71.                 ldi Temp5,0   ;в НОЛЬ --счетчик "единиц"
  72.                 ldi Temp2,0   ;в НОЛЬ --счетчик "опросов"
  73.           ret
  74.         Temp0_Step:
  75.                 cpse Temp0,0        ;в Порт В данные занесены?
  76.                 rjmp Temp0_Step1        ; ДА (если мы уже ОПРАшивали и теперь на нов Шаг+
  77.                 ldi Temp0,0b0001000     ;  НЕТ (если мы вообще только приступили опрашивать
  78.                 rcall Clear_S
  79.                 rcall Delay
  80.                 rjmp Start
  81.           Temp0_Step1:
  82.                 lsl Temp0          ;переход на следующий столбец
  83.                 rcall Compare_T45     ;Выяснениечего больше (Единиц или Нолей)
  84.                 rcall Clear_S
  85.          ret
  86.         Delay:
  87.                 ldi Temp3,0     ;Temp2 -для временного использования
  88.                 ldi Temp6,0     ;Temp4 -для временного использования
  89.           Loop1:
  90.                 dec Temp3              ;первый цикл
  91.                 brne Loop1
  92.                 dec Temp6              ;второй цикл
  93.                 brne Loop1                  ;ИТОГ был- 510 тактов задержки(посчитай)
  94.          ret
  95.  

с идентификацией нажатой кнопки поратаю и выложу завтра

Добавлено спустя 1 час 3 минуты 8 секунд:

давайте пока разберемся с имеющимся кодом
первый участок - это ИНИЦИАЛИЗАЦИЯ переменных
просто обнуляем значения этих регистров
Далее идет СТАРТ!!!!
первой строчкой мы получаем данные из Порта А и заносим их в переменную отведенную нами под эти цели и ... сравниваем во второй строчке полученные данные с НУЛЕм (а есть ли у нас вообще данные в Порту А??)
и если данные сть то выполняется команда через строчку...
(команда CPSE сравнивает два регистра и если они равны между собой, то строчка стоящая после этого условия (CPSE) пропускается и выполняется третья (в нашемм случае выполняется rjmp Zero))
далее команды относительного перехода, которые переносят нас на следующий логический узел
собственно можно сказать на следующую подпрограмму. так как процедур и функций в АСМЕ несуществует - это единственный способ как-то логически и компактно разместить весь исполнительный код.
а чтобы все было понятно и можно было вызвать из люого места, лчше размещать после "Метки:"
так например
asm:
  1.  
  2.         Opros_1:
  3.                 cpse Temp2,0    ;ОПРОС первый?
  4.                 rcall Opros_2   ; если ОПРОС не первый          --переход
  5.                 inc Temp2       ; если ОПРОС первый        увеличиваем счетчик ОПРОСОВ
  6.                 rcall Delay     ;-----задержка
  7.          ret
  8.  

этот код выполняется если мы делаем первый опрос.
т.е. можно назвать этот участок Процедурой Opros_1.

Добавлено спустя 13 минут 3 секунды:

команда RET говорит Процессору, что процедура законцена и надо возвращаться на строчку из которой она была вызвана, т.е. в нашем случае на
rjmp Start
в процедурах Not_Zero: и Zero:
НО возврат будет только в том случае, если мы вызвали эту процедуру (Opros_1) командой rcall или call если мы перешли на эту метку другой командой: rjmp, jmp, breq,brne и др. команды перехода, то возврата назад не будет, нам надо непосредственно указывать в конце процедуры такой скажем RJMP Start
это можно посмотреть в Процедуре, скажем -- Not_Zero:
если мы не впишем вконце строку "RJMP Start", то процессор начнет выполнять дальше код, а дальше у нас "Zero:", а нам не нужно чтобо выполнялась сейчас это "процедура", посему мы и отправляем процессор на Старт вручную.
В начало
cybermerlin
Гость







СообщениеСр, 04-Окт-2006 10:36 
Цитата

ну вот программа была сделана (правда еще есть пару нюансов, но мы их по ходу разгребем :)
в продолжение Обучалки с которой я начинал, назвал я свой исходник code.asm
скачал tavrasm в папку у которого была папкп appnotes в ней был m162def.inc
его надо включать в свой исходник. Вот как выглядит начачло моего исходника
asm:
  1.  
  2. .include "C:\SPAWN\proging\avr\tavrasm\appnotes\m162def.inc"
  3.  
  4. .def    Temp0=R16       ;переименование РОН    -моя прихоть
  5. .def    Temp1=R17
  6. .def    Temp2=R18
  7. .def    Temp3=R19
  8. .def    Temp4=R20
  9. .def    Temp5=R21
  10. .def    Temp6=R22
  11. .def    Temp7=R23
  12. .def    Temp8=R24
  13. .def    Temp9=R25
  14.  
  15. ;****************************************************
  16. ; РАБОТА КОМПАРАТОРА
  17. ;вызывается как прерывание таймера на 30мс
  18. ;****************************************************
  19. .org 0x1a
  20.         TIMER1_COMPA:
  21.          cli
  22.                 ldi Temp0,0          ;обнуление таймера
  23.                 out TCNT1H,Temp0
  24.                 out TCNT1L,Temp0
  25.                 call Clear_s
  26.                 call Clear_sALL
  27.                 call Start
  28.                 call Under_Buttons
  29.          sei
  30. reti
  31. ;****************НАЧАЛО************************
  32. .cseg         ;начало программного сегмента
  33. .org 0      ;начальный адрес 0
  34.  

первой строчкой именно это мы и сделали (включили код ИНК файла себе в код.
далее идет переименование (точнее присвоение) имен Регистрам Общего Назначения (РОН), это сделано не для всех РОНов, т.к. все они нам врядли понадобятся, по мере необходимости, конечно же можно будет добавлять еще здесь такие "переменные".
Последние две строчки - ОБЯЗАТЕЛЬНЫ. без них у нас программа не будет работать. CSEG - обозначает начало программного сегмента
ORG - задает начальный адрес. В данном случае он = 0
Т.е. мы инициализируем начальный сегмент программы.
-----------------------------------
Т.к. мы используем прерывание одного из таймеров нашего МК, сначала надо его сконфигурировать.
Но еще раньше надо нам разместить ссылки на все вектора прерывания.
asm:
  1.  
  2. ;****************НАЧАЛО************************
  3. .cseg         ;начало программного сегмента
  4. .org 0      ;начальный адрес 0
  5.                 ;ссылки на прерывания
  6.                 ;вектора прерываний
  7. rjmp Reset                        ;ссылки на прерывания
  8. rjmp    EXT_INT0        ;   External Interrupt Request 0
  9. rjmp    EXT_INT1        ;   External Interrupt Request 1
  10. rjmp    EXT_INT2        ;   External Interrupt Request 2
  11. rjmp    PC_INT0               ;    Pin Change Interrupt Request 0
  12. rjmp    PC_INT1
  13. rjmp    TIMER3_CAPT
  14. rjmp    TIMER3_COMPA
  15. rjmp    TIMER3_COMPB
  16. rjmp    TIMER3_OVF
  17. rjmp    TIMER2_COMP
  18. rjmp    TIMER2_OVF
  19. rjmp    TIMER1_CAPT
  20. rjmp    TIMER1_COMPA
  21. ;rjmp   TIMER1_COMPB
  22. ;rjmp   TIMER1_OVF
  23. ;rjmp   TIMER0_COMP
  24. ;rjmp   TIMER0_OVF
  25. ;rjmp   SPISTC
  26. ;rjmp   USART0_RXC
  27. ;rjmp   USART1_RXC
  28. ;rjmp   USART0_UDRE
  29. ;rjmp   USART1_UDRE
  30. ;rjmp   USART0_TXC
  31. ;rjmp   USART1_TXC
  32. ;rjmp   EE_RDY
  33. ;rjmp   ANA_CMP
  34. ;rjmp   SPM_RDY
  35.  

КСТАТИ, советую использовать RJMP, а не JMP, т.к. последняя команда занимает больше места чем первая.
вот столько у наших таймеров векторов прерываний.
команда rjmp - выполняет относительный переход.
В конце я сделаю архив "Система команд 8-разрядных RISC микроконтроллеров семейства AVR" и выложу где-н :)
далее
у нас есть ссылки на вектора, а описание самих векторов нет.
на все вектора описания делать не надо, мы сделаем только для интересующего нас TIMER1_COMPA и вектора СБРОСА Reset
а на остальные вектора мы должны все равно указать метки в коде, иначе процессор будет искть куда ему перейти и когда не найдет очень сильно рассердится :).
вот они наши метки на вектора:
asm:
В начало
cybermerlin
Гость







СообщениеПн, 09-Окт-2006 14:42 
Цитата

asm:
  1.  
  2. EXT_INT0:
  3. EXT_INT1:
  4. EXT_INT2:
  5. PC_INT0:
  6. PC_INT1:
  7. TIMER3_CAPT:
  8. TIMER3_COMPA:
  9. TIMER3_COMPB:
  10. TIMER3_OVF:
  11. TIMER2_COMP:
  12. TIMER2_OVF:
  13. TIMER1_CAPT:
  14. ;TIMER1_COMPA:
  15. TIMER1_COMPB:
  16. TIMER1_OVF:
  17. TIMER0_COMP:
  18. TIMER0_OVF:
  19. SPISTC:
  20. USART0_RXC:
  21. USART1_RXC:
  22. USART0_UDRE:
  23. USART1_UDRE:
  24. USART0_TXC:
  25. USART1_TXC:
  26. EE_RDY:
  27. ANA_CMP:
  28. SPM_RDY:

теперь желательно бы вставить метку на вектор СБРОСА (RESET)
вот с ним у меня были определнного рода проблемы и решились они жестким помещением кода его обработчика по адресу (который по идее должен следовать сразу после ссылок на прерывания, а именно (для моего МК) 0x38
Делается это директивой .org (-установить положение в сегменте) итак, сам код RESET
asm:
  1. ;RESET
  2. ;****************************************************
  3. ; ИНИЦИАЛИЗАЦИЯ
  4. ;****************************************************
  5. .org 0x38
  6. Reset:      ;START
  7.  cli
  8. 1:      ldi Temp0,0b01000000
  9.         out TIMSK,Temp0  ;разрешить прерывание компаратора
  10. 2:      ldi Temp0,0b00000010
  11.         out TCCR1B,Temp0        ;тактовый сигнал = CK/8
  12.  
  13. 3:      ldi Temp0,0x75                ;инициализация компаратора
  14.         out OCR1AH,Temp0
  15. 4:      ldi Temp0,0x30
  16.         out OCR1AL,Temp0
  17.  
  18. 5:      ldi ZH,High(RamEnd)   ;инициализация стека for work in the RCALL
  19.         out SPH,ZH
  20. 6:      ldi ZL,Low(RamEnd)
  21.         out SPL,ZL
  22.        
  23. 7:      ldi Temp0,0b00001111;настройка каналов порта В на выдачу данных
  24.         out DDRB,Temp0
  25. 8:      ldi Temp0,0b0000000   ;настройка каналов порта A на получение данных
  26.         out DDRA,Temp0
  27.  
  28. 9:      eor Temp0,Temp0              ;обнуление таймера
  29.         out TCNT1H,Temp0
  30.         out TCNT1L,Temp0
  31.  sei
  32. reti
  33. ;*******************-end-*****************************
  34.  

теперь потихоньку разъясним что да как.
cli - oчистить флаг глобального прерывания в регистре статуса (SREG) запрещает прерывания
ldi Temp0,0b01000000 - заносим в РОН (который мы переименовали в Temp0) число в двоичном виде
брррр
в общем так, я расписал метки (цифры с двоеточием) напротик пары команд, и теперича разъясню
в общем, по первой метке мы устанавливаем в регистр TIMSK бит 1 отвечающий за разрешение использования компаратора, если мы этого не сделаем, то не сможем никаким образом использовать прервать цикл программы, по достижении таймера 30 мс, и, как следствие, выполнить работу по обработке кнопок, которые у нас подключены на матрице.
Вторая метка - устанавливает в регистре TCCR1B использование тактового сигнала = CK/8 (как рассчитать какой тактовый сигнал нам нужен, т.е. с какой скоростью должен тикать таймер, был объяснено раньше)
третья и четвертая - инициализация компаратора. этот регистр - составной. у него есть старшие и младшие разряды (верхний и нижний). в третьей мы записываем старший разряд нашего шестнадцатеричного значения, четвертой- младший
пятая - инициализация стека, без этой и шестой пары мы не сможем пользоваться rcall. вот и заносим адрес последней ячейки ОЗУ (с помощью RamEnd) в РОН и затем в регистр стека
семь - ОТСТУПИМ. Т.к. у меня 23 кнопки подключены ввиде матрицы (таблицы) состоящей из 4 стлбцов и 6 строк, и, причем чтобы опросить все кнопки я должен подавать сигнал через стробы (столбцы) архитектурно, которые у меня подключены к порту В, а строки к порту А. Т.е. получаю сигналы посланные с Порта В я на порту А. Следовательно, я должен сконфигурировать порт В (первые его 4 канала) на ввод, а Порт А на на вывод. Делается это при помощи регистра ввода\вывода DDRA DDRB где буква указывает на имя порта. Получаю данные (с порта А) через регистр PinA, а выдаю сигнал (единичку) на порт В регистром PortB.
так, седьмая метка - это настройка каналов порта В на выдачу данных, т.е. мы можем подавать сигнал только 4 каналам Порта В регистром PortB
восемь - настройка каналов порта A на получение данных, т.е. в нашем случае мы со всех каналов ПОЛУЧАЕМ данные и ничего выдать через них не можем!
девять - ну это обнуление таймера. т.е. сбрасываем значение таймера на НОЛЬ (иными словами заставляем его начать работу с НАЧАЛА)
В начало
cybermerlin
Гость







СообщениеЧт, 12-Окт-2006 11:22 
Цитата

команды:
sei - Установить флаг глобального прерывания (разрешает использование прерываний
reti - возвращает из прерывания (Вернуться и разрешить прерывания)
в принципе sei можно здесь не использовать указав последнюю команду. НО мы лучше лишний раз разрешим использовать прерывания

далее я выкладываю на сегодняшний день сделанный исходник с коментариями.
если чего не понятно в нем будет пишите.
изменения которые я буду в нем вносить я буду описывать здесь и выкладывать измененный участок.
Так будет проще и лучше (наверно)



zxc.rar
 Описание:

Скачать
 Имя файла:  zxc.rar
 Размер:  3.71 KB
 Загружен:  549 раз(а)

В начало
cybermerlin
Гость







СообщениеПн, 16-Окт-2006 12:22 
Цитата

пока отложим до появления первых неясностей код обработки
(скажу сразу пока не доделан до конца, но помере его доделки все комментарии будут выкинуты здесь)
Возьмемся за реализацию передачи Скан-кодов клавиатуры нашей через RS-232 порт по протоколу MODBUS RTU.
что это за протокол и почему его используем?
Используем его - потому что начальника сказала однака!
Что за протокол?
Цитата:
Стандарт Modbus устанавливает последовательный протокол обмена
данными между одним ведущим (контроллером или компьютером ) и
несколькими ведомыми (обычно модулями ввода-вывода) устройствами.
Ведущее ус тройс тво выполняет роль клиента (т.е. выдает запроссерверу), а ведомое выполняет роль сервера (поставляет данные в ответ на запрос).
Протокол Modbus имеет два режима передачи: режим RTU (Remote
Terminal Unit – «удаленное терминальное устройство») и режим ASCII.
Стандарт предусматривает, что режим RTU в протоколе Modbus должен
присутствовать обязательно, а режим ASCII является опционным. Пользователь может выбирать не обходимый ему режим , но все модули,
включенные в сеть Modbus, должны иметь один и тот же режим передачи
Принципом функционирования обмена в стандарте Modbus RTU позволяет унифицировать команды обмена благодаря стандартизации номеров (адресов) регистров и функций их чтения-записи. Режим RTU имеет
также большую информационную пропускную способность, чем режим
ASCII при тойже скорости передачи битов.

Протокол Modbus предполагает, что только одно ведущее устройство
(контроллер) и до 247 ведомых (модулей ввода-вывода) могут быть объединены в промышленную сеть. Обмен данными всегда инициируется
ведущим устройством . Ведомые устройства никогда не начинают передачу данных, пока не получат запрос от ведущего. Ведомые устройства
также не могут обмениваться данными друг с другом . Поэтому в любой
момент времени в сети Modbus может происходить только один акт обмена.
Адрес а с 1 по 247 являются адресами Modbus устройств в сети. Адрес а с
248 по 255 являются зарезервированными. В сети не должно быть у стройств с одинаковыми адресами.
Ведущее устройство не имеет адреса.

В RTU режиме сообщение начинает восприниматься как новое после паузы (тишины) на шине длительностью не менее 3,5 символов (это составляет 14 бит), т.е. ведичина паузы в секундах будет различной в зависимости от скорости передачи.
Структура кадра протокола следующая (общее макс кол-во байтв кадре - 256)

адрескод функцииданныеконтрольная сумма
1 байт1 байтN байт (до 252 байт)2 байта

в нашем режиме каждый байт сообщения содержит два 4-битных Hex символа. Каждое сообщение должно быть послано в виде непрерывного потока шестнадцатеричных символов.
данные передаются младшими разрядами вперед

стартовый бит12345678Бит паритетаСтоп бит

бит паритета (еще называют битом четности, потому что он отображает четность наличия единиц и нулей в байте (как-то так) можно не использовать, тогда вместо него второй стоповый бит должен.


Добавлено спустя 44 минуты 44 секунды:

Цитата:
коды функций являются числами в диапазоне от 1 до 127. Коды от 128 до 255 зарезервированы для пересылки в ответном сообщении кодов ошибок. Код "0" не используется.
Если сервер нормально выполнил принятую от клиента функцию, то в ответе поле "код функции" содержит ту же информацию, что и в запросе. В противном случае сервер выдает код ошибки. В случае ошибки код функции в ответе равен коду функции в запросе, увеличиенному на 128.
В начало
cybermerlin
Гость







СообщениеВт, 17-Окт-2006 14:20 
Цитата

так так
как самый мегаизвращенец я начаал топтаться на месте, пока модбас у меня уложится в голове.
Займемся оптимайзем кода нашего (файл выложен выше)
если вы помните у меня первой строкой идет вложение файла m162def.inc,
/сам файлик подредактированный тож возьмите здесь же/
а внем в конце (строка 664) записана строка
asm:
  1. .equ    TIMER1COMPAaddr     = $01A

.equ - директива присваивает метке значение.
таким образом вместо строки
asm:
  1. .org 0x1a 

мы спокойно можем записать
asm:
  1. .org TIMER1COMPAaddr
и это будет правильно и красиво!
теперь я немного поработал с началом нашего файла кода и с первой строки и до рабочего кода
;****************************************************
; РАБОТА
;****************************************************
Work:
хорошо ужав и отработав вписал следующее. ОБЯЗАТЕЛЬНО поменяйте у себя в файликах!!!!!
asm:
  1. .include "C:\SPAWN\proging\avr\tavrasm\appnotes\m162def.inc"
  2.  
  3. .def    Temp0=R16   ;переименование РОН        -моя прихоть
  4. .def    Temp1=R17
  5. .def    Temp2=R18
  6. .def    Temp3=R19
  7. .def    Temp4=R20
  8. .def    Temp5=R21
  9. .def    Temp6=R22
  10. .def    Temp7=R23
  11. .def    Temp8=R24
  12. .def    Temp9=R25
  13.  
  14. ;****************НАЧАЛО************************
  15. .cseg         ;начало программного сегмента
  16. .org 0      ;начальный адрес 0
  17.         rjmp Reset                  ;ссылки на прерывания
  18.         rjmp    TIMER1_COMPA
  19. reti
  20. ;****************************************************
  21. ; РАБОТА КОМПАРАТОРА
  22. ;вызывается как прерывание таймера на 30мс
  23. ;****************************************************
  24. .org TIMER1COMPAaddr
  25.         TIMER1_COMPA:
  26.          cli
  27.                 ldi Temp0,0          ;обнуление таймера
  28.                 out TCNT1H,Temp0
  29.                 out TCNT1L,Temp0
  30.                 call Clear_s
  31.                 call Clear_sALL
  32.                 call Start
  33.                 call Under_Buttons
  34.          sei
  35. reti
  36. ;RESET
  37. ;****************************************************
  38. ; ИНИЦИАЛИЗАЦИЯ
  39. ;****************************************************
  40. .org 0x38
  41. Reset:      ;START
  42.  cli
  43.         ldi Temp0,0b01000000
  44.         out TIMSK,Temp0  ;разрешить прерывание компаратора
  45.         ldi Temp0,0b00000010
  46.         out TCCR1B,Temp0        ;тактовый сигнал = CK/8
  47.  
  48.         ldi Temp0,0x75    ;инициализация компаратора
  49.         out OCR1AH,Temp0
  50.         ldi Temp0,0x30
  51.         out OCR1AL,Temp0
  52.  
  53.         ldi ZH,High(RamEnd)     ;инициализация стека for work in the RCALL
  54.         out SPH,ZH
  55.         ldi ZL,Low(RamEnd)
  56.         out SPL,ZL
  57.        
  58.         ldi Temp0,0b00001111    ;настройка каналов порта В на выдачу данных
  59.         out DDRB,Temp0
  60.         ldi Temp0,0b0000000     ;настройка каналов порта A на получение данных
  61.         out DDRA,Temp0
  62.  
  63.         eor Temp0,Temp0  ;обнуление таймера
  64.         out TCNT1H,Temp0
  65.         out TCNT1L,Temp0
  66.  sei
  67. ;reti
  68. ;*******************-end-*****************************
  69.  

ну как вам?? значительно уменьшилось? и преобразилось?
это называется мы учимся. Полезно все таки иногда потоптаться на месте!



m162def.rar
 Описание:

Скачать
 Имя файла:  m162def.rar
 Размер:  3.48 KB
 Загружен:  471 раз(а)



Последний раз редактировалось: cybermerlin (Чт, 26-Окт-2006 12:29), всего редактировалось 2 раз(а)
В начало
cybermerlin
Гость







СообщениеЧт, 26-Окт-2006 11:44 
Цитата

asm:
  1.  
  2. ;****************НАЧАЛО************************
  3. .dseg
  4.         Scan_code: .byte 4      ;сюда сканКоды можно закинуть и не держать их в Temp8
  5.         Flag_Press: .byte 1     ;Флаг наличия нажатых кнопок в прошлой сессии
  6.                                                 ;----нужно сделать проверку состояния этих кнопок и их инактивацию
  7. .cseg         ;начало программного сегмента
  8.  

Нам стало не хватать РОНов, значит мы можем задействовать память SRAM, которая отдана производителями МК в резерв.
Конфигурится он директивой .dseg
.dseg - сегмент данных.
Узнать сколько у вас памяти можно в ДатаШите. В нашем случае на странице 303-305 в таблице Registry Summаry.
Таким оюразом, чтобы мы могли спокойненько работать и "коллекционировать" скан-коды нажатых кнопок, мы их просто временно выгрузим по ячейкам памяти, а потомо, когда будем комплектовать пакет данных для передачи другому устройству (БУ), будем брать потихоньку и вставлять в пакетик.
директива .byte - резервирует байты в ОЗУ.
В нашем случае под Scan_code мы зарезервировали 4 байта, потом, если не хватит мы можем еще добавить :)
Записывать и читать из памяти можно командами sts & lds = запись и чтение в/из ОЗУ соответственно. Работать с ними нужно как с командами ввода/вывода данных в ПОРТы.
Если переменная состоит из нескольких ячеек (наш случай - 4 байта), то при операции следует указывать относительный адрес той, к которой мы обращаемся. При этом, имя переменной всегда указывает на нулевую ячейку.
asm:
  1. lds Temp8, Scan_code;загружаем в Temp
  2.                   ;0-ю ячейку переменной Digit
  3.  
  4. lds Temp8,Scan_code+1 ;в Temp1 - 1-ю ячейку Scan_code
  5. lds Temp8,Scan_code+2 ;в Temp2 - 2-ю ячейку
  6.  

вот так мы попеременно заносим в РОН Temp8 значения 0-3-его байтов, находящихся в памяти по метке Scan_code (именуемой переменной).
-----------------------
Теперь немного сконфигурим порт используемый для передачи пакетиков протокола.
asm:
  1. ;****************************************************
  2. ; ИНИЦИАЛИЗАЦИЯ
  3. ;****************************************************
  4. .org 0x38
  5. Reset:      ;START
  6. .............................
  7.         out DDRA,Temp0
  8.  
  9.         ldi temp0, 0    ;конфигурирование USART для протокола MODBUS
  10.         out UCSR0A,temp0
  11.         out UBRR0H,temp0
  12.         ldi temp0,0b00011000
  13.         out UCSR0B,temp0
  14.         ldi temp0,0b10001110
  15.         out UCSR0C,temp0
  16.         ldi temp0,0x25
  17.         out UBRR0L,temp0        ;конец конфигурирования USART
  18.  
  19.         eor Temp0,Temp0 ;обнуление таймера
  20.  

UCSR0A - можно считать регистром состояния работы порта USART
UBRR0H - верхний адрес регистра скорости передачи данных
UBRR0L - сответственно - нижний.
так как у нас скорость передачи 19200 bit/s, смотрим по таблице в ДШ(ДатаШите) на странице 192 табличку. У нас кварц на частоте 8 МГц, отлично, смотрим первый большой столбец, в строчке с этой скоростью мы видим два варианта и оба они дают процент ошибок одинаковый = 0,2%, чудьненько, будем использовать первый вариант, чтобы не конфигурить UCSR0A регистр
значит в UBRR0L вписываем = 0x25 (обратите внимание, зачастую данные даются в HEX кодировке!!!)
UCSR0B, UCSR0C - конфигурим формат пакетов, работу порта - синхро/асинхронный, и размер раздела отведенного в пакете под наши данные (скан коды клавки) - в ТЗ(техЗадании) нам сказано что под данные мы должны отвести 8 бит!.
размер этот конфигурится битами UCSZ2-UCSZ0 у этих регистров, здесь уж смотрите в ДШ опять на стр. 189 таблица номер 76.
Значения битов этих в нашем случае - "011"
БИТ ПАРИТЕТА (иначе - бит четности) мы не сипользуем - посему вдаваться пока не будем, устанавливаем в "0" в битах - UPM1-UPM0.
Так как мы используем ассинхронный режим передачи - бит UMSEL устанавливаем в "0".
строение байтов (регистров) UCSR0B, UCSR0C обязательно посмотрите на страничке 186-188.
Тогда будет понятно в какой последовательности мы должны выставлять значения битов :).
В начало
Показать сообщения:   
Страница 1 из 1
Перейти:  
Новая тема  Ответить  Печать

Вы можете начинать темы
Вы можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете присоединять файлы в этом форуме
Вы можете скачивать файлы в этом форуме
хостинг от .masterhost 
Rambler's Top100