реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Микроконтролеры AVR. Джон Мортон. Ошибки в книге?
Merovey
сообщение Oct 27 2009, 12:40
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 24-08-07
Из: Санкт-Петербург
Пользователь №: 30 043



Добрый день!
Речь идет не о банальных опечатках, а о более глобальных ошибках.
Например, вот фрагмент кода, который формирует секундную задержку для микроконтроллера AT90S1200. Кварц на 2.4576 МГц.

Код
     ldi Count30,30
     ldi Mark80,80  
TimeLoop:
    out TCNT0,temp  
    cp temp,Mark80  
    brne TimeLoop    
    subi  Mark80,-80
    dec   Count30    
    brne  TimeLoop

Понимаю, что вместо out TCNT0,temp должно быть in temp,TCNT0. Быстрей всего это косяк переводчика. Но насколько работоспособен сам принцип формирования такой задержки? Насколько я понял, таймер считает до 255 и начинает заново, значит после 3-х циклов, когда Mark80 превысит значение 255 равенства не наступит. Правильно ли я понимаю, или есть какие-то особенности?
Go to the top of the page
 
+Quote Post
V_G
сообщение Oct 27 2009, 13:33
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 818
Регистрация: 15-10-09
Из: Владивосток
Пользователь №: 52 955



А как байт (Mark80) может превысить 255?
А какую частоту считает TCNT0?
Go to the top of the page
 
+Quote Post
Merovey
сообщение Oct 27 2009, 13:46
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 24-08-07
Из: Санкт-Петербург
Пользователь №: 30 043



Цитата
А как байт (Mark80) может превысить 255?

Рабочие регистры 8 разрядные, следовательно максимальное шестнадцатеричное число может поместить FF или 255 в десятичном формате.
Код
subi Mark80, -80

на 4 итерации, следовательно мы превысим 255
Я на это не обратил внимание.
Я имел ввиду, что таймер только до 255 досчитает, потом обнулится.
Или я что-то не так понимаю?

Цитата
А какую частоту считает TCNT0?

СК/1024
Go to the top of the page
 
+Quote Post
Палыч
сообщение Oct 27 2009, 14:02
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Merovey @ Oct 27 2009, 15:40) *
Но насколько работоспособен сам принцип формирования такой задержки?
Вы не привели начало программы... Но, если инициализация проведена "правильно", и пределитель = 1024, то 30 * 80 * 1024 = 2457600. Вроде всё правильно. Насколько это жизнеспособно? Имхо, такие (по продолжительности) задержки в программе - самоубийство (разве, что что-то совсем простое проектируется, но таких устройств в жизни не бывает). Ставить задержки в программу можно (нужно) только если требуемая задержка сопоставима по продолжительности со временем работы процедуры обработки прерывания. Учебный пример может быть далёк от жизни, поскольку он иллюстрирует некий приём, метод работы.

Цитата(Merovey @ Oct 27 2009, 16:46) *
Код
subi Mark80, -80

на 4 итерации, следовательно мы превысим 255
Регистр таймера - 8 бит, и переменная Mark80 - тоже. В переменной Mark80 хранится значение регистра таймера, уменьшенное на 80. Т.е. через 80*1024 тактов генератора счетный регистр таймера примет значение, такое же как и Mark80, значение в Mark80 "отодвинем" ещё на 80 и счетчик Count30 уменьшим на единицу. И так 30 раз (первоначальное значение счетчика). Итого: через 30*80*1024 тактов покинем TimeLoop (если строго говорить, то плюс ещё сколько-то тактов).
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Oct 27 2009, 14:34
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Как переводчик может перепутать: "out TCNT0,temp" и "in temp,TCNT0"??? Да и вообще зачем переводчику править текст проги? Как говорится "если в слове МИР перепутать 3 буквы, то получится нецензурщина". Это явный косяк автора. Причём похоже на всю голову.

