Пишу свою первую прошивку на 16F876A. Вольтамперметр. Написал для начала исходник для вольтметра. Результаты показаний на дисплее отображаются корректно. Вот исходник.
; ЗАДЕРЖКА 50 ms del_50ms movlw .238 movwf Reg_tmp1 movlw .65 movwf Reg_tmp2 wr1 decfsz Reg_tmp1, F goto wr1 decfsz Reg_tmp2, F goto wr1 return ; ЗАДЕРЖКА 1 ms del_1ms movlw .75 movwf Reg_tmp1 movlw .2 movwf Reg_tmp2 wr2 decfsz Reg_tmp1, F goto wr2 decfsz Reg_tmp2, F goto wr2 return ;delay = 20 machine cycles del_20mcs movlw .6 movwf Reg_tmp1 wr3 decfsz Reg_tmp1, F goto wr3 return end
Но при попытке добавить в исходник OUT_I подпрограмму для вывода показаний амперметра - программа неимоверно глючит. На дисплее моргает U= и ничего не происходит. Все виснет даже если я не вызываю подпрограмму OUT_I... Но если я убираю из исходника подпрограмму OUT_U то все работает но уже в режиме показаний амперметра. Подпрограммы OUT_U и OUT_I никак не хотят вместе дружить. А по отдельности все прекрасно работает. Помогите - не знаю куда копать!!! Метки менял. Среда разработки MPLAB IDE v8.66. Прошиваю PICkit 2 Вот подпрограмма.
Код:
OUT_I ; выводим I на дисплей содержимое регистров Thou, Hund, Tens, Ones (тысячи, сотни, десятки, единицы) banksel ADCON0 ; переходим в регистр ADCON0 movlw b'01001001' ; включаем модуль АЦП, RA1 - вход, Fosc/8 movwf ADCON0 ; -//- banksel ADCON1 ; переходим в регистр ADCON1 movlw b'10000000' ; включаем правое выравнивание movwf ADCON1 ; -//- bcf STATUS,RP0 ; переход в банк 0 bsf ADCON0,2 ; включаем преобразование АЦП call del_20mcs btfsc ADCON0,2 ; ожидаем завершения goto $-1 ; преобразования movfw ADRESH ; перепишем результат преобразования movwf Reg_tmpH ; в старший временный регистр banksel ADRESL ; переходим в регистр ADRESL movfw ADRESL ; перепишем результат преобразования bcf STATUS,RP0 ; переход в банк 0 movwf Reg_tmpL ; в младший временный регистр
call TRANSFORMER_dig ; перекодируем двоичное число результата преобразования в десятичное movlw 0xC0 ; курсор в пределах второй строки ( 0xС0 - начало ) call LCD_com ; загружаем команду movlw 0x49 ; I call LCD_dig ; загружаем данные movlw 0x3D ; = call LCD_dig ; загружаем данные movf Thou,W ; копируем в W содержимое Thou btfsc Thou,0 ; проверяем значение регистра тысячных показаний, если 1, значит переполнение показаний goto overflow_I ; отправляемся отображать 9,99А movf Hund,W ; копируем в W содержимое Hund call TABL_dig ; отправляем на дисплей содержимое Hund call LCD_dig ; загружаем данные movlw 0x2C ; , call LCD_dig ; загружаем данные movf Tens,W ; копируем в W содержимое Tens call TABL_dig ; отправляем на дисплей содержимое Tens call LCD_dig ; загружаем данные movf Ones,W ; копируем в W содержимое Ones call TABL_dig ; отправляем на дисплей содержимое Ones call LCD_dig ; загружаем данные movlw 0x41 ; A call LCD_dig ; загружаем данные return overflow_I movlw 0x39 ; 9 (выводим 9,99А вместо 10,23А) call LCD_dig ; загружаем данные movlw 0x2C ; , call LCD_dig ; -//- movlw 0x39 ; 9 call LCD_dig ; загружаем данные movlw 0x39 ; 9 call LCD_dig ; загружаем данные movlw 0x41 ; A call LCD_dig ; загружаем данные return
Не знаю я никакого ЗАЕЦа . Единственное что я использовал из чужих трудов в разработке своей программы лежит в прикрепленном Файле. Автор Blaze. Если Вам не трудно - дайте ссылку на труды ЗАЕЦа в разработке аналогичного устройства. Не видите перехода на OUT_I потому что даже без перехода в эту ПП все глючит. Глюки исчезают при полном удалении ПП OUT_I или OUT_U. Работают они по отдельности, а вместе не хотят. Smen поищу. А как правильно вызвать ПП? Вот полный проект.
#define RS_LCD LCD_tmp1,RB4 ; назначаем вывод команд RS на PORTA для LCD #define E_LCD LCD_tmp1,RB5 ; назначаем вывод команд E на PORTA для LCD #define LCD_PORT_E_RS PORTB ; назначаем порт для вывода данных PORTB для LCD #define LCD_PORT PORTC ; назначаем порт для вывода данных PORTC для LCD (8 разрядов)
;;;;;;;;;;;;;;;;;;; ; старт программы ; ;;;;;;;;;;;;;;;;;;; org 0 goto START ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; инициализация контроллера ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; START bcf STATUS,RP0 ; переход в банк 0 banksel OPTION_REG ; переходим в регистр OPTION_REG movlw b'10001110' ; отключаем подтягивающие резисторы PORTB, включаем предделитель перед WDT 1:64 movwf OPTION_REG ; -//- banksel INTCON ; переходим в регистр INTCON movlw b'00000000' ; глобальный запрет прерываний movwf INTCON ; -//- banksel PIE1 ; переходим в регистр PIE1 movlw b'00000000' ; глобальный запрет периферийных прерываний movwf PIE1 ; -//- banksel PIE2 ; переходим в регистр PIE2 movlw b'00000000' ; глобальный запрет прерываний EEPROM, CCP2 movwf PIE2 ; -//- banksel TRISA ; переходим в регистр PORTA movlw b'00000011' ; настраиваем все порты на выход, AN0, AN1 на вход movwf TRISA ; -//- banksel TRISB ; переходим в регистр PORTB movlw b'00000000' ; настраиваем все порты на выход movwf TRISB ; -//- banksel TRISC ; переходим в регистр PORTC movlw b'00000000' ; настраиваем все порты на выход movwf TRISC ; -//- banksel T1CON ; переходим в регистр T1CON movlw b'00000000' ; отключаем модуль T1CON movwf T1CON ; -//- banksel T2CON ; переходим в регистр T2CON movlw b'00000000' ; отключаем модуль T2CON movwf T2CON ; -//- banksel CCP1CON ; переходим в регистр CCP1CON movlw b'00000000' ; отключаем модуль CCP1 movwf CCP1CON ; -//- banksel CCP2CON ; переходим в регистр CCP2CON movlw b'00000000' ; отключаем модуль CCP2 movwf CCP2CON ; -//- banksel SSPSTAT ; переходим в регистр SSPSTAT movlw b'00000000' ; отключаем модуль SSPSTAT movwf SSPSTAT ; -//- banksel SSPCON ; переходим в регистр SSPCON movlw b'00000000' ; отключаем модуль SSPCON movwf SSPCON ; -//- banksel SSPCON2 ; переходим в регистр SSPCON2 movlw b'00000000' ; отключаем модуль SSPCON2 movwf SSPCON2 ; -//- banksel TXSTA ; переходим в регистр TXSTA movlw b'00000000' ; отключаем модуль TXSTA movwf TXSTA ; -//- banksel RCSTA ; переходим в регистр RCSTA movlw b'00000000' ; отключаем модуль RCSTA movwf RCSTA ; -//- banksel ADCON0 ; переходим в регистр ADCON0 movlw b'00000000' ; отключаем модуль АЦП movwf ADCON0 ; -//- banksel ADCON1 ; переходим в регистр ADCON1 movlw b'00000000' ; отключаем модуль АЦП movwf ADCON1 ; -//- bsf STATUS,RP0 ; переход в банк 1 bcf STATUS,RP0 ; переход в банк 0 clrwdt
;;;;;;;;;;;;;;;;;;;;;;;;; ; инициализация дисплея ; ;;;;;;;;;;;;;;;;;;;;;;;;; call del_100ms ; начальная задержка 100 милисекунд movlw b'00000001' ; очищаем дисплей call LCD_com ; загружаем команду call del_5ms movlw b'00000110' ; сдвиг курсора вправо call LCD_com ; загружаем команду movlw b'00001100' ; отключаем курсор call LCD_com ; загружаем команду movlw b'00010100' ; двигаем курсор вправо call LCD_com ; загружаем команду movlw b'00111000' ; вкл 8 разрядный ввод данных, размер символа 5х8 символов call LCD_com ; загружаем команду
gooo call OUT_U ; отправляемся читать данные АЦП, и вывод данных на дисплей call OUT_I ; отправляемся читать данные АЦП, и вывод данных на дисплей call del_100ms call del_100ms clrwdt goto gooo
OUT_U ; выводим U на дисплей содержимое регистров Thou, Hund, Tens, Ones (тысячи, сотни, десятки, единицы) banksel ADCON0 ; переходим в регистр ADCON0 movlw b'01000001' ; включаем модуль АЦП, RA0 - вход, Fosc/8 movwf ADCON0 ; -//- banksel ADCON1 ; переходим в регистр ADCON1 movlw b'10000000' ; включаем правое выравнивание movwf ADCON1 ; -//- bcf STATUS,RP0 ; переход в банк 0 bsf ADCON0,2 ; включаем преобразование АЦП call del_20mcs werf btfsc ADCON0,2 ; ожидаем завершения goto werf ; преобразования movfw ADRESH ; перепишем результат преобразования movwf Reg_tmpH ; в старший временный регистр banksel ADRESL ; переходим в регистр ADRESL movfw ADRESL ; перепишем результат преобразования bcf STATUS,RP0 ; переход в банк 0 movwf Reg_tmpL ; в младший временный регистр
call TRANSFORMER_dig ; перекодируем двоичное число результата преобразования в десятичное movlw 0x80 ; курсор в пределах первой строки ( 0x80 - начало ) call LCD_com ; загружаем команду movlw 0x55 ; U call LCD_dig ; загружаем данные movlw 0x3D ; = call LCD_dig ; загружаем данные movf Thou,W ; копируем в W содержимое Thou btfsc Thou,0 ; проверяем значение регистра тысячных показаний, если 1, значит переполнение показаний goto overflowU ; отправляемся отображать 9,99V movf Hund,W ; копируем в W содержимое Hund call TABL_dig ; отправляем на дисплей содержимое Hund call LCD_dig ; загружаем данные movlw 0x2C ; , call LCD_dig ; загружаем данные movf Tens,W ; копируем в W содержимое Tens call TABL_dig ; отправляем на дисплей содержимое Tens call LCD_dig ; загружаем данные movf Ones,W ; копируем в W содержимое Ones call TABL_dig ; отправляем на дисплей содержимое Ones call LCD_dig ; загружаем данные movlw 0x56 ; V call LCD_dig ; загружаем данные return overflowU movlw 0x39 ; 9 (выводим 9,99V вместо 10,23V) call LCD_dig ; загружаем данные movlw 0x2C ; , call LCD_dig ; -//- movlw 0x39 ; 9 call LCD_dig ; загружаем данные movlw 0x39 ; 9 call LCD_dig ; загружаем данные movlw 0x56 ; V call LCD_dig ; загружаем данные return
OUT_I ; выводим I на дисплей содержимое регистров Thou, Hund, Tens, Ones (тысячи, сотни, десятки, единицы) banksel ADCON0 ; переходим в регистр ADCON0 movlw b'01001001' ; включаем модуль АЦП, RA1 - вход, Fosc/8 movwf ADCON0 ; -//- banksel ADCON1 ; переходим в регистр ADCON1 movlw b'10000000' ; включаем правое выравнивание movwf ADCON1 ; -//- bcf STATUS,RP0 ; переход в банк 0 bsf ADCON0,2 ; включаем преобразование АЦП call del_20mcs desa btfsc ADCON0,2 ; ожидаем завершения goto desa ; преобразования movfw ADRESH ; перепишем результат преобразования movwf Reg_tmpH ; в старший временный регистр banksel ADRESL ; переходим в регистр ADRESL movfw ADRESL ; перепишем результат преобразования bcf STATUS,RP0 ; переход в банк 0 movwf Reg_tmpL ; в младший временный регистр
call TRANSFORMER_dig ; перекодируем двоичное число результата преобразования в десятичное movlw 0xC0 ; курсор в пределах второй строки ( 0xС0 - начало ) call LCD_com ; загружаем команду movlw 0x49 ; I call LCD_dig ; загружаем данные movlw 0x3D ; = call LCD_dig ; загружаем данные movf Thou,W ; копируем в W содержимое Thou btfsc Thou,0 ; проверяем значение регистра тысячных показаний, если 1, значит переполнение показаний goto overflowI ; отправляемся отображать 9,99A movf Hund,W ; копируем в W содержимое Hund call TABL_dig ; отправляем на дисплей содержимое Hund call LCD_dig ; загружаем данные movlw 0x2C ; , call LCD_dig ; загружаем данные movf Tens,W ; копируем в W содержимое Tens call TABL_dig ; отправляем на дисплей содержимое Tens call LCD_dig ; загружаем данные movf Ones,W ; копируем в W содержимое Ones call TABL_dig ; отправляем на дисплей содержимое Ones call LCD_dig ; загружаем данные movlw 0x41 ; A call LCD_dig ; загружаем данные return overflowI movlw 0x39 ; 9 (выводим 9,99A вместо 10,23A) call LCD_dig ; загружаем данные movlw 0x2C ; , call LCD_dig ; -//- movlw 0x39 ; 9 call LCD_dig ; загружаем данные movlw 0x39 ; 9 call LCD_dig ; загружаем данные movlw 0x41 ; A call LCD_dig ; загружаем данные return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Подпрограмма трансформации двоичного числа в десятичное ; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TRANSFORMER_dig movf Reg_tmpL,W ; копируем младший байт результата преобразования АЦП в movwf bin2 ; в bin2 movf Reg_tmpH,W ; копируем старший байт результата преобразования АЦП в movwf bin1 ; в bin1 ;bin2 = младший байт преобразуемого числа ;bin1 = старший байт преобразуемого числа ;bcd3 ( младший полубайт ) = единицы ;bcd3 ( старший полубайт ) = десятки ;bcd2 ( младший полубайт ) = сотни ;bcd2 ( старший полубайт ) = тысячи ;bcd1 ( младший полубайт ) = десятки тысяч movlw .16 movwf ctr clrf bcd1 clrf bcd2 clrf bcd3 goto start adjdec movlw 0x33 addwf bcd1,f addwf bcd2,f addwf bcd3,f movlw 0x03 btfss bcd1,3 subwf bcd1,f btfss bcd2,3 subwf bcd2,f btfss bcd3,3 subwf bcd3,f movlw 0x30 btfss bcd1,7 subwf bcd1,f btfss bcd2,7 subwf bcd2,f btfss bcd3,7 subwf bcd3,f start rlf bin2,f rlf bin1,f rlf bcd3,f rlf bcd2,f rlf bcd1,f decfsz ctr,f goto adjdec ; окончание конвертирования movf bcd1,w ; распределение результата по регистрам movwf TenK ; десятки тысяч swapf bcd2,w movwf Thou ; тысячи movf bcd2,w movwf Hund ; сотни swapf bcd3,w movwf Tens ; десятки movf bcd3,w movwf Ones ; единицы return
TABL_dig andlw b'00001111' ; маскируем старший полубайт W (обнуляем 4 старших байта) addwf PCL,f ; Содержимое счетчика команд PC увеличивается на величину содержимого аккумулятора W. retlw 0x30 ; 0 retlw 0x31 ; 1 retlw 0x32 ; 2 retlw 0x33 ; 3 retlw 0x34 ; 4 retlw 0x35 ; 5 retlw 0x36 ; 6 retlw 0x37 ; 7 retlw 0x38 ; 8 retlw 0x39 ; 9 retlw 0x41 ; A retlw 0x42 ; B retlw 0x43 ; C retlw 0x44 ; D retlw 0x45 ; E retlw 0x46 ; F
Ищи в сети книги и диск. Подсчитывать адрес регистров через CBLOCK и переходы через $ ни каждому захочется. Если хочеш помощи, выкладывай проект МПЛАБ , а не куски кода.
Пробовал - бестолку! Прямо мистика какая то. Подпрограммы по отдельности работают прекрасно(с удалением из кода одной или другой подпрограммы). Но строит подпрограммы оставить вместе в коде и даже не вызывать мешающую подпрограмму - все равно глюк! Как? Если подпрограмма не вызывается, а просто стоит невостребованная???
Пробовал - бестолку! Прямо мистика какая то. Подпрограммы по отдельности работают прекрасно(с удалением из кода одной или другой подпрограммы). Но строит подпрограммы оставить вместе в коде и даже не вызывать мешающую подпрограмму - все равно глюк! Как? Если подпрограмма не вызывается, а просто стоит невостребованная???
Никакой мистики. Для начала, Вас не смущают сообщения компилятора, типа:
Код:
Message[302] D:\PROV\16F876A\16F876A.ASM 196 : Register in operand not in bank 0. Ensure that bank bits are correct. Warning[203] D:\PROV\16F876A\16F876A.ASM 297 : Found opcode in column 1. (andlw)
Почему просто нельзя ногой дрыгать? Если вы хотите байтом выводить, так тогда его сперва считать нужно, затем выставить нужные биты, а уж затем только выводить. Ну, и вся программа такая, в общем. Глюк сидел, как и говорил выше. Подправил программу (см. аттач) Кстати, а в чём Вы вообще программу отлаживали? Это же сразу должно быть заметно. Заодно приложил проект для Протеуса, и для МПЛАБа с Протеусом. Учитесь с отладкой работать. P.S.: Ещё Протеус ругается, что время АЦП не выдержано. Он, конечно, может и ошибаться, но я не проверял. Это уж сами как-нибудь.
otest писал(а):
Перенеси таблицу в начало программы.
Можно, конечно, и так, но это - половинчатая мера. Лучше сразу правильно делать.
Всем большое спасибо за помощь и правильные наводки! Разобраться помогла статья http://chipmk.ru/index.php?option=com_c ... 5-10-13-47 где все толково описано насчет организации памяти. Smen дрыгал ногами я раньше пока не наткнулся на отрицательные нюансы эффекта чтения-модификации-записи. После этого я и стал использовать переменную, вместо правки порта. Правлю переменную, потом запись в порт! Если честно я отладочными средствами пользоваться не умею. Отладку производил в готовом устройстве. Если не трудно - дайте ссылку где грамотно описан процесс отладки...
пока не наткнулся на отрицательные нюансы эффекта чтения-модификации-записи.
Так не надо на него "натыкаться" и всего делов.
4uvak писал(а):
я отладочными средствами пользоваться не умею. Отладку производил в готовом устройстве.
Так Вы никогда ничего не отладите. В МПЛАБе выбираете подходящий дебагер. Включаете симуляцию (зелёная кнопочка). F7 - пошаговая отладка F9 - "воспроизведение" Точки останова - двойной клик ЛКМ на нужной строке. Откройте проект, который в аттаче, всё поймёте. Там, в качестве дебагера Протеус, поэтому его сперва установить надо.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения