标题: Pico OSD, a PIC video superimposer [打印本页] 作者: star 时间: 2012-8-21 15:15 标题: Pico OSD, a PIC video superimposer 本帖最后由 star 于 2012-8-21 15:17 编辑
/*
***************************************************************
****************
* pico OSD : simple PIC OSD PAL video superimposer
***************************************************************
****************
*
* This program shows how to superimpose a text on a PAL composite video signal
* with a PIC and only 4 resistors.
*
* source code for mikro C compiler V7.0.0.3
* feel free to use this code at your own risks
*
* target : PIC12F683 @25MHz
* HS clock, no watchdog.
*
*
*
*
***************************************************************
****************
*/
#include "built_in.h"
#include "fonts.h"
/*************************
* CONSTANTS DEFINITIONS
*************************/
/*
* CVREF = (VR<3:0>/24) × VDD
* PAL CLIP LEVEL : 0.625 V
*/
#define CLIP_VOLTAGE 625 // in mV
#define CLIP_LEVEL (CLIP_VOLTAGE * 24 / 5000) // for VR bits CMCON<3:0>
#define OUT GPIO.F2 // video output
#define HSYMBOLS 11 // number of horizontal symbols
#define FONTH 7 // pixel font height
#define T0FREQ (Clock_kHz() * 1000 / 4) // number of TMR0 ticks
in one second
#define T028us (unsigned char)(T0FREQ * 0.000028) // number of TMR0
ticks in 28 µs
/************************
* PSEUDO FUNCTIONS
************************/
/*
* this macro definition sets message display from line l, color c (1=white, 0=black),
font size s
*/
#define setMsg(l, c, s) vStart = l ; vStop = vStart + FONTH * s ; lHeight = s ; OUT = c
/*
* set output depending on bit number x of the current position indexed to by FSR
* Note : if you use a 20 Mhz crystal instead of a 25 Mhz crystal, remove NOP
*/
#define SETPIXEL(x) asm { BTFSC INDF, x ; skip next intruction if bit x is
set } asm { BCF TRISIO, 2 ; set GP2 as output and
superimpose pixel } asm { NOP ; no operation
(enlarges pixel) } asm { BSF TRISIO, 2 ; set
GP2 as high Z input (no pixel superimposed) }
/*
* write the 5 bits of the current character in the current line,
* then increment FSR to point to the next character
*/
#define WRITECHAR() SETPIXEL(0) SETPIXEL(1)
SETPIXEL(2) SETPIXEL(3)
SETPIXEL(4) FSR++
/***********************
* VARIABLES DEFINITIONS
***********************/
/*
* demo message to be scrolled
*/
const
unsigned
char
scroll_msg[]
=
"Scroll text : pico OSD is scrolling this very long message
on your screen, and then will rewind it very fast. Ready ? Now !"
;
unsigned
char
line
=
0
;
// current line number
unsigned
char
ctrLine
=
0
;
// counter of line to be repeated (to make big sized fonts)
unsigned
char
bm[FONTH][HSYMBOLS]
absolute
0x23
;
// bitmap to be superimposed to video
unsigned
char
display
absolute
0xa0
;
// address of data to be displayed, ensure it is in the
same memory bank as TRISIO
unsigned
char
msg[HSYMBOLS
+
1]
;
// dynamic string to be displayed
volatile
unsigned
char
vStart
=
255
absolute
0x20,
// vertical start : first line to be superimposed
vStop
absolute
0x21,
// vertical stop : last line to be superimposed
lHeight
absolute
0x22
;
// line height : number of time the same line must be
displayed
unsigned
int
frm
;
// frame counter
unsigned
char
sec
=
0,
// RTC seconds,
mn
=
0,
// minutes,
hours
=
0
;
// hours
/****************************
* Interrupt Service routine
****************************/
/*
* since no other interrupts but CMIE are enabled, no need to check this flag.
*/
void
interrupt()
{
if(CMCON0.COUT)
// if comparator output changed to high
{
if((line
>=
vStart)
&&
(line
<
vStop))
// if we are in display window
{
FSR
=
display
;
// load FSR with current bitmap address
ctrLine++
;
// increment same line counter
if(ctrLine
==
lHeight)
// do we have to change ?
{
display
+=
HSYMBOLS
;
// yes, change display location to next bitmap row
ctrLine
=
0
;
// reset counter
}
TMR0
=
0
;
// keep timer 0 clear to prevent false start of frame
detection
}
else
if(TMR0
>=
T028us)
// if, check low pulse duration
{
line
=
0
;
// we are in a new frame sync, reset line counter
ctrLine
=
0
;
// reset same line counter
display
=
(char)bm
;
// points to the bitmap start
}
}
else
// compatator output changed to low
{
TMR0
=
0
;
// clear timer 0
if(line
<
254)
// if we can
{
line++
;
// increment line counter (only first 255 lines are used)
}
/*
* Real Time Clock
*/
frm++
;
// increment frames counter
if(frm
==
625
*
25)
// PAL is made of 25 frames of 625 lines per second
{
frm
=
0
;
// clear counter
sec++
;
// increment seconds
if(sec
>=
60)
// check for seconds rollover
{
sec
=
0
;
// clear seconds
mn++
;
// increment minutes
if(mn
>=
60)
// check for minutes rollover
{
mn
=
0
;
// clear minutes
hours++
;
// increment hours
}
}
}
}
PIR1.CMIF
=
0
;
// clear comparator interrupt flag
}
/*
* update display bitmap with character c at column pos
*/
void
updatechar(unsigned
char
c,
unsigned
char
pos)
{
unsigned
char
py,
col
;
/*
* check for under/overflow
*/
if(c
<
32)
c
=
32
;
else
if(c
>
128)
c
=
32
;
else
c
-=
32
;
// control characters under space in ASCII table are not
displayed
for(col
=
0
;
col
<
5
;
col++)
// for each character columns
{
unsigned
char
fnt
=
fonts[c
*
5
+
col]
;
// get bitmap font
unsigned
char
mask
=
1
<<
col
;
// build bitmap mask
for(py
=
0
;
py
<
FONTH
;
py++)
// for each character lines
{
if(fnt.F0)
{
bm[py][pos]
|=
mask
;
// set pixel
}
else
{
bm[py][pos]
&=
~mask
;
// clear pixel
}
fnt
>>=
1
;
// shift bitmap mask
}
}
}
/*
* update display message with constant string pointed to by m with offset o within
the string
*/
void
updateMsg(const
char
*m,
unsigned
char
o)
{
unsigned
char
n,
l,
c
;
/*
* get string length
*/
l
=
0
;
while(m[l++])
;
for(n
=
0
;
n
<
HSYMBOLS
;
n++)
// for all symbols
{
c
=
m[o++]
;
// get character
o
%=
l
;
// circularize string
updateChar(c,
n)
;
// put character to display bitmap
}
}
/*
* 10 ms delay, c times
*/
void
delay10ms(unsigned
char
c)
{
do
{
Delay_ms(10)
;
}
while(--c)
;
}
/*
* program entry
*/
void
main()
{
unsigned
char
i
;
GPIO
=
0b100
;
// GP2 is set to one be default (text is superimposed in
white)
TRISIO
=
0b110
;
// GP1 is video input, GP2 is video output (set to high Z
first)
CMCON0
=
0b10100
;
// comparator module : no output, uses internal voltage
reference
VRCON
=
0b10100000
|
CLIP_LEVEL
;
// voltage reference module : inverted output, low level
ANSEL
=
0b10
;
// all pins but GP1 (comparator input) as digital