ПО измерителя длительности сигнала

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Аватара пользователя
coredumped
Опытный кот
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Re: ПО измерителя длительности сигнала

Сообщение coredumped »

Вот, лови. Этот код взят из моего старого проекта на tiny2313. Портировать на мегу легко - замени таблицу векторов прерываний и фсё :)
Вложения
uart.asm.zip
(1.59 КБ) 156 скачиваний
Все будет только лучше, в крайнем случае - хуже.
Реклама
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Вроде что-то написал. Подсмотрел пример в книге Ю.Ревича. Описывается программа для Периодомера стр.180.
Вот что получилось:

Код: Выделить всё

.include   "m16def.inc"

.def temp  = R16
.def count0 = R17
.def count1 = R18
.def count2 = R19

;============векроты прерываний=============

rjmp RESET 		    ; Reset Handler
reti ;rjmp EXT_INT0 		; IRQ0 Handler
reti ;rjmp EXT_INT1 		; IRQ1 Handler
reti ;rjmp TIM2_COMP 		; Timer2 Compare Handler
reti ;rjmp TIM2_OVF 		; Timer2 Overflow Handler
rjmp TIM1_OVF 		; Timer1 Overflow Handler
rjmp TIM1_CAPT 		; Timer1 Capture Handler
reti ;rjmp TIM1_COMPA 	    ; Timer1 CompareA Handler
reti ;rjmp TIM1_COMPB   	; Timer1 CompareB Handler
reti ;rjmp TIM0_OVF 		; Timer0 Overflow Handler
reti ;rjmp SPI_STC 		    ; SPI Transfer Complete Handler
reti ;rjmp USART_RXC 		; USART RX Complete Handler
reti ;rjmp USART_UDRE 	    ; UDR Empty Handler
reti ;rjmp USART_TXC 		; USART TX Complete Handler
reti ;rjmp ADC 		        ; ADC Conversion Complete Handler
reti ;rjmp EE_RDY 		    ; EEPROM Ready Handler
reti ;rjmp ANA_COMP 		; Analog Comparator Handler
reti ;rjmp TWSI 		    ; Two-wire Serial Interface Handler
reti ;rjmp EXT_INT2 		; IRQ2 Handler
reti ;rjmp TIM0_COMP 		; Timer0 Compare Handler
reti ;rjmp SPM_RDY 		    ; Store Program Memory Ready Handler

RESET:

ldi temp,low(ramend)
out SPL,temp
ldi temp,high(ramend)
out SPH,temp

ldi temp, 0b10111111; настроить ICP1 на вход (вывод PD6)
out DDRD,temp

clr count2
clr count1
clr count0

ldi temp,(1<<TICIE1)|(1<<TOIE1); разрешить прерывание по захвату
out TIMSK,temp; и переполнение таймера

clr temp
out TCNT1H,temp; обнулить таймер
out TCNT1L,temp

ldi temp, 0b01000000; разрешить захват по фронту, 
out TCCR1B,temp ; но таймер остановлен

sei

TIM1_OVF:

inc count2

reti


TIM1_CAPT: ;процедура захвата (произошло прерывание)

ldi temp, 0b01000010; разрешить захват по фронту, частота 2МГц
out TCCR1B,temp; и запуск таймера

ldi temp, 0b00000010; разрешить захват по спаду, частота 2МГц
out TCCR1B,temp; таймер не останавливаем

in count0,ICR1L; запомнить содержимое таймера
in count1,ICR1H

ldi temp, 0b01000000; остановить таймер 
out TCCR1B,temp 

clr temp; и очистить таймер
out TCNT1H,temp
out TCNT1L,temp

// записать значения count0,count1,count2 в память для
// последущей выдачи по UART
reti //выйти из подпрограммы обработки прерывания
Должно работать так: Измеряем промежуток времени между фронтом и спадом. Следовательно, устанавливаем захват по фронту и разрешаем прерывания. Прерывание наступает, запускаем таймер и устанавливаем захват по спаду. Прерывание по спаду срабатывает, останавливаем таймер и запоминаем содержимое регистра захвата. Вроде бы так...
Если нет поправьте.
Входной сигнал подаю на вывод ICP1.

