CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

80 column video display on your HDTV (480i)

 
Post new topic   Reply to topic    CCS Forum Index -> Code Library
View previous topic :: View next topic  
Author Message
equack



Joined: 21 Sep 2009
Posts: 21

View user's profile Send private message

80 column video display on your HDTV (480i)
PostPosted: Sun Sep 05, 2010 4:53 pm     Reply with quote

You can get an 80x25 character video display out of a PIC18F26K20. All you need is a suitable crystal and two resistors.

Minimal hardware setup:
    1. Run the PIC at 3.3 volts.
    2. Use a 14.31818 mHz crystal (4x NTSC colorburst)
    3. Connect pin C2 to a video output connector via a 680 ohm resistor.
    4. Connect pin C7 to a video output connector via a 330 ohm resistor.
    5. Connect the video output connector to the composite input of a TV or monitor. Make sure you have both signal and ground connections.


For the complete project details including schematic, board layout, and hex files please visit my web page:

http://www.quackenbush.com/lab/picvideo.html


Notes:
    1. The PIC18F26K20 is rated at 64mHz. With a 4X PLL we run it at 57.3 mHz. You might be able to overclock a slower (48mHz) PIC.
    2. Change to #define CRYSTAL13 if you have a 13.5 mHz crystal. This gives you CCIR-601 square pixels.
    3. You can use the internal 16mhz oscillator but the display will be wavy. A 16mhz crystal works OK but there is a large right hand border.
    2. You need a PIC with ~3800 bytes of RAM because an 80 column video display takes 2000 bytes. 40 column mode still takes more than 1536 so you can't use an 18F25K20.
    3. For better results use the luma channel of an S-video connection.
    4. For best results use the component video "Y" input on your HDTV (the green plug)
    5. Uncomment the line "#define COLUMN40" if you want a 40 column video display instead.
    6. The entire video generation is run inside a global interrupt handler leaving the processor free to run your own code without polling or timing restrictions.
    7. The code uses the EUSART in master synchronous mode as a video shift register. This means no UART. If you need a serial port you could try get get your hands on a PIC 18F26J22 which has a second EUSART.
    8. The PIC 18F26K20 has hardware slew rate control of its output pins. Changing the slew rate affects the quality of the video. The best setting depends on the display device you are using.
    9. This was compiled using version 4.112 of the CCS compiler. It will not work correctly on version 4.095, so make sure you have the latest version of the compiler.
    10. The ROM font is 8X8 pixel ASCII. The upper 128 characters are inverse video. There are some special symbols in the lower 32 characters.


Code:

/*
      40/80 Column Video Display using a PIC18F26K20.

      Copyright (c) 2010 Erik C. Quackenbush
      Non-commercial distribution permitted.

CPU Crystal is:
14.318180 mHz which is 4X NTSC colorburst giving 69.84 nanosecond pixels
13.5 mHz which is CCIR-601 square pixels 74.07 nanoseconds
16 mHz which is the maximum clock rate (4X=64mhz) with 62.5 nanosecond pixels

hardware details:

connect the video output to PIN_C2 through a 680 ohm resistor
connect the video output to PIN_C7 through a 330 ohm resistor
run the chip at 3.3 volts
optionally connect an LED to PIN_A5
optionally connect a transistor driven speak to pin C1

we're using EUSART as our video shift register.
baud rate divisor is 0 so it outputs one pixel per CPU clock (Fosc/4)
which should be 14.318 mHz or ~70ns

we use timer 2 to generate an interrupt at the beginning of each scan line.
We use a divide by 4 prescaler and set the period register to 227. This
gives us 908 cycles per line at 14.31818 mHz

we are only generating odd fields- not a true interlaced signal

*/
#include <18F26K20.H>

//#define CRYSTAL13       // 13.5mHz crystal CCIR-601 square pixels
#define CRYSTAL14     // 14.31818 mHz crystal NTSC pixels (4X color burst)
//#define CRYSTAL16     // 16mHz internal oscillator works but the display
                        // is wavy. You really need an HS crystal.

//#define  COLUMN40       // define COLUMN40 if you want a 40 column display
                        // comment it out if you want an 80 column display
                        // 40 columns looks good on standard TV sets.
                        // 80 columns looks good on most flat panel TVs.
                                               

/**************************************************************************/

#ifdef CRYSTAL14
#use     delay(clock=57272720)
#endif

#ifdef CRYSTAL13
#use  delay(clock=54000000)
#endif

#ifdef CRYSTAL16
#use  delay(clock=64000000)
#endif

#fuses   H4,NOWDT,NOPROTECT,BROWNOUT,PUT,NOLVP

//#include <string.h>
//#include <stdio.h>
#define ROMFONT 0x2000
#rom int8 ROMFONT={
   0x00, 0x3c, 0x03, 0xff, 0xff, 0x03, 0xc0, 0x03, // 0
   0x03, 0x00, 0xc0, 0x18, 0x00, 0x00, 0x18, 0x18,
   0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,
   0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x38, 0x3c,
   0x00, 0x08, 0x12, 0x14, 0x1c, 0x26, 0x0c, 0x10,
   0x10, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
   0x1c, 0x08, 0x1c, 0x1c, 0x10, 0x3e, 0x18, 0x3e,
   0x1c, 0x1c, 0x00, 0x00, 0x20, 0x00, 0x04, 0x1c,
   0x1c, 0x08, 0x1e, 0x1c, 0x0e, 0x3e, 0x3e, 0x1c,
   0x22, 0x1c, 0x38, 0x22, 0x04, 0x22, 0x22, 0x1c,
   0x1e, 0x1c, 0x1e, 0x1c, 0x3e, 0x22, 0x22, 0x41,
   0x22, 0x22, 0x3e, 0x1c, 0x02, 0x1c, 0x00, 0x00,
   0x08, 0x00, 0x02, 0x00, 0x20, 0x00, 0x10, 0x00,
   0x02, 0x08, 0x10, 0x04, 0x0c, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x10, 0x08, 0x04, 0x00, 0x00,
   0xff, 0xc3, 0xfc, 0x00, 0x00, 0xfc, 0x3f, 0xfc,
   0xfc, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xe7,
   0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7,
   0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xc7, 0xc3,
   0xff, 0xf7, 0xed, 0xeb, 0xe3, 0xd9, 0xf3, 0xef,
   0xef, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf,
   0xe3, 0xf7, 0xe3, 0xe3, 0xef, 0xc1, 0xe7, 0xc1,
   0xe3, 0xe3, 0xff, 0xff, 0xdf, 0xff, 0xfb, 0xe3,
   0xe3, 0xf7, 0xe1, 0xe3, 0xf1, 0xc1, 0xc1, 0xe3,
   0xdd, 0xe3, 0xc7, 0xdd, 0xfb, 0xdd, 0xdd, 0xe3,
   0xe1, 0xe3, 0xe1, 0xe3, 0xc1, 0xdd, 0xdd, 0xbe,
   0xdd, 0xdd, 0xc1, 0xe3, 0xfd, 0xe3, 0xff, 0xff,
   0xf7, 0xff, 0xfd, 0xff, 0xdf, 0xff, 0xef, 0xff,
   0xfd, 0xf7, 0xef, 0xfb, 0xf3, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xef, 0xf7, 0xfb, 0xff, 0xff,
   0x00, 0x7e, 0x03, 0xff, 0xff, 0x03, 0xc0, 0x03, // 1
   0x03, 0x00, 0xc0, 0x18, 0x00, 0x00, 0x18, 0x18,
   0xff, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,
   0x00, 0x18, 0x10, 0x08, 0x18, 0x18, 0x44, 0x66,
   0x00, 0x08, 0x12, 0x14, 0x2a, 0x26, 0x12, 0x10,
   0x08, 0x08, 0x14, 0x08, 0x00, 0x00, 0x00, 0x20,
   0x22, 0x0c, 0x22, 0x22, 0x18, 0x02, 0x04, 0x20,
   0x22, 0x22, 0x00, 0x00, 0x10, 0x00, 0x08, 0x22,
   0x22, 0x14, 0x22, 0x22, 0x12, 0x02, 0x02, 0x22,
   0x22, 0x08, 0x10, 0x12, 0x04, 0x36, 0x22, 0x22,
   0x22, 0x22, 0x22, 0x22, 0x08, 0x22, 0x22, 0x41,
   0x22, 0x22, 0x20, 0x04, 0x02, 0x10, 0x08, 0x00,
   0x08, 0x00, 0x02, 0x00, 0x20, 0x00, 0x28, 0x00,
   0x02, 0x00, 0x00, 0x04, 0x08, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x4c, 0x38,
   0xff, 0x81, 0xfc, 0x00, 0x00, 0xfc, 0x3f, 0xfc,
   0xfc, 0xff, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xe7,
   0x00, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7,
   0xff, 0xe7, 0xef, 0xf7, 0xe7, 0xe7, 0xbb, 0x99,
   0xff, 0xf7, 0xed, 0xeb, 0xd5, 0xd9, 0xed, 0xef,
   0xf7, 0xf7, 0xeb, 0xf7, 0xff, 0xff, 0xff, 0xdf,
   0xdd, 0xf3, 0xdd, 0xdd, 0xe7, 0xfd, 0xfb, 0xdf,
   0xdd, 0xdd, 0xff, 0xff, 0xef, 0xff, 0xf7, 0xdd,
   0xdd, 0xeb, 0xdd, 0xdd, 0xed, 0xfd, 0xfd, 0xdd,
   0xdd, 0xf7, 0xef, 0xed, 0xfb, 0xc9, 0xdd, 0xdd,
   0xdd, 0xdd, 0xdd, 0xdd, 0xf7, 0xdd, 0xdd, 0xbe,
   0xdd, 0xdd, 0xdf, 0xfb, 0xfd, 0xef, 0xf7, 0xff,
   0xf7, 0xff, 0xfd, 0xff, 0xdf, 0xff, 0xd7, 0xff,
   0xfd, 0xff, 0xff, 0xfb, 0xf7, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xf7, 0xf7, 0xf7, 0xb3, 0xc7,
   0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 2
   0x03, 0x18, 0xc0, 0x18, 0x00, 0x00, 0x18, 0x18,
   0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18,
   0x00, 0x18, 0x30, 0x0c, 0x3c, 0x18, 0x04, 0x66,
   0x00, 0x08, 0x12, 0x3e, 0x0a, 0x10, 0x0a, 0x08,
   0x04, 0x10, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x10,
   0x32, 0x08, 0x20, 0x20, 0x14, 0x02, 0x02, 0x10,
   0x22, 0x22, 0x08, 0x00, 0x08, 0x3c, 0x10, 0x20,
   0x3a, 0x22, 0x22, 0x02, 0x22, 0x02, 0x02, 0x02,
   0x22, 0x08, 0x10, 0x0a, 0x04, 0x2a, 0x26, 0x22,
   0x22, 0x22, 0x22, 0x02, 0x08, 0x22, 0x22, 0x41,
   0x14, 0x22, 0x10, 0x04, 0x04, 0x10, 0x14, 0x00,
   0x10, 0x18, 0x1a, 0x18, 0x2c, 0x18, 0x08, 0x18,
   0x1a, 0x08, 0x18, 0x24, 0x08, 0x37, 0x1e, 0x1c,
   0x1e, 0x3c, 0x1a, 0x38, 0x1c, 0x22, 0x22, 0x22,
   0x22, 0x24, 0x3c, 0x08, 0x08, 0x08, 0x32, 0x04,
   0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
   0xfc, 0xe7, 0x3f, 0xe7, 0xff, 0xff, 0xe7, 0xe7,
   0xff, 0x00, 0xff, 0xff, 0xff, 0xe7, 0xe7, 0xe7,
   0xff, 0xe7, 0xcf, 0xf3, 0xc3, 0xe7, 0xfb, 0x99,
   0xff, 0xf7, 0xed, 0xc1, 0xf5, 0xef, 0xf5, 0xf7,
   0xfb, 0xef, 0xd5, 0xf7, 0xff, 0xff, 0xff, 0xef,
   0xcd, 0xf7, 0xdf, 0xdf, 0xeb, 0xfd, 0xfd, 0xef,
   0xdd, 0xdd, 0xf7, 0xff, 0xf7, 0xc3, 0xef, 0xdf,
   0xc5, 0xdd, 0xdd, 0xfd, 0xdd, 0xfd, 0xfd, 0xfd,
   0xdd, 0xf7, 0xef, 0xf5, 0xfb, 0xd5, 0xd9, 0xdd,
   0xdd, 0xdd, 0xdd, 0xfd, 0xf7, 0xdd, 0xdd, 0xbe,
   0xeb, 0xdd, 0xef, 0xfb, 0xfb, 0xef, 0xeb, 0xff,
   0xef, 0xe7, 0xe5, 0xe7, 0xd3, 0xe7, 0xf7, 0xe7,
   0xe5, 0xf7, 0xe7, 0xdb, 0xf7, 0xc8, 0xe1, 0xe3,
   0xe1, 0xc3, 0xe5, 0xc7, 0xe3, 0xdd, 0xdd, 0xdd,
   0xdd, 0xdb, 0xc3, 0xf7, 0xf7, 0xf7, 0xcd, 0xfb,
   0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 3
   0xff, 0x3c, 0xff, 0x1f, 0x1f, 0xf8, 0xf8, 0xff,
   0x00, 0xff, 0xff, 0x00, 0x00, 0xf8, 0x1f, 0xff,
   0xff, 0x18, 0x7e, 0x7e, 0x7e, 0x18, 0x1f, 0x3c,
   0x00, 0x08, 0x00, 0x14, 0x1c, 0x08, 0x04, 0x00,
   0x04, 0x10, 0x1c, 0x3e, 0x00, 0x3e, 0x00, 0x08,
   0x2a, 0x08, 0x18, 0x18, 0x12, 0x1c, 0x1e, 0x08,
   0x1c, 0x3c, 0x00, 0x08, 0x04, 0x00, 0x20, 0x10,
   0x2a, 0x22, 0x1e, 0x02, 0x22, 0x1e, 0x1e, 0x1a,
   0x3e, 0x08, 0x10, 0x06, 0x04, 0x2a, 0x2a, 0x22,
   0x1e, 0x22, 0x1e, 0x1c, 0x08, 0x22, 0x22, 0x49,
   0x08, 0x14, 0x08, 0x04, 0x08, 0x10, 0x22, 0x00,
   0x00, 0x20, 0x26, 0x24, 0x32, 0x24, 0x1c, 0x24,
   0x26, 0x08, 0x10, 0x14, 0x08, 0x49, 0x22, 0x22,
   0x22, 0x22, 0x26, 0x04, 0x08, 0x22, 0x22, 0x22,
   0x14, 0x24, 0x20, 0x04, 0x08, 0x10, 0x00, 0x1e,
   0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
   0x00, 0xc3, 0x00, 0xe0, 0xe0, 0x07, 0x07, 0x00,
   0xff, 0x00, 0x00, 0xff, 0xff, 0x07, 0xe0, 0x00,
   0x00, 0xe7, 0x81, 0x81, 0x81, 0xe7, 0xe0, 0xc3,
   0xff, 0xf7, 0xff, 0xeb, 0xe3, 0xf7, 0xfb, 0xff,
   0xfb, 0xef, 0xe3, 0xc1, 0xff, 0xc1, 0xff, 0xf7,
   0xd5, 0xf7, 0xe7, 0xe7, 0xed, 0xe3, 0xe1, 0xf7,
   0xe3, 0xc3, 0xff, 0xf7, 0xfb, 0xff, 0xdf, 0xef,
   0xd5, 0xdd, 0xe1, 0xfd, 0xdd, 0xe1, 0xe1, 0xe5,
   0xc1, 0xf7, 0xef, 0xf9, 0xfb, 0xd5, 0xd5, 0xdd,
   0xe1, 0xdd, 0xe1, 0xe3, 0xf7, 0xdd, 0xdd, 0xb6,
   0xf7, 0xeb, 0xf7, 0xfb, 0xf7, 0xef, 0xdd, 0xff,
   0xff, 0xdf, 0xd9, 0xdb, 0xcd, 0xdb, 0xe3, 0xdb,
   0xd9, 0xf7, 0xef, 0xeb, 0xf7, 0xb6, 0xdd, 0xdd,
   0xdd, 0xdd, 0xd9, 0xfb, 0xf7, 0xdd, 0xdd, 0xdd,
   0xeb, 0xdb, 0xdf, 0xfb, 0xf7, 0xef, 0xff, 0xe1,
   0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 4
   0xff, 0x3c, 0xff, 0x1f, 0x1f, 0xf8, 0xf8, 0xff,
   0x00, 0x00, 0xff, 0xff, 0x00, 0xf8, 0x1f, 0xff,
   0xff, 0x18, 0x7e, 0x7e, 0x18, 0x7e, 0x04, 0x00,
   0x00, 0x08, 0x00, 0x3e, 0x28, 0x04, 0x2a, 0x00,
   0x04, 0x10, 0x2a, 0x08, 0x00, 0x00, 0x00, 0x04,
   0x26, 0x08, 0x04, 0x20, 0x3e, 0x20, 0x22, 0x04,
   0x22, 0x20, 0x08, 0x00, 0x08, 0x3c, 0x10, 0x08,
   0x1a, 0x3e, 0x22, 0x02, 0x22, 0x02, 0x02, 0x22,
   0x22, 0x08, 0x10, 0x0a, 0x04, 0x22, 0x32, 0x22,
   0x02, 0x2a, 0x0a, 0x20, 0x08, 0x22, 0x14, 0x2a,
   0x14, 0x08, 0x04, 0x04, 0x10, 0x10, 0x00, 0x00,
   0x00, 0x38, 0x22, 0x04, 0x22, 0x3c, 0x08, 0x24,
   0x22, 0x08, 0x10, 0x0c, 0x08, 0x49, 0x22, 0x22,
   0x22, 0x22, 0x02, 0x18, 0x08, 0x22, 0x22, 0x2a,
   0x08, 0x24, 0x18, 0x08, 0x08, 0x08, 0x00, 0x1e,
   0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
   0x00, 0xc3, 0x00, 0xe0, 0xe0, 0x07, 0x07, 0x00,
   0xff, 0xff, 0x00, 0x00, 0xff, 0x07, 0xe0, 0x00,
   0x00, 0xe7, 0x81, 0x81, 0xe7, 0x81, 0xfb, 0xff,
   0xff, 0xf7, 0xff, 0xc1, 0xd7, 0xfb, 0xd5, 0xff,
   0xfb, 0xef, 0xd5, 0xf7, 0xff, 0xff, 0xff, 0xfb,
   0xd9, 0xf7, 0xfb, 0xdf, 0xc1, 0xdf, 0xdd, 0xfb,
   0xdd, 0xdf, 0xf7, 0xff, 0xf7, 0xc3, 0xef, 0xf7,
   0xe5, 0xc1, 0xdd, 0xfd, 0xdd, 0xfd, 0xfd, 0xdd,
   0xdd, 0xf7, 0xef, 0xf5, 0xfb, 0xdd, 0xcd, 0xdd,
   0xfd, 0xd5, 0xf5, 0xdf, 0xf7, 0xdd, 0xeb, 0xd5,
   0xeb, 0xf7, 0xfb, 0xfb, 0xef, 0xef, 0xff, 0xff,
   0xff, 0xc7, 0xdd, 0xfb, 0xdd, 0xc3, 0xf7, 0xdb,
   0xdd, 0xf7, 0xef, 0xf3, 0xf7, 0xb6, 0xdd, 0xdd,
   0xdd, 0xdd, 0xfd, 0xe7, 0xf7, 0xdd, 0xdd, 0xd5,
   0xf7, 0xdb, 0xe7, 0xf7, 0xf7, 0xf7, 0xff, 0xe1,
   0x00, 0xc3, 0x03, 0x03, 0xc0, 0x03, 0xc0, 0x03, // 5
   0x03, 0x18, 0xc0, 0x00, 0x18, 0x18, 0x00, 0x18,
   0x00, 0x00, 0x00, 0xff, 0x00, 0x18, 0x18, 0x00,
   0x18, 0x18, 0x30, 0x0c, 0x18, 0x3c, 0x1e, 0x00,
   0x00, 0x00, 0x00, 0x14, 0x2a, 0x32, 0x12, 0x00,
   0x08, 0x08, 0x14, 0x08, 0x08, 0x00, 0x00, 0x02,
   0x22, 0x08, 0x02, 0x22, 0x10, 0x22, 0x22, 0x04,
   0x22, 0x10, 0x00, 0x08, 0x10, 0x00, 0x08, 0x00,
   0x02, 0x22, 0x22, 0x22, 0x12, 0x02, 0x02, 0x32,
   0x22, 0x08, 0x12, 0x12, 0x04, 0x22, 0x22, 0x22,
   0x02, 0x12, 0x12, 0x22, 0x08, 0x22, 0x14, 0x2a,
   0x22, 0x08, 0x02, 0x04, 0x20, 0x10, 0x00, 0x00,
   0x00, 0x24, 0x26, 0x24, 0x32, 0x04, 0x08, 0x38,
   0x22, 0x08, 0x10, 0x14, 0x08, 0x49, 0x22, 0x22,
   0x1e, 0x3c, 0x02, 0x20, 0x08, 0x32, 0x14, 0x2a,
   0x14, 0x38, 0x04, 0x08, 0x08, 0x08, 0x00, 0x04,
   0xff, 0x3c, 0xfc, 0xfc, 0x3f, 0xfc, 0x3f, 0xfc,
   0xfc, 0xe7, 0x3f, 0xff, 0xe7, 0xe7, 0xff, 0xe7,
   0xff, 0xff, 0xff, 0x00, 0xff, 0xe7, 0xe7, 0xff,
   0xe7, 0xe7, 0xcf, 0xf3, 0xe7, 0xc3, 0xe1, 0xff,
   0xff, 0xff, 0xff, 0xeb, 0xd5, 0xcd, 0xed, 0xff,
   0xf7, 0xf7, 0xeb, 0xf7, 0xf7, 0xff, 0xff, 0xfd,
   0xdd, 0xf7, 0xfd, 0xdd, 0xef, 0xdd, 0xdd, 0xfb,
   0xdd, 0xef, 0xff, 0xf7, 0xef, 0xff, 0xf7, 0xff,
   0xfd, 0xdd, 0xdd, 0xdd, 0xed, 0xfd, 0xfd, 0xcd,
   0xdd, 0xf7, 0xed, 0xed, 0xfb, 0xdd, 0xdd, 0xdd,
   0xfd, 0xed, 0xed, 0xdd, 0xf7, 0xdd, 0xeb, 0xd5,
   0xdd, 0xf7, 0xfd, 0xfb, 0xdf, 0xef, 0xff, 0xff,
   0xff, 0xdb, 0xd9, 0xdb, 0xcd, 0xfb, 0xf7, 0xc7,
   0xdd, 0xf7, 0xef, 0xeb, 0xf7, 0xb6, 0xdd, 0xdd,
   0xe1, 0xc3, 0xfd, 0xdf, 0xf7, 0xcd, 0xeb, 0xd5,
   0xeb, 0xc7, 0xfb, 0xf7, 0xf7, 0xf7, 0xff, 0xfb,
   0x00, 0x7e, 0x03, 0x03, 0xc0, 0xff, 0xff, 0x03, // 6
   0x03, 0x00, 0xc0, 0x00, 0x18, 0x18, 0x00, 0x18,
   0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x00,
   0x18, 0x18, 0x10, 0x08, 0x18, 0x18, 0x65, 0x00,
   0x00, 0x08, 0x00, 0x14, 0x1c, 0x32, 0x2c, 0x00,
   0x10, 0x04, 0x00, 0x00, 0x08, 0x00, 0x08, 0x02,
   0x1c, 0x1c, 0x3e, 0x1c, 0x10, 0x1c, 0x1c, 0x04,
   0x1c, 0x0c, 0x00, 0x08, 0x20, 0x00, 0x04, 0x08,
   0x3c, 0x22, 0x1e, 0x1c, 0x0e, 0x3e, 0x02, 0x2c,
   0x22, 0x1c, 0x0c, 0x22, 0x3c, 0x22, 0x22, 0x1c,
   0x02, 0x2c, 0x22, 0x1c, 0x08, 0x1c, 0x08, 0x14,
   0x22, 0x08, 0x3e, 0x1c, 0x20, 0x1c, 0x00, 0xff,
   0x00, 0x38, 0x1a, 0x18, 0x2c, 0x38, 0x08, 0x20,
   0x22, 0x10, 0x10, 0x24, 0x08, 0x49, 0x22, 0x1c,
   0x02, 0x20, 0x02, 0x1c, 0x10, 0x2c, 0x08, 0x14,
   0x22, 0x20, 0x3c, 0x10, 0x08, 0x04, 0x00, 0x38,
   0xff, 0x81, 0xfc, 0xfc, 0x3f, 0x00, 0x00, 0xfc,
   0xfc, 0xff, 0x3f, 0xff, 0xe7, 0xe7, 0xff, 0xe7,
   0xff, 0xff, 0xff, 0xff, 0x00, 0xe7, 0xe7, 0xff,
   0xe7, 0xe7, 0xef, 0xf7, 0xe7, 0xe7, 0x9a, 0xff,
   0xff, 0xf7, 0xff, 0xeb, 0xe3, 0xcd, 0xd3, 0xff,
   0xef, 0xfb, 0xff, 0xff, 0xf7, 0xff, 0xf7, 0xfd,
   0xe3, 0xe3, 0xc1, 0xe3, 0xef, 0xe3, 0xe3, 0xfb,
   0xe3, 0xf3, 0xff, 0xf7, 0xdf, 0xff, 0xfb, 0xf7,
   0xc3, 0xdd, 0xe1, 0xe3, 0xf1, 0xc1, 0xfd, 0xd3,
   0xdd, 0xe3, 0xf3, 0xdd, 0xc3, 0xdd, 0xdd, 0xe3,
   0xfd, 0xd3, 0xdd, 0xe3, 0xf7, 0xe3, 0xf7, 0xeb,
   0xdd, 0xf7, 0xc1, 0xe3, 0xdf, 0xe3, 0xff, 0x00,
   0xff, 0xc7, 0xe5, 0xe7, 0xd3, 0xc7, 0xf7, 0xdf,
   0xdd, 0xef, 0xef, 0xdb, 0xf7, 0xb6, 0xdd, 0xe3,
   0xfd, 0xdf, 0xfd, 0xe3, 0xef, 0xd3, 0xf7, 0xeb,
   0xdd, 0xdf, 0xc3, 0xef, 0xf7, 0xfb, 0xff, 0xc7,
   0x00, 0x3c, 0x03, 0x03, 0xc0, 0xff, 0xff, 0x03, // 7
   0x03, 0x00, 0xc0, 0x00, 0x18, 0x18, 0x00, 0x18,
   0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x00,
   0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c,
   0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x02, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0xff, 0xc3, 0xfc, 0xfc, 0x3f, 0x00, 0x00, 0xfc,
   0xfc, 0xff, 0x3f, 0xff, 0xe7, 0xe7, 0xff, 0xe7,
   0xff, 0xff, 0xff, 0xff, 0x00, 0xe7, 0xe7, 0xff,
   0xe7, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe3,
   0xff, 0xff, 0xf3, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xfd, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   0xff, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
}

#define  SYNC_BIT          2
#define  SYNC_PIN          PIN_C2      // pin 13
#define  CLOCK_PIN         PIN_C6      // pin 17
#define  PIXEL_PIN         PIN_C7      // pin 18
#define  SOUND_PIN         PIN_C1
#define  LED_PIN           PIN_A5

const char copyright[]="Copyright (C) 2010 Erik C. Quackenbush, Inc.\r\nNon-commercial distribution permitted\r\nVERSION 1";

#ifdef COLUMN40
   #define CONSOLECOLS   40
#else
   #define CONSOLECOLS   80
#endif
#define CONSOLEROWS   25
#define CONSOLERAM   (CONSOLEROWS*CONSOLECOLS+2) //2082  // why waste 48 bytes of RAM at the end?
#define CONSOLELAST  (CONSOLECOLS*(CONSOLEROWS-1) )
                           // so don't change it.


// These definitions depend upon the oscillator frequency.
// Note that while we can use the chip's internal 16mhz oscillator it is not
// stable. the video signal it generates wiggles around a lot.
// Use a crystal.

#ifdef CRYSTAL14
#define  HLINEPERIOD    227         // period of timer 2 which is pixels per hline divided by 4.
#define  HALFLINE       102         // during VSYNC we emit two pulses per line. this time between them in 4 pixel units
#define  HSyncHChars    8           // duration of HSYNC pulse in 4 pixel units
#define  VSyncHChars    4           // duration of VSYNC pulse in 4 pixel units
   #ifdef COLUMN40
   #define  HBackPorch     20          // horizontal backporch in 4 pixel units
   #else
   #define  HBackPorch     25
   #endif
