;********************************************************************** ; * ; Filename: USB__ADC_Test.asm * ; Date: 3rd september 2005 * ; File Version: 1.0 * ; * ; Author: Ian Stedman * ; Company: * ; * ; * ;********************************************************************** ; * ; Files required: * ; * ; * ; * ;********************************************************************** ; * ; Notes: * ; A simple program to test the PIC16F877 to FTDI USB interface. * ; It reads from the ADC on pin 2 and transmits the 8 bit value via USB. ; Anything received via USB is send to the LEDs on Port B * * ; * ; * ;********************************************************************** list p=16f877 ; list directive to define processor #include ; processor specific variable definitions __CONFIG _LVP_OFF & _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_OFF & _HS_OSC & _WRT_ENABLE_ON & _DEBUG_OFF & _CPD_OFF ; '__CONFIG' directive is used to embed configuration data within .asm file. ; The lables following the directive are located in the respective .inc file. ; See respective data sheet for additional information on configuration word. ;***** VARIABLE DEFINITIONS w_temp EQU 0x40 ; variable used for context saving status_temp EQU 0x41 ; variable used for context saving adcresult EQU 0x42 ; ADC conversion result usbdatarx EQU 0x52 ; Byte received from USB port usbdatatx EQU 0x54 ; Byte to send via USB count EQU 0x45 temp EQU 0x46 time EQU 0x47 temp2 EQU 0x48 NUMHI EQU 0x49 NUMLO EQU 0x4A D0 EQU 0x4B D1 EQU 0x4C D2 EQU 0x4D D3 EQU 0x4E D4 EQU 0x4F D5 EQU 0x50 READBIT EQU 0 ; PORT C Read bit to USB WRITEBIT EQU 1 ; PORT C Write bit to USB TXFULL EQU 2 ; PORT C TX Full input from USB RXFULL EQU 3 ; PORT C RX Full input from USB INPORT EQU 255 ; Sets an I/O port as all inputs OUTPORT EQU 0 ; Seta an I/O port as all outputs ;********************************************************************** ORG 0x000 ; processor reset vector clrf PCLATH ; ensure page bits are cleared goto main ; go to beginning of program ORG 0x004 ; interrupt vector location movwf w_temp ; save off current W register contents movf STATUS,w ; move status register into W register movwf status_temp ; save off contents of STATUS register ; isr code can go here or be located as a call subroutine elsewhere movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt main call picinit mainloop call usbrecv call display call adcdoit movlw 'O' movwf usbdatatx call usbsend movlw ' ' movwf usbdatatx call usbsend ; movf adcresult,W movf ADRESH,W movwf NUMHI movwf usbdatatx ; Ouput upper 2 bits of ADC result call usbsend banksel ADRESL ; Select Bank 1 to read lower 8 bits movf ADRESL,W banksel ADRESH ; Back to Bank 0. movwf NUMLO movwf usbdatatx ; Ouput lower 8 bits of ADC result call usbsend movlw 'B' movwf usbdatatx call usbsend movlw 'C' movwf usbdatatx call usbsend movlw 'D' movwf usbdatatx call usbsend movlw ' ' movwf usbdatatx call usbsend call Bin2DecFast movf D4,W movwf usbdatatx call usbsend movf D3,W movwf usbdatatx call usbsend movf D2,W movwf usbdatatx call usbsend movf D1,W movwf usbdatatx call usbsend movf D0,W movwf usbdatatx call usbsend movlw ' ' movwf usbdatatx call usbsend movlw 'S' movwf usbdatatx call usbsend movlw 'H' movwf usbdatatx call usbsend movf ADRESH,W movwf temp2 clrc rrf temp2,f movf temp2,W movwf usbdatatx call usbsend banksel ADRESL movf ADRESL,W banksel ADRESH movwf temp2 clrc rrf temp2,f movf temp2,W movwf usbdatatx call usbsend movlw 80 movwf time call delay goto mainloop ; remaining code goes here picinit banksel OPTION_REG movlw H'07' movwf OPTION_REG ; Set TMR0 to divide internal clock by 256 banksel TRISB movlw OUTPORT movwf TRISB ;portb [7-0] outputs movwf TRISA ;porta [7-0] outputs movlw H'0C' ;setup portc [2-3] inputs [0-1,4-7] outputs movwf TRISC movlw INPORT ;setup portd as inputs for now (USB port) movwf TRISD movwf TRISA ; Set PORT A as inputs for the ADC! movlw H'80' movwf ADCON1 ;clrf ADCON1 ;left justified, all inputs a/d bcf STATUS,RP0 ;bank 0 movlw H'FF' movwf PORTC ; Ensure Ouputs are 1 (no read/write) clrf PORTB ; All LEDs off. clrf PORTA movlw B'01000001' ;Fosc/8 [7-6], A/D ch0 [5-3], a/d on [0] movwf ADCON0 bsf PORTC,6 ; Debug return ; ADC channel 0 (pin 2) conversion software, the 8 MSBs are stored for later use. adcdoit ;wait for acquision time (20uS) ;(non-critical for this test) bsf ADCON0,GO ;Start A/D conversion Wait btfsc ADCON0,GO ;Wait for conversion to complete goto Wait movf ADRESL,W ;Write A/D result to PORTC andlw H'FE' ; Mask off bit 0 ;movwf temp2 ;clrw ;rrf temp2,W ;Divide by 2! ;movf temp2,W movwf PORTB movwf adcresult return ; At the moment a simple function to output the received USB value to the 8 LEDs on Port B display movf usbdatarx,W ; Recall received data bcf PORTC,7 movf usbdatarx,W movwf PORTB ; Output it, job done! bsf PORTC,7 bsf PORTC,6 bsf PORTC,5 return ; A function to check for data received from the USB interface and if present, read it. ; USB is on port D, RC0=READ, RC3=RX_Flag usbrecv bsf PORTC,5 ; debug ; movf PORTC,W ; Read in port C for debug btfsc PORTC,RXFULL ; See if RX_flag = 0 which indicates there is data in the FIFO retlw 0 ;If we got here there is data to read. Set PORT D = Input, READ=High, wait, READ=Low then read port D banksel TRISD movlw INPORT movwf TRISD ; PORT D now input, safe to start the read access. banksel PORTD bsf PORTC,READBIT nop nop bcf PORTC,READBIT ; READ now active LOW so READ port D nop nop movf PORTD,W movwf usbdatarx bsf PORTC,READBIT ; Set RD = hig return ; A function to send a byte of information via the USB interface. Checks the TXF flag prior to sending. ; USB is on port D, RC1=Write, RC2=TX_Flag ; The data to send will be in usbdatatx usbsend movf PORTC,W ; Read in PORT C for debug btfsc PORTC,TXFULL ; See if TX_Flag = 0 which indicates OK to transmit. retlw 0 ; Return with 0 if full how???? ;If we get here we can transmit. Set PORT D = output, WRITE=High, Wait, WRITE=Low then Write Data, Write=High banksel TRISD movlw OUTPORT movwf TRISD ; PORT D now output banksel PORTD bsf PORTC,WRITEBIT ; Make sure WR is high before data output. movf usbdatatx,W ; movf adcresult,W movwf PORTD nop bcf PORTC,WRITEBIT ; Write now active nop bsf PORTC,WRITEBIT ; All done, WR = high. ; Now tristate the databus, set PORT D to input. banksel TRISD movlw INPORT movwf TRISD ; PORT D now input banksel PORTD ; Return to page 0 nop return ;******************************************************************* ; DELAY Subroutine. This routine provides a 1 second delay. Call for ; as long as you want by storing your desired delay in 'time' before ; calling. ; EXAMPLE ; movlw 10 ; The value here determines the time delay in seconds. ; movwf time ; Store the value. ; call delay ; call the delay routine. ; delay call delay1 ; these lines make sure that the 1 second loop executes n times. decfsz time goto delay return ; When time is up, return from subroutine. delay1 ; The code here initialise the RTCC. bsf STATUS,RP0 movlw 0x07 ; For use by RTCC, prescaler was /256 or 0x07 movwf OPTION_REG ; ditto bcf STATUS,RP0 clrf TMR0 movlw 0x0e ; Delay time value for 1 second movwf count ; store the value movwf temp sloop ; What follows is the actual delay loop for 1 second. btfsc TMR0,5 ; Reset the RTCC, wait for TMR0 bit 5 to go hich goto jmp1 goto sloop jmp1 clrf TMR0 ; RTCC is cleared so decrement the count & repeat. decfsz count goto sloop wlooplo decfsz temp,F goto wlooplo return ; Bonus 12-Bit version ; Leaner and Meaner, 36 instructions ; Ideal for displaying A/D values ; Input: 16-bit binary in NUMHI and NUMLO ; Output: Decimal (BCD) digits in D4(msd),D3,D2,D1,D0(lsd) ; No temporary variables required Bin2DecFast movf NUMHI,w iorlw 0xF0 ;w=H2-16 movwf D1 ;D1=H2-16 addwf D1,f ;D1=H2*2-32 addwf D1,f ;D1=H2*3-48 movwf D2 ;D2=H2-16 addlw -D'5' ;w=H2-21 addwf D2,f ;D2=H2*2-37 Done! addlw D'41' ;w=H2+20 movwf D0 ;D0=H2+20 swapf NUMLO,w iorlw 0xF0 ;w=H1-16 addwf D1,f ;D1=H2*3+H1-64 addwf D0,f ;D0=H2+H1+4, C=1 rlf D0,f ;D0=(H2+H1)*2+9, C=0 comf D0,f ;D0=-(H2+H1)*2-10 rlf D0,f ;D0=-(H2+H1)*4-20 movf NUMLO,w andlw 0x0F ;w=H0 addwf D0,f ;D0=H0-(H2+H1)*4-20 Done! rlf D1,f ;C=0, D1=H2*6+H1*2-128 Done! movlw D'5' movwf D3 movlw D'10' mod0 addwf D0,f ;D(X)=D(X)mod10 decf D1,f ;D(X+1)=D(X+1)+D(X)div10 skpc goto mod0 mod1 addwf D1,f decf D2,f skpc goto mod1 mod2 addwf D2,f decf D3,f skpc goto mod2 return END ; directive 'end of program'