Скорее всего работать нормально не будет.
Не знаю что делать с count2, туда ли я её вообще засунул???
И как говорит господин ARV частота должна быть 1Мгц, а у меня получается 2МГц, потому что Тактовая частота = 16МГц. Величина предделителя 1/8.
И как поставить диапазон измерений от 10мкс до 1с
И надо ли переводить значения регистров count[0:2] в 10-ую сист. счисления? и как это сделать?
Ещё нужно подсчитать число тактов приходящихся на выполнение команд, чтобы погрешность довести до минимума.
Сильно не ругайте, это моя первая так сказать программа с использованием прерываний и переферии. :)
Реклама
akl
Друг Кота
Сообщения: 4446
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ПО измерителя длительности сигнала

Сообщение akl »

Здравствуйте.
-таблица векторов прерываний не соответствует mega16
mega16_irq.GIF
-после SEI нужно дождаться признака измерения, который устанавливать в прерывании CAPT
например

Код: Выделить всё

	.EQU	END=0
	.EQU	BEGIN=7
;	.
;	.
clr temp
out TCNT1H,temp; обнулить таймер
LDI TEMP,8
out TCNT1L,temp;загрузить начальное значение, устраняющее задержку включения таймера
;	.
	CLR	R20           ; очистить регистр признаков

	SER	TEMP
	OUT	TIFR,TEMP	;!!!!!!!!!!!!очистить флаги таймеров чтобы исключить предысторию их появления
	SEI
WAIT:
	SBRS	R20,END ;измерение закончено?
	RJMP	WAIT             ;нет. Ждем
;да. Обрабатываем полученный результат
;	.
;	.
;	.
;	.
	RJMP	RESET



TIM1_CAPT: ;процедура захвата (произошло прерывание)
	SBRC	R20,BEGIN; начало измерения было?
	RJMP	IZMER ;да
;начало измерения
;	ldi temp, 0b01000010; разрешить захват по фронту, частота 2МГц
;	out TCCR1B,temp; и запуск таймера

	ldi temp, 0b00000010; разрешить захват по спаду, частота 2МГц
	out TCCR1B,temp; таймер не останавливаем
	SBR	R20,BEGIN; установить признак начала измерения
	RETI
IZMER:
in count0,ICR1L; запомнить содержимое таймера
in count1,ICR1H

ldi temp, 0b01000000; остановить таймер
out TCCR1B,temp

;clr temp; и очистить таймер
;out TCNT1H,temp
;out TCNT1L,temp

	SBR	R20,END ;установить признак измерения

// записать значения count0,count1,count2 в память для
// последущей выдачи по UART
reti //выйти из подпрограммы обработки прерывания
-длительность импульса, для Вашего случая, равна T=COUNT2...0/(Fcpu/8) и для 10 секундной длительности емкости count2 не хватит. Под count2 отвести регистровую пару XH:XL и наращивание count2 осуществлять ADIW XL,1. Тогда и предделитель таймера не нужно устанавливать, а считать 16-мегагерцовые тики

-примерно тоже самое решается здесь
http://radioded.ru/content/view/95/1/
http://radioded.ru/forum/viewtopic.php?p=1692#p1692
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Спасибо за помощь. Но возникло много вопросов))
akl писал(а): -таблица векторов прерываний не соответствует mega16
Мляя, я думал, что разницы не будет, какое прерывание инициализировать раньше, а какое позже.
akl писал(а): длительность импульса, для Вашего случая, равна T=COUNT2...0/(Fcpu/8) и для 10 секундной длительности емкости count2 не хватит
А ёмкости count2 хватит для длительности в 1секунду? У меня предел 1с. Запись COUNT2...0, Вы имеете ввиду это надо как-то склеить три регистра count2 +count1+count0 ???
И всё-таки переменную count2 оставить в TIM1_OVF: inc count2 reti; ??
akl писал(а): SER TEMP
OUT TIFR,TEMP ;!!!!!!!!!!!!очистить флаги таймеров чтобы исключить предысторию их появления
Почему флаги таймеров очищаются заполнением единиц??

Не много не понятно, как Вы отслеживаете признак измерения. Почему BEGIN равно именно 7 ?

