Jump to content
Sign in to follow this  
anton2488

Сбрасываются Регистры После Обработки Прерываний. Как С Этим Жить?

Recommended Posts

UPD

Прошу прощения, нашлась ошибка, производился декремент постоянного регистра.

Изучаю авр и столкнулся с непреодолимой для меня проблемой.

Простая программа АЦП>програмный делитель>шим. Регистр, в котором постоянно хранится число сдвигов для деления всё время сбрасывается в 0, при этом при этом установленный бит в порте не сбрасывается(сделал для проверки). Не важно, записан ли регистр в РЕСЕТ или в прерывании через кнопку, всё равно происходит сброс. Как такое может быть?

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

Что я делаю не так? Помогите новичку.

.def temp1=r16
.def temp2=r17
.def div1=r18
.def div2=r19


.cseg
.org 0x0000
rjmp RESET
reti//1
rjmp vol//2
reti//3
reti//4
reti//5
reti//6
reti//7
rjmp adcpwm
reti//9
reti//10
reti//11
reti//12
reti//13
reti//14
reti//15

RESET:

ldi r16, (0<<WDRF)// остановка ст. таймера.
out MCUSR, r16
; Write logical one to WDCE and WDE
; Keep old prescaler setting to prevent unintentional Watchdog Reset
in r16, WDTCR
ori r16, (1<<WDCE)|(1<<WDE)
out WDTCR, r16
; Turn off WDT
ldi r16, (0<<WDE)
out WDTCR, r16

ldi temp1,0b00000011
out ddrb,temp1

ldi temp1,0b00011000
out portb,temp1

ldi temp1,0b11000011
out tccr0a,temp1

ldi temp1,0b00000001
out tccr0b,temp1

ldi temp1,0b00100001//УСТАНОВЛЕН СДВИГ ВЛЕВО
out admux,temp1

ldi temp1,0b11101111
out adcsra,temp1

ldi temp1,0b00000000
out adcsrb,temp1

ldi temp1,0b00000000
out mcucr,temp1

ldi temp1,0b00100000
out gimsk,temp1

ldi temp1,0b00011000
out pcmsk,temp1

ldi div1,3// запись коэф деления в постоянный регистр

sei

start:
rjmp start

adcpwm:// прерывание АЦП---------------------------------------------
in temp1,adcl
in temp2,adch

mov div2,div1 // запись коэф. деления из постоянного рег во временный

tst div2//деление
breq zap
l1:
lsr temp2
ror temp1
dec div1
brne l1

zap://запись в шим
out ocr0a,temp2
out ocr0b,temp2
reti

VOL://прерывание кнопки----------------------------------------------------
ldi div1,3// запись коэф деления в постоянный регистр

sbi portb,1//индикатор прерывания


reti

Edited by anton2488

Share this post


Link to post
Share on other sites

А где инициализация стека?

Регистры SPH:SPL не иницилизированы, откуда возникает переполнение стека и сброс контроллера.


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

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

Share this post


Link to post
Share on other sites

Изготовление 2-х слойных плат от 2$, а 4-х слойных от 5$!

Быстрое изготовление прототипа платы всего за 24 часа! Прямая доставка с нашей фабрики!

Смотрите видео о фабрике JLCPCB: https://youtu.be/_XCznQFV-Mw

Посетите первую электронную выставку JLCPCB https://jlcpcb.com/E-exhibition чтобы получить купоны и выиграть iPhone 12, 3D-принтер и так далее...

По конкретнее можно? Какой регистр "постоянно сбрасывается"? div1 в прерывании?

К замечаниям COKPOWENEU добавлю, что заходя в прерывания нужно сохранять в стеке, используемые регистры, а выходя из прерывания - восстанавливать. Не забывайте и про регистр состояния SREG. Иначе логика хода программы после выполнения прерывания может поменяться. Это по организации и "хорошему тону".

А по существу, Вы используете регистр div1. Заходя в прерывание, копируете его и проверяете на нулевое значение его копию div2, а уменьшаете (декрементируете) почему-то div1. Естественно, после трех прерываний Ваш регистр будет иметь значение 0.

Edited by Геннадий

Share this post


Link to post
Share on other sites

Высокая надежность SiC! Как они этого добились?

