; ============================================================================== ; Title: USB to Serial (RS232) converter. ; ; Author: Rob Jansen, Copyright (c) 2020..2020, all rights reserved. ; ; Revision: ; 2020-02-15 : Initial version. ; ; Compiler: 2.5r3 ; ; Description: This program exchanges all data between the USB and the serial ; (RS232) interface. It support 4 baudrates for the serial interface ; using two external jumper settings. ; Serial data is transmitted as 8 bits, no parity, 1 stopbit. ; When configuring the USB via a terminal program, make sure to ; enable flow control via RTS/CTS as to configure the USB device. ; The USB baudrate can be any baudrate, the jumper settings are only ; used for the serial baudrate. Flow control is not needed for the ; serial interface. ; ; Sources: Jallib sample program 16f1455_usb_serial, ; see: http://justanotherlanguage.org/ ; ;=============================================================================== include 16f1455 pragma target clock 48_000_000 ; Some compiler options. pragma warn all no pragma opt variable_reduce no ; Settings for external 12 MHz crystal and system clock 48 MHz. pragma target OSC HS ; External crystal pragma target CLKOUTEN DISABLED ; CLKOUT function is disabled pragma target PLLMULT N4X ; PLL Multipler Selection Bit, 4x Output Frequency Selected pragma target CPUDIV P1 ; No CPU system divide pragma target USBLSCLK F48MHZ ; System clock expects 48 MHz, FS/LS USB CLKENs divide-by is set to 8. pragma target PLLEN ENABLED ; 3x or 4x PLL Enabled pragma target FCMEN DISABLED ; Fail-Safe Clock Monitor is disabled pragma target WRT DISABLED ; Write protection off pragma target STVR ENABLED ; Stack Overflow or Underflow will cause a Reset pragma target LPBOR DISABLED ; Low-Power BOR is disabled pragma target IESO DISABLED ; Internal/External Switchover Mode is disabled pragma target PWRTE ENABLED ; Power up timer enabled pragma target BROWNOUT DISABLED ; No brownout detection pragma target WDT DISABLED ; Watchdog disabled pragma target MCLR INTERNAL ; Internal reset pragma target LVP DISABLED ; No low-voltage programming pragma target VOLTAGE MAXIMUM ; Brown out voltage pragma target CP DISABLED ; Program memory code protection is disabled enable_digital_io() ; Pin aliases. alias configured_led is pin_c0 ; Pin 10. pin_c0_direction = output alias data_led is pin_c1 ; Pin 9. pin_c1_direction = output alias jumper_1 is pin_c3 ; Pin 7. pin_c3_direction = input alias jumper_2 is pin_c2 ; Pin 8. pin_c2_direction = input ; Include and initialize the USB serial driver. include usb_serial ; ========================= Constants and Variables ========================== ; Baudrate values for a target clock of 48 MHz. For SYNC = 0, BRG16 = 1 and ; BRGH = 0 the formula is: baudrate = target_clock/(16 * (n+1)) or ; n = target_clock/(baudrate * 16) - 1 const word USART_9600_BAUD = 312 const word USART_19200_BAUD = 155 const word USART_57600_BAUD = 51 const word USART_115200_BAUD = 25 const word USART_NO_BAUD = 0 const bit USART_TX_FULL = FALSE const bit USART_RX_AVAILABLE = TRUE const word LED_ON_TIME = 20_000 ; Just a random value to keep the LED on. const bit LED_ON = TRUE const bit LED_OFF = FALSE var word current_baudrate var word new_baudrate var word timer var byte character ; ========================= Functions and Procedures ========================== ; Initialize the USART with the given baudrate. procedure usart_init(word in baudrate) Is ; Use 16 bit baudrate generator and set baudrate BAUDCON = 0b0000_1000 SPBRG = baudrate ; Enable transmitter, 8 bits, asynchronous mode. TXSTA = 0b0010_0000 ; Enable receiver and serial port, 8 bits RCSTA = 0b1001_0000 end procedure ; Check if usart data was received and return TRUE when data is available ; and return the data. In ; case of errors clear the error flags. function usart_serial_read(byte out data) return bit Is var bit data_available = FALSE if RCSTA_FERR then ; Framing error, re-enable receiver. RCSTA_SPEN = FALSE RCSTA_SPEN = TRUE elsif RCSTA_OERR then ; Overflow error. Reset receiver otherwise no characters are received. RCSTA_CREN = FALSE RCSTA_CREN = TRUE elsif (PIR1_RCIF == USART_RX_AVAILABLE) then ; All seems well. Return TRUE if a character is available. data = RCREG data_available = TRUE end if return data_available end function ; Pseudo variable for writing a byte to the USART. Blocking procedure. procedure usart_serial_data'put(byte in data) is ; Check if Transmit buffer empty, if not wait for it to empty. while (TXSTA_TRMT == USART_TX_FULL) loop ; Wait until TX buffer is empty end Loop TXREG = data end procedure ; ========================= Main program starts here ========================== ; Initialize the usb driver and some global variables and pins. usb_serial_init() current_baudrate = USART_NO_BAUD new_baudrate = USART_NO_BAUD timer = 0 ; Turn on both control LEDs for 1 second as to show that they are working. data_led = LED_ON configured_led = LED_ON _usec_delay(1_000_000) data_led = LED_OFF configured_led = LED_OFF forever loop ; First (re-) set the USART baudrate if needed. if jumper_1 then if jumper_2 then new_baudrate = USART_115200_BAUD else new_baudrate = USART_57600_BAUD end if else if jumper_2 then new_baudrate = USART_19200_BAUD else new_baudrate = USART_9600_BAUD end if end if if (new_baudrate != current_baudrate) then current_baudrate = new_baudrate usart_init(current_baudrate) end if ; Poll the USB ISR function on a regular base, in order to serve the USB requests. usb_serial_flush() ; Check if USB device has been configured by the Host. if (usb_cdc_line_status() != 0x00) then configured_led = LED_ON else configured_led = LED_OFF end if ; Check for received charactaer from the USB and if present copy it to the USART. if usb_serial_read(character) then usart_serial_data = character data_led = LED_ON timer = 0 end if ; Check for received charactaer from the UART and if present copy it to the USB. if usart_serial_read(character) then usb_serial_data = character data_led = LED_ON timer = 0 end if ; The timer is used to keep the data LED on for some time. Note that the ; timing is not exact since there is no real reference time but the precise ; on time of the LED is not that relevant. if (timer == LED_ON_TIME) then data_led = LED_OFF else timer = timer + 1 end if end loop