Там где Вы поставили комментарии на моём коде, значит оно не нужно?
Реклама
Эиком - электронные компоненты и радиодетали
akl
Друг Кота
Сообщения: 4446
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ПО измерителя длительности сигнала

Сообщение akl »

"...я думал, что разницы не будет, какое прерывание инициализировать раньше, а какое позже."
У каждого представителя AVR-семейства своя жестко фиксированная таблица векторов прерываний.
"Почему флаги таймеров очищаются заполнением единиц??"
Так принято разработчиком, описано в DS и новации здесь не катят. :dont_know:
"А ёмкости count2 хватит для длительности в 1секунду? У меня предел 1с. Запись COUNT2...0, Вы имеете ввиду это надо как-то склеить три регистра count2 +count1+count0 ???
И всё-таки переменную count2 оставить в TIM1_OVF: inc count2 reti; ??"

Да, для 1-й секунды емкости count2 хватит. Значение длительности будет равно 65536*count2+256*count1+1*count0
"Почему BEGIN равно именно 7 ?"
Это мой произвольный выбор. Естественно, Вы можете его не придерживаться. Просто признаки BEGIN и END должны быть различными.
"Там где Вы поставили комментарии на моём коде, значит оно не нужно?"
Нет, мною только закомментированы команды, лишние и добавлены нужные, на мой взгляд.
Реклама
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Хорошо. Учту Ваши дополнения и замечания, и попробую написать нормальный код. Обязательно выложу.
Ещё небольшой вопросец:
Эта запись
ldi temp, 0b01000000;
out TCCR1B,temp
Устанавливает захват по фронту, а вот таймер запустится или нет??

Он запустится только при такой записи?:
ldi temp, 0b01000010
out TCCR1B,temp
Т.е. без коэффициента предделителя или внешней частоты синхронизации таймер не запуститься ведь?
Имею ввиду запустится, т.е. начнёт считать такты процессора.
Реклама
akl
Друг Кота
Сообщения: 4446
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ПО измерителя длительности сигнала

Сообщение akl »

Запись

Код: Выделить всё