За несколько лет кропотливых исследований и совершенствования технологии компания Infineon смогла довести показатели надежности и стабильности параметров высоковольтных и быстродействующих карбид-кремниевых транзисторов линейки CoolSiC практически до уровня их кремниевых собратьев.

Подробнее

А где инициализация стека?

Регистры SPH:SPL не иницилизированы, откуда возникает переполнение стека и сброс контроллера.

в авр студио 5 и 6 не нужно инициализировать, всё само.

По конкретнее можно? Какой регистр "постоянно сбрасывается"? div1 в прерывании?

К замечаниям COKPOWENEU добавлю, что заходя в прерывания нужно сохранять в стеке, используемые регистры, а выходя из прерывания - восстанавливать. Не забывайте и про регистр состояния SREG. Иначе логика хода программы после выполнения прерывания может поменяться. Это по организации и "хорошему тону".

А по существу, Вы используете регистр div1. Заходя в прерывание, копируете его и проверяете на нулевое значение его копию div2, а уменьшаете (декрементируете) почему-то div1. Естественно, после трех прерываний Ваш регистр будет иметь значение 0.

всё верно, я перепутал и декременировал регистр div1 где должно постоянно хранится значение, в этом и была проблема.

Про сохранение регистров не слышал. Чем это вызвано? Каким образом прерывание может изменить значение регистров, если с ними не работают в прерывании. Но идея хороша, можно сэкономить регистр.

Share this post


Link to post
Share on other sites

Материалы вебинара «STM32L5. Секреты оценки энергопотребления»

Опубликованы запись и материалы вебинара КОМПЭЛ, посвященного первому семейству МК STM32L5 на ядре Cortex-M33. На вебинаре было рассказано о самых распространенных ошибках при расчете энергопотребления микроконтроллеров и о специальном тесте ULPMark, позволяющем дать наиболее объективную оценку энергоэффективности. Измерения проводились на демонстрационной платформе STM32L562E-DK.

Подробнее

Точно "само"? Вообще-то это было бы неправильное поведение. Покажите скомпилированный hex-файл.

Насчет прерываний - речь не о конкретном а об общем случае. А там возможны хотя бы операции сравнение, инкремента/декремента и прочие, влияющие на SREG. Представьте если такое прерывание возникнет между cp и breq. То, что шанс возникновения такой ошибки мал только усугубляет ситуацию: труднее найти ошибку. Ну и прерывание часто использует те же регистры, что и основная программа, а чтобы они друг другу не мешали, при входе и выходе в прерывание делают пары push/pop. Плюс не надо запоминать какое прерывание с какими регистрами работает. Например, в прерывании надо инкременировать содержимое ячейки 0x0100 ОЗУ.

ANY_INT:
  push r16   ;сохраняем r16
  in r16,SREG
  push r16   ;сохраняем SREG

  lds r16,0x0100 ;какие-то полезные действия
  inc r16
  sts 0x0100,r16

  pop r16   ;восстанавливаем SREG
  out SREG,r16
  pop r16   ;восстанавливаем r16
reti


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

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

Share this post


Link to post
Share on other sites

Снижена цена на AC/DC и DC/DC преобразователи Mornsun в Компэл!

Компэл и компания Mornsun снизили цены на преобразователи AC/DC-преобразователи семейств LS и LDE. По привлекательной цене также предлагаются DC/DC-преобразователи изолированных семейств поколений R2 и R3 различного конструктивного исполнения.

Подробнее

COKPOWEHEU все уже объяснил. В обработчике прерывания нужно сохранять/восстанавливать только используемые в этом прерывании регистры и SREG, чтобы при возвращении из прерывания все эти регистры содержали те же значения, что и при входе в прерывание. Тогда основная программа будет выполняться по принципу "как ни в чем не бывало". Это гарантирует логику основного цикла без изменений (последствий прерываний). А чтобы не забивать стек излишними сохранениями я, например, сохраняю SREG в свободном регистре младшей группы R3-R15, т.к. они редко используются.

Share this post


Link to post
Share on other sites

Точно "само"? Вообще-то это было бы неправильное поведение. Покажите скомпилированный hex-файл.