Исходя из приведенного вами текста (с учётом замены out на in) мы видим следующее:
1) TCNT не устанавливается в цикле. Таким образом после сравнения он продолжает считать дальше.
2) Mark80 вычитается по 80, что вообще необъяснимо.

Первое сравнение получим при значении таймера 80
Последующие сравнения будут происходить ч/з 176

Таким образом округлённо получим задержку 176*30+80=5380. При делителе 1024 это составит чуть больше 2 сек.

Даже если предположить, что я ошибся в расчётах и задержка высчитана правильно, то это всё равно из ряда вон выходящий пример с дурным стилем.

Стандартным видом задержки является что-то в виде следующего.

Код
wait:
    ldi        w1,high(FCnt)    ; Загрузить счётчик задержки
    ldi        w2,low(FCnt); Загрузить счётчик задержки
wt01:
;    rjmp    pc+1
;    rjmp    pc+1
;    rjmp    pc+1
;    rjmp    pc+1
;    rjmp    pc+1
;    rjmp    pc+1
    subi    w2,1
    sbci    w1,0
    brcc    wt01


Где длительность приблизительно равна (1+1+2)*FCnt -1+2 такта (без учёта прерываний).

Если к примеру мы разрэмим 2 rjmp, то результат будет (2+2+1+1+2)*FCnt -1+2 такта и так далее.

В качестве ядра (там где стоят rjmp) мы можем считать события. В том числе переполнения таймера или элементарные отсчёты таймера. Например при частоте 2.4576 при делителе 1024 один такт таймера составит 0.416666 мс соответственно секунда составит 2400 тактов. Если мы возьмём по 80 (как в примере), то получим 30*80=2400.

Соответственно прога быдет выглядеть так (без инициализации таймера и сохраняя стилистику автора)

Код
wait_1s:
    ldi    w1,30        ; Загрузить счётчик задержки
    ldi    temp,0
    out    TCNT0,w2
    ldi    w2,80
wt01:
    in    temp,TCNT
    cp    temp,w2    
    brne    wt01
    ldi    temp,0
    out    TCNT0,w2
    dec    w1
    brne    wt01


Реально обычно так не делают. Обычно исходят из того, что 2400 / 256 = 9.... Итого получается 9 полных циклов + 96 тактов.
Задержка выглядит так:

Код
wait_1s:
    ldi    temp,-96        ; Загрузить счётчик задержки
    out    TCNT0,temp
    sbi    TIFR,TOV0
    ldi    temp,9
wt01:
    sbis    TIFR,TOV0
    rjmp    wt01
    sbi    TIFR,TOV0
    dec    temp
    brne    wt01
Go to the top of the page
 
+Quote Post
Палыч
сообщение Oct 27 2009, 14:59
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(SasaVitebsk @ Oct 27 2009, 17:34) *
Исходя из приведенного вами текста (с учётом замены out на in) мы видим следующее:
1) TCNT не устанавливается в цикле. Таким образом после сравнения он продолжает считать дальше.
2) Mark80 вычитается по 80, что вообще необъяснимо.
Вы - недоглядели: вычитается минус 80 (т.е. значение увеличивается на 80). Т.е. значение переменной Mark80 каждый раз "сдвигается" на 80 единиц относительно предыдущего и равенство счетного регистра таймера и переменной наступает через 80 * 1024 (1024 - это пределитель) тактов генератора.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Oct 27 2009, 15:03
Сообщение #7


Нечётный пользователь.
******

Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417



Цитата(SasaVitebsk @ Oct 27 2009, 16:34) *
2) Mark80 вычитается по 80, что вообще необъяснимо.
Вычитается по "минус 80".
Итого сравнения через 80
30*80*1024 = 2457600


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Oct 27 2009, 17:26
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(ReAl @ Oct 27 2009, 18:03) *
Вычитается по "минус 80".
Итого сравнения через 80
30*80*1024 = 2457600

Согласен. Упустил. Но ...
1. нет начальной инициализации таймера
2. Если её добавить, то результирующая программа будет длинее мной приведенной, плюс занимает 3 регистра, что для 1200 немало ну и согласитесь как то заумно ...
Go to the top of the page
 