ldi temp, 0b01000000;
out TCCR1B,temp
удерживает таймер в остановленном состоянии. Все другие комбинации 3-х младших бит разрешают работу таймера
Бит ICES1 регистра TCCR1B определяет перепад, по которому содержимое таймера будет копироваться в ICR1 и при этом будет взводиться флаг
ICF1 регистра TIFR. Собственно прерывание по захвату разрешается битом TICIE1 регистра TIMSK. Важный момент! Прерывание CAPT будет вызвано независимо от состояния таймера. Считает он или нет- неважно.
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Вот, изменил как Вы сказали :(

Код: Выделить всё

.include   "m16def.inc" 

.equ end = 0
.equ begin = 7

.def temp  = R16
.def count0 = R17
.def count1 = R18
.def count2 = R19
.def flg = R20

;============векроты прерываний=============

rjmp RESET 		    ; Reset Handler
reti ;rjmp EXT_INT0 		; IRQ0 Handler
reti ;rjmp EXT_INT1 		; IRQ1 Handler
reti ;rjmp TIM2_COMP 		; Timer2 Compare Handler
reti ;rjmp TIM2_OVF 		; Timer2 Overflow Handler
rjmp TIM1_CAPT 		; Timer1 Capture Handler
reti ;rjmp TIM1_COMPA 	    ; Timer1 CompareA Handler
reti ;rjmp TIM1_COMPB   	; Timer1 CompareB Handler
rjmp TIM1_OVF 		; Timer1 Overflow Handler
reti ;rjmp TIM0_OVF 		; Timer0 Overflow Handler
reti ;rjmp SPI_STC 		    ; SPI Transfer Complete Handler
reti ;rjmp USART_RXC 		; USART RX Complete Handler
reti ;rjmp USART_UDRE 	    ; UDR Empty Handler
reti ;rjmp USART_TXC 		; USART TX Complete Handler
reti ;rjmp ADC 		        ; ADC Conversion Complete Handler
reti ;rjmp EE_RDY 		    ; EEPROM Ready Handler
reti ;rjmp ANA_COMP 		; Analog Comparator Handler
reti ;rjmp TWSI 		    ; Two-wire Serial Interface Handler
reti ;rjmp EXT_INT2 		; IRQ2 Handler
reti ;rjmp TIM0_COMP 		; Timer0 Compare Handler
reti ;rjmp SPM_RDY 		    ; Store Program Memory Ready Handler

RESET:

ldi temp,low(ramend)
out SPL,temp
ldi temp,high(ramend)
out SPH,temp

ldi temp, 0b10111111; настроить ICP1 на вход (вывод PD6)
out DDRD,temp

clr count2
clr count1
clr count0

ldi temp,(1<<TICIE1)|(1<<TOIE1); разрешить прерывание по захвату
out TIMSK,temp; и переполнение таймера

clr temp
out TCNT1H,temp; обнулить таймер
ldi temp,8
out TCNT1L,temp; загрузить начальное значение, устраняющее задержку включения таймера

ldi temp, 0b01000000; разрешить захват по фронту, 
out TCCR1B,temp ; но таймер остановлен

clr flg; очистить регистр признаков

ser temp
out TIFR,temp; очистить флаги таймеров чтобы исключить предысторию их появления

sei

WAIT:

sbrs flg,end; измерение закончено?
rjmp WAIT; нет, ждём
; обрабатываем полученный результат


rjmp RESET


TIM1_OVF:

inc count2

reti


TIM1_CAPT: ;продцедура захвата (произошло прерывание)

sbrc flg,begin; начало измерения было?
rjmp IZMER; да

;ldi temp, 0b01000010; разрешить захват по фронту, частота 2МГц
;out TCCR1B,temp; и запуск таймера

ldi temp, 0b00000010; разрешить захват по спаду, частота 2МГц
out TCCR1B,temp; таймер не останавливаем

sbr flg,begin; установить признак начала измерения
reti

IZMER:

in count0,ICR1L; запомнить содержимое таймера
in count1,ICR1H

ldi temp, 0b01000000; остановить таймер 
out TCCR1B,temp 

sbr flg,end; установить признак измерения

// записать значения count0,count1,count2 в память для
// последущей выдачи по UART
rjmp RESET
Но многое неясно. :?

1. Почему в метке TIM1_CAPT: таймер не запускается с захватом по фронту?
;ldi temp, 0b01000010; разрешить захват по фронту, частота 2МГц
;out TCCR1B,temp; и запуск таймера
В RESET ведь таймер не запустили, а просто разрешили захват по фронту.
Получается, нигде нет строки на запуск таймера.
Я так понимаю, чтобы таймер запустить нужно выставить бит предделителя (их 3 - младших в регистре TCCR1B)

2. Что Вы подразумеваете под:
; обрабатываем полученный результат
в метке WAIT?

3. Метка WAIT. Она же идёт сразу после цикла RESET. Какой от неё смысл? Ведь измерение ещё не началось, а там уже проверяется на конец измерения...

4. 65536*count2+256*count1+1*count0 И вот эту запись придётся реализовать и выдать по УАРТ? Или она уже будет содержаться в регистрах перед отправкой?

Как всё сложно то... :cry:
akl
Друг Кота
Сообщения: 4446
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ПО измерителя длительности сигнала

Сообщение akl »

Здравствуйте.
-обратите внимание на таблицу векторов прерываний для mega16!!!!! Она по прежнему неправильная
1. Почему в метке TIM1_CAPT: таймер не запускается с захватом по фронту?
;ldi temp, 0b01000010; разрешить захват по фронту, частота 2МГц
;out TCCR1B,temp; и запуск таймера
В RESET ведь таймер не запустили, а просто разрешили захват по фронту.
Получается, нигде нет строки на запуск таймера.
Я так понимаю, чтобы таймер запустить нужно ыставить бит предделителя (их 3 - младших в регистре TCCR1B)

-захват по фронту был подготовлен ранее до метки WAIT. А вот когда он произошел, то, анализируя признак BEGIN, который еще равен 0, командами

Код: Выделить всё

	ldi temp, 0b00000010; разрешить захват по спаду, частота 2МГц
	out TCCR1B,temp; таймер не останавливаем
	SBR	R20,BEGIN
разрешается работа таймера в режиме счета Fcpu/8 и изменяется разрешение захвата по спаду. Также устанавливается признак начала измерения BEGIN, по которому программа и определит, что следующее прерывание захвата будет концом измерения. Для этого устанавливается признак END...
2. Что Вы подразумеваете под:
; обрабатываем полученный результат
в метке WAIT?

-нет, после установки признака END

3. Метка WAIT. Она же идёт сразу после цикла RESET. Какой от неё смысл? Ведь измерение ещё не началось,
а там уже проверяется на конец измерения...
-совершенно верно, программа уйдет с метки WAIT по установленному признаку END. Это будет возможно после измерения,
т.е. ожидаем передний фронт->когда прошел передний фронт запускаем счетчик, разрешаем ожидание спада импульса и устанавливаем признак начала измерения BEGIN-> когда прошел спад импульса устанавливаем признак END->считываем значения count2,count1,count0

4. 65536*count2+256*count1+1*count0 И вот эту запись придётся реализовать и выдать по УАРТ?
Или она уже будет содержаться в регистрах перед отправкой?
- да, значение count2,count1,count0 имеет такие веса

Должен уточнить, что счетчик запускается с тактированием Fcpu/8 и значение задержки запуска счетчика нужно установить равным 1, а не 8.
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Значит вот так:

Код: Выделить всё

ldi temp,1
out TCNT1L,temp; загрузить начальное значение, устраняющее задержку включения таймера
Ну сделал такую таблицу, выдаёт ошибки

Код: Выделить всё

.cseg
.org 0x0000
rjmp RESET 		    ; Reset Handler
.org EXT_INT0         ; IRQ0 Handler
     reti
.org EXT_INT1         ; IRQ1 Handler
     reti
.org TIM2_COMP        ; Timer2 Compare Handler
     reti
.org TIM2_OVF         ; Timer2 Overflow Handler
     reti
.org TIM1_CAPT        ; Timer1 Capture Handler
     rjmp TIM1_CAPT
.org TIM1_COMPA       ; Timer1 CompareA Handler
     reti
.org TIM1_COMPB       ; Timer1 CompareB Handler
     reti
.org TIM1_OVF         ; Timer1 Overflow Handler
     rjmp TIM1_OVF
.org TIM0_OVF         ; Timer0 Overflow Handler
     reti
.org SPI_STC          ; SPI Transfer Complete Handler
     reti
.org USART_RXC        ; USART RX Complete Handler
     reti
.org USART_UDRE       ; UDR Empty Handler
     reti
.org USART_TXC        ; USART TX Complete Handler
     reti
.org ADC              ; ADC Conversion Complete Handler
     reti
.org EE_RDY           ; EEPROM Ready Handler
     reti
.org ANA_COMP         ; Analog Comparator Handler
     reti
.org TWSI             ; Two-wire Serial Interface Handler
     reti
.org EXT_INT2         ; IRQ2 Handler
     reti
.org TIM0_COMP        ; Timer0 Compare Handler
     reti
.org SPM_RDY          ; Store Program Memory Ready Handler
     reti

вот ошибка
C:\qq\2.asm(10): error: Use of undefined or forward referenced symbol 'EXT_INT0' in .org
C:\qq\2.asm(11): error: Overlap in .cseg: addr=0x0 conflicts with 0x0:0x1

и таких ещё для каждого прерывания., конфликт с соседними адресами...
akl
Друг Кота
Сообщения: 4446
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ПО измерителя длительности сигнала

Сообщение akl »

В m16def.inc вектора названы по другому.

Код: Выделить всё

.equ	INT0addr=$002	;External Interrupt0 Vector Address
.equ	INT1addr=$004	;External Interrupt1 Vector Address
.equ	OC2addr =$006	;Output Compare2 Interrupt Vector Address
.equ	OVF2addr=$008	;Overflow2 Interrupt Vector Address
.equ	ICP1addr=$00A	;Input Capture1 Interrupt Vector Address
.equ	OC1Aaddr=$00C	;Output Compare1A Interrupt Vector Address
.equ	OC1Baddr=$00E	;Output Compare1B Interrupt Vector Address
.equ	OVF1addr=$010	;Overflow1 Interrupt Vector Address
.equ	OVF0addr=$012	;Overflow0 Interrupt Vector Address
.equ	SPIaddr =$014	;SPI Interrupt Vector Address
.equ	URXCaddr=$016	;UART Receive Complete Interrupt Vector Address
.equ	UDREaddr=$018	;UART Data Register Empty Interrupt Vector Address
.equ	UTXCaddr=$01A	;UART Transmit Complete Interrupt Vector Address
.equ	ADCCaddr=$01C	;ADC Interrupt Vector Address
.equ	ERDYaddr=$01E	;EEPROM Interrupt Vector Address
.equ	ACIaddr =$020	;Analog Comparator Interrupt Vector Address
.equ    TWIaddr =$022   ;Irq. vector address for Two-Wire Interface
.equ	INT2addr=$024   ;External Interrupt2 Vector Address
.equ	OC0addr =$026   ;Output Compare0 Interrupt Vector Address
.equ	SPMRaddr=$028   ;Store Program Memory Ready Interrupt Vector Address
Если Вы любитель символики, то вместо

Код: Выделить всё

.org $02
пишите

Код: Выделить всё

.org INT0addr ;   (во щасьте то)
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Мляяя, ну не знал я такого...)
А переходить на обработчик прерывания нужно командой rjmp? если оставить reti к обработчику не перейдёт?

