Перейти к содержанию

Вопрос По Программе Джона Мортона "частотомер"


Рекомендуемые сообщения

Всем доброго времени суток! Я у Вас тут впервые поэтому если что не так пните по нужному адресу. Суть проблемы такова: паять прошивать микроконтроллеры научился, а после захотел научиться писать под AVR программы. С большим энтузиазмом взялся читать книгу Джона Мортона(прилагаю). Все было более-менее понятно до программы "Частотомер". Далее пошел темный лес. Решил повторить ее, переписал код, собрал схему попутно исправляя ошибочную схему и код автора. Скомпилировал без ошибок и начал испытывать в Proteus. по прилагаемому скриншоту видно что что-то не так. А что именно не могу понять. Мои догадки что это пункт кода про конвертирование цифр. И так бился перечитывал, находил у автора несоответствие подаваемого материала данной программы в обучении с его готовым листингом. Но даже с этими коррективами она не работает. Спасибо за понимание.

Morton._AVR_VVODNIY_KURS.djvu

post-195592-0-01553100-1447611836_thumb.jpg

частотомер.txt

Ссылка на комментарий
Поделиться на другие сайты

  • Ответов 107
  • Создана
  • Последний ответ

Топ авторов темы

Топ авторов темы

Изображения в теме

Динамическая индикация в протеусе работает не адекватно. Собирайте схему в живую. Можно попытаться для протеуса, в вашей программе уменьшить частоту индикации, может и заработает.

Изменено пользователем andryxa
Ссылка на комментарий
Поделиться на другие сайты

По состоянию входов индикатора, в данный момент должна светится перевернутая зеркально "шестерка" во втором разряде, значит нужно инвертировать таблицу значений сегментов для данного индикатора.

Ps Ну, и правильно подключить сегменты.

Errare humanum est. Коли людЯм позволено, что же о нас то говорить!
 

Ссылка на комментарий
Поделиться на другие сайты

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

По состоянию входов индикатора, в данный момент должна светится перевернутая зеркально "шестерка" во втором разряде, значит нужно инвертировать таблицу значений сегментов для данного индикатора.

Ps Ну, и правильно подключить сегменты.

Ок. подкоректирую отпишусь!
Ссылка на комментарий
Поделиться на другие сайты

Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. 

Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств. Подробнее параметры и результаты тестов новой серии PLM по ссылке.

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

Изменил настройки индикатора для пробы на 1нс. Вижу поочередное медленное переключение 3-х нулей.

s4pkc4kpk.jpg

Изменено пользователем Dastan89
Ссылка на комментарий
Поделиться на другие сайты

Ну так, посмотри что выходит с порта и подключи правильно сегменты, или таблицу подкорректируй.

Errare humanum est. Коли людЯм позволено, что же о нас то говорить!
 

Ссылка на комментарий
Поделиться на другие сайты

Похвально, что начали с ассемблера.

Вот только когда обнаружилась ошибка стоило бы ее решить. Например, создать отдельный проект для проверки именно динамической индикации, потом объединить с основным. Или пошаговая отладка. Ну и, может я путаю, но AT90S1200 несколько устарел, лучше бы выбрали например ATmega8 или ATmega48-328, или, если хотите более простые - ATtiny2313 (хотя с ней почему-то часто возникают вопросы). Впрочем, разницы особой нет.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Спасибо за ценный совет.Да, я читал что данный микроконтроллер устарел. Пусть и стек у него аппаратный, но я придерживаюсь мнения автора книги, в том что выбираем микроконтроллер под конкретную задачу. Я закончил университет по специальности "Моделирование и компьютерное проектирование РЭС ", нам преподавали немного програмирования на С для помигать светодиодом, а так у меня было все завязано Altium, Kompas, OrCad и сотни других программ. Пять умею, собирал, разводил схемы и прошивал схемы нескольких микроконтроллерах(для примера, часы на ин-12, с температурой), просто но работает. А потом захотел сам попробывать писать программы. Выбор пал на ассемблер. Ввиду того что я его больше понял чем С, да и знаменитый DiHalt, советовал. Ибо с С на ассемблер труднее перейти чем на оборот. Хотя это чисто субъективное мнение. Но вот беда у Мортона застопорился, а как мне отладить правильно при таком объеме не знаю. Хотя небольшие программы сигнализация 3-кнопки и килогерцовая сирена отлаживал в Avr studio.

