⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 video.htm

📁 单片机VIDEO源代码及说明.其实我也不知道里面是做什么用的.我只是拿来学C编程的.
💻 HTM
📖 第 1 页 / 共 2 页
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<!-- saved from url=(0053)http://instruct1.cit.cornell.edu/courses/ee476/video/ -->
<HTML><HEAD><TITLE>Video</TITLE>
<META http-equiv=Content-Type content="text/html; charset=iso-8859-1">
<META content="MSHTML 6.00.2800.1400" name=GENERATOR></HEAD>
<BODY bgColor=#ffffff>
<P align=center><FONT size=+2>Cornell University<BR>Electrical Engineering 476 
<BR>Video Generation<BR></FONT><FONT size=+2>with AVR 
microcontrollers</FONT></P>
<P align=left><B>Introduction</B></P>
<P align=left>A television (TV) monitor is a good example of a device which 
needs hard-realtime control. The TV is controlled by periodic synchronization 
(sync) pulses. If a sync pulse is late, the TV picture quality suffers. So a 
late calculation is worth nothing. The AVR mcus are fast enough to generate 
black and white (but not color) sync and image content, as long as you 
obsessively pay attention to the time required for every operation.</P>
<P align=left>Small TV monitors also seem to be one of the cheapest graphics 
devices you can buy, include audio amplifiers and speakers, and are designed to 
be almost bullet-proof. A perfect lab device. </P>
<P align=left><B>Video Generation</B></P>
<P align=left>There are several very good references for understanding how TVs 
are controlled by a pulse sequence. I particularly liked the Stanford EE281 <A 
href="http://www.stanford.edu/class/ee281/handouts/lab4.pdf">Handout #7 
</A>entitled "TV paint". Also very useful were <A 
href="http://www.rickard.gunee.com/projects/">Software generated video</A>, by 
Rickard Gun閑, <A href="http://www.williamson-labs.com/480_tv.htm">Video 
Tutorials</A> by Glen A. Williamson, and <A 
href="http://www.geocities.com/CapeCanaveral/Launchpad/3632/dvm.htm">various 
excellent projects</A> by Alberto Riccibitti.</P>
<P align=left>The goal is to generate non-interlaced, black and white video, 
with enough image content to be interesting as a graphics device. The software 
described here implements an NTSC-rate, non-interlaced, video signal. For ease 
of teaching, I wanted as much of the code as possible to be in C, with litttle 
or no assembler. The first version of the code is entirely in CodeVision C and 
generates a 64 (horizontal) by 100 (vertical) bit map. The CodeVision compiler 
controls (in the <CODE>Project:Configure... </CODE>menu) must be set to default 
to:</P>
<UL>
  <LI><CODE>signed char</CODE> 
  <LI>a data stack size of &lt;=100 
  <LI>optimize for speed. </LI></UL>
<P align=left>The "video engine" consists of two parts:</P>
<UL>
  <LI>Sync generation 
  <LI>Image generation </LI></UL>
<P align=left>These parts are described in the next two paragraphs.</P>
<P align=left><U>Sync Generation</U></P>
<P align=left>Since uniform pulses are required every 63.5 microseconds to cause 
horizontal sync, the natural choice is to run timer 1 at full speed (8 MHz), and 
interrupt on compare match after 508 timer ticks. However, if you use 63.625 
microseconds (509 timer ticks), then each frame is exactly 1/60 of a second, so 
building software timers is easier. If you just enter the ISR directly from 
running code, the time to enter can vary by a couple of machine cycles, which is 
several 100 nanoseconds. This variability causes unacceptable visual jitter on 
the TV. The solution, originally used by Alberto Riccibitti is to put the mcu to 
sleep just before the interrupt will occur. The version of the code shown below 
puts the sleep command in a while loop which is executed once per horizontal 
line for lines 1 to 230 (the image content). Between line 231 and line 262, the 
main loop executes once per frame functions, such as raster updates. During this 
interval, a few sleep commands are scattered through the code to keep the sync 
accurate. The ISR code which generates the sync is shown below. All of the logic 
for counting lines, inverting the horizontal sync to make vertical sync, and 
running the i/o port are contained within the 5 microsecond pulse time. This ISR 
must be entered from the mcu "sleep" state to reduce jitter.</P>
<P align=left><PRE>interrupt [TIM1_COMPA] void t1_cmpA(void)  
begin 
  //start the Horizontal sync pulse    
  PORTD = syncON;     
  //count timer 0 at 1/usec
  TCNT0=0;
  //update the curent scanline number
  LineCount ++ ;   
  //begin inverted synch after line 247 to make vertical sync
  //note that at least 3 lines before this must be left at BLACK
  //level for the TV to lock on properly
  if (LineCount==248)
  begin 
    syncON = 0b00100000;
    syncOFF = 0;
  end
  //back to regular sync after line 250 to make the
  //required 10 blank lines before starting a new frame
  if (LineCount==251)	
  begin
    syncON = 0;
    syncOFF = 0b00100000;
  end  
  //start new frame after line 262
  if (LineCount==263) 
  begin
     LineCount = 1;
  end 
  //end sync pulse
  PORTD = syncOFF;  
end  
</PRE>
<P><U>Image Generation</U></P>
<P align=left>The displayed image is stored in an 800 byte array in the RAM of 
the Mega163. The image bits are packed so than 8 displayed bits are stored in 
each byte. This gives a resolution of 6400 total addressable points. To speed up 
dot generation (and produce a tighter raster) the eight array bytes for one line 
are preloaded into registers. Each bit can then be put on the screen in 4 
machine cycles. All loops must be unrolled to keep the rate constant during one 
line. There are a set of variables which are declared which must be the very 
first variables to be declared. The compiler puts these in registers. The code 
depends on register allocation for speed. <FONT color=#ff0000>Note that 
CodeVision version 1.23.7 changes register allocations.</FONT> A new version 
which corrects the complier dependencies is in the the <I>Optimization and Bug 
Fixes</I> section near the bottom of this page. Also near the bottom of the page 
is an improved <FONT color=#ff0000>Mega32 version</FONT>.</P><PRE>char syncON, syncOFF, v1, v2, v3, v4, v5, v6, v7, v8; 
int i,LineCount;
</PRE>
<P align=left>The actual image is generated by copying RAM into registers v1-v8 
at the beginning of a line, then blasting them out of registers as fast as 
possible to make a dense raster. The following while loop waits for each sync 
pulse in sleep mode, then processes one line.</P><PRE>while(1)
  begin
  
    //precompute pixel index for next line
    if (LineCount&lt;ScreenBot &amp;&amp; LineCount&gt;=ScreenTop) 
    begin 
       //left-shift 3 would mean individual lines
       // &lt;&lt; 2 means line-double the pixels so that they are
	   //about as tall as they are wide.
	   //The 0xfff8 constant clips the lower 3 bits so that the
	   //byte address within a line can be added after the sleep.
       i=(LineCount-ScreenTop)&lt;&lt; 2 &amp; 0xfff8; 
       
   end
   
   //stall here until next line starts
    //sleep enable; mode=idle  
    //use sleep to make entry into sync ISR uniform time  
       
    #asm ("sleep"); 
     
    //The code here to executes once/line.
    //--Usable lines 1 to about 240, but
	// the raster is written on lines 30 to 230.
	// Any other processing must occur on lines 1-30 or 231-262.
    
    if (LineCount&lt;ScreenBot &amp;&amp; LineCount&gt;ScreenTop) 
    begin
      //load the pixels for one line into registers for speed
      v1 = screen[i]; 
      v2 = screen[i+1];
      v3 = screen[i+2];
      v4 = screen[i+3]; 
      v5 = screen[i+4]; 
      v6 = screen[i+5];
      v7 = screen[i+6];
      v8 = screen[i+7];
        
      //now blast the pixels out to the screen
        PORTD.6=v1 &amp; 0b10000000; 
        PORTD.6=v1 &amp; 0b01000000;
        PORTD.6=v1 &amp; 0b00100000; 
        PORTD.6=v1 &amp; 0b00010000;
        PORTD.6=v1 &amp; 0b00001000; 
        PORTD.6=v1 &amp; 0b00000100;
        PORTD.6=v1 &amp; 0b00000010; 
        PORTD.6=v1 &amp; 0b00000001;
        
        PORTD.6=v2 &amp; 0b10000000; 
        PORTD.6=v2 &amp; 0b01000000;
        PORTD.6=v2 &amp; 0b00100000; 
        PORTD.6=v2 &amp; 0b00010000;
        PORTD.6=v2 &amp; 0b00001000; 
        PORTD.6=v2 &amp; 0b00000100;
        PORTD.6=v2 &amp; 0b00000010; 
        PORTD.6=v2 &amp; 0b00000001; 
        
        PORTD.6=v3 &amp; 0b10000000; 
        PORTD.6=v3 &amp; 0b01000000;
        PORTD.6=v3 &amp; 0b00100000; 
        PORTD.6=v3 &amp; 0b00010000;
        PORTD.6=v3 &amp; 0b00001000; 
        PORTD.6=v3 &amp; 0b00000100;
        PORTD.6=v3 &amp; 0b00000010; 
        PORTD.6=v3 &amp; 0b00000001; 
            
        PORTD.6=v4 &amp; 0b10000000; 
        PORTD.6=v4 &amp; 0b01000000;
        PORTD.6=v4 &amp; 0b00100000; 
        PORTD.6=v4 &amp; 0b00010000;
        PORTD.6=v4 &amp; 0b00001000; 
        PORTD.6=v4 &amp; 0b00000100;
        PORTD.6=v4 &amp; 0b00000010; 
        PORTD.6=v4 &amp; 0b00000001; 
             
        PORTD.6=v5 &amp; 0b10000000; 
        PORTD.6=v5 &amp; 0b01000000;
        PORTD.6=v5 &amp; 0b00100000; 
        PORTD.6=v5 &amp; 0b00010000;
        PORTD.6=v5 &amp; 0b00001000; 
        PORTD.6=v5 &amp; 0b00000100;
        PORTD.6=v5 &amp; 0b00000010; 
        PORTD.6=v5 &amp; 0b00000001;
             
        PORTD.6=v6 &amp; 0b10000000; 
        PORTD.6=v6 &amp; 0b01000000;
        PORTD.6=v6 &amp; 0b00100000; 
        PORTD.6=v6 &amp; 0b00010000;
        PORTD.6=v6 &amp; 0b00001000; 
        PORTD.6=v6 &amp; 0b00000100;
        PORTD.6=v6 &amp; 0b00000010; 
        PORTD.6=v6 &amp; 0b00000001; 
            
        PORTD.6=v7 &amp; 0b10000000; 
        PORTD.6=v7 &amp; 0b01000000;
        PORTD.6=v7 &amp; 0b00100000; 
        PORTD.6=v7 &amp; 0b00010000;
        PORTD.6=v7 &amp; 0b00001000; 
        PORTD.6=v7 &amp; 0b00000100;
        PORTD.6=v7 &amp; 0b00000010; 
        PORTD.6=v7 &amp; 0b00000001;
             
        PORTD.6=v8 &amp; 0b10000000; 
        PORTD.6=v8 &amp; 0b01000000;
        PORTD.6=v8 &amp; 0b00100000; 
        PORTD.6=v8 &amp; 0b00010000;
        PORTD.6=v8 &amp; 0b00001000; 
        PORTD.6=v8 &amp; 0b00000100;
        PORTD.6=v8 &amp; 0b00000010; 
        PORTD.6=v8 &amp; 0b00000001;  
      
        PORTD.6=0 ; 
    end

