.equ pin_a = 0x01 ; 0
.equ pin_b = 0x10 ; 4
.equ pin_c = 0x40 ; 6
.macro bit_set
ldi temp,@1
out @0,temp
.endm
.macro bit_reset
ldi temp,255^(@1)
out @0,temp
.endm
;**********************************
; установка битов а и с
bit_set portd,(pin_a | pin_c)
; Сброс битов a и b
bit_reset portd,(pin_a | pin_b)
Впрочем, PORTD я тоже бы спрятал внутрь макроса, так, что при смене оборудования пришлось бы править только макросы, а основной код остался бы без изменений.
Кто мешает тебе выдумать порох непромокаемый? (К. Прутков, мысль № 133)
LDI R16,1<<7|1<<5 ;к примеру, 7 и 5 биты это флаги других событий
; ldi r16, 0xff^((!0<<bit_b)|(!0<<bit_a)) ; в "temp"-e будет = 0хEE (0b1110 1110)
GOTEST:
SBR R16,1<<bit_a|1<<bit_b|1<<bit_c
NOP
CBR R16,1<<bit_a|1<<bit_b|1<<bit_c
RJMP GOTEST
"Но в другие биты вписываются единицы, их как видеть?" - при подготовке маски в конструкции
ldi temp, (1<<3)
подразумевается - что только третий бит будет "1", остальные - нули, и их не видно - это как-бы само-собой.
Далее - накладываем маску на регистр выделенный под ключ-флаги
or r_flag, temp
и получаем (если 3-й бит был "0") изменившийся 3-й бит.
Чтобы также красиво-читабельно "нарисовать" маску для "выключения" 3-го бита -? -приходится немного поизвращатся
ldi temp, ~(!0<<3) ; - "нарисовали" маску
в третьем бите вдно что "0", в остальных - еденицы, и их не видно
and r_flag, temp ; - "выключили" 3-й бит
"akl" - Ваша правда - командами SBR и CBR - получается быстрее, чем в моем случае (и ведь знакомы сочетание этих букв , а как-то мимо ушей)
Спасибо.
Здравствуете.
Таймер/счетчик-1 запрограммирован "Fast PWM" 8-бит. При отладке в AVR Studio 4.18, 4.19 Т/С-1 ведет себя как "Phase correct PWM" (TCNT - счетный регистр должен при "Fast PWM" от "0" досчитать до "FF", выставить флаг переполнения, сброситься в "0" и опять до "FF"... , у меня при отладке "TCNT" от "0" считает до "FF", после от "FF" считает до "0", выставляет флаг переполнения и т.д. ...?) Пробовал и на Хрюшке и на 7-ке. В Протеусе симуляция проходит правильно. Не могу понять - или ручки кривые, или студия корявая?
В AVR Studio 5.1 - отладка проходит ровно, но на моем ноутПуке - с тормозами, и не могу при отладке регистры переименовать, так, как они в программе обозваны директивой ".def" -? (вообще какую нибудь фишку придумали, чтобы переименование происходило в автоматическом-полуавтоматическом режиме ) Спойлер;
.include "m8def.inc" ;подключение стандартного заголовочного файла для ATmega8
.list ;данная директива включает генерацию кода в листинг, т.е.
;далее в файле *.lss будет фиксироваться ассемблерный код
.def temp = r16 ; Рабочая лошадка (везде)
.cseg ;данная директива означает, что дальше идет код программы
.org 0 ;данная директива означает, что код программы будет
;располагаться с 0ого адреса в FLASH
;ВЕКТОР ПРЕРЫВАНИЙ
rjmp initial ;прерывание от … , ссылаемся на обработчик прерывания - initial
rjmp 0 ;rjmp service_INT0 ;внешнее прерывание 0
rjmp 0 ;rjmp service_INT1 ;внешнее прерывание 1
rjmp 0 ; service_OC2 ;совпадение TCNT2 и OCR2
rjmp 0 ; service_OVF2 ;переполнение TCNT2
rjmp 0 ;rjmp service_ICP1 ;захват в ICP1
rjmp service_OC1A ;совпадение TCNT1 и OCR1A
rjmp 0 ;rjmp service_OC1B ;совпадение TCNT1 и OCR1B
rjmp service_OVF1 ;переполнение TCNT1
rjmp service_OVF0 ;переполнение TCNT0
rjmp 0 ;rjmp service_SPI ;прерывание от модуля SPI
rjmp 0 ;rjmp service_URXC ;получение байта по USART
rjmp 0 ;rjmp service_UDRE ;опустошение UDR в USART
rjmp 0 ;rjmp service_UTXC ;передача байта по USART
rjmp 0 ;rjmp service_ADCC ;прерывание от АЦП
rjmp 0 ;rjmp service_ERDY ;завершение записи в EEPROM
rjmp 0 ;rjmp service_ACI ;прерывание от компаратора
rjmp 0 ;rjmp service_TWI ;прерывание от модуля TWI
rjmp 0 ;rjmp service_SPMR ;завершение выполнения spm
.org 0x20 ;данная директива означает, что код программы будет располагаться
;с слова 0x20 в FLASH или с адреса 0x40 (т.к. в FLASH адресация идет
;по словам а не байтам, а одно слово это два байта)
;УСТАНОВКА СТЕКА
initial: ldi R16,low(RAMEND) ;скопируем в R16 младщий байт из константы RAMEND,
;которая определена в m8def.inc и хранит размер SRAM
out SPL,R16 ;скопируем значение из R16 в SPL
ldi R16,high(RAMEND) ;скопируем в R16 старший байт из константы RAMEND,
;которая определена в m8def.inc
out SPH,R16 ;скопируем значение из R17 в SPH
;
; ---------- set T0 -------
;++++++++++++++++++++++++++++++++++++++++++++++
; таймер Т/С-0 режим Normal - предделитель 64 и сброс при переполнении(256)
; 8000000/(256*64) = 488,28125Гц - с такой частатой будет происходить опрос всех кнопок
; 1/488,28125Гц = 0,002048сек = 2,048мс - для подавления дребизга времени достаточно
; 2,048мс * 256 = 0,524288сек - при пользованием одним регистром, для подсчета кол-ва
; прерываний, энтервал времени которое можно отмерить - маловат...
;
; - предделитель 256 и сброс при переполнении(256)
; 8000000/(256*256) = 122,0703125Гц, 1/122,0703125Гц = 0,008192сек = 8,192мс
; 8,192мс * 256 = 2,097152сек - вот сдесь энтервальчик приличный, да и опрос
; кнопок 122 раа в секунду - тоже вроде не плохо...
;
; 8000000/(256*1024) = 30,517578125Гц, 1/30,517578125Гц = 0,032768сек = 32,768мс
; 32,768мс * 256 = 8,388608сек
; ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
in temp, timsk
ori temp, (1<<TOIE0);0b00000001; прерывание по переролнению T0
out timsk, temp
clr temp
; ldi temp, 0x0aa ; для отладки
out tcnt0, temp ; обнуляем счетный регистр
ldi temp,(0<<CS02)|(1<<CS01)|(0<<CS00);0b00000100 ; предделитель=000-стоим,001-0,010-8,011-64,100-256,101-1024
out tccr0, temp ; "спусковой крючок" для запуска счетчика
; -------- end set T0 ------------------
;+++++++++++++++++++++++++++++++++++++++
; ---------- set T1 -------
; Для выполнения цикла записи 16-битного регистра первым должен
; быть загружен старший байт значения, который помещается в регистр
; TEMP. При последующей записи младшего байта он объединяется с
; содержимым регистра TEMP, и оба байта одновременно (в одном и том же
; такте) записываются в 16-битный регистр. Если требуется изменить
; несколько 16-битных регистров таймера/счетчика, а старшие байты всех
; записываемых значений одинаковы, то загрузку старшего байта достаточно
; выполнить только один раз.
; Для выполнения цикла чтения 16-битного регистра первым должен
; быть прочитан младший байт. При его чтении содержимое старшего байта
; помещается в регистр TEMP. При последующем чтении старшего байта
; возвращается значение, сохраненное в регистре TEMP. Исключение
; составляют только регистры сравнения OCR/7A/B/C, при чтении которых
; регистр TEMP не задействуется.
; При выполнении цикла обращения к 16-битному регистру
; таймера/счетчика прерывания должны быть запрещены.
;
;============(mega8)=========
; TCCR1A - управление Т/С-1
; 7(COM1A1) (= 0) ; Режим работы блока сравнения
; 6(COM1A0) (= 0) ; ^
; 5(COM1B1) (= 0) ; ^
; 4(COM1B0) (= 0) ; ^
; 3(FOC1A) (= 0) ; Принудительное изменение состояния вывода ОС
; 2(FOC1B) (= 0) ; Принудительное изменение состояния вывода ОС
; 1(WGM11) (= 0) ; Режим работы таймера/счетчика.
; 0(WGM10) (= 1) ; Режим работы таймера/счетчика.
;
; TCCR1B - управление Т/С-1
; 7(ICNC1) (= 0) ; Управление схемой подавления помех блока захвата.
; 6(ICES1) (= 0) ; Выбор активного фронта сигнала захвата.
; 5(-----) (xxx) ;
; 4(WGM13) (= 0) ; Режим работы таймера/счетчика.
; 3(WGM12) (= 1) ; Режим работы таймера/счетчика.
; 2(CS12) (= 0) ;|\ Управление тактовым сигналом.
; 1(CS11) (= 1) ; ---(000-счет остановлен, 001-0,010-8,011-64,100-256,101-1024)
; 0(CS10) (= 0) ;|/
; ---------------
; WMG13 WMG12 WMG11 WMG10 | счет(TOP) | обнавление OCR | уст. TOV |
;--------------------------------------------------------------------------------------------
; 0 0 0 0 - Normal | FFFF | немедленно | FFFF |
;--------------------------------------------------------------------------------------------
; 0 0 0 1 - Phase correct PWM, 8-битный | 00FF | при TOP (FF) | 0000 |
;--------------------------------------------------------------------------------------------
; 0 0 1 0 - Phase correct PWM, 9-битный | 01FF | при TOP (1FF) | 0000 |
;--------------------------------------------------------------------------------------------
; 0 0 1 1 - Phase correct PWM, 10-битный | 03FF | при TOP (3FF) | 0000 |
;--------------------------------------------------------------------------------------------
; 0 1 0 0 - CTC (сброс при совпадении) | OCR | немедленно | FFFF |
;--------------------------------------------------------------------------------------------
;-> 0 1 0 1 - Fast PWM, 8-битный | 00FF | при TOP (FF) | при TOP |
;--------------------------------------------------------------------------------------------
; 0 1 1 0 - Fast PWM, 9-битный | 01FF | при TOP (1FF)| при TOP |
;--------------------------------------------------------------------------------------------
; 0 1 1 1 - Fast PWM, 10-битный | 03FF | при TOP (3FF)| при TOP |
;--------------------------------------------------------------------------------------------
; 1 0 0 0 - Phase and Frequency Correct PWM | ICR | 0000 | 0000 |
;--------------------------------------------------------------------------------------------
; 1 0 0 1 - Phase and Frequency Correct PWM | OCR | 0000 | 0000 |
;--------------------------------------------------------------------------------------------
; 1 0 1 0 - Phase correct PWM | ICR | при TOP (FFFF) | 0000 |
;--------------------------------------------------------------------------------------------
; 1 0 1 1 - Phase correct PWM | OCR | при TOP (FFFF) | 0000 |
;--------------------------------------------------------------------------------------------
; 1 1 0 0 - CTC (сброс при совпадении) | ICR | немедленно | FFFF |
;--------------------------------------------------------------------------------------------
; 1 1 0 1 -
;--------------------------------------------------------------------------------------------
; 1 1 1 0 - Fast PWM | ICR | при TOP | при TOP |
;--------------------------------------------------------------------------------------------
; 1 1 1 1 - Fast PWM | OCR | при TOP | при TOP |
;--------------------------------------------------------------------------------------------
; Настройка таймера Т1 на "Phase PWM"
; без дергания ногами при совпадении,
; и предделитель ...
;-----------------------
ldi temp, 128;0x7a
out OCR1AL, temp ; регистр сравнения
in temp, timsk
ori temp, (1<<TOIE1)|(1<<OCIE1A);0b00010100; прерывание по переполнению Т1 и совпадению T1а,
out timsk, temp
ldi temp, (0<<WGM11)|(1<<WGM10) ;0b0000001 ; Fast PWM 8-битный
out TCCR1A, temp ;
ldi temp, (0<<WGM13)|(1<<WGM12)|(0<<CS12)|(1<<CS11)|(0<<CS10); Phase correct PWM, 8-битный, предделитель 8
out TCCR1B, temp ; - "спусковой крючок" для запуска счетчика
;--------------------
sei
;*********************************************************
;; - типа основной цыкл т.е. свободное время - генерим х.з. что.
; инвертируем пин (I/O)
main_prog:
sbic pinb,4; пропустить если пин = 0
rjmp msh4
sbi portb,4 ; установить пин в 1
rjmp mshe4
msh4:
cbi portb,4 ;сбросить пин в 0
mshe4:
rjmp main_prog
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; инвертируем пин "pinb,1" каждый раз когда попадаем
; здесь при переполнение TCNT1
sbic pinb,1; пропустить если пин = 0
rjmp msha
sbi portb,1 ; установить пин в 1
rjmp mshae
msha:
cbi portb,1 ;сбросить пин в 0
mshae:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cbi portb,5 ;сбросить пин в 0
reti
; end - service_OVF1 -------------
;===============
;****************************************
;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
service_OC1a: ;совпадение TCNT1 и OCR1A
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; инвертируем пин "pinb,2" каждый раз когда попадаем
; здесь при совпадение TCNT1 и OCR1A
sbic pinb,2; пропустить если пин = 0
rjmp msh
sbi portb,2 ; установить пин в 1
rjmp mshe
msh:
cbi portb,2 ;сбросить пин в 0
mshe:
;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
; на portb,5 после резюка с кондером должна быть пила
inc temp
out OCR1AL, temp ; регистр сравнения
sbi portb,5 ; установить пин в 1
reti
; end --- service_OC2 ----
;----------------------------------------
;====
service_OVF0: ;переполнение TCNT0
; инвертируем пин (I/O)
sbic pinb,3; пропустить если пин = 0
rjmp msa
sbi portb,3 ; установить пин в 1
rjmp msae
msa:
cbi portb,3 ;сбросить пин в 0
msae:
; nop
reti
Vaha писал(а):Не могу понять - или ручки кривые, или студия корявая?
Симулятор2 попробуйте. Там должно быть нормально как и в железе.
Не совсем корректно просто записывать младшую часть 16-разрядных регистров таймера. Они имеют больший чем 8 бит диапазон.
; на portb,5 после резюка с кондером должна быть пила
LDI R17,0
out OCR1AH,R17 ; старший байт регистра сравнения
inc temp
out OCR1AL, temp ; младший байт регистра сравнения
sbi portb,5 ; установить пин в 1
reti
Пробовал обе версии - 4.18 и 4.19 - одинаково. Поставил 5.1 - все хорошо, но с тормазами и не удобно - регистры не могу подписать при отладке. Качаю "свежий" дистрибутив версии 4.19 с ru_track - попробую его.
"akl" - на счет корректности - при инициализации т/с-1 записывал в старший и младший регистры, но когда в регистр управления "TCCR1B" вписывалась информация о 8-и битном режиме - старший регистр сравнения "OCR1AH" - обнулялся (в отладчике) - ?
Здравствуйте, уважаемые форумчане!
Видел уже здесь похожий вопрос с не совсем верным ответом на него.
Пардон за незнание очевидных вещей - буду крайне признателен тому, кто ткнет меня носом в ошибку.
Ситуация - имеется avr studio 7, МК Atmega128 и STK500, программа с генерацией прерываний для таймера с счетчиком по совпадению (СТС).
Отладочная плата при запуске просто начинает мигать светодиодами и пока примитивно ставится цель изменения частоты мигания при нажатия на определенные кнопки.
Так вот, если выделять команды задания таймера в отдельную функцию, то реакция на кнопки вообще пропадает. При добавлении в общий main появляется, но это меня не устраивает. Функция, меняющая частоту в свою очередь меняет её только один раз и то по непонятной мне логике.
Вопрос - как исправить код, сделать адекватной реакцию на кнопки с объявлением таймера в отдельной функции и изменять частоту при нажатии, код:
An-SU писал(а):пока примитивно ставится цель изменения частоты мигания при нажатия на определенные кнопки.
зачем вы для этого работаете с TCNT1? период мигания у вас определяется значением OCR1 - его и обновляйте, а таймер пусть колбасит все время с "прежними" настройками.
или я неверно понял вашу цель?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
ARV, с TCNT1 я работаю только в местах предполагаемых рестартов таймера, обнуляя его для надежности
А в своей функции TIM16_Write я как раз вношу число в OCR1
Но вот, как написал, проблема в том, что почему-то до этих процедур вообще не доходит в случае отсутствия реакции на кнопки
я не предполагаю, я вижу некоторую путаницу в коде, всякие случаи и т.п.
и просто предлагаю продумать алгоритм еще раз.
нужно ли запрещать прерывания на время опроса кнопок?
как их опрашивать?
нужно ли их запрещать при обновлении таймера?
нужно ли менять TCNT1?
что вообще нужно делать?
после ответов на все вопросы у вас все заработает.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
ARV, путаница есть и спасибо за пищу для размышления, поскольку это лишь тренировочный код для меня и это я всё позже поправлю, но проблема в том, что я не понимаю пока просто почему, когда я выношу команды инициализации таймера в отдельную функцию, то у меня до опроса состояния кнопок вообще не доходит!
И это меня пока смущает более всего.
ARV, Вы меня не поняли. Статью я прочёл и абсолютно с ней согласен, но вопрос иной, а именно:
Почему выполнение программы не доходит до момента опроса кнопок?
Я же просто выношу команды в отдельную функцию.
То есть если я просто пишу те же самые команды в main, где и есть опрос, то реакция есть.
(Что в 1 случае, что во 2 суть и алгоритм неизменен (если сейчас абстрагироваться от того, что вообще делают кнопки))
Да в том-то и дело, что абсолютно одинаковый код...
Добавлено after 1 minute 44 seconds:
Ни у одного меня такая шляпа, как я понял
[uquote="gis",url="/forum/viewtopic.php?p=3431667#p3431667"]Может кто-нибудь подсказать? Допустим мне надо перенести часть кода из обработчика внешнего прерывания в основной цикл. Допустим я делаю так.
#include <avr/io.h>
#include <avr/interrupt.h>
char n;
ISR (INT0_vect)
{
n=1;
PORTB|=0x01;//поднимаем первую ножку, чтобы убедиться, что прерывание произошло
}
int main(void)
{
DDRB=0xFF;
PORTB=0x00;
DDRD=0x00;
PORTD=0xFF;
EICRA |= (1<<ISC01)|(0<<ISC00);// прерывание по заднему фронту
EIMSK |= (1<<INT0);
asm ("sei");
while(1)
{
if (n)
{
PORTB|=0x02;//вторая из основного цикла
n=0;
}
}
}
В итоге прерывание происходит, а код внутри условия if не выполняется. Пробывал разные вариации, ничего не получатся.[/uquote]
да что все начинающие наступают на одни и те же грабли - это закономерно.
однако, чтобы вам можно было помочь, вам необходимо предоставить всю информацию о проблеме. то есть как минимум 2 варианта кода: который работает и который не работает. потому как я уже говорил - неправильные ваши "выносы" делают код неработоспособным. это 100%
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...