И все же ткните носом конкретно что и как если можно по шагам мне отладить эту программу. В одиночку мне не осилить, сколь бы книг не прочитал.

Ссылка на комментарий
Поделиться на другие сайты

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

PORTB = arr[i];
PORTD = (1<<i);

а так

PORTD = 0; //сначала гасим все сегменты
PORTB = arr[i];
PORTD = (1<<i);

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

; поскольку прогамма Display вызывается часто

; (не реже 1 раз в секунду)

А должна хотя бы 100 раз в секунду, а то мерцать будет сильно. Другой комментарий говорит о 64 мс, то есть 15 Гц, что тоже мало. А что, синхронизироваться с таймером нельзя?
ldi temp,0b11111100   ; 0
 mov R0,temp

Раз уж допускаются макросы, было бы красивее сделать

ldi temp, (1<<SEG_A | 1<<SEG_B | 1<<SEG_C | 1<<SEG_D | 1<<SEG_E | 1<<SEG_F)
out R0, temp

то есть отдельные биты вместо магических чисел. Впрочем, в данном случае и числа неплохо расшифровываются.

Но для начала попробуйте убрать все, не относящееся к индикации и отладьте именно этот кусок.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

У меня впечатление, что ты не понимаешь саму суть динамической индикации, и что должно происходить при исполнении кода.

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

PS "рюшечки" в виде пауз для контрастности, пока опустим.

Errare humanum est. Коли людЯм позволено, что же о нас то говорить!
 

Ссылка на комментарий
Поделиться на другие сайты

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

Ссылка на комментарий
Поделиться на другие сайты

Строчки, где выводятся в порт В значение символа, и в порт D знакоместо, и что выводится.

Errare humanum est. Коли людЯм позволено, что же о нас то говорить!
 

Ссылка на комментарий
Поделиться на другие сайты

Я знаю как это работает

В таком случае вам не составит труда написать код, реализующий только динамическую индикацию. Протеус ее вполне сносно моделирует, если, конечно, не делать частоту 1 Гц.

Делать частотометр на камне со всего одним таймером - ИМХО не самая удачная идея, неоправданное усложнение программы и необходимость подсчета тактов (легко ошибиться). Возьмите хотя бы ATtiny2313, вроде по размера такая же, но достать проще, 2 таймера на борту, большая тактовая частота (20 МГц вместо 12) и наличие ОЗУ (аж 128 байт). Пусть один таймер занимается счетом внешних импульсов, второй - времени, а индикация крутится в бесконечном цикле (там точность все равно не нужна). Выводимое значение, как и таблицу число-код, нагляднее хранить в ОЗУ, а не в регистрах.

.

Так можете написать код, реализующий только вывод трехзначного числа динамической индикацией, или помочь?

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Я еще очень плохо понимаю assembler, но вот так сойдет? Правда если строго соответствовать тех.заданию, то пишем вместо

 .byte 4-byte 3

и в разделе инициализации убрать один регистр допустим

temp4=R19

. Я правильно понял?

s5kgi4pvd.jpg

