roboforum.ru

Технический форум по робототехнике.

Ресетится (RESET) бессовестно - почему?

Ресетится (RESET) бессовестно - почему?

GrayHunter » 16 апр 2011, 12:12

Проблема в том, что почему-то то ли по окончанию программы, то ли где-то в процессе её выполнения МК ресетится/перезагружается. Программа = 300 строк.

Прерывания включены, чтобы нулевой таймер мог работать (Timer0 overflow), RESET стоит после настроек прерываний, перед настройками портов и прочих настроек, а после идёт Begin и сама программа.

Если программу отключить/вместо неё сделать банальное мигание светодиодом по времени (используя нулевой таймер), то всё будет нормально (т.е. перезагружаться не будет).
Нигде на RESET перепрыгов (rjmp) нет (кроме в настройках прерываний, 1 раз).

AtMega8 на 8 мгЦ (внутр.)
Пишу в Студии на Асме.

Вопрос: что может вызывать перезагрузку в моём случае? какие есть предположения?


Фото платы для моего программатора (извините за качество):
Фотография 2011-04-16 в 12.05 #2.jpg


Фотография 2011-04-16 в 12.05.jpg

Re: Ресетится (RESET) бессовестно - почему?

Vovan » 16 апр 2011, 12:21

GrayHunter писал(а):Проблема в том, что почему-то то ли по окончанию программы, то ли где-то в процессе её выполнения МК ресетится/перезагружается.

-
GrayHunter писал(а):Если программу отключить/вместо неё сделать банальное мигание светодиодом по времени (используя нулевой таймер), то всё будет нормально (т.е. перезагружаться не будет).

= ?
Примеч.: ? = текст программы
к примеру: у меня схема из 455 деталей и нифига не работает, ошибок не нашел. Если отключить часть схемы из 300деталей, остальная часть нормально работает. Помогите...

Re: Ресетится (RESET) бессовестно - почему?

GrayHunter » 16 апр 2011, 12:28

Не хотел нагружать вас, думал есть какие-то классические грабли :)

Вот весь код (я только учусь, так что на стиль прошу не обращать внимания - проблема лишь с перезагрузкой :oops: ):

Код: Выделить всёРазвернуть
.include "m8def.inc"  ; подключаем заголовочный файл для ATmega8L-8PU, (ATmega8L-8PI), PbFree PDIP28

.def     Temp=R16               ; разное
.def     module_1_full=R17          ; Увлажнитель
.def     module_2_full=R18         ; Мойщик
.def     module_3_full=R19         ; Полив
.def     module_3_in_progress=R20   ; Процесс полива
.def     SubSecondCount=R21         ; расширитель таймера
.def     Sek=R22               ; Cекунды
.def     Min=R23               ; Минуты
.def     Hour=R24               ; Часы
.def     Module_3_was_off=R25      ; Модуль №3 был выключен кнопкой


.cseg  ; начало программного сегмента
.org 0  ; задает начальный адрес. В данном случае он = 0


;************_ НОЖКИ _************
;PB0 - Помпа / насос
;PB1 - клапан №1
;PB2 - клапан №2
;PB3 - клапан №3
;PB4 - светодиод протечек
;PB5 -
;PB6 -
;PB7 -

;PD0 - протечка №1 / Alarm_Main
;PD1 - протечка №2 / Alarm_2
;PD2 - кнопка вкл/выкл модуля №1
;PD3 - кнопка вкл/выкл модуля №2
;PD4 - кнопка вкл/выкл модуля №3
;PD5 - кнопка вкл/выкл Принуждителя модуля №1
;PD6 - кнопка вкл/выкл Принуждителя модуля №2
;PD7 - кнопка вкл/выкл Принуждителя модуля №3

;PC0 - верхний датчик модуля №1
;PC1 - нижний датчик модуля №1
;PC2 - верхний датчик модуля №2
;PC3 - нижний датчик модуля №2
;PC4 -
;PC5 -
;PC6 -



;************_ НАСТРОЙКА ПРЕРЫВАНИЙ _************
         rjmp    Reset         
         nop                  
         nop                  
         nop                  
         nop                  
         nop                  
         nop                  
         nop                  
         nop                  
         rjmp TIMER0_OVF         



;************_ ПРОЧИЕ НАСТРОЙКИ _************
RESET:                         
ldi Temp, low(RAMEND)     ; инициализация стека
out SPL, Temp           ; инициализация стека
ldi Temp, high(RAMEND)  ; инициализация стека
out SPH, Temp           ; инициализация стека

ldi Temp, 0xBF ; калибровка частоты внутреннего генератора на 8 мГЦ
out osccal, Temp

      ldi Temp,0b00011111  ; определение ножек МК портов B (1 = вывод | 0 = ввод). Порты B относятся к Питанию помпы, клапанам и светодиоду протечек
      out DDRB,Temp        ; настраивает ножки МК портов B в соответствии с данными выше
      ldi Temp,0b00011111  ; подаём напряение на определённые порты/ножеки, чтобы потом оно было нормальным, не тусклым
      out PortB,Temp

      ldi Temp,0b00000000  ; определение ножек МК портов D (1 = вывод | 0 = ввод). Порты D относятся к Проверке протечек и кнопкам
      out DDRD,Temp        ; настраивает ножки МК портов D в соответствии с данными выше
      ldi Temp,0b00000000  ; подаём напряение на определённые порты/ножки
      out PortD,Temp

      ldi Temp,0b0000000   ; определение ножек МК портов C (1 = вывод | 0 = ввод). Порты C относятся к Датчикам
      out DDRC,Temp        ; настраивает ножки МК портов C в соответствии с данными выше
      ldi Temp,0b0000000   ; подаём напряение на определённые порты/ножки
      out PortC,Temp

ldi Temp,4            ; предделитель считает каждый 256 импульс
out TCCR0,Temp         ; то есть при тактовой частоте 8 Мгц прерывания будут происходить каждые 8192 мкс
                  ; в одной секунде таких кусочков 122, а значит в регистр расширитель надо записать число 256-122=134
ldi   SubSecondCount, 134   ;      
   
ldi Temp,0b00000001      ; разрешение прерываний Переполнения Таймера 0
out TIMSK,Temp         ;
sei                ; разрешить Прерывания

clr Sek               ; обнуляем Секунды
clr Min               ; обнуляем Минуты
clr Hour            ; обнуляем Часы

ldi Module_3_was_off,0   ; Модуль №3 ещё кнопкой Не выключался
ldi module_3_in_progress,0 ; завершить Процесс полива

;************_ ЧТОБЫ НОЖКИ НОРМАЛЬНО ОБЕСПЕЧИВАЛИСЬ ТОКОМ, а не "тускло" _************
; cbi PORTB, PB0
; cbi PORTB, PB1
; cbi PORTB, PB2
; cbi PORTB, PB3
cbi PORTB, PB4


;************_ ФЛАГИ И ПРОВЕРКИ _************
      sbi PORTB, PB4          ; зажечь светодиод протечек
Wait_1: cpi Sek, 1            ; секунды равны 1?
      brne Wait_1            ; пока нет
      CBI PORTB, PB4         ; да, погасить светодиод протечек

Begin:         sbis PIND,0          ; проверка есть ли протечка №1 (получаем данные с ножки PD0 и сравнение/сама проверка)
            rcall Alarm_Main   ; есть замыкание / протечка №1
            sbic PIND,2          ; нет замыкания / проверка вЫключен ли модуль №1 (получаем данные с ножки PD2 и сравнение/сама проверка)
            ldi module_1_full,1 ; нет замыкания / вЫключен - вЫключить модуль №1
            sbic PIND,2         ; есть замыкание / проверка вЫключен ли модуль №1 (получаем данные с ножки PD2 и сравнение/сама проверка)
            rjmp Alarm_2       ; нет замыкания / вЫключен - перейти к Проверке протечки №2
            sbis PIND,5       ; есть замыкание / проверка включоно ли Принуждение модуля №1 (получаем данные с ножки PD5 и сравнение/сама проверка)
            ldi module_1_full,0 ; есть замыкание / включено - включить модуль №1
            sbis PIND,5        ; нет замыкания / проверка включоно ли Принуждение модуля №1 (получаем данные с ножки PD5 и сравнение/сама проверка)
            rjmp Alarm_2       ; есть замыкание / включено - перейти к Проверке протечки №2
            rcall Module_1_full_Check ; нет замыкания / проверка пуст или полон модуль №1

Alarm_2:      sbis PIND,1      ; проверка есть ли протечка №2 (получаем данные с ножки PD1 и сравнение/сама проверка)
            rcall Alarm_2_yes ; есть замыкание / протечка №2
            CBI PORTB, PB4     ; нет замыкания / погасить светодиод протечек
Alarm_2_end:   sbic PIND,3      ; нет замыкания / проверка вЫключен ли модуль №2 (получаем данные с ножки PD3 и сравнение/сама проверка)

               ldi module_2_full,1 ; нет замыкания / вЫключен - вЫключить модуль №2
               sbic PIND,3       ; есть замыкание / проверка вЫключен ли модуль №2 (получаем данные с ножки PD3 и сравнение/сама проверка)
               rjmp Module_3       ; нет замыкания / вЫключен - перейти к Модулю №3
               sbis PIND,6       ; есть замыкание / проверка включоно ли Принуждение модуля №2 (получаем данные с ножки PD6 и сравнение/сама проверка)
               ldi module_2_full,0 ; есть замыкание / включено - включить модуль №2
               sbis PIND,6       ; нет замыкания / проверка включоно ли Принуждение модуля №2 (получаем данные с ножки PD6 и сравнение/сама проверка)
               rjmp Module_3       ; есть замыкание / включено - перейти к Модулю №3
               rcall Module_2_full_Check ; нет замыкания / проверка пуст или полон модуль №2

Module_3:      sbic PIND,4         ; нет замыкания / проверка вЫключен ли модуль №3 (получаем данные с ножки PD4 и сравнение/сама проверка)
            rcall Module_3_Off ; нет замыкания / вЫключен - вЫключить модуль №3 и Запомнить, что модуль №3 был выключен кнопкой
            sbic PIND,4         ; есть замыкание / проверка вЫключен ли модуль №3 (получаем данные с ножки PD4 и сравнение/сама проверка)
            rjmp Management      ; нет замыкания / вЫключен - перейти к ***_Управлению_***
            sbis PIND,7         ; есть замыкание / проверка включоно ли Принуждение модуля №3 (получаем данные с ножки PD7 и сравнение/сама проверка)
            ldi module_3_full,0 ; есть замыкание / включено - включить модуль №3
            sbis PIND,7         ; нет замыкания / проверка включоно ли Принуждение модуля №3 (получаем данные с ножки PD7 и сравнение/сама проверка)
            rjmp Management      ; есть замыкание / включено - перейти к ***_Управлению_***
            CPI module_3_in_progress,1 ; нет замыкания / проверка идёт ли Процесс полива модуля №3
            breq In_progress_module_3  ; есть замыкание
            cpi Module_3_was_off,1      ; проверить вЫключался ли Модуль №3 кнопкой
            BRNE Mudule_3_Go_On
         clr Sek                     ; обнуляем Секунды
         clr Min                     ; обнуляем Минуты
         clr Hour                  ; обнуляем Часы
         ldi Module_3_was_off,0         ; обнуляем память, что Модуль №3 был вЫключен кнопкой

         ; __ Сутки (24 часа и одна секунда) прошли? __
Mudule_3_Go_On: cpi Hour, 0
            BRNE Management         ; ещё нет / не равно / перейти к ***_Управлению_**
            cpi Min, 0
            BRNE Management         ; ещё нет / не равно / перейти к ***_Управлению_**
            cpi Sek, 1
            BRNE Management         ; ещё нет / не равно / перейти к ***_Управлению_**
            ldi module_3_full,0         ; да, Сутки Прошли / равно / включить модуль №3
            ldi module_3_in_progress,1 ; активировать Процесс полива
            rjmp Management            ; перейти к ***_Управлению_**
In_progress_module_3:   cpi   Sek, 10       ; Сколько Секунд Поливать
                  BRLO Management      ; время полива ещё не прошло
                  ldi module_3_full,1       ; время полива прошло - вЫключить модуль №3
                  ldi module_3_in_progress,0 ; завершить Процесс полива



;************_ УПРАВЛЕНИЕ _************
Management: ldi Temp,0
         CPSE Temp, module_1_full
         rcall Module_1_full_set_Close
         rcall Module_1_full_set_Open