Насчет прерываний - речь не о конкретном а об общем случае. А там возможны хотя бы операции сравнение, инкремента/декремента и прочие, влияющие на SREG. Представьте если такое прерывание возникнет между cp и breq. То, что шанс возникновения такой ошибки мал только усугубляет ситуацию: труднее найти ошибку. Ну и прерывание часто использует те же регистры, что и основная программа, а чтобы они друг другу не мешали, при входе и выходе в прерывание делают пары push/pop. Плюс не надо запоминать какое прерывание с какими регистрами работает. Например, в прерывании надо инкременировать содержимое ячейки 0x0100 ОЗУ.

Спасибо, по sreg дельное замечание, могли бы возникнуть проблемы.

контроллер тини45

:020000020000FC
:100000000FC0189518951895189518951895189566
:1000100035C0189518951895189518951895189530
:1000200000E004BF01B5086101BD00E001BD03E0CF
:1000300007BB08E108BB03E80ABD01E003BF01E21A
:1000400007B90FEE06B900E003B928E07894B39B36
:100050000CC0B49B01C0FBCFB49BFECF2830B9F3DA
:1000600040FD01C023954395F2CFB39BFECF2223E1
:1000700071F340FF01C02A954A95E9CF04B115B14B
:10008000322F332361F0169507953A95E1F740FF3B
:1000900006C0612F502F66955795050F161F19BD85
:0400A00018BD1895DA
:00000001FF

Сейчас возникла друга проблема. Пытаюсь перенести программу на мегу48

ldi temp1,0b01100000

out admux,temp1

пишет ошибку

Error 1 Operand 1 out of range: 0x7c

каким образом вносить данные в эти регистры если in и out не работают с этими адресами?

тут случайно банк памяти не нужно переключать?

А, нашёл

<a name="#top">lds r2, $FF00 ; Загрузить в r2 содержимое SRAM по адресу $FF00

add r2, r1 ; Сложить r1 с r2

sts $FF00, r2 ; Записать обратно

Edited by anton2488

Share this post


Link to post
Share on other sites

Пишите sts admux,temp1. Она более "дальнобойная".

А есть другие команды, которыми можно записать?

Я сейчас не могу записать единицу в 6 бит, который запускает цап.

ldi temp1,0b11101111

sts adcsra,temp1

а записывается 0b10101111

В чем может быть причина, и как записать бит? В тини всё нормально записывается.

Share this post


Link to post
Share on other sites

:020000020000FC
:100000000FC0189518951895189518951895189566
:1000100035C0189518951895189518951895189530
:1000200000E004BF01B5086101BD00E001BD03E0CF
:1000300007BB08E108BB03E80ABD01E003BF01E21A
:1000400007B90FEE06B900E003B928E07894B39B36
:100050000CC0B49B01C0FBCFB49BFECF2830B9F3DA
:1000600040FD01C023954395F2CFB39BFECF2223E1
:1000700071F340FF01C02A954A95E9CF04B115B14B
:10008000322F332361F0169507953A95E1F740FF3B
:1000900006C0612F502F66955795050F161F19BD85
:0400A00018BD1895DA
:00000001FF

Как и следовало ожидать, записи в SPH:SPL нет. Должно быть что-то вроде 0FE5 0DBF 01E0 0EBF (ldi r16,5F | out 0x3D,r16 | ldi r16,0x01 | out 0x3E,r16 где 0x3D=SPL, 0x3E=SPH, 0x015F=RAMEND). То есть стек все-таки не инициализирован.

Сейчас возникла друга проблема. Пытаюсь перенести программу на мегу48

ldi temp1,0b01100000

out admux,temp1

пишет ошибку

Error 1 Operand 1 out of range: 0x7c

Рекомендую такой код

.macro uout
   .if @0<0x40
       out @0,@1
   .else
       sts @0,@1
   .endif
.endm
.macro uin
   .if @1<0x40
       in @0,@1
   .else
       lds @0,@1
   .endif
.endm

Использование вместо обычных in / out

ldi temp1,0b01100000

uout admux,temp1


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

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

Share this post


Link to post
Share on other sites

А где смотреть нужно?

Вот я добавил инициализацию стека.

Но указатель стека и раньше и сейчас указывает на то же значение 0x015F