.include "tn2313def.inc"
.list
.def temp1=R16
.def temp2=R17
.def temp3=R18
.def temp4=R19
.def temp =R20
.dseg
Digit: .byte 4
;-----------------
.cseg
.org 0
rjmp RESET ; Reset Handler
rjmp EXT_INT0 ; IRQ0 Handler
rjmp EXT_INT1 ; IRQ1 Handler
rjmp TIM_CAPT1 ; Timer1 Capture Handler
rjmp TIM_COMP1 ; Timer1 Compare Handler
rjmp TIM_OVF1 ; Timer1 Overflow Handler
rjmp TIM_OVF0 ; Timer0 Overflow Handler
rjmp UART_RXC ; UART RX Complete Handler
rjmp UART_DRE ; UDR Empty Handler
rjmp UART_TXC ; UART TX Complete Handler
rjmp ANA_COMP ; Analog Comparator Handler
;-----------------------------------------
EXT_INT0 : ret
EXT_INT1 : ret
TIM_CAPT1 : ret
TIM_OVF0 : ret
TIM_OVF1 : ret
UART_RXC : ret
UART_DRE : ret
UART_TXC : ret
ANA_COMP : ret
TIM_COMP1 : ret
;--------------------------------------------
reset: ldi temp1,RamEnd ;инициализация стека
 out SPL,temp1
 cli
 ldi temp,0b11111111 ;настройка портов
 out ddrb,temp
 ldi temp,0b00001111
 out ddrd,temp
 ldi temp,4
 sts Digit ,temp	 ;загрузка начальных значений
 ldi temp,3
 sts Digit+1,temp
 ldi temp,2
 sts Digit+2,temp
 ldi temp,1
 sts Digit+3,temp

;*********************************************************
;MAIN
;*********************************************************
IndicCycle: rcall Display	 ;цикл индикации
				 rjmp IndicCycle
;*********************************************************
Display:
;последовательный вывод на индикацию содержимого
;переменной Digit
		 lds temp1,Digit	 ;загружаем 0-ю ячейку
		 ldi temp,0b00001110 ;активируем 0-й разряд
							 ;индикации
		 out PortD,temp
		 rcall Decoder	 ;вызываем 7-сегм.декодер
		 out PortB,temp1 ;выводим значение в порт
		 rcall Delay1		 ;ждем
		 lds temp1,Digit+1
		 ldi temp,0b00001101
		 out PortD,temp
		 rcall Decoder
		 out PortB,temp1
		 rcall Delay1
		 lds temp1,Digit+2
		 ldi temp,0b00001011
		 out PortD,temp
		 rcall Decoder
		 out PortB,temp1
		 rcall Delay1
		 lds temp1,Digit+3
		 ldi temp,0b00000111
		 out PortD,temp
		 rcall Decoder
		 out PortB,temp1
		 rcall Delay1
		 ret

;*********************************************************
Decoder:
;Преобразование двоичного числа
;в код 7-сегментного индикатора
		 ldi ZL,Low(DcMatrix*2) ;инициализация массива
		 ldi ZH,High(DcMatrix*2)
		 ldi temp2,0				 ;прибавление переменной
		 add ZL,temp1		 ;к 0-му адресу массива
		 adc ZH,temp2
		 lpm					 ;загрузка значения
		 mov temp1,r0
		 ret
DcMatrix:
;массив - таблица истинности декодера
		 ;	 hgfedcba hgfedcba
		 .db 0b00111111,0b00000110 ;0,1
		 .db 0b01011011,0b01001111 ;2,3
		 .db 0b01100110,0b01101101 ;4,5
		 .db 0b01111101,0b00000111 ;6,7
		 .db 0b01111111,0b01101111 ;8,9
;*********************************************************
Delay1:
;цикл задержки
		 push temp1
		 push temp2

		 ldi temp1,0
		 ldi temp2,1
d11:	 dec temp1
		 brne d11
		 dec temp2
		 brne d11
		 pop temp2
		 pop temp1
		 ret

Ссылка на комментарий
Поделиться на другие сайты

Как-то так. Может, найдете полезные решения в моем коде. Если там ошибки - заранее извиняюсь, давно на ассемблере не писал, да и проверить не на чем.

