📄 lcd.c
字号:
}
/*消点子程序*/
void ClrDot(int row,int col)
{
int pageaddr,pagelr,data0,bit;
int bitclr=0x01;
PAGEADD=0xB8;
pageaddr=row/8; //页面地址
pagelr=PAGEADD|pageaddr;
command=pagelr;
WRCommandL();
WRCommandR();
bit=~(bitclr<<(row%8));
if (col<50)
{
command=col; //设置列地址
WRCommandL();
command=0xe0; //设置读-修改-写
WRCommandL();
data0=RDDataL(); //空读
data0=RDDataL(); //读取该处的初始数据
data=(data0&bit);
WRDataL();
command=0xEE; //退出读-修改-写
WRCommandL();
}
else
{
col-=50;
command=col; //设置列地址
WRCommandR();
command=0xe0; //设置读-修改-写
WRCommandR();
data0=RDDataR(); //空读
data0=RDDataR(); //读取该处的初始数据
data=(data0&bit);
WRDataR();
command=0xEE; //退出读-修改-写
WRCommandR();
}
}
/*画线子程序:为了回避复杂的浮点运算,采用了整数数字微分的方法*/
/*以(x行,y列)为起点,以(x1行,y1列)为终点画一条直线*/
void DrawLines(int x,int y,int x1,int y1)
{
int dx,dy,err = 0;
if(y != y1)
{
if(y1 < y) /*这个判断语句保证了y1>=y这个前提*/
{
dx = y1; dy = x1;
y1 = y; x1 = x;
y = dx; x = dy;
}
dy = y1 - y;
dx = x1 - x;
if((x1 >= x)&&((y1 - y) <= (x1 - x)))
{
for(;x != x1;)
{
if(err < 0)
{
DrawDot(x + 1,y);
x += 1;
err += dy;
}
else
{
DrawDot(x + 1,y + 1);
x += 1;
y += 1;
err += (dy - dx);
}
}
}
else
if((x1 >= x)&&((y1 - y) > (x1 - x)))
{
for(;y != y1;)
{
if(err < 0)
{
DrawDot(x + 1,y + 1);
x += 1;
y += 1;
err += (dy - dx);
}
else
{
DrawDot(x,y + 1);
y += 1;
err -= dx;
}
}
}
else
if((x1 < x)&&((y1 - y) <= (x - x1)))
{
for(;x != x1;)
{
if(err < 0)
{
DrawDot(x - 1,y);
x -= 1;
err += dy;
}
else
{
DrawDot(x - 1,y + 1);
x -= 1;
y += 1;
err += (dy + dx);
}
}
}
else
if((x1 < x)&&((y1 - y) > (x1 - x)))
{
for(;y != y1;)
{
if(err < 0)
{
DrawDot(x - 1,y + 1);
x -= 1;
y += 1;
err += (dy + dx);
}
else
{
DrawDot(x,y + 1);
y += 1;
err += dx;
}
}
}
}
else
{
dx = x; dy = x1;
if(x < x1)
{
dx = x1;
dy = x;
}
for(;dy < dx;dy++)
DrawDot(dy,y);
}
}
/*画圆子程序:这里应用贝森海姆圆算法来绘制一个圆,以(x,y)为圆心以r为半径画一个圆*/
void DrawCircle(int x,int y,int r)
{
int x1,y1,x2,y2,a,b,delta1,delta2;
x1 = 0; y1 = r;
x2 = r; y2 = 0;
for(;x1 <= x2;)
{ a = x1; b = y1;
delta1 = (a + 1) * (a + 1) + b * b - r * r - b;
if(delta1 >= 0)
{ x1 += 1;
y1 -= 1;
}
else
{x1 += 1;
}
a = y2; b = x2;
delta2 = (a + 1) * (a + 1) + b * b - r * r - b;
if(delta2 >= 0)
{ x2 -= 1;
y2 += 1;
}
else
{y2 += 1;
}
DrawDot(x1 + x,y1 + y);
DrawDot(x1 + x,-1 * y1 + y);
DrawDot(-1 * x1 + x,y1 + y);
DrawDot(-1 * x1 + x,-1 * y1 + y);
DrawDot(x2 + x,y2 + y);
DrawDot(x2 + x,-1 * y2 + y);
DrawDot(-1 * x2 + x,y2 + y);
DrawDot(-1 * x2 + x,-1 * y2 + y);
}
}
/*画坐标轴,x0(行)y0(列)为原点坐标,length为坐标长度*/
void DrawCoordinate(int x0,int y0,int length)
{
DrawLines(x0,y0-4,x0,y0+length); //横轴
DrawLines(x0+4,y0,x0-length,y0); //纵轴
DrawLines(x0,y0+length,x0-4,y0+length-4); //横轴箭头
DrawLines(x0,y0+length,x0+4,y0+length-4);
DrawLines(x0-length,y0,x0-length+4,y0+4); //纵轴箭头
DrawLines(x0-length,y0,x0-length+4,y0-4);
}
//获得数组中的最大值
int GetMaxNum(int *ptr,int cnt)
{
int i,max = 0;
for(i = 0;i < cnt;i++)
{
if(max < ptr[i])
max = ptr[i];
}
return max;
}
char CanDraw(int x,int y,char fillstyle)
{
if(fillstyle == 0)
{
if((x + y) / 4 * 4 == x + y)
return 1; /*是偶数的话返回1,画该点*/
else
return 0;
}
else
{
if(((x - y) >= 0 ? (x - y) : (y - x)) / 4 * 4 == ((x - y) >= 0 ? (x - y) : (y - x)))
return 1; /*是偶数的话返回1,画该点*/
else
return 0;
}
}
/*把屏幕某一部分涂黑:(x,y)是区域左上角坐标,(x1,y1)是区域右下角坐标,最后一个参数是填充方式*/
void BarFill(int x,int y,int x1,int y1,char fillstyle)
{
int i,j;
for(i = y;i <= y1;i++)
for(j = x;j <= x1;j++)
if((CanDraw(j,i,fillstyle))||((i == y)||(i == y1)||(j == x1)||(j == x)))
DrawDot(i,j);
}
/*图像显示程序:根据一个整数数组(里面有cnt个元素)显示一个柱状的显示图,
参数x,y,x1,y1代表一个矩形区域的左上角和右下角的坐标*/
void DrawBars(int *ptr,int cnt,int x,int y,int x1,int y1)
{
int k;
int yitem = ((y1-y+1)/GetMaxNum(ptr,cnt));
int xitem = ((x1-x+1)/cnt);
DrawCoordinate(y1,x,x1-x+5);
if(yitem == 0)
yitem = 1;
for(k = 0;k < cnt;k++)
{
if(k / 2 * 2 == k) /*k为偶数的话*/
{
BarFill(x+4+xitem*k,y1-yitem*ptr[k],x+xitem*(k+1),y1,0);
}
else
BarFill(x+4+xitem*k,y1-yitem*ptr[k],x+xitem*(k+1),y1,1);
}
}
/*休闲状态*/
/*进入休闲状态*/
void StatisDriveON(void){
command=0xAe; //关显示
WRCommandL();
WRCommandR();
command=0xA5; //进入休闲状态
WRCommandL();
WRCommandR();
}
/*退出休闲状态*/
void StatisDriveOFF(void){
command=0xAF; //退出休闲状态
WRCommandL();
WRCommandR();
command=0xA4; //开显示
WRCommandL();
WRCommandR();
}
/*ADC实验*/
/*逆向排序*/
void ADCReverse(void){
command=0xA1; //逆向排列
WRCommandL();
// WRCommandR();
command=0xB8; //设置页面地址
WRCommandL();
// WRCommandR();
command=0x00; //设置列地址
WRCommandL();
// WRCommandR();
data=0x0F;
for(i=0;i<50;i++){
WRDataL();
// WRDataR();
WaitNms(1000);}
}
/*该例程中采用的是4*4键盘。
0xEE,"F1",0xDE,"1",0xBE,"2",0x7E,"3",
0xED,"F2",0xDD,"4",0xBD,"5",0x7D,"6",
0xEB,"F3",0xDB,"7",0xBB,"8",0x7B,"9",
0xE7,"F4",0xD7,"clear",0xB7,"0",0x77,"enter"
KeyValue[4]={0xfe,0xfd,0xfb,0xf7};
KeyTable[16]={0xee,0xde,0xbe,0x7e,
0xed,0xdd,0xbd,0x7d,
0xeb,0xdb,0xbb,0x7b,
0xe7,0xd7,0xb7,0x77};
由于GP32的PTA口兼有键盘中断功能,因此将键盘的行、列共8条线连接到PTA口上,
其中行1-4连接到PTA0-3上,列1-4连接到PTA4-7上。这里提供一个键盘编程实例,
涉及如何扫描键盘获得键值,中断获取键值,键盘编码等问题。在编程时将PTA0-3定义为输出,
将PTA4-7定义为输入并具有内部上拉电阻,那么"F1"键对应于PTA7~PTA0=11101110,即$EE;
"1"键对应于PTA7~PTA0=11011110,即$DE;...;"#"键对应于PTA7~PTA0=01110111,即$77。*/
/*键盘初始化*/
void KeyInit(void){
PTA=0x00;
DDRA=0x0f;
PTAPUE=0xf0;
INTKBIER=0xf0;
}
/*读按键值*/
unsigned char ReadKey(void){
unsigned char temp,tempdata,key;
unsigned int k;
for(k=0;k<4;k++){ //依次扫描四行
temp=KeyValue[k]; //使第k根行扫描线为低电平
tempdata=PTA; //
tempdata|=0x0F; //PTA4-7保留原态,令PTA0-3为1
tempdata&=temp;
PTA=tempdata;
nop();
nop();
tempdata=PTA;
tempdata&=0xF0;
if (tempdata!=0xf0) {
key=PTA;
goto readkey1;
}
}
readkey1: return key;
}
/*键盘中断*/
@interrupt void KeyISR(void){
unsigned char KeyValue;
unsigned int OutValue;
unsigned char k;
INTKBSCR|=0x02;
KeyValue=ReadKey();
for(k=0;k<16;k++){
if(KeyValue==KeyTable[k]){
OutValue=k;
}
// break;
}
/*F1显示西文,F2文本方式下显示汉字,F3图形方式下显示汉字,F4*/
switch(OutValue){
case 0: //"F1"显示西文字符串
CLRDisplayL();
CLRDisplayR();
DisplayChar();
break;
case 1: //"1"
CLRDisplayL();
CLRDisplayR();
DrawDot(15,15); //画点
DrawDot(50,90);
break;
case 2: //"2"
CLRDisplayL();
CLRDisplayR();
DrawDot(10,10); //先画点再消点
DrawDot(40,90);
WaitNms(2000);
ClrDot(10,10);
ClrDot(40,90);
break;
case 3: //"3"
CLRDisplayL();
CLRDisplayR();
DrawLines(20,10,30,90);//画线
break;
case 4: //"F2"
CLRDisplayL();
CLRDisplayR();
break;
case 5: //"4"
CLRDisplayL();
CLRDisplayR();
DrawCircle(40,40,30); //画圆
break;
case 6: //"5"
CLRDisplayL();
CLRDisplayR();
DrawCoordinate(50,6,40); //画坐标轴
break;
case 7: //"6"
CLRDisplayL();
CLRDisplayR();
DrawBars(ptr,5,5,5,58,58); //画柱状图
break;
case 8: //"F3"图形方式下显示汉字
CLRDisplayL();
CLRDisplayR();
DisplayChinese();
break;
case 9: //"7"
CLRDisplayL();
CLRDisplayR();
// LeftScroll(); //画面左滚
break;
case 10: //"8"
CLRDisplayL();
CLRDisplayR();
UpScroll(); //画面上滚
break;
case 11: //"9"
CLRDisplayL();
CLRDisplayR();
// RightScroll(); //画面右滚
break;
case 12: //"F4"
CLRDisplayL();
CLRDisplayR(); //
ADCReverse();
break;
case 13: //"Clear"
CLRDisplayL();
CLRDisplayR();
break;
case 14: //"0"
CLRDisplayL();
CLRDisplayR();
DownScroll(); //画面下滚
break;
case 15: //"Enter"
break;
}
KeyInit();
INTKBSCR|=0x04;
INTKBSCR&=~0x02;
}
//PLL初始化
void PLLInit(void){
PCTL=0; //关闭PLL,准备进行设置
PBWC=0x80; //自动带宽模式
PCTL=1; //R=1
PMSH=1;
PMSL=0x2c; //N=012c
PMRS=0x80; //L=80
PCTL=0x22; //E=2,PLLON=1,启动PLL
while(!(PBWC&0x40)); //等待稳定输出
PCTL|=0x10; //频率锁定,选PLL作为时钟源
}
/* 系统集成模块(SIM)初始化,禁止COP(看门狗)*/
void SIMInit(void) {
CONFIG2=0x01; /* 内部总线时钟用作SCI的时钟*/
CONFIG1=0x3d; /* 允许LVE复位信号,禁止LVI的电源,LVI工作在5V,*/
/* 经过32个CGMXCLK周期退出STOP模式,禁止COP模块 */
}
/*主函数*/
void main(void)
{
unsigned char Row=0xc0;
sei(); //关中断
SIMInit(); //SIM初始化
PLLInit(); //PLL初始化
DDRC=0x0F;
PTCPUE=0xFF; //上拉电阻允许
PTC.byte=0xff;
DDRC=0xFF;
PTB=0xff;
DDRB=0xff;
Init_LCDL(); //屏幕右初始化
Init_LCDR(); //屏幕右初始化
DisplayChinese(); //初始显示中文
DisplayChar(); //初始显示西文
// UpScroll();
// DownScroll();
// ADCReverse();
// DrawDot(0,0);
// DrawDot(5,60);
// ClrDot(5,10);
KeyInit(); //键盘初始化
cli(); //关中断
for(;;); //等待键盘中断,并进行处理
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -