控制器7920
代码没啥好说,我尽量多写了注释,播放动画也很流畅的
亮点就是支持中英文混合输出,其他没啥
昨天发现座的公交车上用的也是这种12864 ,显示温度和时间...
#ifndef _LCD12864_H #define _LCD12864_H #include "my51.h" #define LCD_dataBus P0 //总线 sbit LCD_EN = P3^4; //使能控制 sbit LCD_RS = P3^5; //数据_命令选择端 sbit LCD_RW = P3^6; //读写控制 sbit LCD_PSB= P3^7; //串并选择,H并行,L串行 extern bool bShowPicFlag; //绘图时图像显示控制(仅控制GDRAM) /*************************基本功能函数*********************************************/ extern void LCD12864_init(); //初始化,必须置顶调用 extern void LCD12864_setPos(u8 row, u8 cols); //设置光标位置 extern void LCD12864_writeByte(u8 dat); //写一个字节 extern void LCD12864_writeCmd(u8 cmd); //写指令 extern u8 LCD12864_readByte(); //读一个字节ram extern u8 LCD12864_readIR(); //读暂存器 extern bool LCD12864_isBusy(); //判忙 /*************************调用基本字库显示文字**************************************/ //独创支持全角半角字符及中英混合的字符串,或字符串的子串,起始行号row(0-3)和列坐标cols(0-15),写满屏幕为止 //行号4-7行是滚动区 extern void LCD12864_writeData(u8 row, u8 cols,u8* pBuf,u8 dataSize);//写一堆数据 extern void LCD12864_earseSomeDDRam(u8 row,u8 cols,u8 dataSize); //擦除N字节DDRam /*************************用户自定义图标字体****************************************/ extern void LCD12864_writeCGRAM(u8 userRamNum,u8* pCGRAM_userCode); //写自定义图标字体 extern void LCD12864_showCGRAM(u8 row,u8 cols,u8 num) ; //显示自定义图标字体,row(0-3),cols(0-15) extern void LCD12864_clearCGRAM(u8 CGRAM_groupNum) ; //CGRAM清零(初始化也可清0) /*************************图像显示功能函数**********************************************/ extern void LCD12864_showGDRAM(bool bShowImage); //GDRAM绘图显示开关 extern void LCD12864_clearGDRAM(); //液晶整个可视区的GDRAM快速清0 //前4参数:起始点x(0-7)位址,y(0-63)坐标,要显示的宽度(1-128)和高度(1-64)[可显示从图像左上角开始的部分区域] //后4参数:图像代码地址,图像本身的宽度(1-128)和高度(1-64), 反白(true反白,false不反白) //画图填充GDRAM ,注:显示的区域或者图像本身宽度必须是8的倍数 extern u8 LCD12864_drawGDRAM(u8 x,u8 y,u8 width,u8 height,u8 *pImageCode,u8 imageWidth,u8 imageHight,bool bReverse); extern void LCD12864_drawDot(u8 x,u8 y,u8 flag); //打点,x(0-127),y(0-63),flag(0正常,1反白,2清0) extern bool LCD12864_drawXYLine(u8 x1, u8 y1,u8 x2, u8 y2,u8 flag); //画水平或垂直直线 extern void LCD12864_drawAnyLine(u8 x1, u8 y1,u8 x2, u8 y2,u8 flag) ; //画任意直线 extern void LCD12864_drawRectangle(u8 x,u8 y ,u8 width,u8 height,u8 flag);//画矩形 extern void LCD12864_drawFillRect(u8 x,u8 y, u8 width,u8 hight,u8 flag); //填充矩形,可对矩形区反白或清0 extern void LCD12864_drawVerticalSquare(u8 x,u8 y,u8 r,u8 flag) ; //画站立的正方形 extern void LCD12864_drawCircle(u8 x0,u8 y0,u8 r,u8 flag); //画圆 //打点法全屏画图有点慢了,打点法反白矩形区还可以,建议矩形范围小一些,不然比较慢 //打点法效果最好,因为文字的矩形区比较小,速度很快 //不过绘图法反白文字效率高,flash空间充裕的建议用绘图法 /***************************全屏滚动*******************************************/ //需要滚动时,用LCD12864_writeScrollData()函数,参数和LCD12864_writeData()一样 extern void LCD12864_writeScrollData(u8 row,u8 cols,u8* pBuf,u8 dataSize);//写数据 (滚动模式) extern void LCD12864_setScrollPos(u8 row, u8 cols); //设置滚动模式的坐标 extern void LCD12864_showScrollCGRAM(u8 row,u8 cols,u8 CGRAM_groupNum);//用于CGRAM滚动显示前执行 extern void LCD12864_startScroll(u8 scrollNum,u16 delay_ms); //滚动开始 #endif
#include "lcd12864.h" //图像与文字,图像与用户图标,像素重合时是异或关系 //文字与用户图标是覆盖关系 bool bShowPicFlag=false; //绘图时图像显示控制 /* u8 LCD12864_table[]={"123456789"}; */ void LCD12864_drawFillRect(u8 x,u8 y, u8 width,u8 hight,u8 flag)//填充任意位置的整个矩形 {//矩形起始坐标x(0-127),y(0-63),宽(1-128)高(1-64),flag有3种值,0正常填充,1反色,2清0 u8 i=0; u8 j=0; if(0==width||0==hight) //矩形宽度或高度为0时返回 { return ; } if( (x+width>128 ||(y+hight)>64) ) { led2=0; return; } for(j=0;j<hight;j++) { for(i=0;i<width;i++) { LCD12864_drawDot(x+i, y+j,flag); } } } void LCD12864_drawRectangle(u8 x,u8 y, u8 width,u8 hight,u8 flag)//画矩形 { //矩形起始坐标x(0-127),y(0-63),宽度(1-128)和高度(1-64) flag有3种值,0正常写1,1反色,2清0 if(0==width||0==hight) //矩形宽度或高度为0时返回 { return ; } width--;hight--; LCD12864_drawXYLine(x, y,x+width, y, flag); LCD12864_drawXYLine(x+width, y,x+width, y+hight, flag); LCD12864_drawXYLine(x, y,x, y+hight, flag); LCD12864_drawXYLine(x, y+hight,x+width, y+hight, flag); } bool LCD12864_drawXYLine(u8 x1,u8 y1, u8 x2, u8 y2, u8 flag)//画水平或垂直直线 { //起始点坐标和终点坐标,x(0-127),y(0-63), flag有3种值,0正常写1,1反色,2清0 u8 n=0; if(flag>2|| x1>127||x2>127||y1>63||y2>63) { return false; } if(x1==x2) { for(n=0;n<abs(y2-y1)+1;n++) { LCD12864_drawDot( x1,y1+(y2>=y1?n:-n) ,flag); } } if(y1==y2) { for(n=0;n<abs(x2-x1)+1;n++) { LCD12864_drawDot(x1+(x2>=x1?n:-n),y1,flag) ; } } return true; } void LCD12864_drawCircle(u8 x0,u8 y0,u8 r,u8 flag) { s8 a,b; s8 di; if(r>31 ||r==0) return; //参数过滤,次液晶显示的最大圆半径为31 a=0; b=r; di=3-2*r; //判断下个点位置的标志 while(a<=b) { LCD12864_drawDot(x0-b,y0-a,flag); //3 LCD12864_drawDot(x0+b,y0-a,flag); //0 LCD12864_drawDot(x0-a,y0+b,flag); //1 LCD12864_drawDot(x0-b,y0-a,flag); //7 LCD12864_drawDot(x0-a,y0-b,flag); //2 LCD12864_drawDot(x0+b,y0+a,flag); //4 LCD12864_drawDot(x0+a,y0-b,flag); //5 LCD12864_drawDot(x0+a,y0+b,flag); //6 LCD12864_drawDot(x0-b,y0+a,flag); a++; //使用Bresenham算法画圆 if(di<0) di +=4*a+6; else { di +=10+4*(a-b); b--; } LCD12864_drawDot(x0+a,y0+b,flag); } } void LCD12864_drawVerticalSquare(u8 x,u8 y,u8 r,u8 flag) //画站立的正方形 { u8 a,b; float c=0; a = 0; b = r; c = 3 - 2*r; while(a < b) { LCD12864_drawDot(x+a,y+b,flag); LCD12864_drawDot(x-a,y+b,flag); LCD12864_drawDot(x+a,y-b,flag); LCD12864_drawDot(x-a,y-b,flag); LCD12864_drawDot(x+b,y+a,flag); LCD12864_drawDot(x-b,y+a,flag); LCD12864_drawDot(x+b,y-a,flag); LCD12864_drawDot(x-b,y-a,flag); if(c < 0) { c = c+4*a + 6; } else { c= c + 4*(a - b) + 10; b-=1; } a = a + 1; //控制打点间隔 } if(a == b) { LCD12864_drawDot(x+a,y+b,flag); LCD12864_drawDot(x-a,y+b,flag); LCD12864_drawDot(x+a,y-b,flag); LCD12864_drawDot(x-a,y+b,flag); LCD12864_drawDot(x+b,y+a,flag); LCD12864_drawDot(x-b,y+a,flag); LCD12864_drawDot(x+b,y-a,flag); LCD12864_drawDot(x-b,y-a,flag); } } void LCD12864_drawAnyLine(u8 StartX, u8 StartY,u8 EndX, u8 EndY, u8 flag) //画任意直线 { u8 t, distance ; /*根据屏幕大小改变变量类型(如改为int型)*/ s16 x = 0 , y = 0 ; s8 incx, incy, dx, dy ; if((StartX==EndX) ||(StartY==EndY)) { LCD12864_drawXYLine(StartX,StartY,EndX,EndY,flag); return; } dx = EndX - StartX ; dy = EndY - StartY ; incx = dx > 0 ?1:-1; incy = dy > 0 ?1:-1; dx = abs( dx ); dy = abs( dy ); if( dx > dy ) { distance = dx ; } else { distance = dy ; } LCD12864_drawDot( StartX, StartY, flag ) ; //反白补点 for( t = 0 ; t <= distance+1 ; t++ ) { LCD12864_drawDot( StartX, StartY, flag ) ; x += dx ; y += dy ; if( x > distance ) { x -= distance ; StartX += incx ; } if( y > distance ) { y -= distance ; StartY += incy ; } } } void LCD12864_drawDot(u8 x, u8 y,u8 flag) //画点,0打点,1反色,2清0 { //x(0-127),y(0-63),flag有3种值,0正常写1,1反色,2清0 u8 x_word=0; //水平(0-127)个像素中的哪个字,一字16位 u8 x_mode=0; //取余 u8 y_part=0; u8 y_bit=0; u8 tempH=0; u8 tempL=0; x_word=x>>4; //在哪一个字(0-7) ,x_word=x/16 x_mode=x&0x0f; //在该字的哪一位 ,x_mode= x%16 y_part=y>>5; //在哪个屏0或1 ,y_part=y/32 y_bit= y&0x1f; //垂直方向,y_bit范围(0-31),y_bit=y%32 bShowPicFlag?LCD12864_writeCmd(0x36):LCD12864_writeCmd(0x34); LCD12864_writeCmd(0x80+y_bit); //垂直坐标 LCD12864_writeCmd(0x80+8*y_part+x_word); //水平位址 LCD12864_readByte(); tempH=LCD12864_readByte(); //先将该字16位数据保存 tempL= LCD12864_readByte(); LCD12864_writeCmd(0x80+y_bit); //重设地址,因为AC计数器变了 LCD12864_writeCmd(0x80+8*y_part+x_word); //水平位址 if(0==flag) //不反白,打1, { if(x_mode<8) //如果x_mode小于8,说明点应位于该字的左边高8位中 { LCD12864_writeByte( tempH | bit(7- x_mode) ); //LCD12864_writeByte(tempL); } else { //LCD12864_writeByte(tempH); LCD12864_readByte(); //让AC走半步 LCD12864_writeByte(tempL|bit(15-x_mode)); } } else if(1==flag) //反白,该点与原来的状态相反 { if(x_mode<8) //如果x_mode小于8,说明点应位于该字的左边高8位中 { if(tempH & bit(7- x_mode)) //原来是1 { LCD12864_writeByte( tempH&~bit(7- x_mode) ); //写0 } else //原来是0 { LCD12864_writeByte( tempH | bit(7- x_mode) ); //写1 } } else { LCD12864_readByte(); //让AC走半字 if(tempL& bit(15-x_mode)) //原来是1的写0 { LCD12864_writeByte(tempL&~bit(15-x_mode)); //写0 } else { LCD12864_writeByte(tempL|bit(15-x_mode)); //写0 } } } else if(2==flag) //清0 { if(x_mode<8) //如果x_mode小于8,说明点应位于该字的左边高8位中 { LCD12864_writeByte( tempH&~bit(7- x_mode) ); } else { LCD12864_readByte(); //让AC走半字 LCD12864_writeByte(tempL&~bit(15-x_mode)); } } } void LCD12864_showGDRAM(bool bShowImage) //GDRAM图像显示开关 { if(bShowImage) //开启显示 { LCD12864_writeCmd(0x36); LCD12864_writeCmd(0x30); } else //关闭显示 { LCD12864_writeCmd(0x34); LCD12864_writeCmd(0x30); } } //填充GDRAM u8 LCD12864_drawGDRAM(u8 x,u8 y,u8 width,u8 height,u8* pImageCode,u8 imageWidth,u8 imageHight,bool bReverse) {//前4参数:起始点x(0-7)位址,y(0-63)坐标,要显示的宽度(1-128)和高度(1-64)[可显示从图像左上角开始的部分区域] //后4参数:图像代码地址,图像本身的宽度(1-128)和高度(1-64), 反白(true反白,false不反白) u8 i=0; u8 j=0; if( height > imageHight ) //检测显示高度,宽度不检测不会乱码 { //显示的高度不能超过图片本身高度 return 0x01; //也就是说可显示图像的部分区域(从图像左上角开始的部分区域) } width>>=3; //像素宽度转化为字节个数,所以width必须是8的整数倍 imageWidth>>=3; //像素宽度转化为字节个数,所以width必须是8的整数倍 if(bShowPicFlag) { LCD12864_writeCmd(0x36); //改写GDRAM时,开启绘图显示,可防止动画显示时闪动 } else { LCD12864_writeCmd(0x34); //改写GDRAM时,关闭绘图显示 } for(j=0;j<height;j++) //写GDRAM { if(y+j>31) //地址变换 { LCD12864_writeCmd(0x80+y+j-32); //垂直坐标 LCD12864_writeCmd(0x88+x); //水平位址 } else { LCD12864_writeCmd(0x80+y+j); LCD12864_writeCmd(0x80+x); } for(i=0;i<width;i++) //水平方向写数据,带反白控制 { LCD12864_writeByte(bReverse?~pImageCode[imageWidth*j+i]:pImageCode[imageWidth*j+i]); } } LCD12864_writeCmd(0x30); return 0x02; } void LCD12864_clearGDRAM() //液晶可视区的绘图GDRAM清0 { u8 j=0; u8 i=0; LCD12864_writeCmd(0x34); //扩展指令 for(j=0;j<64;j++) //垂直方向地址手动增加,当j=64时清整个GDram { //我们只要清可视区的GDRAM就可以了 LCD12864_writeCmd(0x80+j); //y轴坐标 LCD12864_writeCmd(0x80); //x轴坐标 for(i=0;i<32;i++) //水平方向位址自动增加 { LCD12864_writeByte(0x00); } } LCD12864_writeCmd(0x30); //回到基本指令 } /*--------------------------------CGRAM start----------------------------------------------*/ void LCD12864_clearCGRAM(u8 CGRAM_groupNum)//将用户自定义编码区CGRAM清0 { //参数一是CGRAM的4组用户空间组号码(0~3) ,参数二是用户自定义图表或汉字的编码 u8 i,addr=0; bShowPicFlag?LCD12864_writeCmd(0x36):LCD12864_writeCmd(0x34);//扩展指令,绘图开关保持 LCD12864_writeCmd(0x02); //SR等于0,允许设置卷动地址 LCD12864_writeCmd(0x30); //恢复为8位并行,基本指令集 addr=(CGRAM_groupNum<<4)|0x40; //将CGRAM空间号转换为相应存储地址 LCD12864_writeCmd(addr); //定位到该位址(用户空间位址范围0x40-0x7F共128字节) for(i=0;i<16;i++) //将用户自定义编码写入该16*16位元组空间 { LCD12864_writeByte(0); //连续写2个字节共16位 LCD12864_writeByte(0); } } void LCD12864_writeScrollCGRAM(u8 CGRAM_groupNum, u8* pUserCode)//将用户自定义编码写入CGRAM { //参数一是CGRAM的4组用户空间组号码(0~3) ,参数二是用户自定义图表或汉字的编码 u8 i,addr=0; if(bShowPicFlag) { LCD12864_writeCmd(0x36); //开启绘图显示,可流畅播放动画 } else { LCD12864_writeCmd(0x34); //默认关闭绘图显示 } LCD12864_writeCmd(0x02); //SR等于0,允许设置卷动地址 LCD12864_writeCmd(0x30); //恢复为8位并行,基本指令集 addr=(CGRAM_groupNum<<4)|0x40; //将CGRAM空间号转换为相应存储地址 LCD12864_writeCmd(addr); //定位到该位址(用户空间位址范围0x40-0x7F共128字节) for(i=0;i<16;i++) //将用户自定义编码写入该16*16位元组空间 { LCD12864_writeByte(pUserCode[i*2]); //连续写2个字节共16位 LCD12864_writeByte(pUserCode[i*2+1]); } } void LCD12864_writeCGRAM(u8 CGRAM_groupNum, u8* pUserCode)//将用户自定义编码写入CGRAM { //参数一是CGRAM的4组用户空间组号码(0~3) ,参数二是用户自定义图表或汉字的编码 u8 i,addr=0; if(bShowPicFlag) { LCD12864_writeCmd(0x36); //开启绘图显示,可流畅播放动画 } else { LCD12864_writeCmd(0x34); //默认关闭绘图显示 } LCD12864_writeCmd(0x02); //SR等于0,允许设置卷动地址 LCD12864_writeCmd(0x30); //恢复为8位并行,基本指令集 addr=(CGRAM_groupNum<<4)|0x40; //将CGRAM空间号转换为相应存储地址 LCD12864_writeCmd(addr); //定位到该位址(用户空间位址范围0x40-0x7F共128字节) for(i=0;i<16;i++) //将用户自定义编码写入该16*16位元组空间 { LCD12864_writeByte(pUserCode[i*2]); //连续写2个字节共16位 LCD12864_writeByte(pUserCode[i*2+1]); } } void LCD12864_showScrollCGRAM(u8 row,u8 cols,u8 CGRAM_groupNum)//滚动CGRAM { //row(0-3), cols(0-15) //第三个参数是用户空间号码(0~3共4组空间号码),该号码乘2就是它所对应的[调用用户空间编码] LCD12864_setScrollPos(row,cols); LCD12864_writeByte(0x00);//4组用户空间的编码的高字节都固定为0,我猜这是为和E文ASCII码区分开 LCD12864_writeByte(CGRAM_groupNum*2); //对应编码00h,02h,04h,06h LCD12864_showCGRAM(row,cols,CGRAM_groupNum); } void LCD12864_showCGRAM(u8 row,u8 cols,u8 CGRAM_groupNum)//定位液晶光标,并显示自定义内容 { //row(0-3), cols(0-15) //第三个参数是用户空间号码(0~3共4组空间号码),该号码乘2就是它所对应的[调用用户空间编码] LCD12864_setPos(row,cols); LCD12864_writeByte(0x00);//4组用户空间的编码的高字节都固定为0,我猜这是为和E文ASCII码区分开 LCD12864_writeByte(CGRAM_groupNum*2); //对应编码00h,02h,04h,06h } /*--------------------------------CGRAM end----------------------------------------------*/ /*--------------------------------DDRAM start----------------------------------------------*/ void LCD12864_earseSomeDDRam(u8 row,u8 cols,u8 dataSize) //擦除N个字节DDRam { //row(0-3),cols(0-15),如果起始地址是汉字的低字节,则会一同擦除汉字的高字节 LCD12864_setPos(row, cols); //定位 if(cols%2!=0) //如果从奇数列开始 { LCD12864_readByte(); //空读一次,让位址指针移动半字 if(LCD12864_readByte()>127) //检测高位是否是汉字码 { LCD12864_setPos(row, cols); //是汉字码的话要擦除,不然要乱码 LCD12864_writeByte(' '); //其实是写空格,看不到了就等于擦除了 } //连续写2个0的话是乱码 } while(dataSize--) //擦除 { if(cols) //cols>0 { if(0==cols%16) //如果一行满了 { row++; //准备将光标移到下一行 cols=0; //列坐标置于行首 LCD12864_setPos(row, cols); //设置新光标 } } LCD12864_writeByte(' '); //其实是写空格,但为啥不写0呢 cols++; //因为0与是CGRAM重码了,写2个0会乱码的 } } /***************************************************************************************** pBuf如果用来修饰字符串,dataSize=strlen(pBuf); pBuf如果是一个字符数组,dataSize=sizeof(pBuf); strlen()虽然也可以用来计算字符数组长度,但遇到'\0'时就会返回,不会再计算后面的其他字符 在VC中strlen()只能计算字符串长度,不能计算字符数组,否则编译出错 sizeof("你好5"),sizeof("你好56"),最终液晶光标位置是一样的,故不要用sizeof计算字符串 *****************************************************************************************/ void LCD12864_writeData(u8 row,u8 cols,u8* pBuf,u8 dataSize)//写数据 { //支持全角半角字符及中英混合的字符串,也可写入字符串的子串,(行坐标0~3,列坐标0~15) u8 flag=0; //液晶低字节ram数据检测标志,0不检测 LCD12864_setPos(row, cols); //设置光标 if(cols%2!=0) //列号不为偶数(汉字在液晶上要偶对齐) { //要让位址空移一个字节,执行下面这句读操作后,效果是达到了 LCD12864_readByte();//但AC值没变,我怀疑除了这个AC字型指针,另有一个标志位没公开) flag=1; //此时需要检测液晶低位字节ram } //因为高位字节现在可能是汉字码 while(dataSize--) //循环处理目标字节流 { if(0==cols%2) //偶对齐时,对于ram高字节 { if(*pBuf>127) //如果写入ram的高字节是汉字码 { flag=0; //下一次不要检测低字节,因为肯定是汉字了 } else //如果高字节是半角字符 { flag=1; //若在低字节ram写入汉字就乱码了,故检测 } } if(cols%2!=0) //对于液晶低字节 { if(flag) //如果要检测低字节 { if(*pBuf>127) //如果低字节是汉字码 { LCD12864_writeByte(0x20); //插入一个空格 cols++; //字节计数器++ flag=0; //清检测标志 } } } if(cols) //行尾检测 { if(0==cols%16) //如果一行满了 { row++; //准备将光标移到下一行 cols=0; //列坐标置于行首 LCD12864_setPos(row, cols); //设置新位址 } } LCD12864_writeByte(*pBuf++); //终于可以写数据了 cols++; //列号累加 } } //滚屏模式的写数据函数 void LCD12864_writeScrollData(u8 row,u8 cols,u8* pBuf,u8 dataSize)//写数据,卷动模式 { //支持全角半角字符及中英混合的字符串,也可写入字符串的子串,(行坐标0~3,列坐标0~15) u8 flag=0; //液晶低字节ram数据检测标志,0不检测 LCD12864_writeData(row,cols,pBuf,dataSize); LCD12864_setScrollPos(row, cols); //设置光标 if(cols%2!=0) //列号不为偶数(汉字在液晶上要偶对齐) { //要让位址空移一个字节,执行下面这句读操作后,效果是达到了 LCD12864_readByte();//但AC值没变,我怀疑除了这个AC字型指针,另有一个标志位没公开) flag=1; //此时需要检测液晶低位字节ram } //因为高位字节现在可能是汉字码 while(dataSize--) //循环处理目标字节流 { if(0==cols%2) //偶对齐时,对于ram高字节 { if(*pBuf>127) //如果写入ram的高字节是汉字码 { flag=0; //下一次不要检测低字节,因为肯定是汉字了 } else //如果高字节是半角字符 { flag=1; //若在低字节ram写入汉字就乱码了,故检测 } } if(cols%2!=0) //对于液晶低字节 { if(flag) //如果要检测低字节 { if(*pBuf>127) //如果低字节是汉字码 { LCD12864_writeByte(0x20); //插入一个空格 cols++; //字节计数器++ flag=0; //清检测标志 } } } if(cols) //行尾检测 { if(0==cols%16) //如果一行满了 { row++; //准备将光标移到下一行 cols=0; //列坐标置于行首 LCD12864_setScrollPos(row, cols); //设置新位址 } } LCD12864_writeByte(*pBuf++); //终于可以写数据了 cols++; //列号累加 } } void LCD12864_startScroll(u8 scrollNum,u16 delay_ms) //滚动 { //scrollNum建议值为64 u8 i; LCD12864_writeCmd(0x34); LCD12864_writeCmd(0x03); for(i=0x40;i<0x40+scrollNum;i++) { LCD12864_writeCmd(i); //设置卷动地址 delayms(delay_ms); //实际使用时建议用定时器处理 } LCD12864_writeCmd(0x40); //补滚一行 LCD12864_writeCmd(0x30); } void LCD12864_setScrollPos(u8 row, u8 cols) //设置光标位置 ,卷动模式 { //row行坐标0~3 u8 newPos=0; //cols列坐标0~15 switch(row) { case 0: { row=0xa8; } break; case 1: { row=0xb8; } break; case 2: { row=0xa0; } break; case 3: { row=0xb0; } break; default: //如果需要检测行坐标范围,可在这里加代码 break; } newPos=row+cols/2; //液晶写指令坐标只能8级,我的函数中列坐标是16级的,支持半角全角混合 LCD12864_writeCmd(newPos); } void LCD12864_setPos(u8 row, u8 cols) //设置光标位置 { //row行坐标0~3 u8 newPos=0; //cols列坐标0~15 switch(row) { case 0: { row=0x80; } break; case 1: { row=0x90; } break; case 2: { row=0x88; } break; case 3: { row=0x98; } break; case 4: { row=0xa0; } break; case 5: { row=0xb0; } break; case 6: { row=0xa8; } break; case 7: { row=0xb8; } break; default: //如果需要检测行坐标范围,可在这里加代码 break; } newPos=row+cols/2; //液晶写指令坐标只能8级,我的函数中列坐标是16级的,支持半角全角混合 LCD12864_writeCmd(newPos); } /* void LCD12864_setPos(u8 row, u8 cols) //设置光标位置 { //row行坐标0~3 u8 newPos=0; //cols列坐标0~15 switch(row) { case 0: { row=0x80; } break; case 1: { row=0x90; } break; case 2: { row=0x88; } break; case 3: { row=0x98; } break; default: //如果需要检测行坐标范围,可在这里加代码 break; } newPos=row+cols/2; //液晶写指令坐标只能8级,我的函数中列坐标是16级的,支持半角全角混合 LCD12864_writeCmd(newPos); } */ void LCD12864_init() //初始化 { delayms(40); //rst由低到高后保持40ms以上,我们的rst接VCC LCD_PSB= 1; //选择并口方式 LCD12864_writeCmd( B(110000) ); //0x30,启用基本指令集 delayXus(15); //要求延时100us以上,(8+6x)*1.085=106us LCD12864_writeCmd( B(110000) ); //0x30,要求写2次该指令 delayXus(5); //要求延时37us以上,(8+6x)*1.085=41us LCD12864_writeCmd( B(1100) ); //0x0f,整体显示,游标,游标反白 delayXus(15); //要求延时100us以上 LCD12864_writeCmd( B(0001) ); //0x01,清屏指令,整屏幕写满空格 delayms(10); //要求延时10ms以上 LCD12864_writeCmd( B(110) ); //0x06,进入模式设置,游标自动指向下一位置, delayms(5); //手册上没说这里要延时,额,还是加上吧 } void LCD12864_writeCmd(u8 cmd) //写指令 { while(LCD12864_isBusy()); LCD_EN=0; //使能 拉低 LCD_RW=0; //写 LCD_RS=0;_nop_(); //命令 LCD_EN=1; //使能 LCD_dataBus=cmd; //送指令 _nop_();_nop_(); //稳定 LCD_EN=0;_nop_(); //取走 } void LCD12864_writeByte(u8 dat) //写一个字节 { while(LCD12864_isBusy()); LCD_EN=0; //使能先拉低 LCD_RW=0; //写 LCD_RS=1;_nop_(); //数据 LCD_EN=1; LCD_dataBus=dat; _nop_();_nop_(); //延时大于1.5us LCD_EN=0;_nop_(); //下降沿取走数据 } u8 LCD12864_readByte() //读数据暂存器Data Register { //用的时候要空操作一次 u8 temp=0; while(LCD12864_isBusy());//忙检测 LCD_dataBus=0xff; //用总线读数据时必须先置为输入模式 LCD_EN=0; //使能线拉低 LCD_RW=1; //读 LCD_RS=1;_nop_(); //数据 LCD_EN=1;_nop_(); //使能 temp=LCD_dataBus; //取走数据 _nop_(); LCD_EN=0; //使能恢复 return temp; } bool LCD12864_isBusy() //检测液晶是否忙 { if(LCD12864_readIR() & 0x80) //检测BF位 { return TRUE; //忙 } return FALSE; //不忙 } u8 LCD12864_readIR() //读指令暂存器Instruction Register { u8 temp=0; LCD_EN=0; //使能准备 LCD_RW=1; //读 LCD_RS=0;_nop_(); //命令字 LCD_dataBus=0xff; //准备输入 LCD_EN=1;_nop_(); //使能 temp=LCD_dataBus; //提取数据 _nop_(); LCD_EN=0; //使能拉低 return temp; }
相关推荐
亮点就是支持中英文混合输出,其他没啥。 lcd12864.h源码如下: #ifndef _LCD12864_H #define _LCD12864_H #include "my51.h" #define LCD_dataBus P0 //总线 sbit LCD_EN = P3^4; //使能控制 sbit LCD_RS = P3^5; //...
毕业设计选题 -未来生鲜运输车设计.pptx
内容概要:本文详细探讨了基于樽海鞘算法(SSA)优化的极限学习机(ELM)在回归预测任务中的应用,并与传统的BP神经网络、广义回归神经网络(GRNN)以及未优化的ELM进行了性能对比。首先介绍了ELM的基本原理,即通过随机生成输入层与隐藏层之间的连接权重及阈值,仅需计算输出权重即可快速完成训练。接着阐述了SSA的工作机制,利用樽海鞘群体觅食行为优化ELM的输入权重和隐藏层阈值,从而提高模型性能。随后分别给出了BP、GRNN、ELM和SSA-ELM的具体实现代码,并通过波士顿房价数据集和其他工业数据集验证了各模型的表现。结果显示,SSA-ELM在预测精度方面显著优于其他三种方法,尽管其训练时间较长,但在实际应用中仍具有明显优势。 适合人群:对机器学习尤其是回归预测感兴趣的科研人员和技术开发者,特别是那些希望深入了解ELM及其优化方法的人。 使用场景及目标:适用于需要高效、高精度回归预测的应用场景,如金融建模、工业数据分析等。主要目标是提供一种更为有效的回归预测解决方案,尤其是在处理大规模数据集时能够保持较高的预测精度。 其他说明:文中提供了详细的代码示例和性能对比图表,帮助读者更好地理解和复现实验结果。同时提醒使用者注意SSA参数的选择对模型性能的影响,建议进行参数敏感性分析以获得最佳效果。
2025年中国生成式AI大会PPT(4-1)
内容概要:本文详细介绍了基于Simulink平台构建无刷直流电机(BLDC)双闭环调速系统的全过程。首先阐述了双闭环控制系统的基本架构,即外层速度环和内层电流环的工作原理及其相互关系。接着深入探讨了PWM生成模块的设计,特别是占空比计算方法的选择以及三角波频率的设定。文中还提供了详细的电机参数设置指导,如转动惯量、电感、电阻等,并强调了参数选择对系统性能的影响。此外,针对PI控制器的参数整定给出了具体的公式和经验值,同时分享了一些实用的调试技巧,如避免转速超调、处理启动抖动等问题的方法。最后,通过仿真实验展示了系统的稳定性和鲁棒性,验证了所提出方法的有效性。 适用人群:从事电机控制研究的技术人员、自动化工程领域的研究生及科研工作者。 使用场景及目标:适用于需要深入了解和掌握无刷直流电机双闭环调速系统设计与优化的人群。主要目标是帮助读者学会利用Simulink进行BLDC电机控制系统的建模、仿真和参数优化,从而提高系统的稳定性和响应速度。 其他说明:文章不仅提供了理论知识,还包括了许多实践经验和技术细节,有助于读者更好地理解和应用相关技术。
内容概要:本文详细介绍了西门子S7-1200 PLC与施耐德ATV310/312变频器通过Modbus RTU进行通讯的具体实现步骤和调试技巧。主要内容涵盖硬件接线、通讯参数配置、控制启停、设定频率、读取运行参数的方法以及常见的调试问题及其解决方案。文中提供了具体的代码示例,帮助读者理解和实施通讯程序。此外,还强调了注意事项,如地址偏移量、数据格式转换和超时匹配等。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是那些需要将西门子PLC与施耐德变频器进行集成的工作人员。 使用场景及目标:适用于需要通过Modbus RTU协议实现PLC与变频器通讯的工程项目。目标是确保通讯稳定可靠,掌握解决常见问题的方法,提高调试效率。 其他说明:文中提到的实际案例和调试经验有助于读者避免常见错误,快速定位并解决问题。建议读者在实践中结合提供的代码示例和调试工具进行操作。
内容概要:本文详细介绍了如何使用Verilog在FPGA上实现IIC(Inter-Integrated Circuit)主从机驱动。主要内容包括从机和主机的设计,特别是状态机的实现、寄存器读取、时钟分频策略、SDA线的三态控制等关键技术。文中还提供了详细的代码片段,展示了从机地址匹配逻辑、主机时钟生成逻辑、顶层模块的连接方法以及仿真实验的具体步骤。此外,文章讨论了一些常见的调试问题,如总线竞争、时序不匹配等,并给出了相应的解决方案。 适合人群:具备一定FPGA开发基础的技术人员,尤其是对IIC协议感兴趣的嵌入式系统开发者。 使用场景及目标:适用于需要在FPGA平台上实现高效、可靠的IIC通信的应用场景。主要目标是帮助读者掌握IIC协议的工作原理,能够独立完成IIC主从机系统的开发和调试。 其他说明:文章不仅提供了理论讲解,还包括了大量的实战经验和代码实例,有助于读者更好地理解和应用所学知识。同时,文章还提供了一个思考题,引导读者进一步探索多主设备仲裁机制的设计思路。
内容概要:本文介绍了一款基于C#开发的拖拽式Halcon可视化抓边、抓圆控件,旨在简化机器视觉项目中的测量任务。该控件通过拖拽操作即可快速生成测量区域,自动完成边缘坐标提取,并提供实时反馈。文中详细描述了控件的工作原理和技术细节,如坐标系转换、卡尺生成、边缘检测算法封装以及动态参数调试等功能。此外,还讨论了一些常见问题及其解决方案,如坐标系差异、内存管理等。 适合人群:从事机器视觉开发的技术人员,尤其是熟悉C#和Halcon的开发者。 使用场景及目标:适用于需要频繁进行边缘和圆形特征测量的工业自动化项目,能够显著提高测量效率并减少编码工作量。主要目标是将复杂的测量任务转化为简单的拖拽操作,使非专业人员也能轻松完成测量配置。 其他说明:该控件已开源发布在GitHub上,提供了完整的源代码和详细的使用指南。未来计划扩展更多高级功能,如自动路径规划和亚像素级齿轮齿距检测等。
内容概要:本文详细介绍了西门子200Smart PLC与维纶触摸屏在某疫苗车间控制系统的具体应用,涵盖配液、发酵、纯化及CIP清洗四个主要工艺环节。文中不仅展示了具体的编程代码和技术细节,还分享了许多实战经验和调试技巧。例如,在配液罐中,通过模拟量处理确保温度和液位的精确控制;发酵罐部分,着重讨论了PID参数整定和USS通讯控制变频器的方法;纯化过程中,强调了双PID串级控制的应用;CIP清洗环节,则涉及复杂的定时器逻辑和阀门联锁机制。此外,文章还提到了一些常见的陷阱及其解决方案,如通讯干扰、状态机切换等问题。 适合人群:具有一定PLC编程基础的技术人员,尤其是从事工业自动化领域的工程师。 使用场景及目标:适用于需要深入了解PLC与触摸屏集成控制系统的工程师,帮助他们在实际项目中更好地理解和应用相关技术和方法,提高系统的稳定性和可靠性。 其他说明:文章提供了大量实战经验和代码片段,有助于读者快速掌握关键技术点,并避免常见错误。同时,文中提到的一些优化措施和调试技巧对提升系统性能非常有帮助。
计算机网络课程的结课设计是使用思科模拟器搭建一个中小型校园网,当时花了几天时间查阅相关博客总算是做出来了,现在免费上传CSDN,希望小伙伴们能给博客一套三连支持
《芋道开发指南文档-2023-10-27更新》是针对软件开发者和IT专业人士的一份详尽的资源集合,旨在提供最新的开发实践、范例代码和最佳策略。这份2023年10月27日更新的文档集,包含了丰富的模板和素材,帮助开发者在日常工作中提高效率,保证项目的顺利进行。 让我们深入探讨这份文档的可能内容。"芋道"可能是一个开源项目或一个专业的技术社区,其开发指南涵盖了多个方面,例如: 1. **编程语言指南**:可能包括Java、Python、JavaScript、C++等主流语言的编码规范、最佳实践以及常见问题的解决方案。 2. **框架与库的应用**:可能会讲解React、Vue、Angular等前端框架,以及Django、Spring Boot等后端框架的使用技巧和常见应用场景。 3. **数据库管理**:涵盖了SQL语言的基本操作,数据库设计原则,以及如何高效使用MySQL、PostgreSQL、MongoDB等数据库系统。 4. **版本控制**:详细介绍了Git的工作流程,分支管理策略,以及与其他开发工具(如Visual Studio Code、IntelliJ IDEA)的集成。 5. **持续集成与持续部署(CI/CD)**:包括Jenkins、Travis CI、GitHub Actions等工具的配置和使用,以实现自动化测试和部署。 6. **云服务与容器化**:可能涉及AWS、Azure、Google Cloud Platform等云计算平台的使用,以及Docker和Kubernetes的容器化部署实践。 7. **API设计与测试**:讲解RESTful API的设计原则,Swagger的使用,以及Postman等工具进行API测试的方法。 8. **安全性与隐私保护**:涵盖OAuth、JWT认证机制,HTTPS安全通信,以及防止SQL注入、
内容概要:本文介绍了一种先进的综合能源系统优化调度模型,该模型将风电、光伏、光热发电等新能源与燃气轮机、燃气锅炉等传统能源设备相结合,利用信息间隙决策(IGDT)处理不确定性。模型中引入了P2G(电转气)装置和碳捕集技术,实现了碳经济闭环。通过多能转换和储能系统的协同调度,提高了系统的灵活性和鲁棒性。文中详细介绍了模型的关键组件和技术实现,包括IGDT的鲁棒性参数设置、P2G与碳捕集的协同控制、储能系统的三维协同调度等。此外,模型展示了在极端天气和负荷波动下的优异表现,显著降低了碳排放成本并提高了能源利用效率。 适合人群:从事能源系统优化、电力调度、碳交易等相关领域的研究人员和工程师。 使用场景及目标:适用于需要处理多种能源形式和不确定性的综合能源系统调度场景。主要目标是提高系统的灵活性、鲁棒性和经济效益,减少碳排放。 其他说明:模型具有良好的扩展性,可以通过修改配置文件轻松集成新的能源设备。代码中包含了详细的注释和公式推导,便于理解和进一步改进。
毕业设计的论文撰写、终期答辩相关的资源
该是一个在 Kaggle 上发布的数据集,专注于 2024 年出现的漏洞(CVE)信息。以下是关于该数据集的详细介绍:该数据集收集了 2024 年记录在案的各类漏洞信息,涵盖了漏洞的利用方式(Exploits)、通用漏洞评分系统(CVSS)评分以及受影响的操作系统(OS)。通过整合这些信息,研究人员和安全专家可以全面了解每个漏洞的潜在威胁、影响范围以及可能的攻击途径。数据主要来源于权威的漏洞信息平台,如美国国家漏洞数据库(NVD)等。这些数据经过整理和筛选后被纳入数据集,确保了信息的准确性和可靠性。数据集特点:全面性:涵盖了多种操作系统(如 Windows、Linux、Android 等)的漏洞信息,反映了不同平台的安全状况。实用性:CVSS 评分提供了漏洞严重程度的量化指标,帮助用户快速评估漏洞的优先级。同时,漏洞利用信息(Exploits)为安全研究人员提供了攻击者可能的攻击手段,有助于提前制定防御策略。时效性:专注于 2024 年的漏洞数据,反映了当前网络安全领域面临的新挑战和新趋势。该数据集可用于多种研究和实践场景: 安全研究:研究人员可以利用该数据集分析漏洞的分布规律、攻击趋势以及不同操作系统之间的安全差异,为网络安全防护提供理论支持。 机器学习与数据分析:数据集中的结构化信息适合用于机器学习模型的训练,例如预测漏洞的 CVSS 评分、识别潜在的高危漏洞等。 企业安全评估:企业安全团队可以参考该数据集中的漏洞信息,结合自身系统的实际情况,进行安全评估和漏洞修复计划的制定。
内容概要:本文档作为建模大赛的入门指南,详细介绍了建模大赛的概念、类型、竞赛流程、核心步骤与技巧,并提供实战案例解析。文档首先概述了建模大赛,指出其以数学、计算机技术为核心,主要分为数学建模、3D建模和AI大模型竞赛三类。接着深入解析了数学建模竞赛,涵盖组队策略(如三人分别负责建模、编程、论文写作)、时间安排(72小时内完成全流程)以及问题分析、模型建立、编程实现和论文撰写的要点。文中还提供了物流路径优化的实战案例,展示了如何将实际问题转化为图论问题并采用Dijkstra或蚁群算法求解。最后,文档推荐了不同类型建模的学习资源与工具,并给出了新手避坑建议,如避免过度复杂化模型、重视可视化呈现等。; 适合人群:对建模大赛感兴趣的初学者,特别是高校学生及希望参与数学建模竞赛的新手。; 使用场景及目标:①了解建模大赛的基本概念和分类;②掌握数学建模竞赛的具体流程与分工;③学习如何将实际问题转化为数学模型并求解;④获取实战经验和常见错误规避方法。; 其他说明:文档不仅提供了理论知识,还结合具体实例和代码片段帮助读者更好地理解和实践建模过程。建议新手从中小型赛事开始积累经验,逐步提升技能水平。
该资源为protobuf-6.30.1-cp310-abi3-win32.whl,欢迎下载使用哦!
内容概要:本文档详细介绍了基于Linux系统的大数据环境搭建流程,涵盖从虚拟机创建到集群建立的全过程。首先,通过一系列步骤创建并配置虚拟机,包括设置IP地址、安装MySQL数据库等操作。接着,重点讲解了Ambari的安装与配置,涉及关闭防火墙、设置免密登录、安装时间同步服务(ntp)、HTTP服务以及配置YUM源等关键环节。最后,完成了Ambari数据库的创建、JDK的安装、Ambari server和agent的部署,并指导用户创建集群。整个过程中还提供了针对可能出现的问题及其解决方案,确保各组件顺利安装与配置。 适合人群:具有Linux基础操作技能的数据工程师或运维人员,尤其是那些需要构建和管理大数据平台的专业人士。 使用场景及目标:适用于希望快速搭建稳定可靠的大数据平台的企业或个人开发者。通过本指南可以掌握如何利用Ambari工具自动化部署Hadoop生态系统中的各个组件,从而提高工作效率,降低维护成本。 其他说明:文档中包含了大量具体的命令行指令和配置细节,建议读者按照顺序逐步操作,并注意记录下重要的参数值以便后续参考。此外,在遇到问题时可参照提供的解决方案进行排查,必要时查阅官方文档获取更多信息。
内容概要:本文详细介绍了如何在MATLAB R2018A中使用最小均方(LMS)自适应滤波算法对一维时间序列信号进行降噪处理,特别是针对心电图(ECG)信号的应用。首先,通过生成模拟的ECG信号并加入随机噪声,创建了一个带有噪声的时间序列。然后,实现了LMS算法的核心部分,包括滤波器阶数、步长参数的选择以及权重更新规则的设计。文中还提供了详细的代码示例,展示了如何构建和训练自适应滤波器,并通过图形化方式比较了原始信号、加噪信号与经过LMS处理后的降噪信号之间的差异。此外,作者分享了一些实用的经验和技术要点,如参数选择的影响、误差曲线的解读等。 适用人群:适用于具有一定MATLAB编程基础并对信号处理感兴趣的科研人员、工程师或学生。 使用场景及目标:本教程旨在帮助读者掌握LMS算法的基本原理及其在实际项目中的应用方法,特别是在生物医学工程、机械故障诊断等领域中处理含噪信号的任务。同时,也为进一步探索其他类型的自适应滤波技术和扩展到不同的信号处理任务奠定了基础。 其他说明:尽管LMS算法在处理平稳噪声方面表现出色,但在面对突发性的强干扰时仍存在一定局限性。因此,在某些特殊场合下,可能需要与其他滤波技术相结合以获得更好的效果。
内容概要:本文详细介绍了基于TMS320F2812 DSP芯片的光伏并网逆变器设计方案,涵盖了主电路架构、控制算法、锁相环实现、环流抑制等多个关键技术点。首先,文中阐述了双级式结构的主电路设计,前级Boost升压将光伏板输出电压提升至约600V,后级采用三电平NPC拓扑的IGBT桥进行逆变。接着,深入探讨了核心控制算法,如电流PI调节器、锁相环(SOFGI)、环流抑制等,并提供了详细的MATLAB仿真模型和DSP代码实现。此外,还特别强调了PWM死区时间配置、ADC采样时序等问题的实际解决方案。最终,通过实验验证,该方案实现了THD小于3%,MPPT效率达98.7%,并有效降低了并联环流。 适合人群:从事光伏并网逆变器开发的电力电子工程师和技术研究人员。 使用场景及目标:适用于光伏并网逆变器的研发阶段,帮助工程师理解和实现高效稳定的逆变器控制系统,提高系统的性能指标,减少开发过程中常见的错误。 其他说明:文中提供的MATLAB仿真模型和DSP代码可以作为实际项目开发的重要参考资料,有助于缩短开发周期,提高成功率。