Next_2: CPSE Temp, module_2_full
      rcall Module_2_full_set_Close
      rcall Module_2_full_set_Open
Next_3: CPSE Temp, module_3_full
      rcall Module_3_full_set_Close ; иначе закрыть клапан №3
      rcall Module_3_full_set_Open

Next_4: CPSE Temp, module_1_full
      rjmp Begin             ; если не равно
      CPSE Temp, module_2_full ; если равно
      rjmp Begin              ; если не равно
      CPSE Temp, module_3_full ; если равно
      rjmp Begin             ; если не равно
      sbi PORTB, PB0          ; вЫключить помпу / если равно

      rjmp Begin



;************_ ПОДПРОГРАММЫ  _************
   Alarm_Main: CBI PORTB, PB0 ; выключаем помпу
            CBI PORTB, PB1 ; закрываем клапан №1
            CBI PORTB, PB2 ; закрываем клапан №2
            CBI PORTB, PB3 ; закрываем клапан №3
            sbi PORTB, PB4 ; зажечь светодиод протечек
      Block:   sbis PIND,0    ; проверка есть ли протечка №1 (получаем данные с ножки PD0 и сравнение/сама проверка)
            rjmp Block       ; есть замыкание / протечка №1
            CBI PORTB, PB4 ; погасить светодиод протечек
            ret
   
   
   Module_1_full_Check: sbis PINC,0             ; замкнут ли Верхний датчик модуля №1 (получаем данные с ножки PC0 и сравнение/сама проверка)
                   rjmp Module_1_full_Check_2  ; есть замыкание / модуль полный
                   sbis PINC,1              ; нет замыкания / замкнут ли Нижний датчик модуля №1 (получаем данные с ножки PC1 и сравнение/сама проверка)
                   rjmp Module_1_full_Check_2  ; есть замыкание / модуль недостаточно пуст, чтобы в его доливать
                   ldi module_1_full,0       ; нет замыкания / модуль пустой
                   rjmp Module_1_full_Check_exit
   Module_1_full_Check_2: ldi module_1_full,1
   Module_1_full_Check_exit: ret
   
   
   Alarm_2_yes: ldi module_1_full,1
   sbi PORTB, PB4 ; зажечь светодиод протечек
   rjmp Alarm_2_end
   ret
   
   
   Module_2_full_Check: sbis PINC,2             ; замкнут ли Верхний датчик модуля №2 (получаем данные с ножки PC2 и сравнение/сама проверка)
                   rjmp Module_2_full_Check_2  ; есть замыкание / модуль полный
                   sbis PINC,3             ; нет замыкания / замкнут ли Нижний датчик модуля №2 (получаем данные с ножки PC3 и сравнение/сама проверка)
                   rjmp Module_2_full_Check_2  ; есть замыкание / модуль недостаточно пуст, чтобы в его доливать
                   ldi module_2_full,0       ; нет замыкания / модуль пустой
                   rjmp Module_2_full_Check_exit
   Module_2_full_Check_2: ldi module_2_full,1
   Module_2_full_Check_exit: ret


  Module_3_Off: ldi module_3_full,1 ; вЫключить модуль №3
  ldi Module_3_was_off,1 ; Запомнить, что модуль №3 был выключен кнопкой
  ret

   
   
   Module_1_full_set_Open: sbi PORTB, PB1 ; открыть клапан №1
                     sbi PORTB, PB0 ; включить помпу
                     ret


   Module_1_full_set_Close: CBI PORTB, PB1 ; закрыть клапан №1
                      rjmp Next_2
                      ret

   
   Module_2_full_set_Open: sbi PORTB, PB2 ; открыть клапан №2
                     sbi PORTB, PB0 ; включить помпу
                     ret
                     

   Module_2_full_set_Close: CBI PORTB, PB2 ; закрыть клапан №2
                      rjmp Next_3
                      ret                     
   
   
   Module_3_full_set_Open: sbi PORTB, PB3 ; открыть клапан №3
                     sbi PORTB, PB0 ; включить помпу
                     ret
                     
                     
   Module_3_full_set_Close: CBI PORTB, PB3 ; закрыть клапан №3
                      rjmp Next_4
                      ret                     
                     

                     