+Quote Post
Merovey
сообщение Oct 28 2009, 07:32
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 24-08-07
Из: Санкт-Петербург
Пользователь №: 30 043



Цитата(Палыч @ Oct 27 2009, 17:02) *


Ну один из примеров, где используется этот принцип, вполне, мне кажется, применим. Как система управления на светофоре. А насчет отодвинем 30 раз? после 4 раз мы же переполним регистр Mark80? Да и таймер, получается, столько не отсчитает..

Цитата(SasaVitebsk @ Oct 27 2009, 17:34) *
Стандартным видом задержки является что-то в виде следующего.


Что-то похожее есть у автора, например так же секундная задержка:
Код
ldi Delay1,0x00
ldi Delay2,0x35
ldi Delay3,0x0C

Loop:
subi Delay1,1
sbci Delay2,0
sbci Delay3,0
brcc Loop


Предыдущий способ предлагается использовать когда нужно во время работы счетчика выполнять другие действия.
Но, мне кажется, Вы правы. Без инициализации таймера не работоспособен пример.. Во всяком случае я не понимаю, как он может работать 01.gif
Причина редактирования: Нарушение п.3.4 правил форума.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Oct 28 2009, 07:57
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Merovey @ Oct 28 2009, 10:32) *
А насчет отодвинем 30 раз? после 4 раз мы же переполним регистр Mark80? Да и таймер, получается, столько не отсчитает..
Переполним... Но, и счетный регистр таймера работает с переполнением. Поэтому я и употребил - "отодвинем".

Цитата(Merovey @ Oct 28 2009, 10:32) *
Без инициализации таймера не работоспособен пример.. Во всяком случае я не понимаю, как он может работать
Сама книга - мне недоступна, и Вы привели из неё толко выдержку. Конечно, инициализация таймера должна быть (как минимум установить прескалер). В книгах бывает объясняют работу с устройствами "по-частям": отдельно - инициализация, отдельно - использование... Куски кода предполагается - объединит читатель. Может и в этой книге так?
Go to the top of the page
 
+Quote Post
Merovey
сообщение Oct 28 2009, 12:31
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 24-08-07
Из: Санкт-Петербург
Пользователь №: 30 043



Ну вот пример программы из книги, где это используется. Поочередно включаются светодиоды:
CODE
.device at90s1200
.nolist
.include "C:\Program Files\Atmel\AVR Studio\1200def.inc"
.list

.def temp=r16
.def Mark240=r17
.def Counter=r18
.def Speed=r19

rjmp Init

Init:
ser temp
out DDRB,temp
ldi temp,0b11111100
out DDRD,temp

ldi temp,0b00000001
out PortB,temp

ldi temp,0b00000011
out PortD,temp

ldi temp,0b00000101
out TTCR0,temp

ldi Mark240,240
ldi Counter,5
ldi Speed,5

Start:
; Проверяется нажатие кнопки уменьшения скорости
sbic PinD,0
rjmp UpTest
inc Speed
cpi Speed,11
brne ReleaseDown
dec Speed

ReleaseDown:
sbis PinD,0
rjmp ReleaseDown

; Проверяется нажатие кнопки увеличения скорости
UpTest:
sbic PinD,1
rjmp Timer
dec Speed
brne ReleaseUp
inc Speed

ReleaseUp:
sbis PinD,0
rjmp ReleaseUp

; Формируем задержку
Timer:
in temp,TCNT0
cp temp,Mark240
brne Timer

subi Mark240,-240
dec Counter
brne Start

;Меняем СИД
mov Counter,Speed

in temp,PortB
lsl temp
brcc PC+2
ldi temp,0b00000001

out PortB,temp
rjmp Start


Цитата(Палыч @ Oct 28 2009, 10:57) *
Переполним... Но, и счетный регистр таймера работает с переполнением. Поэтому я и употребил - "отодвинем".


но переполнение происходит же не одинаково? время разве не уедет? я понимаю так, достигли мы в Mark80 значения 240. Прибавляем 80, получаем переполнение. А Timer считает дальше (до 255), и равенство будет не ранее, чем переполнится Timer и дойдет до нужного значения, так? Это время будет соответствовать тому же периоду, что и увеличение со 160 до 240?
Причина редактирования: Нарушение п.3.4 Правил форума.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Oct 28 2009, 13:11
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954



Цитата(Merovey @ Oct 28 2009, 15:31) *
Код
.device at90s1200
ldi temp,0b00000101
out TTCR0,temp

Вот это - и есть инициализация таймера. rolleyes.gif
Остальные регистры = Initial Value - "значение при включении/сбросе".

P.S. Уж не знаю чья ошибка, но регистр называется TCCR0

Цитата(Merovey @ Oct 28 2009, 15:31) *
но переполнение происходит же не одинаково? время разве не уедет?
Почему же происходит не одинаково? Пусть счетный регистр таймера и Mark80 в текущий момент имеют значение 240. Произошло сравнение (они равны); прибавляем к Mark80 значение 80 (вычитаем минус 80) - получаем Mark80 равным 64 (240+80=320; 320 -не помещается в байт; один разряд с весом 256 вылез за старший разряд байта; 320-256=64). На таймер/счетчик поступают с пределителя импульсы; счетный регистр их считает:
241 242 ... 254 255 0 1 ... 63 64
Значение на счетном регистре достигнет 64 через те же 80 импульсов от пределителя.

P.S. Может так понятнее: Увеличить число на 80 - абсолютно то же самое, что прибавить 80 раз по единице.
Go to the top of the page
 
+Quote Post
Merovey
сообщение Oct 29 2009, 06:02
Сообщение #13


Участник
*

Группа: Участник
Сообщений: 43
Регистрация: 24-08-07
Из: Санкт-Петербург
Пользователь №: 30 043



Цитата(Палыч @ Oct 28 2009, 16:11) *
P.S. Уж не знаю чья ошибка, но регистр называется TCCR0


Это моя ошибка, точнее описка.

Цитата(Палыч @ Oct 28 2009, 16:11) *
Почему же происходит не одинаково? Пусть счетный регистр таймера и Mark80 в текущий момент имеют значение 240. Произошло сравнение (они равны); прибавляем к Mark80 значение 80 (вычитаем минус 80) - получаем Mark80 равным 64 (240+80=320; 320 -не помещается в байт; один разряд с весом 256 вылез за старший разряд байта; 320-256=64). На таймер/счетчик поступают с пределителя импульсы; счетный регистр их считает:
241 242 ... 254 255 0 1 ... 63 64
Значение на счетном регистре достигнет 64 через те же 80 импульсов от пределителя.


Теперь понял. Спасибо. Насчет первичной инициализации понятно. Я думал, еще в самом цикле нужно определять ).
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Oct 30 2009, 09:05
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Разобраться с самим МК, конечно надо. И немного ассемблера не помешает. Ну а дальше надо двигаться в сторону Си. Это сэкономит вам кучу времени и сейчас более актуально. А заодно позволит уйти от частного МК к общему пониманию работы с МК.
Go to the top of the page
 
+Quote Post
Valek
сообщение Nov 1 2012, 08:00
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 22
Регистрация: 19-06-07
Из: Челябинск
Пользователь №: 28 542



У меня есть вопрос какраз по этой книге. Когда мы рассматриваем задержки с применением команд subi и sbci, мы расчитываем число которое нам нужно записать в регистры по формуле T*F/x. х у нас приведен в таблице для разных диапазонов времени и тактовой частоты. ВОПРОС, КАК МЫ ПОЛУЧАЕМ ЭТОТ Х?

Сообщение отредактировал Valek - Nov 1 2012, 08:01
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 30th June 2025 - 19:47
Рейтинг@Mail.ru


Страница сгенерированна за 0.01558 секунд с 7
ELECTRONIX ©2004-2016