</PRE>
<P align=left>The raster generation code needs to run fast to get good pixel 
density. Once the TV gets to line 231, there is some extra time to do 
computations, interact with users, or update state. See the code below for 
examples.</P>
<P align=left><B>Video DAC</B></P>
<P align=left>Two bits of a port are used to generate three video levels:</P>
<UL>
  <LI>Sync level = 0 volts 
  <LI>Black level = 0.3 
  <LI>White level = 1.0 </LI></UL>
<P>The circuit is shown below.</P>
<P><IMG height=209 src="Video.files/VideoDAC.png" width=354></P>
<P align=left><B>Graphics primitives</B></P>
<P align=left>There are a few primitive operations which are nice to have:</P>
<UL>
  <LI>Draw/erase/invert a point 
  <LI>Detect a point intensity 
  <LI>Draw text 
  <LI>Draw lines </LI></UL>
<P>The point, line and detection graphics primitives are implemented in the <A 
href="http://instruct1.cit.cornell.edu/courses/ee476/video/videoKal.c">fourth 
example code</A> below. The fifth code example has improved character 
generation. I implemented three character generators. The 8x8 and 3x5 pixel 
character generators are very fast, but have limited placement of characters in 
the x-direction. The 5x7 character generator has pixel-accurate placement, but 
is much slower.</P>
<P>All drawing must be done during TV scan lines 230-260 and 1-30 to avoid 
visual artifacts (flickering). Drawing is done by writing bits (pixels) into the 
main <CODE>screen</CODE> array, while the array is not being displayed.</P>
<P><U>Draw a point</U></P>
<P>The point code is a function which takes three parameters: an x coordinate in 
the range of 0-63, a y coordinate in the range of 0-99, and a color given as 0 
means black, 1 means white, and 2 means invert the pixel. The pixels are packed 
into bytes, so there is an addressing step which looks strange. There are 8 
pixels/byte and 8 bytes/line. Thus, the x coordinate has to be divided by 8 to 
get the byte number within a line and the y coordinate has to be multiplied by 8 
to get the appropriate group of 8 bytes corresponding to a line. The 
<CODE>1&lt;&lt;(7-(x &amp; 0x7))</CODE> construction isolates (within the byte) 
which bit must be set/cleared.</P><PRE>//plot one point 
//at x,y with color 1=white 0=black 2=invert
void video_pt((char x, char y, char c)
begin
	//The following odd construction 
  	//sets/clears exactly one bit at the x,y location
	i=((int)x &gt;&gt; 3) + ((int)y &lt;&lt; 3) ;  
 	if (c==1) 	screen[i] = screen[i] | 1&lt;&lt;(7-(x &amp; 0x7)); 
  	if (c==0)	screen[i] = screen[i] &amp; ~(1&lt;&lt;(7-(x &amp; 0x7))); 
  	if (c==2)	screen[i] = screen[i] ^ (1&lt;&lt;(7-(x &amp; 0x7)));
end
</PRE>
<P><U>Read back a point </U>
<P>
<P align=left>The read back code is a function which takes an x coordinate in 
the range of 0-63, a y coordinate in the range of 0-99, and returns a character 
with value 1 if the pixel is white and 0 if it is black.</P><PRE>//return the value of one point 
//at x,y with color 1=white 0=black 2=invert
char video_set((char x, char y)
begin
	//The following construction 
  	//detects exactly one bit at the x,y location
	i=((int)x &gt;&gt; 3) + ((int)y &lt;&lt; 3) ;   
	return ( screen[i] &amp; 1&lt;&lt;(7-(x &amp; 0x7)));   	
end
</PRE>
<P>
<P align=left><U>Draw a line</U></P>
<P align=left>The line drawing code takes two (x,y) coordinates and connects 
them with a line drawn with a Breshenham algorithm. The Breshenham algorithm 
avoids all multiplys and divides (except by 2), so it is fast on a small 
processor. It also ensures a dense line with points in adjacent pixels. The 
CodeVision compiler control panel must set to allow signed <B>char</B>s.</P><PRE>//plot a line 
//at x1,y1 to x2,y2 with color 1=white 0=black 2=invert 
//NOTE: this function requires signed chars   
//Code is from David Rodgers,
//"Procedural Elements of Computer Graphics",1985
void video_line(char x1, char y1, char x2, char y2, char c)
begin
	char x,y,dx,dy,e,j, temp;
	char s1,s2, xchange;
	x = x1;
	y = y1;
	dx = cabs(x2-x1);
	dy = cabs(y2-y1);
	s1 = csign(x2-x1);
	s2 = csign(y2-y1);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -