equack
Joined: 21 Sep 2009 Posts: 21
|
80 column video display on your HDTV (480i) |
Posted: Sun Sep 05, 2010 4:53 pm |
|
|
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
}
|
|
|