#endif                              // change the backporch to adjust the
                                    // horizontal (overscan) position.
#ifdef CRYSTAL13
#define  HLINEPERIOD    215
#define  HALFLINE       96
#define  HSyncHChars    7   
#define  VSyncHChars    4     
#define  HBackPorch     16
#endif

#ifdef CRYSTAL16
#define  HLINEPERIOD    254
#define  HALFLINE       115
#define  HSyncHChars    8 
#define  VSyncHChars    4     
#define  HBackPorch     27   
#endif

#define  VSYNCLINE      220            // change this to adjust the top margin (overscan area)
#define  ACTIVE         CONSOLEROWS*8  // 200 active lines.
#define  FIELDLINES     262            // We're off by a half line but we're not interlaced.
#define  OVERSCANLINES  10

//
// EUSART
// we're using the EUSART as a high speed shift register to
// output pixels. Master synchronous transmit mode.
//

#define  SPEN_BIT  7
#define  SPEN      0x80  // serial port enable
#define  CSRC      0x80  // master mode/slave
#define  SYNC      0x20  // synchronous/asynchronous
#define  TXEN      0x10  // transmit/receive

#byte    RCSTA=   0xFAB
#byte    TXSTA=   0xFAC // transmit control and status
#byte    TXREG=   0xFAD
#byte    RCREG=   0xFAE
#byte    SPBRG=   0xFAF // baud rate
#byte    SPBRGH=  0xFB0 // high byte

