Форум по Роботика
Технически форум => Общ форум => Темата е започната от: Lampard87 в Април 27, 2012, 09:12:58 pm
-
Здравейте. Написах една програма и рекох да я симулирам на Proteus, но дисплея не показва нищо. Тъй като програмата не е никак малка, написах една елементарна, с която само да се изписва "LCD TEST" на дисплея и пак нищо. Ето я и нея:
list p=16f872
title "LCD Test"
#include <p16f872.inc>
__config _CPD_ON & _WDT_OFF & _PWRTE_ON & _XT_OSC
;*************** Дефиниране на константи и променливи ***********
w EQU 0
f EQU 1
Disp_On EQU H'0C'
Disp_Off EQU H'08'
Entry_Inc EQU H'06'
CBLOCK H'20'
Counter
LCD_Temp
BF_Temp
ENDC
;************** Дефиниране на входно-изходни изводи *************
#define RS PORTC,0
#define RW PORTC,1
#define E PORTC,2
;****************************************************************
; Потребителска програма
;****************************************************************
ORG H'0000' ; Вектор на НУ
goto Start
ORG H'0004' ; Вектор на прекъсване
goto Int_Service
;****************************************************************
; Начало на програмата
;****************************************************************
Start bcf STATUS,RP1
bsf STATUS,RP0
movlw B'00000101' ; pull-up, вътрешен такт за TMR0
movwf OPTION_REG ; такт 1:64
bcf STATUS,RP0
clrf PORTA
clrf PORTB
clrf PORTC
bsf STATUS,RP0
clrf TRISA ; RA0-RA5 - изходи
clrf TRISB ; RB0-RB7 - изходи
clrf TRISC ; RC0-RC7 - изходи
bcf STATUS,RP0
goto main
;****************************************************************
; Използвани подпрограми
;****************************************************************
;------------- Програма за обслужване на прекъсванията ----------
Int_Service
return
;------------- Начална инициализация на LCD модула --------------
Init_LCD
call Wait1 ; Изчакай 16ms
movlw B'00110000'
movwf PORTB
bsf E
bcf E
call Wait2 ; Изчакай 5ms
movlw B'00111000'
movwf PORTB
bsf E
bcf E
movlw Disp_Off
call Send_Command
movlw Disp_On
call Send_Command
movlw Entry_Inc
call Send_Command
return
;------------- Изпращане на команда към LCD дисплея -------------
Send_Command
movwf LCD_Temp
call Check_BF
movf LCD_Temp,w
movwf PORTB
bcf RW
bcf RS
bsf E
bcf E
return
;----------------- Изпращане на кода на символа -----------------
Send_Char
movwf LCD_Temp
call Check_BF
movf LCD_Temp,w
movwf PORTB
bcf RW
bsf RS
bsf E
bcf E
return
;------------------- Проверка на флаг "Зает" --------------------
Check_BF
bsf STATUS,RP0
movlw H'FF'
movwf TRISB
bcf STATUS,RP0
bcf RS
bsf RW
bsf E
bcf E
movf PORTB,w
movwf BF_Temp
btfsc BF_Temp,7
goto Check_BF
bcf RW
bsf STATUS,RP0
clrf TRISB
bcf STATUS,RP0
return
;----------------- Подпрограми за времезадръжка -----------------
Wait1 clrf TMR0 ; Времезадръжка 16ms
bcf INTCON,T0IF
Loop1 btfss INTCON,T0IF
goto Loop1
return
Wait2 movlw D'176' ; Времезадръжка 5ms
movwf TMR0
bcf INTCON,T0IF
Loop2 btfss INTCON,T0IF
goto Loop2
return
Wait3 movlw D'128' ; Времезадръжка 2s
movwf Counter
clrf TMR0
Again3 bcf INTCON,T0IF
Loop3 btfss INTCON,T0IF
goto Loop3
decfsz Counter,f
goto Again3
return
;****************************************************************
; Главна програма
;****************************************************************
main call Init_LCD
movlw H'84'
call Send_Command
movlw 'L'
call Send_Char
movlw 'C'
call Send_Char
movlw 'D'
call Send_Char
movlw H'C0'
call Send_Command
movlw 'T'
call Send_Char
movlw 'E'
call Send_Char
movlw 'S'
call Send_Char
movlw 'T'
call Send_Char
call Wait3 ; Изчакай 2s
goto main
END
Ето и снимки на симулацията:
http://dox.bg/files/dw?a=9ebe23144f
http://dox.bg/files/dw?a=13ce430d8f
Задал съм честотата на микроконтролера при симулацията. Някакви идеи къде бъркам ?
-
Здрасти програмката ти маи е мешина скара :D Имаш много времезадръжки а само един Counter за Wait e Counter за Wait1 Counter1 и тн. Не може да ползваш един Counter за всички. Друго къде в началото на програмата си задал кои вход-изход е аналогов и кой дигитален. То не е само да напишеш Clrf PORTA,B,C и тн. Много постно обслужване на прекъсване даже нулево. За мен програмата е много зле на пръв поглед още. Нека и колегите да кажат но моето мнение е това. И банките не си избрал правилно, имаш 4 банки избират се не само с 5 и 6 бит на STATUS RPO и RP1. Datasheet-a май не си го гледал.
-
Не мисля, че е проблем да използвам един регистър - Counter, тъй като преди употребата му го зареждам със съответната стойност.
Програмката е възможно да е поомешена, защото набързо я орязах от първоначалната ми, въпреки че е подобна на примера от книгата на Кенаров. Не схванах нещо за входовете/изходите. Оставих изводите от всеки порт да са изходи.
Забелязах, че има много теми в чуждестранни форуми за моя проблем, но така и не открих защо не се появяват символите на дисплея.
-
Е не може да режеш и да искаш да ти се даде отговор къде е грешно. Книгата е за 84А тук ти работиш с PIC който иска доста повече.
-
Ето ти нещо резнато и от мен това съм го правил за подобен PIC сравни с твоето инициализация избор на банки и тн.
list p=16F877A
include <P16F877A.INC>
;FOSC = 20MHz
__CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _WRT_OFF & _LVP_OFF & _CPD_OFF
;********************* Дефиниране на Макроси **************************
BANK0 MACRO ;MACRO to select data RAM bank 0
bcf STATUS,RP0
bcf STATUS,RP1
ENDM
BANK1 MACRO ;MACRO to select data RAM bank 1
bsf STATUS,RP0
bcf STATUS,RP1
ENDM
BANK2 MACRO ;MACRO to select data RAM bank 2
bcf STATUS,RP0
bsf STATUS,RP1
ENDM
BANK3 MACRO ;MACRO to select data RAM bank 3
bsf STATUS,RP0
bsf STATUS,RP1
ENDM
LOAD_DATA_EEPROM MACRO ;MACRO for loading constants in internal EEPROM
org 0x2100
DATA 0x00
ENDM
;
;***EndMacros
;********************* Дефиниране на константи и променливи **************************
W EQU 0
f EQU 1
Z EQU 2
CBLOCK 0x20 ;0 RAM starts at address 20h
Counter
Counter1
IPortB
IPortB0
IPortB1
IPortB2
BlokStage
TempCoutPortF
ENDC
CBLOCK 0x070
Wtemp
STATUStemp
PCLATHtemp
FSRtemp
ENDC
;--------------------- Дефиниране на входно-изходните портове ------------------------
;#define SCK PORTC, 3 ;Изход Тактова честота
;#define SDI PORTC, 4 ;SDI за SPI
;#define SDO PORTC, 5 ;SDO за SPI
#define SS PORTA, 5 ;SS за SPI
#define REC IPortB, 0 ;Бутон за запис
#define PLAY IPortB, 1 ;Бутон за възпроизвеждане
#define STOP IPortB, 2 ;Бутон за стоп
#define SV_REC PORTB, 3 ;Светодиод за запис
#define SV_PLAY PORTB, 4 ;Светодиод за възпроизвеждане
#define SV_STOP PORTB, 5 ;Светодиод за стоп
;***StartBlock************************************************************************
; Начало на програма
;*************************************************************************************
ORG 0x0000 ;start address = 0000h
goto start
;***EndBlock**************************************************************************
;***StartBlock************************************************************************
; Обработка на прекъсванията
;*************************************************************************************
ORG 0x0004 ;interrupt address = 0004h
;-----------------Блок за влизане в прекъсване -------------------
movwf Wtemp ; Store W-reg
swapf STATUS,W ; Swap status to be saved into W
clrf STATUS ; bank 0, Clears IRP,RP1,RP0
movwf STATUStemp ; Save status to bank zero STATUS_TEMP
movf PCLATH,W ; pages 1, 2 and/or 3
movwf PCLATHtemp ; Save PCLATH into W
clrf PCLATH ; Page zero, regardless of current page
movf FSR,W ; Copy FSR to W
movwf FSRtemp ; Copy FSR from W to FSR_TEMP
;-----------------------------------------------------------------
nop
nop
;-----------------Блок за излизане от прекъсване -----------------
clrf STATUS ; bank0
movf FSRtemp,W ; Restore FSR register
movwf FSR
movf PCLATHtemp,W ; Restore PCLATH
movwf PCLATH ; Move W into PCLATH
swapf STATUStemp,W ; Swap STATUS_TEMP register into W (sets bank to original state)
movwf STATUS ; Move W into STATUS register
swapf Wtemp,F ; Swap W_TEMP
swapf Wtemp,W ; Swap W_TEMP into W
retfie ; end of interrupt vector
;-----------------------------------------------------------------
;***EndBlock**************************************************************************
;***StartBlock************************************************************************
; Използвани подпрограми
;*************************************************************************************
;--------------- Подпрограма "Wait_Tpud" формира времезадръжка от Xms ----------------
Wait_Tpud:
movlw D'10' ;Задава времето
movwf Counter ;
clrf TMR0 ;Нулира TMR0
again: ;Изпълни цикъла отново
bcf INTCON, T0IF ;Нулира бит T0IF
loop1:
btfss INTCON, T0IF ;Бит T0IF=1
goto loop1 ;Не,повтори отново
decfsz Counter,f ;
goto again ;Изпълни цикъла отново
return ;Връща към главна програма докадето е прекратена
;---endSub
start:
BANK1 ;Избор на Банка 1
movlw b'10010110' ;nternal instruction cycle clock (CLKO), Prescaler is assigned to the Timer0 module,TMR0 Rate 1 : 128
movwf OPTION_REG ;
movlw b'00000111' ;Настроиване на компараторния блок - всички компаратори изключени
movwf CMCON ;
movlw b'00000110' ;Настроиване на изходите само като цифрови
movwf ADCON1 ;
movlw b'11011111' ;RA0-RA4-Входове, RA5-Изход за SS(SLAVE Select)
movwf TRISA ;
movlw b'00000111' ;RB0-RB2-Входове, RB3-RB7-Изход
movwf TRISB ;
bcf TRISC, 3 ;SCK изводи на SPI.
bsf TRISC, 4 ;SDI
bcf TRISC, 5 ;SDO
movlw b'01000000' ;инициализация на SPI (SSPSTAT) - (CKE)Transmit occurs on transition from active to Idle clock state
movwf SSPSTAT ;
BANK0 ;Избор на Банка 0
bsf SS ;Забрана на SS(PORTA,0)
clrf PORTB ;Нулиране на PORTB
clrf PORTC ;Нулиране на PORTC
movlw b'00100010' ;инициализация на SPI (SSPCON) - (CKP)Idle state for clock is a low level, SPI Master mode, clock = FOSC/64 (312,5KHz)
movwf SSPCON ;
movlw b'00000111'
movwf IPortB
movwf IPortB0
movwf IPortB2
movlw .200
movwf TempCoutPortF
clrf BlokStage
goto main
nop
;***EndBlock**************************************************************************
-
Проблема ти е в преписването. Като сменяш контролера се променя програмата според спецификацията на новия контролер, съответно и _CONFIG.
В старт програмата като минеш в банка 1 добави:
MOVLW H'06'
MOVWF ADCON1
- от прекъсване се излиза с RETFIE не с RETURN !
- при инициализацията на дисплея първо се чака 40 милисекунди, не 16
- започваш с команда 30, но не знам как си свързал порта с дисплея та не мога да го коментирам това преди да видя схемата
- после пак има пауза и избираш режим, ти гледам че пердашиш на 8 бита
- никъде не виждам адрес за изписване на каквото пишеш там, с H'01' се нулира РАМ'а, иначе първоначален адрес е каквото му е кеф след стартирането
На пръв поглед това виждам като грешки.
-
Подкарах дисплея, но странното е че първия символ от първия ред липсва - в случая L, независимо на коя позиция ще го разположа. Защо се получи така?
Това са снимки от симулацията:
(http://alfa.kachi-snimka.info/images/arx1335709780t.JPG)
(http://alfa.kachi-snimka.info/images/bfi1335709803x.JPG)
А това е кода:
list p=16f870
title "LCD Test"
#include <p16f870.inc>
__config _CPD_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _XT_OSC & _LVP_OFF & _CPD_OFF
;*************** Дефиниране на константи и променливи ***********
w EQU 0
f EQU 1
Disp_On EQU H'0C'
Disp_Off EQU H'08'
Entry_Inc EQU H'06'
CBLOCK H'20'
Counter
LCD_Temp
BF_Temp
ENDC
;************** Дефиниране на входно-изходни изводи *************
#define RS PORTC,0
#define RW PORTC,1
#define E PORTC,2
;****************************************************************
; Потребителска програма
;****************************************************************
ORG H'0000' ; Вектор на НУ
goto Start
ORG H'0004' ; Вектор на прекъсване
goto Int_Service
;****************************************************************
; Начало на програмата
;****************************************************************
Start bcf STATUS,RP1
bsf STATUS,RP0
movlw B'10000101' ; вътрешен такт за TMR0
movwf OPTION_REG ; такт 1:64
bcf STATUS,RP1
bcf STATUS,RP0
clrf PORTA
clrf PORTB
clrf PORTC
bcf STATUS,RP1
bsf STATUS,RP0
movlw H'06'
movwf ADCON1
clrf TRISA ; RA0-RA5 - изходи
clrf TRISB ; RB0-RB7 - изходи
clrf TRISC ; RC0-RC7 - изходи
bcf STATUS,RP1
bcf STATUS,RP0
goto main
;****************************************************************
; Използвани подпрограми
;****************************************************************
;------------- Програма за обслужване на прекъсванията ----------
Int_Service
retfie
;------------- Начална инициализация на LCD модула --------------
Init_LCD
call Wait1 ; Изчакай 16ms
movlw B'00110000'
movwf PORTB
bsf E
bcf E
call Wait2 ; Изчакай 5ms
movlw B'00111000'
movwf PORTB
bsf E
bcf E
movlw Disp_Off
call Send_Command
movlw Disp_On
call Send_Command
movlw Entry_Inc
call Send_Command
return
;------------- Изпращане на команда към LCD дисплея -------------
Send_Command
movwf LCD_Temp
call Check_BF
movf LCD_Temp,w
movwf PORTB
bcf RW
bcf RS
bsf E
bcf E
return
;----------------- Изпращане на кода на символа -----------------
Send_Char
movwf LCD_Temp
call Check_BF
movf LCD_Temp,w
movwf PORTB
bcf RW
bsf RS
bsf E
bcf E
return
;------------------- Проверка на флаг "Зает" --------------------
Check_BF
bcf STATUS,RP1
bsf STATUS,RP0
movlw H'FF'
movwf TRISB
bcf STATUS,RP1
bcf STATUS,RP0
bcf RS
bsf RW
bsf E
bcf E
movf PORTB,w
movwf BF_Temp
btfsc BF_Temp,7
goto Check_BF
bcf RW
bcf STATUS,RP1
bsf STATUS,RP0
clrf TRISB
bcf STATUS,RP1
bcf STATUS,RP0
return
;----------------- Подпрограми за времезадръжка -----------------
Wait1 clrf TMR0 ; Времезадръжка 16ms
bcf INTCON,T0IF
Loop1 btfss INTCON,T0IF
goto Loop1
return
Wait2 movlw D'176' ; Времезадръжка 5ms
movwf TMR0
bcf INTCON,T0IF
Loop2 btfss INTCON,T0IF
goto Loop2
return
Wait3 movlw D'128' ; Времезадръжка 2s
movwf Counter
clrf TMR0
Again3 bcf INTCON,T0IF
Loop3 btfss INTCON,T0IF
goto Loop3
decfsz Counter,f
goto Again3
return
;****************************************************************
; Главна програма
;****************************************************************
main call Init_LCD
Send_Message
movlw H'80'
call Send_Command
movlw 'L'
call Send_Char
movlw 'C'
call Send_Char
movlw 'D'
call Send_Char
Second_Line
movlw H'C0'
call Send_Command
movlw 'T'
call Send_Char
movlw 'E'
call Send_Char
movlw 'S'
call Send_Char
movlw 'T'
call Send_Char
Stop_Send
nop
goto Stop_Send
END
Edit: Изтървана буква.
-
По принцип в симулациите се спазват стриктно максималните времена. Всяка инструкция отнема определено време.
Ако му сложиш по 4 или 5 NOP'a преди return в подпрограмите Send_Command и Send_Char ще се оправи симулацията.
На живо ще тръгне и така както е сега.
-
Пробвах сега с 4-битов интерфейс, но не тръгва - пак е празен дисплея. Къде пак бъркам ?
Направих следните промени:
- При инциализацията на дисплея изпращам команда 0010000 за 4-битов интерфейс, както и 00101000 за двуредов режим 5х8 точки. Изглежда по този начин:
;------------- Начална инициализация на LCD модула --------------
Init_LCD
call Wait1 ; Изчакай 16ms
movlw B'00110000'
movwf PORTB
bsf E
bcf E
call Wait2 ; Изчакай 5ms
movlw B'00100000'
movwf PORTB
bsf E
bcf E
movlw B'00101000'
call Send_Command
movlw Disp_Off
call Send_Command
movlw Disp_On
call Send_Command
movlw Entry_Inc
call Send_Command
return
- В подпрограмата за изпращане на команди изпращам двете тетради поотделно. Заменям тази част:
;------------- Изпращане на команда към LCD дисплея -------------
Send_Command
movwf LCD_Temp
call Check_BF
movf LCD_Temp,w
movwf PORTB
bcf RW
bcf RS
bsf E
bcf E
nop
nop
nop
nop
return
с тази:
;------------- Изпращане на команда към LCD дисплея -------------
Send_Command
movwf LCD_Temp
call Check_BF
movf LCD_Temp,w
andlw H'F0'
movwf PORTB
bcf RW
bcf RS
bsf E
bcf E
swapf LCD_Temp,w
andlw H'F0'
movwf PORTB
bsf E
bcf E
nop
nop
nop
nop
return
- По същия начин и в подпрограмата за изпращане на символ.
-
Никъде не написа дали заработи 8 битовия режим.
По принцип промените за 4 битов режим са коректни, но си пропуснал да промениш и подпрограмата Check_BF,
която в този си вид чете 8 бита. Имаш два варианта.
- На мястото на call Check_BF да сложиш call Wait2, въпреки че и само 160 микросекунди ще са са достатъчни.
- Да промениш Check_BF да чете в 4 битов режим, трябва да се добавят още няколко команди и проблема е решен
-
8-битовият режим тръгна нормално, след като добавих празните операции както ме посъветва.
А ще можеш ли да ми напишеш как да променя подпрограмата Check_BF за 4-битов режим ? Използвам RB4-RB7 за връзка с дисплея, съответно към D4-D7, а D0-D3 са на маса.
-
Направих две запитвания към дисплея и след това проверих флага (бит 7) и се получи номера.
-
В 4 битов режим всеки байт се предава на два такта. На теория флага, който проверяваш, е в първата тетрада и може да се провери директно и така както е програмата, но има LCD контролери, които ще забият ако не прочетеш и втората тетрада. Симулацията е предвидена и за тоя вариант и затова не тръгва. На живо би трябвало да работи и така. За да не ти дава грешка, след като запишеш състоянието на порта(т.е. старшата тетрада) в BF_Temp, му пусни още един импулс за да си прати и младшата тетрада, която ти няма да четеш защото не ти трябва, но... мир да има.
Добави:
...
movf PORTB,w
movwf BF_Temp
bsf E
bcf E
btfsc BF_Temp,7
goto Check_BF
...
-
CarBeta5 благодаря много за помощта.