Ладно, теперь буду колдовать с выводом данных по UART 8)
akl
Друг Кота
Сообщения: 4446
Зарегистрирован: Пт мар 07, 2008 06:54:43
Откуда: Ижевск

Re: ПО измерителя длительности сигнала

Сообщение akl »

Для mega16 лучше, ИМХО прыгать JMP в пределах всего адресного пространства. Возвращаться, на первых порах, RETI (I-бит SREG аппаратно взводится)
Аватара пользователя
Meteor
Друг Кота
Сообщения: 3961
Зарегистрирован: Пн июл 13, 2009 14:37:39
Откуда: Московская область, наукоград.....
Контактная информация:

Re: ПО измерителя длительности сигнала

Сообщение Meteor »

Еще один советик.
В обработке прерываний, лучше в самом начале сохранить содержимое регистра SREG в стеке, а в окончании обработки восстановить. Это позволит не наступать на грабли с нестандартной и неожиданной обработкой данных вне прерываний
Загружая на вход компьютера "мусор", на выходе получим "мусор^32".
PS. Не работаю с: Proteus, Multisim, EWB, Micro-Cap... не спрашивайте даже
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6321
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: ПО измерителя длительности сигнала

Сообщение Jack_A »

Meteor писал(а): В обработке прерываний, лучше в самом начале сохранить содержимое регистра SREG в стеке, а в окончании обработки восстановить.
Не лучше всего, а ОБЯЗАТЕЛЬНО. Более того, в некоторых микропроцессорных системах ( Intel x86, PDP-11 ) слово состояния сохраняется и при выходе восстанавливается автоматически. Почему Атмели съэкномили - ХЗ. Но, как правильно замечено, новичок на этих граблях может получить немало неприятностей.
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Jack_A писал(а): Не лучше всего, а ОБЯЗАТЕЛЬНО. Более того, в некоторых микропроцессорных системах ( Intel x86, PDP-11 ) слово состояния сохраняется и при выходе восстанавливается автоматически.
Вот. А я думал, что в Атмеле тоже самое - аппаратное сохранение регистра флагов в стек.