:020000020000FC
:100000000FC0189518951895189518951895189566
:1000100039C018951895189518951895189518952C
:1000200001E00EBF0FE50DBF00E004BF01B50861A0
:1000300001BD00E001BD03E007BB08E108BB03E828
:100040000ABD01E003BF01E207B90FEE06B900E007
:1000500003B928E07894B39B0CC0B49B01C0FBCFDC
:10006000B49BFECF2830B9F340FD01C023954395E2
:10007000F2CFB39BFECF222371F340FF01C02A953C
:100080004A95E9CF04B115B1322F332361F01695AB
:1000900007953A95E1F740FF06C0612F502F66950E
:0C00A0005795050F161F19BD18BD1895C7
:00000001FF

Спасибо, макросы попробую. Для регистров выше 0x40 требуется sts, в даташите указаны какие то адреса в скобках 0x20 (0x40) EEDR что они означают?

Не знаете почему не устанавливается бит ADSC запуска ацп в adcsra на меге48? Даже не знаю куда копать, в даташите о особых условиях запуска ничего не нашёл.

Share this post


Link to post
Share on other sites

ATmega48P


.def temp1=r16
.def temp2=r17

.cseg
.org 0x0000
rjmp RESET
reti//1
reti//2
reti//3
reti//4
reti//5
reti//6
reti//7
reti//8
reti//9
reti//10
reti//11
reti//12
reti//13
reti//14
reti//15
reti//16
reti//17
reti//18
reti//19
reti//20
reti//21
rjmp adcpwm
reti//23
reti//24
reti//25
reti//26

RESET:


ldi r16, high(RAMEND); Main program start
out SPH,r16 ; Set Stack Pointer to top of RAM
ldi r16, low(RAMEND)
out SPL,r16

ldi temp1,0b00000000
out ddrb,temp1

ldi temp1,0b11100000
out ddrd,temp1

ldi temp1,0b00000000
out ddrc,temp1

ldi temp1,0b00000000
out portb,temp1

ldi temp1,0b00000000
out portc,temp1

//timer
ldi temp1,0b10100011
out tccr0a,temp1

ldi temp1,0b00000001
out tccr0b,temp1

//adc
ldi temp1,0b00100000//УСТАНОВЛЕН СДВИГ ВЛЕВО
sts admux,temp1

ldi temp1,0b00000000
sts adcsrb,temp1

ldi temp1,0b10101111//инициализация без запуска цап
sts adcsra,temp1
ldi temp1,0b11101111//инициализация с запуском цап
sts adcsra,temp1
sei


start:

rjmp start

adcpwm://запись из цап в шим

lds temp1,adcl
lds temp2,adch

sbi portd,7// проверка прерывания

out ocr0a,temp2

reti

Edited by anton2488

Share this post


Link to post
Share on other sites

Reti//21 лишняя строка в таблице векторов и таблица длиннее на один вектор. Именно на строке reti//21 должен находиться вектор прерывания по окончанию преобразования.

Share this post


Link to post
Share on other sites

Reti//21 лишняя строка в таблице векторов и таблица длиннее на один вектор. Именно на строке reti//21 должен находиться вектор прерывания по окончанию преобразования.

Помогло! Дурацкая ошибка. Непонятно, почему бит adsc не загорается в симуляторе, из-за этого пошёл не в том направлении. Есть ли возможность в симуляторе эмитировать прерывания по цап, чтобы проверять вектора? Простая установка флагов ничего не даёт.

Edited by anton2488

Share this post


Link to post
Share on other sites

По идее должно быть при выставлении ADIF ну и глобального прерывания.


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

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

Share this post


Link to post
Share on other sites

Опять какая то странная ситуация возникла(мега48п)

clr r16

out EEARH, r16

out EEARL, r16

sbi eecr,0

in div1,eedr

Error 1 Undefined symbol: EEARH

вот прямо из даташита копировал

; Set up address (r18:r17) in address register

out EEARH, r18

out EEARL, r17

; Start eeprom read by writing EERE

sbi EECR,EERE

; Read data from Data Register

in r16,EEDR

с EEARL всё нормально работает

Edited by anton2488

Share this post


Link to post
Share on other sites