// CCP

#define CCP1IF    2
#define CCP2IF    1

#byte CCPR1H=0xFBF
#byte CCPR1L=0xFBE

#byte CCPR2H=0xFBC
#byte CCPR2L=0xFBB

// interrupts

#byte PIE1=0xF9D
#byte PIR1=0xF9E
#byte PIR1=       0xF9E
#byte PIR2=       0xFA1 
#byte INTCON3=    0xFF0

#define INT2IF    1  // bit 1 of INTCON3 is external interrupt #2
#define INT2MASK (1<<INT2IF)
#define TMR2IF    1  // bit 1 (not bit 0)
#define TMR2IE    1  // bit 1 (not bit 0)

// PORT C latch
#byte    LATC=    0xF8B

// indirect addressing
#byte    INDF0=   0xFEF
#byte    POSTINC0=0xFEE
#byte    POSTDEC0=0xFED

#byte    FSR0H=   0xFEA
#byte    FSR0L=   0xFE9

#byte    INDF1=   0xFE7
#byte    POSTINC1=0xFE6
#byte    FSR1H=   0xFE2
#byte    FSR1L=   0xFE1


#byte    INDF2=   0xFDF
#byte    POSTINC2=0xFDE
#byte    FSR2H=   0xFDA
#byte    FSR2L=   0xFD9

#byte    PRODH=   0xFF4
#byte    PRODL=   0xFF3

// table access to ROM
#byte    TBLPTRU= 0xFF8
#byte    TBLPTRH= 0xFF7
#byte    TBLPTRL= 0xFF6
#byte    TABLAT=  0xFF5


// Slew rate control

#byte    SLRCON=  0xF78    // this PIC allows you to decrease the
#define  PORTC_SLEW  0x04  // slew rate of the output ports under software control
                       

// global

#byte    STATUS=  0xFD8
#byte    BSR=     0xFE0
#byte    PCLATH=  0xFFA


/******************** GLOBAL VARIABLES *************************/

unsigned char console[CONSOLERAM];
#locate console=0x100      // this address is hard coded because
                           // it must be at the start of a page (256).
                           // You could change it to 0x200, 0x300, etc.
                           // but not 0x180, 0x317, etc.

int conX=0,conY=0;     // position of cursor
#define CURSOR (32+128) // reverse video space cursor



int seconds=0,minutes=0,hours=0,fields=0,blankscreen=0;
unsigned int32 ticks=0; // number of horizontal video lines since powerup

//#include "ps2.c"      // PS/2 keyboard support coming soon

// this is our offset into console memory

#ifdef COLUMN40

unsigned char Dubs[256];
unsigned char Dubs2[256];
#locate Dubs=0x500
#locate Dubs2=0x600