Ну тогда так:

Код: Выделить всё

.def sflag = R21
;---начало обработчика---
in sflag,SREG
push sflag

;---код обработчика---

pop sflag
out SREG,sflag
reti
Ведь для этих целей в начале программы инициализируем стек??? Или для чего то ещё?
Тогда в процессорах х86 не надо инициализировать стек))
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Наткнулся на сайт http://easyelectronics.ru/avr-uchebnyj- ... -uart.html
Пытаюсь вывести строку String: .db "TEST: send data to UART",0
но выдаёт ошибку error: Invalid directive: '.data'
Ниже код, покажите пожалуйста чего не хватает, и что лишнее. Буфер пока не формирую, сейчас хочу просто выдать строку по УАРТ, для проверки.

Код: Выделить всё

.include   "m16def.inc"

.equ 	XTAL = 16000000 	
.equ 	baudrate = 115200  
.equ 	bauddivider = XTAL/(16*baudrate)-1

.equ begin = 2; переменная признак, для сравнения с UDR

.macro PUSHF ; Макрос, помещающий в стек SREG и R16
           in R20,SREG
           push R20
           push R16
.endmacro

.macro POPF ; Макрос, восстановления из стека SREG и R16
           pop R16
           pop R20
           out SREG,R20
.endmacro