.def r16,temp
.def r17,pos
.dseg
digit: .byte 4 ;здесь удобнее хранить сразу коды для отображения на индикаторе - все равно считывать обратно не планируется
num_mask: .byte 4
.cseg
DcMatrix: .db <...>
;эта процедура вызывается только один раз, при инициализации. Вообще, ее лучше оформить просто как кусок кода
INIT:
 ldi XH,high(digit)
 ldi XL,low(digit)
 ldi temp,0
 st X+,temp ;по умолчанию все разряды 0, можно и не инициализировать, все равно затрется по ходу программы
 st X+,temp
 st X+,temp
 st X+,temp

 ldi temp,0b00001110 ;маски для выбора нужного разряда. Из ОЗУ это чуть быстрее, чем из ПЗУ
 st X+,temp
 ldi temp,0b00001101
 st X+,temp
 ldi temp,0b00001011
 st X+,temp
 ldi temp,0b00000111
 st X+,temp
ret
; процедура вызывается для каждого разряда, во избежание бесполезных зацикливаний
DISPLAY:
 ldi ZH,0 ;поскольку в tn2313 всего 128 байт ОЗУ, старший байт адреса всегда равен 0
 ldi ZL,low(digit) ;инициализируем младший байт
 add ZL,pos ;переходим к заданной позиции
 ldi temp, 0b00011111 ;вот о чем я говорил - прежде чем изменить значение гасим все сегменты
 out PORTD,temp
 ld temp, Z ;загружаем значение по известному адресу и выводим его в порт (сегменты все еще погашены)
 out PORTB,temp
 add ZL,4 ;разница между областями digit и num_mask (где маски для выбора разряда) равна 4, так и сдвигаем
 ld temp,Z
 out PORTD,temp ;зажигаем именно нужный разряд
 inc pos ;переход к следующему
 andi pos,3 ;поскольку число разрядов "круглое", вместо честного сравнения можно воспользоваться лог. AND и оставить 2 младших разряда
ret
;процедура записи десятичного значения (temp) в разряд (new_pos)
SET_DIGIT:
 ldi ZH,high(DcMatrix*2)
 ldi XL,low(DcMatrix*2)
 add ZL,temp ;переход к символу нужного числа
 ldi temp,0 ;то что затираем temp никого не волнует, временный регистр он и есть
 adc ZH,new_pos
 lpm temp ;считываем (сразу в temp, незачем лишняя пересылка из r0)
 ldi ZH,0
 ldi ZL,low(digit)
 add ZL,new_pos ; переход к нужному разряду, в который будем записывать
 st Z,temp
ret

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Спасибо, на досуге гляну и проверю в железе. А пока если Вы не против, для себя и Вас буду развивать мой вопрос с написанием программы частотомера. На данный момент имея выше написанную подпрограмму работы с дисплеем, как мне ее правильно адаптировать к коду автора, с этим у меня загвоздка. Затем нужен счетчик который будет отсчитывать от 0 и до 999 и также при выходе за предел измерения дать команду: что показать на дисплее "HI". Так же как это связать с подсчетом импульсов на входе микроконтроллера?

Ссылка на комментарий
Поделиться на другие сайты

С кодом автора? А оно надо? Свое разрабатывать интереснее.

Что такое частота? Это количество колебаний в единицу времени. Количество колебаний можно посчитать на входе T0 (T1, T2 и т.д. если есть) таймера в соответствующем режиме. То есть используем один таймер, частота которого заранее не известна. Время можно посчитать вторым таймером, уже тактируемым от кварца, то есть с известной частотой. Для простоты стоит посмотреть в сторону режима CTC и вызовом прерывания. Потом просто делим, что насчитал первый таймер на то, что насчитал второй, и получаем частоту.

Пусть тактовая частота контроллера 20 МГц (максимальная для tn2313, не терять же впустую часть диапазона измерения). Также пусть время преобразования будет 0.1 с, не слишком быстро, но и с большей скоростью человек считать данные вряд ли сможет. Тогда делитель равен 20МГц * 0.1с = 2`000`000. Подбираем предделитель таймера:

1:1 => 2`000`000 > 65536 (максимум для 16-битного таймера) - не подходит