;************_ ОБРАБОТЧИК ПРЕРЫВАНИЯ Timer0 overflow _************         
TIMER0_OVF:
         push   Temp         ; сохранили регистр в стеке
         push   r15            ; сохранили регистр в стеке
         in      r15,   $3f      ; сохранили статус регистр
         inc      SubSecondCount   ; инкремент регистра расширителя
         cpi      SubSecondCount, 0
         brne   end         ; переход, если не было переполнения
; регистр расширитель досчитал до переполнения, то есть секунда прошла
         ldi   SubSecondCount, 134   ; перезагрузка расширителя
         inc      Sek            ; инкремент секунд
         cpi      Sek,   60      ; проверка переполнения
         brne   end            ; нет переполнения - выход
         clr      Sek            ; иначе обнуляем секунды
         inc      Min            ; и инкрементируем минуты
         cpi      Min,   60      ; проверка переполнения
         brne   end            ; нет переполнения - выход
         clr      Min            ; иначе обнуляем минуты
         inc      Hour         ; и инкрементируем часы
         cpi      Hour,   24      ; проверка переполнения
         brne   end            ; нет переполнения - выход
         clr      Hour         ; иначе обнуляем часы (при этом как раз сутки и прошли)
                           ;
         ;ldi      Temp,   1      
         ;eor      Led,    Temp   ; если флаг был нулем - он станет единицей (НУЖНО ОПРЕДЕЛИТЬ РЕГИСТР "LED")
                              ; если флаг был единицей - он станет нулем
         
; делаем зачистку за собой
end:      out      $3f,   r15      ; восстановили статус регистр
         pop      r15            ;
         pop      Temp         ;
         reti               ;

Re: Ресетится (RESET) бессовестно - почему?

Vovan » 16 апр 2011, 12:49

бегло просмотрел (не вникая): бросается в глаза 1.использование SBIS и SBIC - если SBIS(C) вызываем rcall-ом некую подпрогу, а если НЕТ то ЧТО?
и 2.не понял почему в подпрогах ret? мождь так и задумано, не разбирался, но опять же если там ret то остается дорога куда?
мождь ещё что-то, но пока постарайтесь самому себе объяснить алгоритм:
если то (SBIX)
то это (подпрога)
а иначе то-то (идем туда)
;а там ret...
если не поможет, вечером постараюсь внимательнее посмотреть

Re: Ресетится (RESET) бессовестно - почему?

GrayHunter » 16 апр 2011, 13:33

SBIX мне нужен для того, чтобы проверять ножки (1 или 0). Может есть аналоги?

А ret возвращает, по идее к той команде, что идёт потом (например, после rcall), и это часто бывает новая проверка (SBIX). Так нельзя делать? а как тогда? вставлять nop?

Re: Ресетится (RESET) бессовестно - почему?

Vovan » 16 апр 2011, 13:50

я бы предложил следующий мини-шаблон:
Код: Выделить всёРазвернуть
sbis(c) pinY,X ;если "сработал" пин Х порта Y
rjmp podproga  ;идем в нужную подпрограмму
rjmp start     ;а иначе возвращаемся, например, на старт или в другое место (указать куда)
podproga:
;здесь пишем то что должна делать подпрограмма
rjmp start     ; выход из подпрограммы необходимо обозначать конкретно

;обработчик прерывания можно поместить в любом месте
;важно чем он заканчивается ret - выходом с запретом прерываний
;или reti - выходом с разрешением прерываний

Re: Ресетится (RESET) бессовестно - почему?

Radist » 16 апр 2011, 13:54

Сейчас некогда смотреть пристально, а совет такой - надо походить в симуляторе по шагам. Обычно сброс бывает программный если встречается рет, а на стеке пусто. Еще способ - отключаем половину программы и смотрим, сбрасывается или нет. Ну а далее думаю понятно что делать. Если до ночи не найдете косяк - посмотрю еще раз внимательно. Только ночью и будет свободная минутка.

Re: Ресетится (RESET) бессовестно - почему?

GrayHunter » 16 апр 2011, 15:39

Vovan, т.е. предлагаете, образно говоря, заменить rcall на rjmp, и ret на rjmp ?

Добавлено спустя 1 час 13 минут 49 секунд:
Нить решения нашёл, но нужна ваш ответ -

