转载请注明出处。作者:四极管。广西师范大学 电子工程学院大学生科技创新基地 邮箱: [email protected]。
原文地址:http://blog.csdn.net/yangxingbo0311/article/details/7201097
这个代码是参考基地当时一牛人来做的··后面还有在C++builder上的实现··很炫的哦··很值得借鉴
------------------------------------------------------------------------------------------------ 程序说明:程序由12864的串行模式修改为并行模式,主要是为了提高12864的速度。在原有的 汉字、字符显示功能,绘图功能的基础上,增加了多个功能函数,以完善12864显示各种图象数据的 功能
------------------------------------------------------------------------------------------------ 1.汉字字幕的左移动功能,函数名称为: dispstr_12864_move(uchar x,uchar y1,uchar y2,uchar *pstr1,uint word_number,uint speed) 使用说明:x为文字在屏幕上地址定位横坐标;y1为第(1~4)行文字定位地址坐标;y2为第(1~4)行文字定位地 址坐标;*pstr1为第一行文字组;*pstr2为第二行文字组 ;word_number 移动显示的文字数目;speed 为字幕移 动的速度。该函数的功能大家可以根据自己的需要修改和完善,本函数中只提供基本的移动算法。 -------------------------------------------------------------------------------------------------- 2.12864全屏区域单点描点函数,函数名称为: plot_12864(uchar x,uchar y,uchar *buf),给定一个坐标(x,y),即可在屏幕上对应的坐标显示出一个点 其中,x取值范围为:1~128 y的取值范围为:1~64 !!!注意!!!不可超出规定的取值范围,否则屏幕 有可能不能正常显示,原因是数据溢出缓冲区。 -------------------------------------------------------------------------------------------------- 3.12864全屏区域多点镜像描点函数,函数名称为: mirror_point_12864(uchar center,uchar x,uchar h,uchar *buf)center为对称轴的坐标,即屏幕上对应 的y坐标x为要镜像描点的横坐标,h为镜像描点的高度,buf为数据存放的目标缓存区。此函数主要是用在音乐频 谱的显示上。 ---------------------------------------------------------------------------------------------------- 4.任意两点间画直线的函数,函数名为: draw_Line(uchar x0,uchar y0,uchar x1,uchar y1),采用布兰森汉姆(Bresenham)算法画线,给定两个点的 坐标(x0,y0),(x1,y1)就能实现在这两点间画出直线。辅助实现该函数功能的附属函数有: ①求两个数的绝对值|a-b|的函数abs(uchar a,uchar b) ②画垂直线的函数subsection_point_12864(uchar x,uchar center,uchar h,uchar *buf) ③画横线的函数line_piont(uchar x0,uchar y0,uchar x1,uchar *buf) ---------------------------------------------------------------------------------------------------- 5.画圆函数,函数名为: draw_circle(uchar x0,uchar y0,uchar r),采用布兰森汉姆(Bresenham)算法画圆,先画1/8个圆,然后用对称 方法画出剩下的部分。(x0,y0)为圆心的坐标,x0:1~128 y0:1~64 r为圆的半径:1~31。 ----------------------------------------------------------------------------------------------------- ************************************************************************************************** *************************************************************************************************/ //*******头文件部分********// #include "avr/io.h" #include <util/delay.h> #include "math.h" #define data_port PORTB #define RS_1() {DDRC |= (1<<7);nop();PORTC |= (1<<7);} #define RW_1() {DDRC |= (1<<6);nop();PORTC |= (1<<6);} #define EN_1() {DDRC |= (1<<5);nop();PORTC |= (1<<5);} #define RS_0() {DDRC |= (1<<7);nop();PORTC &= ~(1<<7);} #define RW_0() {DDRC |= (1<<6);nop();PORTC &= ~(1<<6);} #define EN_0() {DDRC |= (1<<5);nop();PORTC &= ~(1<<5);} #define set_output() DDRB = 0XFF #define set_input() DDRB = 0X00 #define port_lcd PINB #define nop() asm("nop") #define uchar unsigned char #define uint unsigned int uchar music[1024]={}; uchar magic[16]={}; //********************************************************************** void delay_100ms(uint i) { uint k; for (k=0;k<i;k++) { _delay_ms(10); _delay_ms(10); _delay_ms(10); _delay_ms(10); _delay_ms(10); _delay_ms(10); _delay_ms(10); _delay_ms(10); _delay_ms(10); _delay_ms(10); } } //********************************************************************** //*************函数部分***************/ /* 名字:busywait_12864() */ /* 功能:检测RT12864M是否忙 */ /* 局部变量:无 */ /* 全局变量:无 */ /* 返回值: 无 */ //************************************/ void busywait_12864(void) { uchar bf=0; loop:RS_0(); RW_1(); EN_1(); set_input(); _delay_us(6); bf = port_lcd; EN_0(); if(bf&0x80)goto loop; set_output(); } //*************函数部分***************/ /* 名字:writecomm_12864() */ /* 功能:写命令进RT12864M */ /* 局部变量:command */ /* 全局变量:无 */ /* 返回值: 无 */ //************************************/ void writecomm_12864(uchar command) { busywait_12864(); set_output(); RS_0(); RW_0(); data_port = command; EN_1(); EN_0(); } //*************函数部分***************/ /* 名字:writedata_12864() */ /* 功能:写数据写进RT12864M */ /* 局部变量:wrdata */ /* 全局变量:无 */ /* 返回值: 无 */ //************************************/ void writedata_12864(uchar wrdata) { busywait_12864(); set_output(); RS_1(); RW_0(); data_port = wrdata; EN_1(); EN_0(); } //*************函数部分***************/ /* 名字:Init_12864() */ /* 功能:初始化RT12864M */ /* 局部变量:无 */ /* 全局变量:无 */ /* 返回值: 无 */ //************************************/ void Init_12864(void) { writecomm_12864(0x30);//功能设置 8位数据,基本指令 _delay_ms(1); writecomm_12864(0x0c);//显示状态 ON,游标OFF,反白OFF _delay_ms(1); writecomm_12864(0x01);//清除显示 _delay_ms(1); writecomm_12864(0x02);//地址归位 } //*************函数部分***************/ /* 名字:locatexy_12864() */ /* 功能:定位显示地址 */ /* 局部变量:x,y */ /* 全局变量:无 */ /* 返回值: 无 */ //************************************/ void locatexy_12864(uchar x,uchar y) { uchar addr=0; switch(y) { case 0:addr=0x80+x;break; case 1:addr=0x90+x;break; case 2:addr=0x88+x;break; case 3:addr=0x98+x;break; default:break; } writecomm_12864(addr); } //*************函数部分***************/ /* 名字:distwochar_12864() */ /* 功能:显示两个字符即一个汉字 */ /* 局部变量:x,y,char1,char2 */ /* 全局变量:无 */ /* 返回值: 无 */ //************************************/ void distwochar_12864(uchar x,uchar y,uchar char1,uchar char2) { locatexy_12864(x,y); writedata_12864(char1); writedata_12864(char2); } //*************函数部分***************/ /* 名字:dispstr_12864() */ /* 功能:显示汉字字组 */ /* 局部变量:x,y,*pstr */ /* 全局变量:无 */ /* 返回值: 无 */ //************************************/ void dispstr_12864(uchar x,uchar y,uchar *pstr) { uint i,t=0; while(pstr[t]!='\0')t++; for(i=0;i<t;i++) { distwochar_12864(x,y,pstr[i],pstr[i+1]); i+=1; x+=1; if(x==8) { x=0; y++; if(y==4)y=0; } } } /*=========================================*/ /* 函数:drawpic(uchar *pdraw); */ /* 功能描述:画图形 */ /* 参数接口:pdraw,是存放图形数据的表 */ /*=========================================*/ void drawpic_12864(uchar *pdraw) { uint x,y; long uint k=0; uchar yaddr=0x80; //writecomm_12864(0x30);//功能设置---8BIT控制界面,绘图显示OFF writecomm_12864(0x34);//功能设置---8BIT控制界面,扩充指令集 for(y=0;y<32;y++) { writecomm_12864(yaddr++);//设置绘图区的Y地址坐标 writecomm_12864(0x80); //设置绘图区的X地址坐标 for(x=0;x<8;x++) { writedata_12864(pdraw[k++]); writedata_12864(pdraw[k++]); } } yaddr=0x80; for(y=0;y<32;y++) { writecomm_12864(yaddr++);//设置绘图区的Y地址坐标 writecomm_12864(0x88); //设置绘图区的X地址坐标 for(x=0;x<8;x++) { writedata_12864(pdraw[k++]); writedata_12864(pdraw[k++]); } } // writecomm_12864(0x32);//功能设置---8BIT控制界面,绘图显示ON writecomm_12864(0x36);//功能设置---8BIT控制界面,绘图显示OFF //返回基本设置 writecomm_12864(0x30);//功能设置 8位数据,基本指令 writecomm_12864(0x0c);//显示状态 ON,游标OFF,反白OFF writecomm_12864(0x02);//地址归位 } //*************函数部分*************************************************** // 名字:dispstr_12864() // 功能:移动显示汉字字组 // 局部变量:x,y12,*pstr1,*pstr2,word_number,speed // 使用说明:x为文字定位地址横坐标? // y1为第(1~4)行文字定位地址坐标 // y2为第(1~4)行文字定位地址坐标 // *pstr1为第一行文字组 // *pstr2为第二行文字组 // word_number 移动显示的文字数目 // speed 移动的速度 // 全局变量:无 // 返回值: 无 //*********************************************************************** void dispstr_12864_move(uchar x,uchar y1,uchar y2, uchar *pstr1, uint word_number,uint speed) { uchar i,t; uint move; for (move=0;move<word_number;move++) { for (t=0;t<16;t++) { for(i=0;i<t;i++) { distwochar_12864(x,y1,pstr1[i+move*2],pstr1[i+move*2+1]); //distwochar_12864(x,y2,pstr2[i+move*2],pstr2[i+move*2+1]); i+=1; x+=1; if(x==8) { x=0; } } } delay_100ms(speed); } } //****************************************************** //*************函数部分********************************/ /* 名字:abs(x1-x0) */ /* 功能:计算两个数相减的绝对值 */ /* 局部变量:取值范围 */ /* */ /* 全局变量:无 */ /* 返回值: 无 */ /* 注意 */ //*****************************************************/ int abs(int a,int b) { uint fabs = 0; if ((a-b)>0) fabs = a-b; else fabs = b-a; return (fabs); } //**************************************************** //*************函数部分****************************/ /* 名字:plot1_12864() */ /* 功能:图象单点描点函数 */ /* 局部变量:取值范围 x:[-64,64] y:[-32,31] */ /* 全局变量:无 */ /* 返回值: 无 */ //*************************************************/ void plot1_12864(int x,int y,uchar *buf) { uchar a=0; if ((x>0)|(x==0)) { if (!((x+64)%8)) { a|=(1<<0); buf[(31-y)*16+((x+64)/8)-1]|=a; } else { a|=(1<<(8-(x+63)%8)); buf[(31-y)*16+((x+64)/8)]|=a; } } else { if (!((64+x)%8)) { a|=(1<<0); buf[(31-y)*16+((64+x)/8)-1]|=a; } else { a|=(1<<(8-(x+64)%8)); buf[(31-y)*16+(64+x)/8]|=a; } } } //*************函数部分****************************/ /* 名字:plot1_12864() */ /* 功能:图象单点描点函数 */ /* 局部变量:取值范围 x:[-64,64] y:[-32,31] */ /* 全局变量:无 */ /* 返回值: 无 */ //*************************************************/ void plot_12864(int x,int y,uchar *buf) { uchar a=0; if (!(x%8)) { a|=(1<<0); buf[(64-y)*16+(x/8)-1]|=a; } else { a|=(1<<(8-x%8)); buf[(64-y)*16+(x/8)]|=a; } } //****************************************************** //*************函数部分********************************/ /* 名字:mirror_point_12864() */ /* 功能:图象多点镜像描点函数 */ /* 局部变量:取值范围 :y:[1,128] */ /* 像距为:h:[1,63] 中心线:center:[1,64] */ /* 全局变量:无 */ /* 返回值: 无 */ /* 注意!!:两点之间的距离不得超过64(12864只有64行)*/ //*****************************************************/ void mirror_point_12864(uchar center,uchar x,uchar h,uchar *buf) { uchar a=0,i,high=0; if (h>31) high = 31; else high = h; if (!(x%8)) { a|=(1<<0); for (i=0;i<high;i++) { buf[(64-center+i)*16+(x/8)-1]|=a; buf[(64-center-i)*16+(x/8)-1]|=a; } } else { a|=(1<<(8-x%8)); for (i=0;i<high;i++) { buf[(64-center+i)*16+(x/8)]|=a; buf[(64-center-i)*16+(x/8)]|=a; } } } //****************************************************** //*************函数部分********************************/ /* 名字:clear_print_12864() */ /* 功能:清除图象数据存储区 */ /* 局部变量:取值范围 :y:[1,128] */ /* */ /* 全局变量:无 */ /* 返回值: 无 */ /* 注意 */ //*****************************************************/ void clear_print_12864(uchar *buffer) { int i; for (i=0;i<1024;i++) { buffer[i] = 0x00; } drawpic_12864(buffer); } //****************************************************** //*************函数部分********************************/ /* 名字:subsection_point_12864() */ /* 功能:分段描点函数 */ /* 局部变量: */ /* */ /* 全局变量:无 */ /* 返回值: 无 */ /* 注意!!:两点之间的距离不得超过64(12864只有64行)*/ //*****************************************************/ void subsection_point_12864(uchar x,uchar center,uchar h,uchar *buf) { uchar a=0,i,high=0; if (h>63) high = 63; else high = h; if (!(x%8)) { a|=(1<<0); for (i=0;i<high;i++) { buf[(64-center-i)*16+(x/8)-1]|=a; } } else { a|=(1<<(8-x%8)); for (i=0;i<high;i++) { buf[(64-center-i)*16+(x/8)]|=a; } } } //*************函数部分********************************/ /* 名字:line_piont() */ /* 功能:画横线函数 */ /* 局部变量: */ /* */ /* 全局变量:无 */ /* 返回值: 无 */ /* 注意!!:两点之间的距离不得超过128(12864只有128宽*/ //*****************************************************/ void line_piont(int x0,int y0,int x1,uchar *buf) { uchar i; for (i=x0;i<x1;i++) { plot_12864(i,y0,buf); } } //*************函数部分********************************/ /* 名字:load_magic_12864() */ /* 功能:加载频谱魔幻花样 */ /* 局部变量:取值范围 :y:[1,128] */ /* */ /* 全局变量:无 */ /* 返回值: 无 */ /* 注意 */ //*****************************************************/ void load_magic_12864(uchar *buffer) { uchar i,h; for (i=0;i<16;i++) { h= buffer[i]; line_piont(i*8+1,h+1,i*8+8,music); line_piont(i*8+1,h+2,i*8+8,music); } } /******************************************************** * 名称:draw_Line() 采用布兰森汉姆(Bresenham)算法画线 * 功能:任意两点间的直线。根据硬件特点,实现加速。 * 入口参数:x0 直线起点所在行的位置 * y0 直线起点所在列的位置 * x1 直线终点所在行的位置 ‘ y1 直线终点所在列的位置 * 出口参数: 无 * 说明:操作失败原因是指定地址超出缓冲区范围。 *********************************************************/ void draw_line(int x0,int y0,int x1,int y1) { int temp; int dx,dy; //定义起点到终点的横、纵坐标增加值 int s1,s2,status,i; int Dx,Dy,sub; dx=x1-x0; if(dx>=0) //X的方向是增加的 s1=1; else //X的方向是降低的 s1=-1; dy=y1-y0; //判断Y的方向是增加还是降到的 if(dy>=0) s2=1; else s2=-1; Dx=abs(x1,x0); //计算横、纵标志增加值的绝对值 Dy=abs(y1,y0); if(Dy>Dx) // { //以45度角为分界线,靠进Y轴是status=1,靠近X轴是status=0 temp=Dx; Dx=Dy; Dy=temp; status=1; } else status=0; //********判断垂直线和水平线******************************************* //if(dx==0) //横向上没有增量,画一条水平线 //line_piont(x0,y0,x1,music); //if(dy==0) //纵向上没有增量,画一条垂直线 // subsection_point_12864(x0,y0,y1,music); //*********Bresenham算法画任意两点间的直线***************************** sub=2*Dy-Dx; //第1次判断下个点的位置 for(i=0;i<Dx+1;i++) { plot_12864(x0,y0,music); //画点 if(sub>=0) { if(status==1) //在靠近Y轴区,x值加1 x0+=s1; else //在靠近X轴区,y值加1 y0+=s2; sub-=2*Dx; //判断下下个点的位置 } if(status==1) y0+=s2; else x0+=s1; sub+=2*Dy; } } /*************************************************************** 名称:Draw_circle (在任意位置画圆) 说明:使用Bresenham法画1/8个圆,在用对称性画出其他的7/8个圆 按下图把圆分为8份 0 7 1 6 2 5 3 4 *****************************************************************/ void draw_circle(uchar x0,uchar y0,uchar r) { int a,b; int di; a=0; b=r; di=3-2*r; //判断下个点位置的标志 while(a<=b) { //plot_12864(uchar x,uchar y,uchar *buf) plot_12864(x0-b,y0-a,music); //3 plot_12864(x0+b,y0-a,music); //0 plot_12864(x0-a,y0+b,music); //1 plot_12864(x0-b,y0-a,music); //7 plot_12864(x0-a,y0-b,music); //2 plot_12864(x0+b,y0+a,music); //4 plot_12864(x0+a,y0-b,music); //5 plot_12864(x0+a,y0+b,music); //6 plot_12864(x0-b,y0+a,music); a++; /***使用Bresenham算法画圆**/ if(di<0) di +=4*a+6; else { di +=10+4*(a-b); b--; } plot_12864(x0+a,y0+b,music); } } //*************函数部分********************************/ /* 名字:cube_3D() */ /* 功能:3D图象变换算法变换立方体 */ /* 局部变量: */ /* */ /* 全局变量:无 */ /* 返回值: 无 */ /* 注意!!:两点之间的距离不得超过64(12864只有64行)*/ //*****************************************************/ /* 定义显示位置 */ //#define OFFSETX 30 uchar OFFSETX = 64; #define OFFSETY 38 #define OFFSETZ 60 /////////////////////////////////立方体加文字///////////////////////////////////////////////////////// /*const signed int aa[23]={8,-8,-8,8,8,-8,-8,8,8,8,8,8,8,0,4,-4,-8,-8,-8,-8,-8,-8,-8}; // x const signed int bb[23]={8,8,-8,-8,8,8,-8,-8,0,-4,4,-2,2,8,8,8,4,4,4,-4,-4,-4,0}; // y const signed int cc[23]={-8,-8,-8,-8,8,8,8,8,6,-6,-6,0,0,-6,6,6,-6,0,6,6,0,-6,0}; // z const int ff[22]={1,2,3,4,5,6,7,8,1,2,3,4,9,9,12,14,14,17,19,20,21,22}; // start const int gg[22]={2,3,4,1,6,7,8,5,5,6,7,8,10,11,13,15,16,19,20,21,18,23}; // end*/ ///////////////////////////////////////////////////////////////////////////////////////////////////// const signed int aa[14]={-16,-14,-18,-12,-20,8,-8,0,20,12,20,12,20,12}; // x const signed int bb[14]={16,10,10,0,0,16,16,0,16,16,10,10,0,0}; // y const signed int cc[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // z const int ff[13]={1,3,1,2,3,6,7,10,12,10,9,12,12}; // start const int gg[13]={3,5,2,4,2,8,8,12,14,9,11,11,13}; // end ///////////////////////////////////////////////////////////////////////////////////////////////////////// /*const signed int aa[16]={-11,-3,-7,11,-3,-13,-1,-7,-13,-1,0,8,4,8,0,0}; // x const signed int bb[16]={20,20,12,16,16,12,12,12,0,0,20,20,16,12,12,0}; // y const signed int cc[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // z const int ff[12]={1,2,4,3,6,8,8,11,11,12,13,14}; // start const int gg[12]={3,3,5,8,7,9,10,16,12,13,14,15}; // end*/ ///////////////////////////////////////////////////////////////////////////////////////////////////////// /*const signed int aa[16]={-26,-26,-16,-12,-12,-3,-3,2,10,18,22,30,22,30,22,30}; // x const signed int bb[16]={16,0,0,16,0,16,0,16,0,16,16,16,8,8,0,0}; // y const signed int cc[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // z const int ff[13]={1,2,4,4,6,5,8,9,11,13,11,13,15}; // start const int gg[13]={2,3,5,6,7,7,9,10,13,15,12,14,16}; // end*/ ///////////////////////////////////////////////////////////////////////////////////////////////////////// int sx,sy,ex,ey; // define global vars for calling graphics subroutines float rotx=0.00; // starting amount of x rotation float roty=0.00; // starting amount of y rotation float rotz=0.00; // starting amount of z rotation /************************************************************************** * 3D显示主程序 ***************************************************************************/ void Disply3D(float xpos,float ypos,float zpos) { int newx[23]; // translated screen x co-ordinates for vertex int newy[23]; // translated screen y co-ordinates for vertex int i,loop; // temp variable for loops int vertex; float xt,yt,zt,x,y,z,sinax,cosax,sinay,cosay,sinaz,cosaz; // lots of work variables for (loop=0;loop<1;loop++) { xpos=xpos+0.00; // move the object ypos=ypos+0.00; // it would wander off screen zpos=zpos+0.00; // really quick, so leave it centered rotx=rotx+0.00; // rotate the cube on X axis roty=roty+0.15; // and on its y axis rotz=rotz+0.00; // dont bother with z or it gets confusing sinax=sin(rotx); // precalculate the sin and cos values cosax=cos(rotx); // for the rotation as this saves a sinay=sin(roty); // little time when running as we cosay=cos(roty); // call sin and cos less often sinaz=sin(rotz); // they are slow routines cosaz=cos(rotz); // and we dont want slow! for (i=0; i<14; i++) // translate 3d vertex position to 2d screen position { x=aa[i]; // get x for vertex i y=bb[i]; // get y for vertex i z=cc[i]; // get z for vertex i yt = y * cosax - z * sinax; // rotate around the x axis zt = y * sinax + z * cosax; // using the Y and Z for the rotation y = yt; z = zt; yt = y * cosax - z * sinax; // rotate around the x axis zt = y * sinax + z * cosax; // using the Y and Z for the rotation y = yt; z = zt; xt = x * cosay - z * sinay; // rotate around the Y axis zt = x * sinay + z * cosay; // using X and Z x = xt; z = zt; xt = x * cosaz - y * sinaz; // finaly rotate around the Z axis yt = x * sinaz + y * cosaz; // using X and Y x = xt; y = yt; x=x+xpos; // add the object position offset y=y+ypos; // for both x and y z=z+OFFSETZ-zpos; // as well as Z newx[i]=(x*64/z)+OFFSETX; // translate 3d to 2d coordinates for screen newy[i]=(y*64/z)+OFFSETY; // drawing so we can see the cube } for (i=0; i<13; i++) // draw the lines that make up the object { vertex=ff[i]-1; // temp = start vertex for this line sx=newx[vertex]; // set line start x to vertex[i] x position sy=newy[vertex]; // set line start y to vertex[i] y position vertex=gg[i]-1; // temp = end vertex for this line ex=newx[vertex]; // set line end x to vertex[i+1] x position ey=newy[vertex]; // set line end y to vertex[i+1] y position if((sx>255) | (sy>255) | (ex>255) |( ey>255)) { sx=255; sy=255; ex=255; ey=255; } draw_line(sx,sy,ex,ey); } } }