long DubW=0x500; // just past the end of the 40 column console RAM
int DubL,DubH;
#locate DubW=0x56
#locate DubH=DubW+1
#locate DubL=DubW

long Dub2W=0x600; // one page past the end of the 40 column console RAM
int Dub2L,Dub2H;
#locate Dub2W=0x58
#locate Dub2H=Dub2W+1
#locate Dub2L=Dub2W

#endif


/*************** end of globals ***********************/

/*************** start of video interrupt code ********/

#INLINE
void UpdateClock(void)
{
   if(fields==60)
   {
      fields=0;
      seconds++;
      if(seconds==60)
      {
         seconds=0;
         minutes++;
         if(minutes==60)
         {
            minutes=0;
            hours++;
         }
      }
   }
}

unsigned int safety[0x15]; // this stores our registers during ISR
#locate safety=0x004

#INT_GLOBAL
void HScan(void)
{
   static int hloop,hcount;
   static long hline=0;       // this holds our current scanline
   static int hlinel,hlineh;
   static long charW=console;// this is our pointer into console RAM
   static int charL,charH;
   static int syncpos=0;      // positive sync pulse
   static int syncshort=0;    // two short sync pulses instead of one long one
   static int syncneg=0;
   static int activeline=0;
   #locate hline=0x50
   #locate hlineh=hline+1
   #locate hlinel=hline
   #locate charW=0x52
   #locate charH=charW+1
   #locate charL=charW
// static variables we preserve between interrupts (no need to make them global)
#asm
      // we have not enabled high priority interrupts so we don't need to
      // pad out interrupt vector with NOPs to get us to 0x018
     
      // we rely on the shadow status,w,&BSR registers to keep track of our
      // state. we don't save them manually

      MOVLB  0x00             // set Bank zero
      BTFSC    syncpos,0      // are we positive sync?
      BCF      LATC,SYNC_BIT  // yes, turn off the sync pin output_low(SYNC_PIN);
      MOVFF    FSR0L,0x0C     // saving the registers takes
      MOVFF    FSR0H,0x07     // 28 instructions
      MOVFF    FSR1L,0x08     // which is almost exactly our 4 microsecond
      MOVFF    FSR1H,0x09     // sync pulse width
      MOVFF    FSR2L,0x0A
      MOVFF    FSR2H,0x0B
      MOVFF    PCLATH,0x14
      BTFSC    syncshort,0    // short sync pulse?
      BSF      LATC,SYNC_BIT  // clear the sync pin early
      MOVFF    TABLAT,0x15
      MOVFF    TBLPTRL,0x16
      MOVFF    TBLPTRH,0x17
      MOVFF    0x00,0x0E
      MOVFF    0x01,0x0F
      MOVFF    0x02,0x10
      MOVFF    0x03,0x11
//    MOVFF    PRODL,0x12   // we don't use the multiplier
//    MOVFF    PRODH,0x13
EndSync:
      BTFSC    syncpos,0      // are we normal sync?
      BSF      LATC,SYNC_BIT  // yes- turn on the sync pin

      BTFSS    PIE1,TMR2IE    // where should this live? earlier?
      GOTO     SkipInt
      // no actual interrupt pending? that
                              // should never happen but if it does we
                              // just go quietly
scanout:     
      BTFSS    activeline,0
      BRA      notactiveline
backporch:
      MOVLW    HBackPorch   // back porch delay
      MOVWF    hcount
chardelay:
      NOP            // four instructions per half character
      DECFSZ   hcount
      BRA      chardelay

      MOVF   hlinel,W
      ANDLW  0x07
      BZ     topofline        // if((hlinel&0x07)!=0)

      MOVLW  CONSOLECOLS//
      SUBWF  charL,F
      MOVLW  0x00
      SUBWFB charH,F  // this is a 16 bit subtract so undercarry
      BRA    setloop    //else

topofline:
      NOP               // it takes 8 scan lines to draw a character. we subtract
      NOP               // charW to the beginning of the line each time except
      NOP               // when we're on the first line (top of char).
      NOP               // The NOPs are here to ensure the same number of cycles
      NOP               // until the first pixel whether we branch or not.

setloop:
      MOVLW    40          // loops per line. we do 2 chars per loop in 80 column mode
      MOVWF    hloop
     
      MOVFF    charL,FSR0L // load our offset into console character memory
      MOVFF    charH,FSR0H     
#ifdef COLUMN40
      MOVFF    Dub2H,FSR1H
      MOVFF    DubH,FSR2H
#endif
      MOVLW    0x07
      ANDWF    hlinel,w
      ADDLW    ROMFONT/256        // assumes font starts at 0x2000, add the line offset
      MOVWF    TBLPTRH
      MOVLW    0
      BSF      RCSTA,SPEN_BIT // turn on the shift register
overscan:
      MOVWF   TXREG
#ifdef COLUMN40
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      MOVWF    TXREG
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      MOVWF    TXREG
      NOP
      NOP
      NOP
      NOP
      NOP
      MOVFF    POSTINC0,TBLPTRL
      CLRF    TXREG
      NOP
//      NOP
pixels:
      TBLRD    *                   // read our font data
      MOVFF    TABLAT,FSR1L
      MOVFF    INDF2,TXREG
      DECF     hloop,F
      NOP                        // we need this NOP

      MOVFF    TABLAT,FSR2L
      MOVFF    POSTINC0,TBLPTRL // move from *FSR0++ to the Table address low byte
      MOVFF    INDF1,TXREG
      BNZ      pixels          // are we done with the line?
endpixels:
      NOP
      NOP
      NOP
      NOP
      MOVFF    INDF2,TXREG
      MOVF     POSTDEC0
      NOP
      NOP
#else
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      MOVWF    TXREG
      NOP
pixels:
      MOVFF    POSTINC0,TBLPTRL // move from *FSR0++ to the Table address low byte
      TBLRD    *                   // read our font data
      MOVFF    TABLAT,TXREG
      DECF     hloop,F
      NOP                        // we need this NOP
      MOVFF    POSTINC0,TBLPTRL // move from *FSR0++ to the Table address low byte
      TBLRD    *                 // read our font data
      MOVFF    TABLAT,TXREG
      BNZ      pixels
endpixels:
      NOP   // we need these in 80 column mode
      NOP
      NOP
#endif

      MOVFF    FSR0L,charL  // save our character position
      MOVFF    FSR0H,charH

      CLRF     RCSTA       // OK, shut off the shift register now

      BRA      postvideo
notactiveline:

      BTFSS    syncpos,0
      BRA      vsynccode
// do a back porch but do not emit video
topbackporch:
      MOVLW    HBackPorch   // back porch delay
      MOVWF    hcount
topchardelay:
      NOP            // four instructions per half character
      DECFSZ   hcount
      BRA      topchardelay

idletime:
      MOVLW    5        // number of instructions div 3- aligns our sync
      MOVWF    hcount
idleloop:
      DECFSZ   hcount
      BRA      idleloop

#ifdef COLUMN40
      NOP
      NOP
      NOP
      NOP
#endif
      MOVLW    0
      BSF      RCSTA,SPEN_BIT // turn on the shift register
      MOVWF    TXREG
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      NOP
      CLRF  RCSTA
      BRA   postvideo
vsynccode:

halfporch:
      MOVLW    HALFLINE // back porch delay
      MOVWF    hcount
halfdelay:
      NOP            // four instructions per half character
      DECFSZ   hcount
      BRA      halfdelay   

      BTFSS    syncpos,0
      BRA      vsyncold

positivesecond:
      BCF      LATC,SYNC_BIT  // yes, turn off the sync pin output_low(SYNC_PIN);
      MOVLW    VSyncHChars
      MOVWF    hcount
secondsyncpos:
      NOP
      DECFSZ    hcount
      BRA       secondsyncpos
      BSF      LATC,SYNC_BIT  // clear the sync pin early
      BRA      vsyncold


halfsyncstart:
      BSF      LATC,SYNC_BIT
      MOVLW VSyncHChars
      MOVWF hcount
halfsyncdelay:
      NOP            // four instructions per loop == 1/2 character at 80 columns (1 character at 40 columns)
      DECFSZ   hcount
      BRA   halfsyncdelay
      BCF      LATC,SYNC_BIT

vsyncold:

      BTFSS    syncneg,0
      BRA      postvideo

      BSF      LATC,SYNC_BIT
      MOVLW VSyncHChars
      MOVWF hcount
halfsyncnegdelay:
      NOP            // four instructions per loop == 1/2 character at 80 columns (1 character at 40 columns)
      DECFSZ   hcount
      BRA   halfsyncnegdelay
      BCF      LATC,SYNC_BIT

      BTFSS    syncshort,0
      BRA      postvideo
      MOVLW 2
      MOVWF hcount
delay4:
      NOP
      DECFSZ hcount,F
      BRA    delay4
      BSF    LATC,SYNC_BIT

postvideo:
#endasm

   hline++;

   if(hline>FIELDLINES)
   {
      hline=0;
   }

   // here we set some flags to determine what the next video line will
   // look like. will it have active pixels? will it have negative sync?

   syncpos=1;     // normal sync
   activeline=0;  // not active video
   syncshort=0;   // full width sync pulse
   syncneg=0;     // end with a negative sync pulse
   
   if(hline<ACTIVE)
   {
      if(blankscreen==0)activeline=1; // the next line is active video
   }
   else if(HLINE==VSYNCLINE+9)
      {
         fields++;
         ticks++;
         //if(ticks%16==0) console[CONSOLERAM-CONSOLECOLS-2]^=0x80; // blink the cursor
         UpdateClock();
         syncpos=0;
      }
      else
      {
      if(hline==ACTIVE)
      {
         charW=console;// this is 0x100 at the end of each active field we reset the pointer into character memory
         syncpos=0;
      }
      else if(hline==VSYNCLINE)     syncshort=1;
      else if(hline==VSYNCLINE+1)   syncshort=1;
      else if(hline==VSYNCLINE+2)   syncshort=1;
      else if(hline==VSYNCLINE+3)   { syncpos=0; syncneg=1; }
      else if(hline==VSYNCLINE+4)   { syncpos=0; syncneg=1; }
      else if(hline==VSYNCLINE+5)   { syncshort=1; syncneg=1; }
      else if(hline==VSYNCLINE+6)   syncshort=1;
      else if(hline==VSYNCLINE+7)   syncshort=1;

   }


   // restore our registers before returning
#asm
      BCF      PIR1,TMR2IF

SkipInt:

//#endasm
//      KBint();
//#asm
      BTFSC  PIR1,TMR2IF
      MOVFF  0x0E,0x00
      MOVFF  0x0F,0x01
      MOVFF  0x10,0x02
      MOVFF  0x11,0x03
      MOVFF  0x0C,FSR0L
      MOVFF  0x07,FSR0H
      MOVFF  0x08,FSR1L
      MOVFF  0x09,FSR1H
      MOVFF  0x0A,FSR2L
      MOVFF  0x0B,FSR2H
//      MOVFF  0x12,PRODL
//      MOVFF  0x13,PRODH
      MOVFF  0x14,PCLATH
      MOVFF  0x15,TABLAT
      MOVFF  0x16,TBLPTRL
      MOVFF  0x17,TBLPTRH
      RETFIE 1             // restore shadow registers

#endasm

}