;***********************************************
String:		.db	"TEST: send data to UART",0
.DSEG
StrPtr:		.data 2
;***********************************************
.cseg
.org 0x0000
     rjmp RESET 	  ; Reset Handler

;============векроты прерываний=============

.org INT0addr         ; IRQ0 Handler
     reti
.org INT1addr         ; IRQ1 Handler
     reti
.org OC2addr          ; Timer2 Compare Handler
     reti
.org OVF2addr         ; Timer2 Overflow Handler
     reti
.org ICP1addr         ; Timer1 Capture Handler
     reti 
.org OC1Aaddr        ; Timer1 CompareA Handler
     reti
.org OC1Baddr         ; Timer1 CompareB Handler
     reti
.org OVF1addr         ; Timer1 Overflow Handler
     reti 
.org OVF0addr         ; Timer0 Overflow Handler
     reti
.org SPIaddr          ; SPI Transfer Complete Handler
     reti
.org URXCaddr         ; USART RX Complete Handler
     rjmp RX_OK
.org UDREaddr         ; UDR Empty Handler
     rjmp UD_OK
.org UTXCaddr         ; USART TX Complete Handler
     reti
.org ADCCaddr         ; ADC Conversion Complete Handler
     reti
.org ERDYaddr         ; EEPROM Ready Handler
     reti
.org ACIaddr          ; Analog Comparator Handler
     reti
.org TWIaddr          ; Two-wire Serial Interface Handler
     reti
.org INT2addr         ; IRQ2 Handler
     reti
.org OC0addr          ; Timer0 Compare Handler
     reti
.org SPMRaddr         ; Store Program Memory Ready Handler
     reti

.ORG   INT_VECTORS_SIZE      	; Конец таблицы прерываний

RESET:

PUSHF  
uart_init:	            LDI 	R16, low(bauddivider)
			OUT 	UBRRL,R16
			LDI 	R16, high(bauddivider)
			OUT 	UBRRH,R16

			LDI 	R16,0
			OUT 	UCSRA, R16

; Прерывания запрещены, прием-передача разрешен.
			LDI 	R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE)
			OUT 	UCSRB, R16	

; Формат кадра - 8 бит, пишем в регистр UCSRC, за это отвечает бит селектор
			LDI 	R16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)
			OUT 	UCSRC, R16
POPF
			RETI

RX_OK:		
PUSHF		        ; Макрос, пихающий в стек SREG и R16
 
		    IN	R16,UDR	        ; Тут главное забрать байт из UDR иначе 
					        ; флаг прерывания не снимется
					        ; Дальше, если время позволяет, можно и обработать
 		    CPI	R16,begin	
		    BRNE Rx_Exit		
		    			 
Rx_Exit:		
POPF			; Достаем SREG и R16
		    RETI

Main:

		    LDI	R17,low(2*String)	; Берем младший байт
		    LDI	R18,High(2*String)	; Берем старший байт
 
		    STS	StrPtr,R17	            ; Сохраняем Младший байт
		    STS	StrPtr+1,R18		; Сохраняем Сташрий байт

LDI R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(1<<UDRIE)
		    OUT UCSRB, R16
		    RJMP UD_OK

UD_OK:     PUSHF		; Макрос, сохраняющий SREG и R16
		    PUSH	ZL		; Сохраняем в стеке Z
		    PUSH	ZH
 
		    LDS	ZL,StrPtr	; Грузим указатели в индексные регистры
		    LDS	ZH,StrPtr+1
 
		    LPM	R16,Z+		; Хватаем байт из флеша. Из нашей строки
 
		    CPI	R16,0		; Если он не ноль, значит читаем дальше
		    BREQ STOP_RX	; Иначе останавливаем передачу
 
		    OUT	UDR,R16		; Выдача данных в усарт.
 
		    STS	StrPtr,ZL	; Сохраняем указатель 
		    STS	StrPtr+1,ZH	; обратно, в память
 