1:8 => 250`000 - не подходит

1:64 => 31250 - подходит!

То есть ставим предделитель 1:64 (CS=0b011), модуль счета 31249 (по формуле еще прибавится 1).

Таким образом, по прерыванию Timer1 можно сохранять сколько насчитал Timer0 (включая количество переполнений), а потом в основном цикле вывести это число с нужной точностью.

Например, T0 насчитал 12345 импульсов за 0.1 с, это эквивалентно 123450 импульсов за 1 с или 123`450 Гц. Наверное, удобнее будет использовать не 1/10 с, а более круглое число, 1/16 например, или 1/8. Сдвинуть на 3-4 разряда гораздо проще, чем заниматься делением.

Для отсчета количества импульсов можно использовать прерывание по переполнению. Главное не забудьте о регистре SREG.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Хорошо. Ну а как хотя бы набросок кода сделать как это может выглядеть. что должно быть в инициализации и что в основной программе. Я тоже буду пробовать составлять код, но Ваша помощь для меня бесценна.

Ссылка на комментарий
Поделиться на другие сайты

Ну не писать же код за вас.

.def temp=r16
.def countH = YH
.def countL = YL
.def flag=r19
.org 0
rjmp RESET
.org 0x0004
rjmp TIMER1_COMPA
.org 0x0006
rjmp TIMER0_OVF
.org 0x0012
reti

RESET:
;настройка портов ввода-вывода, таймеров
;(это процесс неинтересный, его можно найти в справочнике, расписывать лень)
ldi temp,(1<<TOIE0 | 1<<OCIE1A) ;разрешаем прерывания от Т1 (по сравнению) и от Т2 (по переполнению)
out TIMSK,temp
sei
CYCLE:
 rcall DISPLAY ;из предыдущего куска кода, процедура динамической индикации
 sbrs flag,0;проверка 0-го бита регистра flag, если выставлен - пропустить следующую команду
	  rjmp CYCLE ;обратно в бесконечный цикл
 ; теперь достаточно поделить 3-байтное число (countH:countL:TCNT0) на время счета T1 (константа!)
 ; что даст новое значение для индикации
 rcall ITOA ; перевод из числа в массив кодов для отображения на индикаторе. Надеюсь, подробно расписывать не надо
 clr countH ;очищаем переменные перед новым измерением
 clr countL
 out TCNT0,countL
 out TCNT1H, countL
 out TCNT1L, countL
 ldi temp, (0b001 << CS00) ;запуск Т0 в режиме normal с предделителем 1:1
 out TCCR0B,temp
 ldi temp, (1<<WGM12 | 0b011 << CS10) ;запуск Т1 в режиме СТС с предделителем 1:64
 out TCCR1B,temp
 sei
rjmp CYCLE

;обработчик прерывания по сравнению
TIMER1_COMPA: ;кстати, оказалось, что SREG здесь не меняется оО. Меняется temp, но он по логике не будет использован в бесконечном цикле
 ldi temp,0
 out TCCR0B,temp ;останавливаем отсчет, чтобы не считал пока будем преобразовывать в массив для отображения, а то мало ли чего насчитает
 out TCCR1B,temp
 ldi flag,1 ; взводим флаг, чтобы начать преобразование количества импульсов в 4-разрядное десятичное значение
reti
;обработчик прерывания по переполнению
TIMER0_OVF:
 adiw countL,1 ; раз уж есть команда для увеличения на 1 двухбайтного числа - почему бы не воспользоваться. Если нужно отслеживаь переполнение, можно проверить бит C или Z регистра SREG
reti

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Ну и конструкция получилась. А подпрограмму работы дисплея мне в конце всей программы можно разместить или какое то есть особое расположение?

Ссылка на комментарий
Поделиться на другие сайты

Можете проверить меня правильно ли я настроил инициализацию:

;инициализация стека
ldi temp, RAMEND
out SPL, temp
;инициализация портов
ldi temp, 0
out DDRB, temp
ldi temp, 0xFF
out DDRD, temp
;инициализация таймера
ldi temp, 0b00000111
out TCCR1B, temp ;

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы публикуете как гость. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

×
×
  • Создать...