/**************** end of video generation ***************************/

/************ start of console/ video terminal handling functions***/

void CursorOn()
{
   //console[conX+conY*CONSOLECOLS]|=0x80;
}

void CursorOff()
{
   //console[conX+conY*CONSOLECOLS]^=0x80;
}

void ScrollUp(int CR)
{
   long index;

   CursorOff();
   for(index=0;index<CONSOLERAM-CONSOLECOLS;index++)
   {
      console[index]=console[index+CONSOLECOLS];
   }

  for(index=CONSOLELAST;index<CONSOLELAST+CONSOLECOLS;index++) console[index]=32;
 
  if(CR) conX=0;
   CursorOn();
}

void ScreenChar(char symbol)
{
   CursorOff();
   switch(symbol)
   {
      case 8: // backspace
         if(ConX) ConX--;
         break;
      case '\n':// line feed
         ConY++;
         if(ConY==CONSOLEROWS)
         {
            ScrollUp(0);// no carriage return- just a line feed
            ConY--;
         }
         break;
      case '\r': // carriage return
         ConX=0;
         break;
      default:
         console[CONSOLECOLS*ConY+ConX++]=symbol;
         if(ConX>=CONSOLECOLS)
         {
            ConY++;
            if(ConY>CONSOLEROWS)
            {
               ConY=CONSOLEROWS;
               ScrollUp(1);
            }
         }
   }
   CursorOn();
}

void StringWrite(char *dest,char *source) // write a string without writing the terminating NULL
{
  int index=0;
 
  while(source[index]!=0)
  {
   if(dest<CONSOLERAM) *dest++=source[index++];
  }
}