пробовал так:
Код: Выделить всёРазвернуть
sbis PIND,0
rcall Alarm_Main
rjmp Go_on_1
Go_on_1: sbic PIND,
ldi module_1_full,1
rjmp Go_on_2
Go_on_2: sbic PIND,2
rjmp Alarm_2
rjmp Go_on_3
Go_on_3: sbis PIND,5
ldi module_1_full,0

всё ещё перезагружается.

Потом решил всё это закомментить, кроме "ldi module_1_full,0" - всё ровно перезагружается.

И тогда закомментил где-то чуть нижу середины строку "clr Hour" (которая сразу над строкой "ldi Module_3_was_off,0") и о чудо: перезагружаться перестал.

Появилось впечатление, что количество строк (реального кода, не комментариев) ограничено. Это действительно так? :shock:

Добавлено спустя 19 минут 5 секунд:
Когда компилирую, не закоментивая ничего важного (всё оставляю, как задумывалось изначально), да и когда закомментиваю тоже, то пишет, что всё в норме:

Segment Begin End Code Data Used Size Use%
---------------------------------------------------------------
[.cseg] 0x000000 0x000184 388 0 388 8192 4.7%
[.dseg] 0x000060 0x000060 0 0 0 1024 0.0%
[.eseg] 0x000000 0x000000 0 0 0 512 0.0%

Assembly complete, 0 errors. 0 warnings

Re: Ресетится (RESET) бессовестно - почему?

=DeaD= » 16 апр 2011, 18:47

Там же симулятор вроде есть? :roll:

Re: Ресетится (RESET) бессовестно - почему?

Angel71 » 16 апр 2011, 19:04

зачем симулятор? листик, ручка и пошагово, пошагово. :) не помогает только в очень тяжелых случаях.

Re: Ресетится (RESET) бессовестно - почему?

Radist » 16 апр 2011, 21:57

Программа очень большая, но при первом же прогоне нашел два косяка:
1. Настройка портов Д и С сделана неверно. Если это все входы - нужна подтяжка, то есть в порты записать все единицы, а в ддр - нули. Только тогда это будут полноценные входы.
2. Этот косяк посерьезнее. Что такое подпрограмма? Это кусочек программы, в который мы попадаем неоднократно. В него можно попасть откуда угодно, но выход из подпрограммы один - по рету. При вызове подпрограммы в стек кладется адрес возврата, при выходе из подпрограммы адрес снимается со стека. А что я вижу тут:

Код: Выделить всёРазвернуть
Alarm_2:      sbis PIND,1      ;
            rcall Alarm_2_yes ;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            CBI PORTB, PB4     ;
Alarm_2_end:   sbic PIND,3      ;


Alarm_2_yes: ldi module_1_full,1
   sbi PORTB, PB4 ;
   rjmp Alarm_2_end
   ret


Отсюда и все проблемы. При написании программ и их отладке отлично помогает принцип "разделяй и властвуй". Написали кусочек, отладили, не глючит - пишем дальше. Всегда будьте готовы сделать шаг назад. В особо трудных случаях программа стирается и пишется с нуля (это если ну никак ошибка не локализуется).

Re: Ресетится (RESET) бессовестно - почему?

GrayHunter » 17 апр 2011, 01:32

УРААА!!! Он работает :Yahoo!: :Yahoo!:

Спасибо большое за помощь! :good:

P.S.- проблема действительно была в подпрограммах.
P.S.S.- а на порты D и C нужно "минус" подавать, чтобы работало как надо? :oops:

Re: Ресетится (RESET) бессовестно - почему?

Radist » 17 апр 2011, 09:24

Что такое "подавать минус"? Поясните, а то не понятно.

Re: Ресетится (RESET) бессовестно - почему?

GrayHunter » 18 апр 2011, 02:00

Имел ввиду, что нужно не + (vcc) подавать на ножки портов D и С, а - (GND). Так?

Re: Ресетится (RESET) бессовестно - почему?

Radist » 18 апр 2011, 04:05

порт ддр пин
0 0 третье состояние (обрыв)
0 1 выход, нога поглощает ток (выдает ноль)
1 1 выход, нога выдает ток (выдает единицу)
1 0 вход, подтянут к плюсу

Никакое питание на ножки подавать нельзя - для этого есть специальные выводы для подачи питания.


Rambler\'s Top100 Mail.ru counter