Из какого даташита? У Меги48 какой размер EEPROM? Посмотрите внимательно... Нет у нее EEARH (он ей не нужен).

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Сообщения

    • Ещё один туда же. А почему вы все считаете, что если человек попросил помочь с ремонтом, то обязательно идиот или *****й? Посмотрите на себя лет так ...дцать назад. И я ничего не делаю без консультаций со специалистом. У меня с электроникой давно дружеские отношения, вот с инверторами только третий раз сталкиваюсь. До этого монитор отремонтировал с помощью спецов, был ещё телевизор. И не надо смотреть на других свысока! Это не культурно! Никто её не выдирал!!! Видимо не те буквы смотрели)))
    • 24 В при токе 2.5 А это 60 Вт. 27000 вольт при 60 Вт это ток один-два миллиампера. Которые имеют ток утечки выше миллиампера. Собственно, заряжать столь слабым источником не получится, что ты и получил на практике. Перематывай трансформатор на гораздо меньшее напряжение, но на гораздо больший ток, хотя бы в 30 раз!
    • Карочь ребя  , все по  фне шую ...  Холодильник в кухню , капутер  в гостинную ...  
    • Делаю зарядное устройство для электролитических конденсаторов, заряжать решил от ТДКС и схемы ZVS драйвера. Питание беру от лабораторного источника питания (выставляю около 24В и 2,5 А). Зарядить нужно блок флэш электролитов (те, что применяются в вспышке фотоаппаратов, 330В, 120 мкФ каждый) со смешанным подключением (общей емкостью 1280 мФ и напряжением 990В). Этот способ уже рассмотрен здесь: https://youtu.be/et0DtOzbB0U https://youtu.be/t7iZNVMdrU8 Подключил ТДКС к блоку - напряжение зарядки выше 60В не растёт. То есть, показание на мультиметре доходит до 60В и остаётся на месте. При этом, без нагрузки ТДКС работает стабильно, выдаёт хорошую дугу и напряжение выше киловольта. Сами конденсаторы - рабочие. Чем может быть связана такая просадка? Пробовал подключать отдельно линию из 10 параллельных конденсаторов - напряжение достигает максимум 30 В.
    • Если жесткий диск механический, то ему такое не понравится, надо ццд ставить.

  • Набор светодиодов, 500 шт.

  • Similar Content

    • By Сергей Фомин
      Изучаю прерывания на attiny13. Пока остановился на прерываниях по переполнению. Сделал тестовый код в Atmel Studio и сразу через программатор заливаю на тиньку со светодиодом. Проблема в том что гореть он должен 10 секунд и выключаться, а горит примерно 20-23 секунды. Прошу помощи в правильном расчёте. Код ниже (пока учусь сильно не ругайтесь) :
      #define F_CPU 1000000 #define LED PB2 #include <avr/io.h> //#include <util/delay.h> #include <avr/interrupt.h> unsigned char work_time =384;    //  1000000/1024/256=3.8  (0.026 сек)    10/0.026=384 volatile unsigned char temp =0; ISR (TIM0_OVF_vect) {      TCNT0=0x00;     temp ++;     if (temp>=work_time)     {         PORTB &=~(1<<LED);  //Инвертируем состояние         TCCR0B=0x00    // остановка таймера         cli (); //общее запрещение прерываний     } } int main (void) {     init();               while (1)     {              } } void init () {          DDRB |= (1<<LED); // выход     PORTB =(1<<LED); //включен     TCCR0B =0x05; // установка делителя на 1024     TIMSK0 |= _BV(TOIE0);     sei();   // Либо SREG |= (1<<SREG_I); //Разрешаем прерывания глобально     TCNT0 = 0X00;        //Обнулить счётный регистр }  
    • By katet
      Добрый день. Может быть,кто-нибудь уже сталкивался с таким. 
      Занимаюсь доработкой чужого проекта в среде STM32CubeMX, первый раз работаю с библиотекой HAL.
      В этом проекте осуществлялся прием байт по USART1 из ComMon. Проект был открыт в STM32CubeMX, где мной дополнительно были активированы новые модули - RTC, SD, USART2. Настройки USART1 не менялись. 
      Часы реального времени RTC: питание от батарейки, тактирование – от LSE. 
      При приеме байт по USART1 в новом проекте (активны  USART1, RTC, SD, USART2) было выявлено, что после приема 2 байт по USART1 перестает инкрементироваться значение переменной uwTick, отвечающей за прерывания Systick, в результате чего дальнейшая отладка невозможна. Не удается выяснить, в каком месте и почему перестает увеличиваться значение uwTick. При работе со старым проектом (где активен только USART1) uwTick инкрементируется после приема 2 байт.
      Смены приоритета прерываний не происходит, в  функцию HAL_Delay() отладчик не попадает. При вызове функции HAL_ResumeTick(), возобновляющей прерывания Systick, ничего не меняется, значение uwTick остается неизменным.
      Остановка прерываний была обнаружена при попадании в функцию:
      static HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout)
      {
        /* Wait until flag is set */
        while((__HAL_UART_GET_FLAG(huart, Flag) ? SET : RESET) == Status) 
        {
          /* Check for the Timeout */
          if(Timeout != HAL_MAX_DELAY)
          {            
            if((Timeout == 0U)||((HAL_GetTick() - Tickstart ) > Timeout))
            {
              /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */
              CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE));
              CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
              
              huart->gState  = HAL_UART_STATE_READY;
              huart->RxState = HAL_UART_STATE_READY;
              
              /* Process Unlocked */
              __HAL_UNLOCK(huart);
              
              return HAL_TIMEOUT;
            }
          }
        }
        
        return HAL_OK;
      }
      В новом проекте текущее значение uwTick, возвращаемое функцией HAL_GetTick(), всегда равно значению Tickstart. В старом проекте сначала также, но затем uwTick начинает увеличиваться. Выяснить, в каком именно месте кода значение uwTick должно начать увеличиваться, не удается.
      Может быть, у кого-нибудь есть хоть какие-то идеи, с чем может быть связана остановка увеличения значений uwTick, помогите пожалуйста)
      Распиновка и конфигурация обоих проектов: верхняя часть рисунков - первоначальный, работающий вариант,  нижняя - сбой прерываний Systick.


    • By IgnatiusF
      Не могу настроить таймер 0 на работу, и даже не получается понять в чем проблема. Делаю в Proteus, так как это быстрее и нагляднее.
      Пробовал и просто по переполнению делать прерывание (WGM[1..0]  00) и по совпадению (WGM[1..0]  10; OCR0A = 0 - 255), однако прерываний нет. Перед циклом ставлю TCNT0 = 0;
      Тактирование выставляю TCCR0B (CS[2..0] 001, 100, 101).
      Прерывания TIMSK0 (OCIE0A, TOIE0) выставляю, не вызываются. Даже принудительным заносом значения в регистр TIFR0 (OCF0A, TOV0).
      Прерывание пытаюсь выполнить таким образом:
      #include <avr/interrupt.h> volatile unsigned int A = 0; ISR(TIMER0_OVF_vect) { A = 1; } ... while(1) { if (A == 1) PORTB |= (1<<0); } Proteus показывает, что вывод настроен как выход, но всегда 0;
      Конкретный код привести не могу, так как у меня не заработало совсем ничего.
      Внизу я сделал вырезку из даташита на ATMEGA328 по 0 таймеру 8-бит, и занес в один PDF файл.
      ATmega328-106-112.pdf
      Прошу помочь разобраться с таймером и прерываниями для него.
    • Guest Максим
      By Guest Максим
      Всем светлым и умным головам привет!

      Никак не могу найти информацию о данном прерывании TIM1_BRK_UP_TRG_COM.
      Вопрос 1: Что это за стек или система прерываний? 
      Вопрос 2: Когда будет вызываться обработчик прерывания TIM1_BRK_UP_TRG_COM_IRQHandler, если также есть обработчик прерывания TIM1_CC_IRQHandler?
      Вопрос 3: период переполнения таймера равен 100 мкс. Сколько раз будет вызываться обработчик прерывания TIM1_BRK_UP_TRG_COM_IRQHandler до обработчика прерывания TIM1_CC_IRQHandler? По логике вещей, предполагаю, что 100 раз?
      Заранее благодарен!

      Всем радости))
    • By LukaS_St
      Всем привет. Столкнулся с такой проблемой: Пишу программу для устройства мониторинга оборотов двух валов используя датчик холла. Настроил прерывания,  перевод в RPM, все проверил, в .порт отправляются верные значения, и после настройки индикации столкнулся с проблемой неадекватного поведения переменных считающих millis, а после и индикации. В Arduino я не спец, Гляньте на код, может чем помогите. Заранее благодарен.
      #include <EEPROM.h> #define CLOCK 13 //SH_CP #define DATA 11  //DS #define LATCH 10  //ST_CP int numbers[5]; boolean ee = 0; int mh; int hh; int et_mah; int et_shl; int ot_mah; int ot_shl; volatile  int rpm_mah = 0; volatile  int rpm_shl = 0;  int rpmmah_count = 0;  int rpmshl_count = 0; unsigned long lastmillis_mah = 0; unsigned long lastmillis_shl = 0; unsigned long lastmillis_show = 0; unsigned char number[] = {   0b01111110, //0   0b00110000, //1   0b01101101, //2   0b01111001, //3   0b00110011, //4   0b01011011, //5   0b01011111, //6   0b01110000, //7   0b01111111, //8   0b01111011, //9   0b00000001, //-   0b00000000  //тушим индикатор }; void setup() {   Serial.begin(9600);   attachInterrupt(0, rpm_mahovik, FALLING);   attachInterrupt(1, rpm_shluz, FALLING);   pinMode(CLOCK, OUTPUT);   pinMode(DATA, OUTPUT);   pinMode(LATCH, OUTPUT); } void rpm_mahovik() { /* this code will be executed every time the interrupt 0 (pin2) gets low.*/   rpmmah_count++; } void rpm_shluz() { /* this code will be executed every time the interrupt 0 (pin2) gets low.*/   rpmshl_count++; } // чтение //int EEPROM_int_read(int addr) { //  byte raw[2];  // for (byte i = 0; i < 2; i++) raw[i] = EEPROM.read(addr + i);  // int &num = (int&)raw; //  return num; //} // запись //void EEPROM_int_write(int addr, int num) { //  byte raw[2];  // (int&)raw = num;  // for (byte i = 0; i < 2; i++) EEPROM.write(addr + i, raw[i]); //} void show () {   int x;   for (x = 5; x >= 0; x--) {    Serial.print("x= "); Serial.println(x);     //включаем LATCH (Начинаем общение)     digitalWrite(LATCH, LOW);     shiftOut(DATA, CLOCK, LSBFIRST, number[numbers[x]]);     //выключаем LATCH     digitalWrite(LATCH, HIGH);     //отключаем LATCH (чтобы регистр не ждал данных)     digitalWrite(LATCH, HIGH);   } } //void ee_write () {  // EEPROM_int_write(0, mh); //  EEPROM_int_write(2, hh); //  EEPROM_int_write(4, et_mah); //  EEPROM_int_write(6, et_shl); //  EEPROM_int_write(8, ot_mah); //  EEPROM_int_write(10, ot_shl); //} void loop() { //  if ((millis() <= 100) & (ee == 0)) {   //  mh = EEPROM_int_read(0);  //   hh = EEPROM_int_read(2); //    et_mah = EEPROM_int_read(4);  //   et_shl = EEPROM_int_read(6);  //   ot_mah = EEPROM_int_read(8);  //   ot_shl = EEPROM_int_read(10);  //   ee = 1;  // }   if (millis() - lastmillis_mah == 1000) {     detachInterrupt(0);     rpm_mah = rpmmah_count * 60;     rpmmah_count = 0;     lastmillis_mah = millis();     attachInterrupt(0, rpm_mahovik, FALLING);   }   if (millis() - lastmillis_shl == 5000) {     detachInterrupt(1);     rpm_shl = rpmshl_count * 12;     rpmshl_count = 0;     lastmillis_shl = millis();     attachInterrupt(1, rpm_shluz, FALLING);   }   if (millis() - lastmillis_show == 1000) {     numbers[0] = rpm_mah / 1000;     numbers[1] = (rpm_mah % 1000) / 100;     numbers[2] = ((rpm_mah % 1000) % 100) / 10;     numbers[3] = ((rpm_mah % 1000) % 100) % 10;     numbers[4] = rpm_shl / 10;     numbers[5] = rpm_shl % 10;     lastmillis_show = millis();   show(); Serial.print("RPM mah= "); Serial.println (rpm_mah);  Serial.print("RPM shl= "); Serial.println (rpm_shl);   Serial.print("Show millis= "); Serial.println(lastmillis_show); Serial.print("Show mah= "); Serial.println(lastmillis_mah); Serial.print("Show shl= "); Serial.println(lastmillis_shl);   } }
×
×
  • Create New...