void InitConsoleRAM1(void)
{
   long index;
 
   for(index=0;index<CONSOLERAM;index+=CONSOLECOLS) // fill the screen with a test pattern
   {
                                 //123456789-123456789-12345678-123456789-123456789-123456789-123456789-123456789-
#ifdef COLUMN40
                              // 123456789-123456xx789-123456789-123456789-
      sprintf(&console[index],"%2ld THIS IS LINE %2ld          30        40",index/CONSOLECOLS,index/CONSOLECOLS);
//      sprintf(safetemp,"%2ld THIS IS LINE %2ld          30        40",index/CONSOLECOLS,index/CONSOLECOLS);
     
#else
      sprintf(&console[index],"%2ld THIS IS LINE %2ld          30        40        50        60        70        80",index/CONSOLECOLS,index/CONSOLECOLS);
#endif     
//      sprintf(&console[index],"%2ld THIS IS LINE %2ld 123456789-123456789-123456789-123456789-123456789-1234567890",index/80-1,index/80-1);

     //this overwrites our 2000 characters by 1: it adds a null terminator past the end of the thing.
   }

   for(index=0;index<256;index++)
   {
      console[index+160]=index;
   }

   sprintf(&console[CONSOLECOLS/2-4],"EQUACK %d",CONSOLECOLS); // centered at the top of the screen
   strcpy(&console[CONSOLECOLS*12],"The quick brown fox jumped over the lazy dogs.");
}

#ifdef COLUMN40
void Init40Double(void)
{
   long index;
   int dubleft,dubright;
   const unsigned char convert[16]={0x00,0x03,0x0C,0x0F,0x30,0x33,0x3C,0x3F,0xC0,0xC3,0xCC,0xCF,0xF0,0xF3,0xFC,0xFF};


   for(index=0;index<256;index++)
   {
      dubleft=convert[index/16];
      Dubs[index]=dubleft;
   }

   for(index=0;index<256;index++)
   {
      dubright=convert[index%16];
      Dubs2[index]=dubright;
   }
}
#endif //COLUMN40


void InitConsoleRAM2(void)
{
   long index,line;
   long offset;

   for(line=1;line<CONSOLEROWS;line++)
   {
      for(index=0;index<CONSOLECOLS;index+=4)
      {
         offset=index+(line*CONSOLECOLS);
//         console[offset]='@'+line;
         console[offset]='A';
         console[offset+1]='B';
         console[offset+2]='C';
         console[offset+3]='D';
         
      }
   }
   
   
   strcpy(&console[CONSOLECOLS*10],"This is a test of the emergency broadcasting system.");
   strcpy(&console[CONSOLECOLS*14],"AND NOW FOR SOMETHING COMPLETELY DIFFERENT.");
   
}

void InvertScreen(void)
{
   long index;
   
   for(index=CONSOLECOLS;index<CONSOLERAM;index++)
   {
      console[index]^=0x80;
   }
}

void EraseConsoleRAM(void)
{
   long index;
   
   for(index=0;index<CONSOLERAM;index++)
   {
      console[index]=0;
   }
}

void InitSystem(void)
{
 EraseConsoleRAM();
 
 InitConsoleRAM1();

#ifdef COLUMN40
   Init40Double();
#endif

   output_drive(PIXEL_PIN); // this is our video output
   output_drive(CLOCK_PIN); // we could shut this off for RFU.

   SLRCON=0;      //PORTC_SLEW;   // decrease the slew rate of port C for nicer pixels
   SPBRG=0;       // we always set the baud rate to 0, one pixel per Tcy.
   SPBRGH=0;      // in 40 column mode we double our pixels
   TXSTA=CSRC | SYNC | TXEN; // master synchronous transmit mode
   
   output_high(SYNC_PIN); // sync pin goes LOW to drop below IRE 0.3 volts

   setup_timer_2(T2_DIV_BY_4,HLINEPERIOD,1);

/*
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
   setup_ccp2(CCP_COMPARE_RESET_TIMER ); // note that we do not actually enable the interrupt for this.

#define BAUDDIV   1491

   CCPR2H=BAUDDIV/256;
   CCPR2L=BAUDDIV%256;
*/
   enable_interrupts(INT_TIMER2);   // horizontal sync interrupt
   enable_interrupts(GLOBAL);
}


void delay_fields(long interval) // delay a number of vertical blank intervals, 16.7 milliseconds each.
{
   int32 wait;
   
   // If the system runs for 2.25 years this function
   // could hang if called at exactly the wrong time.
   //
   // This function it has an inherent error because the first field will be a partial field
   // which could last between 1 and 261 scan lines.
   //
   wait=ticks+interval;
   for(;;)
   {
      if(ticks>=wait) return;
   }
}

//const char mystring[]={"blah"};


void ScrollOff(void)
{
   int index;
   
   for(index=0;index<25;index++)
   {
      ScrollUp(1);

#ifdef COLUMN40
      sprintf(&console[CONSOLELAST],"Elapsed time %d:%02d:%02d.%02d 56789-123456789-",hours,minutes,seconds,fields);
#else
      sprintf(&console[CONSOLELAST],"Elapsed time %d:%02d:%02d.%02d 56789-123456789-123456789-12345789-123456789-123456789-",hours,minutes,seconds,fields);
#endif
      delay_fields(30); //
   }

}

void Beep(void)
{
   long index;
   
   for(index=0;index<250;index++)
   {
      output_low(SOUND_PIN);
      delay_us(500);
      output_high(SOUND_PIN);
      delay_us(500);
   }
}

void Typewriter(void)
{
   int symbol;
   for(;;)
   {
      if(kbhit())
      {
         blankscreen=1;
//         disable_interrupts(GLOBAL);
         symbol=getc();
         console[CONSOLELAST+ConX++]=symbol&0x7F;
         if(ConX>=CONSOLECOLS)
         {
            ScrollUp(1);
         }
         blankscreen=0;
      }
   }
}

#define RX_PIN PIN_B1

void TypeReader(void)
{
   char symbol;
   int index;
   char hexit[3];

   while(input(RX_PIN)==0) ; // wait for idle
   for(;;)
   {
      symbol=0;
     
      while(input(RX_PIN)) ;   // wait for start bit falling edge
      PIR2^=CCP2IF; // clear the CCP2 interrupt flag
     
      for(index=0;index<8;index++)
      {
         while((PIR2 & CCP2IF) ==0) ; // wait for a CCP2 event
         PIR2^=CCP2IF; // clear the CCP2 event
         if(input(RX_PIN))
         {
            symbol|=0x80;
         }
         symbol>>=1;
      }
         while((PIR2 & CCP2IF) ==0) ; // wait for a CCP2 event
         PIR2^=CCP2IF; // clear the CCP2 event (stop bit)
     
      sprintf(hexit,"%02X",symbol);
      ScreenChar(hexit[0]);
      ScreenChar(hexit[1]);
      ScreenChar(symbol);
      ScreenChar(' ');
   }
}


//---------------Main() entry point--------------------------------
void main( void )
{
   char *right;
   right=copyright;

   output_high(LED_PIN);

   Beep();

   InitSystem();
// InitKeyboard();
// KeyRead();
//   ScrollOff();
   
   for(;;) ; // just wait
}

Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> Code Library All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group