Exit_RX:   POP	ZH		; Все достаем из стека, выходим.
		    POP	ZL
		    POPF
		    RETI
 
; глушим прерывание по опустошению, выходим из обработчика
STOP_RX:    LDI 	R16, (1<<RXEN)|(1<<TXEN)|(1<<RXCIE)|(1<<TXCIE)|(0<<UDRIE)
		    OUT 	UCSRB, R16
		    RJMP	Exit_RX
Аватара пользователя
Uklunok
Вымогатель припоя
Сообщения: 561
Зарегистрирован: Сб апр 03, 2010 10:12:41
Откуда: Хабаровск

Re: ПО измерителя длительности сигнала

Сообщение Uklunok »

Всё, я сдаюсь :( Взял прогу господина coredumped, изменил таблицу прерываний и инициализировал стек для атмеги16. Остальное осталось тоже самое. Залил программу в СТК500. Закрыл AVR-STUDIO. Запустил прогу для мониторинга COM ПОРТА compt39_setup. - Ничего. Потом запустил serial_port_monitor - тоже ничего. Потом запустил ComVC. Никакая из этих программ не показали мне строку, которую передавал по УАРТ "HI!" Может у меня руки не от куда надо растут? Но мне это уже порядком поднадоело. Никто не скажет почему не работает? А лучше - сколько стоит такой проект на интеллектуальном рынке?
Аватара пользователя
coredumped
Опытный кот
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Re: ПО измерителя длительности сигнала

Сообщение coredumped »

Uklunok писал(а):Всё, я сдаюсь :(
Рано сдаешься. Программа не заработала, тк написана для tiny2313, а в mega16 есть один ньюанс при записи в регистр UCSRC - старший бит должен быть равен 1, он называется URSEL. Сорри, что забыл предупредить :dont_know:
То, что для tiny2313 выглядит так:
ldi A, (1<<USBS)|(3<<UCSZ0) ; set frame format: 8data, 1stop bit
out UCSRC,A
А для mega16 будет так:
ldi A, (1<<URSEL)|(1<<USBS)|(3<<UCSZ0) ; set frame format: 8data, 1stop bit
out UCSRC,A
В приложении исправленная программка под mega16, уже с правильными векторами прерываний. Я ее скомпилил и проверил "в железе" - все работает, можешь не сомневаться. Кварц у меня на 3.6864МГц, скорость 9600. Если у тебя другой кварц - подправь эту строчку (частота в герцах!):
.equ clock = 3686400 ;clock frequency

Еще учти, что RS232 - капризная штука. При выборе кварца и скорости обмена обрати внимание на таблицу "Examples of UBRR Settings for Commonly Used Oscillator Frequencies" в даташите на мегу. Там есть колонка Error - в идеале должно быть = 0 или как можно меньше. Если значение Error>5% возможны ошибки (искажения и пропадания символов), но это проявляется обычно на высоких скоростях и при больших объемах передаваемых данных. Те работать будет, но возможны глючки. У тебя какой кварц кстати?
Вложения
uart.asm.zip
(1.6 КБ) 142 скачивания
Все будет только лучше, в крайнем случае - хуже.
Аватара пользователя
Jack_A
Друг Кота
Сообщения: 6321
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Re: ПО измерителя длительности сигнала

Сообщение Jack_A »

Uklunok писал(а):Ведь для этих целей в начале программы инициализируем стек??? Или для чего то ещё?
Тогда в процессорах х86 не надо инициализировать стек))
Стек надо инициализировать в любом случае, неважно - используются ли обработчики прерываний, или вызовы подпрограмм, или Push - Pop -- в любом случае, не безразлично, в каком месте памяти будут происходить эти операции, потому что происходить они должны в конце памяти ( если, конечно, автор - не любитель извратов ).
В х86 - это компьютерные микропроцессоры - этим занимается при загрузке операционная система.
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»