Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: pic16f877a проблема со сравнением 2-х чисел
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры > PIC
Dmitriy_dda
долго бьюсь над проблемкой:
есть 2 макроса сравнения 2-х чисел

Цитата
; Snippet: 16-bit if(A >= cool.gif
; Inputs: A_high, A_low, B_high, B_low
; Strategy: Do a 16-bit A-B and watch for borrow off 16th bit.
if_A_higher_B MACRO A_high, A_low, B_high, B_low, false, true
movf B_low, W
subwf A_low, W ; W = A-B (low)

movlw 0x00 ; Clear W
btfss STATUS, C ; Check for carry on low bytes.
movlw 0x01 ; C=0, B_low < A_low, needed to borrow (sub 1 from high)
; C=1, A_low > B_low, do not sub 1 from high byte

addwf B_high, W ; Adding 1 to B is like subtracting 1 from A (if W=1)
btfsc STATUS, C ; If B_high == FF, can borrow and not realize
goto false ; false cond'n
subwf A_high, W ; W = A-B (high) - borrow if applicable

btfss STATUS, C ; Check whole 16-bit addition for borrow
goto false ; C=0, result needs borrow from 17th bit.
; C=1, result true

; Place result TRUE code here.

goto true
ENDM

; Snippet: 16-bit if(A <= cool.gif
; Inputs: A_high, A_low, B_high, B_low
; Strategy: Do a 16-bit B-A and watch for borrow off 16th bit.
if_A_lower_B MACRO A_high, A_low, B_high, B_low, false, true
movf A_low, W
subwf B_low, W ; W = B-A (low)

movlw 0x00 ; Clear W
btfss STATUS, C ; Check for carry on low bytes.
movlw 0x01 ; C=0, A_low < B_low, needed to borrow (sub 1 from high)
; C=1, B_low > A_low, do not sub 1 from high byte

addwf A_high, W ; Adding 1 to B is like subtracting 1 from A (if W=1)
btfsc STATUS, C ; If A_high == FF, can borrow and not realize
goto false ; false cond'n
subwf B_high, W ; W = B-A (high) - borrow if applicable

btfss STATUS, C ; Check whole 16-bit addition for borrow
goto false ; C=0, result needs borrow from 17th bit.
; C=1, result true
goto true
ENDM


и блок обработки в основном теле программы:
Цитата
main:
clrwdt
pagesel CCP_drive
call CCP_drive ;действия по отсчетам ССР для АЦП и USART

;обращение к ШД:
;ждем некоторое время для регулирования скорости вращения
banksel M_Drive_speed_L
decfsz M_Drive_speed_L,f
goto main_1
movlw 0xFF
movwf M_Drive_speed_L
decfsz M_Drive_speed_H,f
goto main_1
mov_bb_to_bb R_Drive_speed_H,R_Drive_speed_L,M_Drive_speed_H,M_Drive_speed_L
pagesel Motor_drive
call Motor_drive

goto main ;цикл по новой


Цитата
Motor_drive:
;M_Drive_nul EQU 0x23 ;указатель шага двигателя с виртуальным нулевым значением
;M_D_PTR_L EQU 0x24 ;текуший указатель шага на шаговом двигателе
;M_D_PTR_H EQU 0x25
;M_D_PTR_L_new EQU 0x26 ;требуемый указатель на шаговом двигателе
;M_D_PTR_H_new EQU 0x27

banksel M_D_PTR_H

if_A_higher_B M_D_PTR_H, M_D_PTR_L, M_D_PTR_H_new, M_D_PTR_L_new, M_d_start_inc, M_d_4
M_d_4:

if_A_lower_B M_D_PTR_H, M_D_PTR_L, M_D_PTR_H_new, M_D_PTR_L_new, M_d_start_dec, Motor_drive_end
M_d_start_dec:
;если (M_Drive_PTR > M_Drive_PTR_new) то
banksel M_D_PTR_L ;выбираем текуший указатель шага
movlw 0x01
subwf M_D_PTR_L,f ;уменьшить указатель текущего шага на 1
;movlw 0x00
btfsc STATUS,C
goto Motor_drive_result
banksel M_D_PTR_H
decf M_D_PTR_H,f ;если L был 0 стал 255 то уменшить H
goto Motor_drive_result
M_d_start_inc:
;если (M_Drive_PTR < M_Drive_PTR_new) то
banksel M_D_PTR_L ;выбираем текуший указатель шага
incfsz M_D_PTR_L,f ;увеличить указатель текущего шага на 1
goto Motor_drive_result
banksel M_D_PTR_H
incf M_D_PTR_H,f ;если L было 255 и стало 0 то inc H
Motor_drive_result:
;т.к. шаг 0=шагу_32=шагу_64=шагу_96 т.е. значимы для управления только первые 5 байт
banksel M_D_PTR_L
movf M_D_PTR_L,w ;для отсечения 6-х верхних байт - в аккумулятор
andlw b'00000011' ;получаем требуемое смещение
call Table_Motor_Drive_2 ;делаем требуемый шаг по вычесленному смещению
banksel PORTB
movwf PORTB ;посылаем в ПортB сигнал управления ШД
goto Motor_drive_end ;выход
Motor_drive_end:
return


Проблема в том, что даже при равных значениях M_D_PTR и M_D_PTR_new программа довольно часто вылетеает на прирашение или уменьшение текущего шага... Почему это происходит я не понимаю. Причем, если отключать все прерывания и АЦП и банально оставлять только подпрограмму "Motor_drive" то все впорядке.

Подскажите, в где может быть ошибка?
volodya
Цитата(Dmitriy_dda @ Jun 14 2007, 12:57) *
долго бьюсь над проблемкой:
есть 2 макроса сравнения 2-х чисел
и блок обработки в основном теле программы:
Проблема в том, что даже при равных значениях M_D_PTR и M_D_PTR_new программа довольно часто вылетеает на прирашение или уменьшение текущего шага... Почему это происходит я не понимаю. Причем, если отключать все прерывания и АЦП и банально оставлять только подпрограмму "Motor_drive" то все впорядке.

Подскажите, в где может быть ошибка?


Из последней фразы ("если отключать все прерывания и АЦП") следует что один из ресурсов(модет переменная и т.д) испольсзуеться или модифицируется в прерывании, при этом возможно сравнение 2-ух байтовых чисел на половину выполнено, вторая половина обрабатывается после прерывания и результат получается не прав.! 07.gif
Проверте обновление переменных. Например результат преобразования АЦП может записываться во время сравнения, или не восстанавливаються флаги после прерывания.
Проблема в совместном выполнении Вашей прцедуры и прерывании.
Dmitriy_dda
В том то вся и загвоздка, что 1 переменная полностью не зависит от того что в прерываниях происходит (да и используется только в подпрограмме "Motor_drive") , а вторая обновляется по USART (а это происходит очень редко). К тому же, отключив отключив только 1 прерывание (по ССР1) никаких сбоев нету.

Код в прерывании по ССР1:
Код
...ранее выявление и обработка прерываний по USART и АЦП
;--------CCP1--тестим, прерывание по CCP1?
next3:
    Bank0                ;выбор bank0
    btfss    PIR1,CCP1IF    ;проверить флаг приема CCP1IF
    goto    end_int
    Bank1                ;выбор bank1 если CCP1IE установлен
    btfss    PIE1,CCP1IE    ;проверить доступно прерывание если CCP1IF установлен
    goto    end_int        ;если CCP1IF и CCP1IE установлены,
                        ;начать обработку по каналу АЦП
;---------------------------------=>
;----------да, прерывание по CCP1 =>
iv_CCP1:
    banksel    PIR1
    bcf        PIR1,CCP1IF
    incf_bb    ccp_count_H, ccp_count_L;инкримент общего счетчика ССР1

    bcf        STATUS,C
    bcf        STATUS,Z
    decfsz    adc_usart_ccp,f        ;декримент (adc_usart_ccp), если 0 то не выходим а действие
    goto    end_int            ;если не 0 то выход из прерывания по ССР1
    bcf        flag1,flag1_ccp_ready;очистить флаг обработки ССР
    movlw    .20
    movwf    adc_usart_ccp        ;восстановить таймер (adc_usart_ccp)

    goto    end_int            ;Done, выход из прерывания

К вопросу о сохранении контекста, сохраняю так:
Код
    movwf    w_temp
    swapf    STATUS, w
    clrf    STATUS
    movwf    status_temp
    movf    FSR, w
    movwf    FSR_temp
.....
.....всяко разное
.....
    movf    FSR_temp, w
    movwf    FSR
    swapf    status_temp, w
    movwf    STATUS
    swapf    w_temp, f
    swapf    w_temp, w
    retfie

там не должно быть сбоев.
volodya
Внимательнее присмотрелся к тексту первого сообщ.

banksel M_D_PTR_H

if_A_higher_B M_D_PTR_H, M_D_PTR_L, M_D_PTR_H_new, M_D_PTR_L_new, M_d_start_inc, M_d_4
M_d_4:

if_A_lower_B M_D_PTR_H, M_D_PTR_L, M_D_PTR_H_new, M_D_PTR_L_new, M_d_start_dec, Motor_drive_end
M_d_start_dec:
;если (M_Drive_PTR > M_Drive_PTR_new) то


Получ. если M_D_PTR_H >= M_D_PTR_H_new то проверить M_D_PTR_H <= M_D_PTR_H_new ->Или я чайник smile3046.gif или проверить код в тектсе и макросах?
А на счет откл.-вкл.прерывания и реакции на енто -->> взаимосвязь таки есть раз реакция присутствует.
Dmitriy_dda
Все таки более менее разобрался с этой проблемкой.

Почему так было - не ясно.

А суть моего решения такова - в теле программы:
Цитата
main:
clrwdt
pagesel CCP_drive
call CCP_drive ;действия по отсчетам ССР для АЦП и USART

;обращение к ШД:
;ждем некоторое время для регулирования скорости вращения
banksel M_Drive_speed_L
decfsz M_Drive_speed_L,f
goto main_1
movlw 0xFF
movwf M_Drive_speed_L
decfsz M_Drive_speed_H,f

goto main_1
mov_bb_to_bb R_Drive_speed_H,R_Drive_speed_L,M_Drive_speed_H,M_Drive_speed_L
pagesel Motor_drive
call Motor_drive

goto main ;цикл по новой

я регулировал скорость врашения циклом-таймером (выделен красным). Как только убрал нафиг эту вешь и повесил вызов процедуры по прерыванию с ССР1 то все стало норм.

Просто так и не понял: почему так делать было нельзя (введение таймера в тело программы перед вызовом процедуры)
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.