;********************************************************************** ; Filename: serial.asm * ; Date: 2004-02-04 * ; File Version: 1.1 * ; * ; Author: Per Zander * ;********************************************************************** ; Files required: p12c508.inc/p12c509.inc/p16c505.inc * ; * ; These are device dependent include files that * ; define macros for the different registers, * ; ports etc. of the selected device. They are * ; delivered with the MPLAB development * ; environment that can be downloaded from the * ; Microchip homepage (www.microchip.com). * ;********************************************************************** ; Description: ; ; This is a template for a PIC12C508/PIC12C09/PIC16C505 program ; containing a simple serial receiver. The code can probably be ; used with other PIC devices too, but I haven't tested that. ; ; The serial receiver format is 8 bits, no parity, no handshaking. ; One stop bit is sufficient. Data is inverted, so that an rs232 ; signal can be used directly (after appropriate clamping). ; ; The baudrate depends on the rate with which the receiver subroutine ; is called. It needs to be called four times for each bit, and it ; will consume 11 instruction cycles (44 clock cycles) each time it ; is called. This includes the time for the call and return instructions. ; ; Example: ; With a baud rate of 9600 baud the bit time is 104 microseconds. ; The receiver subroutine must then be called every 26th microsecond. ; With a 4 MHz PIC you have 1 instruction per microsecond, and thus ; your main program must have 26 - 11 = 15 instruction cycles between ; each call to the receiver subroutine. ; ; It is important that your main program uses the exact number of ; instruction cycles, and you have to insert nop's or delay loops ; to ensure correct timing. Note that some instructions (e.g. ; call and goto) require two instruction cycles. ; ;********************************************************************** ;*---------- Device select. ----------* ; Replace this with the directive and include file for the appropriate ; PIC device. list p=16c505 ; List directive to define processor #include ; Processor specific variable ; definitions ;*---------- Configuration specification. ----------* ; Replace this with the appropriate configuration for your application. ; Note that the internal RC oscillator will not give you sufficient ; frequency accuracy for serial communication. Therefore I recommend ; the use of a crystal oscillator. __CONFIG _CP_OFF & _WDT_OFF & _MCLRE_OFF & _XT_OSC ;*---------- Port definitions. ----------* ; I have selected port RC5 on the PIC16C505 as the serial receiver ; input port. Change this if you use another pin for the input. ; PORTC in PIC16C505 is register 7. PORTB in PIC16C505 and the GPIO ; in PIC12C508/PIC12C509 is register 6. dport EQU 0x07 ; Data in on PORTC din EQU 0x05 ; Data in on bit 5 ;*---------- Variable definitions. ----------* ; You can of course use other registers than those I have selected, ; just change the numbers. Registers from 7 and up to 0x1f are general ; registers in PIC12C508/PIC12C509. In PIC16C505 the general registers ; are from 8 and up to 0x1f. ; In PIC12C509 and PIC16C505, register numbers between 0x10 and 0x1f ; define multiple registers through banking. These registers can be used ; too, but make sure that you always have the same bank selected when ; calling the receiver subroutine. ser_st EQU 0x08 ; Serial state pointer. rec_d EQU 0x09 ; Receive data shift register. cmd_fl EQU 0x0A ; Flags used by the serial receiver. new_d EQU 0x0B ; Received_data. ;*---------- Program flag definitions. ----------* ; This defines which bits in the 'cmd_fl' register that are used for ; the serial receiver. dav EQU 0x00 ; Data available flag from receiver. dend EQU 0x01 ; Serial receiver end of byte flag. ; The received data is passed to the calling program through the 'new_d' ; register. The availability of new data is signalled by the 'dav' bit ; of the 'cmd_fl' register. When the calling program detects the 'dav' ; bit set, it should copy the data and then reset the 'dav' bit. ;********************************************************************** ;* The program starts here after reset. ;********************************************************************** ORG 0x3FF ; Processor reset vector. ; The PIC processors are pre-programmed with an oscillator calibration ; value. If you use an OTP version (plastic package), you don't need ; to have the calibration value in your code. But with the UV-erasable ; version (ceramic package with window), you need to put in this ; instruction except for the first time you program it. It will do no ; harm to always have it there. Most programmers skip this if it is ; already programmed. It must be a 'movlw' instruction, but the value ; doesn't matter if you use a crystal oscillator. movlw 0x38 ; Osc. cal. value. ORG 0x000 ; Coding begins here. startofprog ; You should always place the main program after the subroutines, ; because the 'call' and 'movwf PCL' instructions can only reach the ; first 256 lines of code. goto init_code ;***************************************************** ;*---------- Serial receive state machine. ----------* ;***************************************************** ;*---------- Jump to current state. ----------* serial_proc movf ser_st, W movwf PCL ;*---------- Idle state. Must see stop bit to leave it. ----------* ser_idle btfss dport, din movlw wait_start movwf ser_st nop retlw 0 ;*---------- Wait for start bit. ----------* wait_start btfsc dport, din movlw sample_data movwf ser_st bcf cmd_fl, dend ; Clear data end flag. retlw 0 ;*---------- Sample data in. ----------* sample_data btfsc dport, din bcf rec_d, 7 ; Clear data bit if input is logic 0. movlw get_end_bit movwf ser_st retlw 0 ;*---------- Wait for next bit. ----------* get_end_bit btfss rec_d, 0 bsf cmd_fl, dend movlw shift_data movwf ser_st retlw 0 ;*---------- Shift data in. ----------* shift_data rrf rec_d, F ; Shift received data. bsf rec_d, 7 ; Preset current bit to 7. movlw test_bitnr movwf ser_st retlw 0 ;*---------- Check if it is the last bit. ----------* test_bitnr movlw sample_data btfsc cmd_fl, dend movlw sample_last ; Last bit if start bit is in rec_bit. movwf ser_st retlw 0 ;*---------- Sample last bit. ----------* sample_last btfsc dport, din bcf rec_d, 7 ; Clear data bit if input is 0. movlw wait_end ser_return movwf ser_st retlw 0 ;*---------- Wait before sampling stop bit. ----------* wait_end movlw set_new_data goto ser_return ;*---------- Move new data. ----------* set_new_data movf rec_d, W movwf new_d movlw preset_rec movwf ser_st retlw 0 ;*---------- Set receive data to all 1's. ----------* preset_rec movlw 0xFF movwf rec_d movlw sample_stop movwf ser_st retlw 0 ;*---------- Sample stop bit. ----------* sample_stop btfss dport, din bsf cmd_fl, dav ; Set dav if correct stop bit. movlw ser_idle movwf ser_st retlw 0 ; Add your other subroutines here, if you have any. ;******************************************* ;*---------- Main program start. ----------* ;******************************************* init_code ; These initial values must be set for the serial receiver: movlw ser_idle movwf ser_st ; Initial state of serial receiver. clrf cmd_fl ; Clear dav and dend flags movlw 0xFF movwf rec_d ; Set receiver shift register to all 1's. ; Here you add the initial settings needed for your main program: ;... Your init code ... ;****************************************** ;*---------- Main program loop. ----------* ;****************************************** main_loop call serial_proc ; This consumes 11 instruction cycles. ; Add your main program code here. Be careful to maintain the correct timing. goto main_loop ; This consumes 2 instruction cycles. endofprog END ; directive 'end of program'