|
在12864上顯示一個(gè)時(shí)鐘,通過(guò)時(shí)鐘模塊的控制使得時(shí)鐘秒針一次轉(zhuǎn)動(dòng)。可調(diào)節(jié)時(shí)間。
單片機(jī)源程序如下:
- /*******************************************************************************************************/
- //程序說(shuō)明:本程序?yàn)?2864(st7920)驅(qū)動(dòng)程序,只實(shí)現(xiàn)了最簡(jiǎn)單的顯示功能
- /*******************************************************************************************************/
- #include<reg52.h>
- #include<intrins.h> //內(nèi)含-NOP-函數(shù)
- #include<stdlib.h> //內(nèi)含rand()函數(shù)
- #include<math.h>
- #include"ds1302.h"
- #define uchar unsigned char
- #define uint unsigned int
- //**********宏定義所需指令
- #define BASIC_SET 0x30
- #define EXTEND_SET 0x34
- #define DRAW_ON 0x36
- #define DRAW_OFF 0x34
- #define PI 3.14
- //*************端口定義
- sbit LCD_RS = P3^5;
- sbit LCD_RW = P3^6;
- sbit LCD_EN = P3^4;
- sbit wela = P2^6;
- sbit dula = P2^7;
- //************變量定義
- //****************短延時(shí)
- void delay(uint k)
- {
- uint i;
- uchar j;
- for(i = 0; i < k ;i ++)
- for(j = 0; j < 5 ;j ++);
- }
- void check_busy()//判忙
- {
- uchar busy;
- P0=0xff;
- LCD_RS=0;
- LCD_RW=1;
- do
- {
- LCD_EN=1;
- busy=P0;
- LCD_EN=0;
- }while(busy&0x80);
- LCD_EN=0;
- }
- //***********12864寫指令函數(shù)
- void write_com(uchar cmd)
- {
- check_busy();
- LCD_RS = 0;
- LCD_RW = 0;
- LCD_EN = 0;
- P0 = cmd;
- delay(50);
- LCD_EN = 1;
- delay(50);
- LCD_EN = 0;
- }
- //********12864寫數(shù)據(jù)函數(shù)
- void write_dat(uchar dat)
- {
- check_busy();
- LCD_RS = 1;
- LCD_RW = 0;
- LCD_EN = 0;
- P0 = dat;
- delay(5);
- LCD_EN = 1;
- delay(5);
- LCD_EN = 0;
- }
- //****************從LCD中讀數(shù)據(jù)
- uchar read_dat(void)
- {
- uchar temp;
- check_busy();
- P0 = 0XFF; //釋放數(shù)據(jù)線
- LCD_RS = 1; //數(shù)據(jù)
- LCD_RW = 1; //讀模式
- LCD_EN = 1; //為高電平進(jìn)行讀數(shù)據(jù)或指令
- delay(1);
- temp = P0;
- LCD_EN = 0;
- return temp;
- }
- //********************************************************
- //設(shè)置光標(biāo)(地址)函數(shù)
- //參數(shù)說(shuō)明:x---為行號(hào),y為列號(hào)
- //********************************************************
- void set_cursor(unsigned char x, unsigned char y)
- {
- unsigned char i;
- switch(x) //確定行號(hào)
- {
- case 0x00: i=0x80; break; //第一行
- case 0x01: i=0x90; break; //第二行
- case 0x02: i=0x88; break; //第三行
- case 0x03: i=0x98; break; //第四行
- default : break;
- }
- i = y+i; //確定列號(hào)
- write_com(i);
- }
- //********************************************************
- //顯示字符函數(shù)
- //********************************************************
- void display_char(unsigned char Alphabet)
- {
- write_dat(Alphabet); //寫入需要顯示字符的顯示碼
- }
- //********************************************************
- //指定位置顯示字符串函數(shù)
- //參數(shù)說(shuō)明:x為行號(hào),y為列號(hào)
- //********************************************************
- void display_string(unsigned char x,unsigned char y,unsigned char *Alphabet)
- {
- unsigned char i=0;
- set_cursor(x,y); //設(shè)置顯示的起始地址
- while(Alphabet[i]!='\0')
- {
- write_dat(Alphabet[i]); //寫入需要顯示字符的顯示碼
- i++;
- }
- }
- //***********************************以下為GDRAM繪圖部分****************************//
- //********繪圖顯示的清屏函數(shù)(因清屏指令在畫圖時(shí)不能用)-----注意!!!!!!!
- void gui_clear()
- {
- uchar i , j , k;
- write_com(EXTEND_SET);//擴(kuò)展指令集,8位數(shù)據(jù)傳輸
- write_com(DRAW_OFF);//繪圖顯示關(guān)閉
- for(i = 0; i < 2; i ++)//分上下兩屏寫
- {
- for(j = 0; j < 32; j ++)
- {
- write_com(0x80 + j);//寫y坐標(biāo)
- delay(1);
- if(i == 0) //寫x坐標(biāo)
- {
- write_com(0x80);
- delay(1);
- }
- else //寫下半屏
- {
- write_com(0x88);
- delay(1);
- }
- for(k = 0; k < 16; k ++)//寫一整行數(shù)據(jù)
- {
- write_dat(0x00);//寫高字節(jié)
- write_dat(0x00);//寫低字節(jié)
- delay(1);
- }
- }
- }
- write_com(DRAW_ON);//打開繪圖顯示
- write_com(BASIC_SET);//打開基本指令集
- }
- //*************************************************************************************************
- //***************有反白顯示功能的打點(diǎn)函數(shù)**********************************************************
- //參數(shù):color=1,該點(diǎn)填充1;color=0,該點(diǎn)填充白色0;
- //*************************************************************************************************
- void GUI_Point(unsigned char x,unsigned char y,unsigned char color)
- {
- unsigned char x_Dyte,x_byte; //定義列地址的字節(jié)位,及在字節(jié)中的哪1位
- unsigned char y_Dyte,y_byte; //定義為上下兩個(gè)屏(取值為0,1),行地址(取值為0~31)
- unsigned char GDRAM_hbit,GDRAM_lbit;
- write_com(0x36); //擴(kuò)展指令命令
- write_com(DRAW_OFF);//繪圖顯示關(guān)閉
- /***X,Y坐標(biāo)互換,即普通的X,Y坐標(biāo)***/
- x_Dyte=x/16; //計(jì)算在16個(gè)字節(jié)中的哪一個(gè)
- x_byte=x&0x0f; //計(jì)算在該字節(jié)中的哪一位
- y_Dyte=y/32; //0為上半屏,1為下半屏
- y_byte=y&0x1f; //計(jì)算在0~31當(dāng)中的哪一行
- write_com(0x80+y_byte); //設(shè)定行地址(y坐標(biāo)),即是垂直地址
- write_com(0x80+x_Dyte+8*y_Dyte); //設(shè)定列地址(x坐標(biāo)),并通過(guò)8*y_Dyte選定上下屏,即是水平地址
- read_dat(); //預(yù)讀取數(shù)據(jù)
- GDRAM_hbit= read_dat(); //讀取當(dāng)前顯示高8位數(shù)據(jù)
- GDRAM_lbit= read_dat(); //讀取當(dāng)前顯示低8位數(shù)據(jù)
- delay(1);
- write_com(0x80+y_byte); //設(shè)定行地址(y坐標(biāo))
- write_com(0x80+x_Dyte+8*y_Dyte); //設(shè)定列地址(x坐標(biāo)),并通過(guò)8*y_Dyte選定上下屏
- delay(1);
- if(x_byte<8) //判斷其在高8位,還是在低8位
- {
- if(color==1)
- {
- write_dat(GDRAM_hbit|(0x01<<(7-x_byte))); //置位GDRAM區(qū)高8位數(shù)據(jù)中相應(yīng)的點(diǎn)
- }
- else
- write_dat(GDRAM_hbit&(~(0x01<<(7-x_byte)))); //清除GDRAM區(qū)高8位數(shù)據(jù)中相應(yīng)的點(diǎn)
- write_dat(GDRAM_lbit); //顯示GDRAM區(qū)低8位數(shù)據(jù)
- }
- else
- {
- write_dat(GDRAM_hbit);
- if(color==1)
- write_dat(GDRAM_lbit|(0x01<<(15-x_byte))); //置位GDRAM區(qū)高8位數(shù)據(jù)中相應(yīng)的點(diǎn)
- else
- write_dat(GDRAM_lbit&(~(0x01<<(15-x_byte))));//清除GDRAM區(qū)高8位數(shù)據(jù)中相應(yīng)的點(diǎn)
- }
- write_com(DRAW_ON); //打開繪圖顯示
- write_com(0x30); //恢復(fù)到基本指令集
- }
- //***********(給定坐標(biāo)并打點(diǎn)的)任意位置打點(diǎn)函數(shù)
- void lcd_set_dot(uchar x,uchar y)
- {
- uchar x_byte,x_bit;//確定在坐標(biāo)的那一字節(jié)哪一位
- uchar y_ping , y_bit;//確定在坐標(biāo)的哪一屏哪一行
- uchar tmph , tmpl;//定義兩個(gè)臨時(shí)變量,用于存放讀出來(lái)的數(shù)據(jù)
- write_com(EXTEND_SET);//擴(kuò)展指令集
- write_com(DRAW_OFF);//繪圖顯示關(guān)閉
- x_byte = x / 16;//算出在哪一字節(jié),注意一個(gè)地址是16位的
- x_bit = x % 16;//& 0x0f;//算出在哪一位
- y_ping = y / 32;//確定在上半屏還是下半屏,0代表上半屏,1代表下半屏
- y_bit = y % 32;//& 0x1f;//確定在第幾行
- write_com(0X80 + y_bit);//先寫垂直地址(最高位必須)
- write_com(0x80 + x_byte + 8 * y_ping);//水平坐標(biāo),下半屏坐標(biāo)起始地址為0x88,(+8*y_ping)就是用來(lái)確定上半屏還是下半屏
- read_dat();//預(yù)讀取數(shù)據(jù)
- tmph = read_dat();//讀取當(dāng)前顯示高8位數(shù)據(jù)
- tmpl = read_dat();//讀取當(dāng)前顯示低8位數(shù)據(jù)
- delay(1);
- write_com(0x80 + y_bit);//讀操作會(huì)改變AC,所以重新設(shè)置一下
- write_com(0x80 + x_byte + 8 * y_ping);
- delay(1);
- if(x_bit < 8)
- {
- write_dat(tmph | (0x01 << (7 - x_bit)));//寫高字節(jié),因?yàn)樽鴺?biāo)是從左向右的,GDRAM高位在昨,低位在右
- write_dat(tmpl);//原低位數(shù)據(jù)送回
- }
- else
- {
- write_dat(tmph);//原高位數(shù)據(jù)送回
- write_dat(tmpl | (0x01 << (15 - x_bit)));
- }
- write_com(DRAW_ON); //打開繪圖顯示
- write_com(BASIC_SET);//回到基本指令集
- }
- //************畫水平線函數(shù)**********************************//
- //x0、x1為起始點(diǎn)和終點(diǎn)的水平坐標(biāo),y為垂直坐標(biāo)***************//
- //**********************************************************//
- void gui_hline(uchar x0, uchar x1, uchar y,color)
- {
- uchar bak;//用于對(duì)兩個(gè)數(shù)互換的中間變量,使x1為大值
- if(x0 > x1)
- {
- bak = x1;
- x1 = x0;
- x0 = bak;
- }
- do
- {
- //lcd_set_dot(x0 , y);//從左到右逐點(diǎn)顯示
- GUI_Point(x0,y,color);
- x0 ++;
- }
- while(x1 >= x0);
- }
- //***********畫豎直線函數(shù)***********************************//
- //x為起始點(diǎn)和終點(diǎn)的水平坐標(biāo),y0、y1為垂直坐標(biāo)***************//
- //**********************************************************//
- void gui_rline(uchar x, uchar y0, uchar y1,color)
- {
- uchar bak;//用于對(duì)兩個(gè)數(shù)互換的中間變量,使y1為大值
- if(y0 > y1)
- {
- bak = y1;
- y1 = y0;
- y0 = bak;
- }
- do
- {
- //lcd_set_dot(x , y0);//從上到下逐點(diǎn)顯示
- GUI_Point(x,y0,color);
- y0 ++;
- }
- while(y1 >= y0);
- }
- //*********任意兩點(diǎn)間畫直線*********************************//
- //x0、y0為起始點(diǎn)坐標(biāo),x1、y1為終點(diǎn)坐標(biāo)**********************//
- //**********************************************************//
- void gui_line(uchar x0 , uchar y0 , uchar x1 , uchar y1,color)
- {
- char dx;//直線x軸差值
- char dy;//直線y軸差值
- char dx_sym;//x軸增長(zhǎng)方向,為-1時(shí)減值方向,為1時(shí)增值方向
- char dy_sym;//y軸增長(zhǎng)方向,為-1時(shí)減值方向,為1時(shí)增值方向
- char dx_x2;//dx*2值變量,用于加快運(yùn)算速度
- char dy_x2;//dy*2值變量,用于加快運(yùn)算速度
- char di; //決策變量
- if(x0 == x1)//判斷是否為垂直線
- {
- gui_rline(x0 , y0 , y1,color);//畫垂直線
- return;
- }
- if(y0 == y1)//判斷是否為水平線
- {
- gui_hline(x0 , x1 , y0,color);//畫水平線
- return;
- }
- dx = x1 - x0;//求取兩點(diǎn)之間的差值
- dy = y1 - y0;
- //****判斷增長(zhǎng)方向,或是否為水平線、垂直線、點(diǎn)*//
- if(dx > 0)//判斷x軸方向
- dx_sym = 1;
- else
- {
- if(dx < 0)
- dx_sym = -1;
- else
- {
- gui_rline(x0 , y0 , y1,color);
- return;
- }
- }
- if(dy > 0)//判斷y軸方向
- dy_sym = 1;
- else
- {
- if(dy < 0)
- dy_sym = -1;
- else
- {
- gui_hline(x0 , x1 , y0,color);
- return;
- }
- }
- /*將dx、dy取絕對(duì)值***********/
- dx = dx_sym * dx;
- dy = dy_sym * dy;
- /****計(jì)算2倍的dx、dy值*******/
- dx_x2 = dx * 1;//我改為了一倍,這樣才跟真實(shí)的兩點(diǎn)對(duì)應(yīng)
- dy_x2 = dy * 1;
- /***使用bresenham法進(jìn)行畫直線***/
- if(dx >= dy)//對(duì)于dx>=dy,使用x軸為基準(zhǔn)
- {
- di = dy_x2 - dx;
- while(x0 != x1)
- {
- //lcd_set_dot(x0,y0);
- GUI_Point(x0,y0,color);
- x0 +=dx_sym;
- if(di < 0)
- di += dy_x2;//計(jì)算出下一步的決策值
-
- else
- {
- di += dy_x2 - dx_x2;
- y0 += dy_sym;
- }
- }
- //lcd_set_dot(x0, y0);//顯示最后一點(diǎn)
- GUI_Point(x0,y0,color);
- }
- else //對(duì)于dx<dy使用y軸為基準(zhǔn)
- {
- di = dx_x2 - dy;
- while(y0 != y1)
- {
- //lcd_set_dot(x0, y0);
- GUI_Point(x0,y0,color);
- y0 += dy_sym;
- if(di < 0)
- di += dx_x2;
- else
- {
- di += dx_x2 - dy_x2;
- x0 += dx_sym;
- }
- }
- GUI_Point(x0,y0,color);
- //lcd_set_dot(x0, y0);//顯示最后一點(diǎn)
- }
- }
- //****************畫圓函數(shù)*********************************//
- //x0、y0為圓心坐標(biāo),r為圓的半徑****************************//
- //*********************************************************//
- void gui_circle(uchar x0 , uchar y0 , uchar r)
- {
- char a , b;
- char di;
- if(r > 31 || r == 0)//圓大于液晶屏或者沒(méi)半徑則返回
- return;
- a = 0;
- b = r;
- di = 3 - 2 * r;//判斷下個(gè)點(diǎn)位置的標(biāo)志
- while(a <= b)
- {
- lcd_set_dot( x0 - b , y0 - a);//3
- lcd_set_dot( x0 + b , y0 - a); //0
- lcd_set_dot( x0 - a , y0 + b); //1
- lcd_set_dot( x0 - b , y0 - a); //7
- lcd_set_dot( x0 - a , y0 - b); //2
- lcd_set_dot( x0 + b , y0 + a); //4
- lcd_set_dot( x0 + a , y0 - b); //5
- lcd_set_dot( x0 + a , y0 + b); //6
- lcd_set_dot( x0 - b , y0 + a);
- a ++;
- //***使用bresenham算法畫圓********/
- if(di < 0)
- di += 4 * a + 6;
- else
- {
- di += 10 + 4 * (a - b);
- b --;
- }
- lcd_set_dot( x0 + a , y0 + b);
- }
- }
- //****************12864初始化函數(shù)
- void lcd_init()
- {
- write_com(0x30);//基本指令操作,8位并口
- delay(1);
- write_com(0x06);//設(shè)置為游標(biāo)右移,DDRAM地址加一,畫面不動(dòng)
- delay(1);
- write_com(0x0c);//顯示開,關(guān)光標(biāo)
- delay(1);
- write_com(0x01);//清除lcd顯示內(nèi)容
- delay(1);
- }
- /***************************************************
- 函數(shù)名稱:LcdTimeX(uint8 Length,uint8 Angle)
- 函數(shù)功能:計(jì)算指針的X坐標(biāo)
- 輸入?yún)?shù):circle_x:圓心橫坐標(biāo)
- Length :半徑長(zhǎng)度
- Angle :角度
- 輸出參數(shù): x坐標(biāo)
- ****************************************************/
- unsigned char Lcd_TimeX(unsigned char circle_x,unsigned char Length,unsigned char Angle)
- {
- unsigned char x;
- if((Angle>0) && (Angle<=15))
- {
- x = circle_x + Length * (sin(PI * Angle / 30));
- }
- else if(Angle > 15 && Angle <= 30)
- {
- x = circle_x + Length * cos((PI * Angle) / 30 - (PI / 2 ));
- }
- else if(Angle > 30 && Angle <= 45)
- {
- x = circle_x - Length * sin((PI * Angle) / 30- PI);
- }
- else
- {
- x = circle_x-Length * cos((PI * Angle) / 30 - ((3 * PI) / 2));
- }
- return x;
- }
- /***************************************************
- 函數(shù)名稱:LcdTimeY(uint8 Length,uint8 Angle)
- 函數(shù)功能:計(jì)算指針的Y坐標(biāo)
- 輸入?yún)?shù):circle_y:圓心縱坐標(biāo)
- Length :半徑長(zhǎng)度
- Angle :角度
- 輸出參數(shù): Y坐標(biāo)
- ****************************************************/
- unsigned char Lcd_TimeY(unsigned char circle_y,unsigned char Length,unsigned char Angle)
- {
- unsigned char y;
- if((Angle>0) && (Angle<=15))
- {
- y = circle_y - Length * (cos(PI * Angle / 30));
- }
- else if(Angle > 15 && Angle <= 30)
- {
- y = circle_y + Length * sin((PI * Angle) / 30 - (PI / 2 ));
- }
- else if(Angle > 30 && Angle <= 45)
- {
- y = circle_y + Length * cos((PI * Angle) / 30- PI);
- }
- else
- {
- y = circle_y - Length * sin((PI * Angle) / 30 - ((3 * PI) / 2));
- }
- return y;
- }
- void init_Point_Clock() //初始化表盤
- {
- unsigned char i;
-
- for(i=0;i<60;i++)
- {
- if((i%5)==0) //畫刻度(0,5,10,15。。。)
- {
- gui_line(Lcd_TimeX(32,30,i),Lcd_TimeY(32,30,i),Lcd_TimeX(32,27,i),Lcd_TimeY(32,27,i),1);
- }
- }
- }
- struct POINT_CLOCK
- {
- unsigned char hour;
- unsigned char minute;
- unsigned char second;
- }Point_Time[2];
- /*========================================================================
- *name:Display_Pointer(struct POINT_CLOCK AA,unsigned char color)
- *function:顯示時(shí)、分、秒指針
- *參 數(shù):結(jié)構(gòu)體: 時(shí)分秒
- * color: 0不顯示 1:顯示
- *注:秒針長(zhǎng)24
- 分針長(zhǎng)17
- 秒針長(zhǎng)12
- =========================================================================*/
- /*void Display_Pointer(struct POINT_CLOCK AA) //指針顯示
- {
- //Lcd_Line(Lcd_TimeX(32,24,AA.second),Lcd_TimeY(32,24,AA.second),32,32,color);
- gui_line(Lcd_TimeX(32,24,AA.second),Lcd_TimeY(32,24,AA.second),32,32,1);//秒針
-
- //Lcd_Line(Lcd_TimeX(32,17,AA.minute),Lcd_TimeY(32,17,AA.minute),32,32,color);
- gui_line(Lcd_TimeX(32,17,AA.minute),Lcd_TimeY(32,17,AA.minute),32,32,1);//分針
-
- //Lcd_Line(Lcd_TimeX(32,12,AA.minute/10+5*(AA.hour%12)),Lcd_TimeY(32,12,AA.minute/10+5*(AA.hour%12)),32,32);
- gui_line(Lcd_TimeX(32,12,AA.minute/10+5*(AA.hour%12)),Lcd_TimeY(32,12,AA.minute/10+5*(AA.hour%12)),32,32,1);
- //時(shí)針
- }*/
- void refresh()
- {
- if(Point_Time[0].second!=Point_Time[1].second) //秒刷新
- {
- gui_line(Lcd_TimeX(32,24,Point_Time[1].second),Lcd_TimeY(32,24,Point_Time[1].second),32,32,0);
- ……………………
- …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼
所有資料51hei提供下載:
12864顯示模擬時(shí)鐘.rar
(59.93 KB, 下載次數(shù): 45)
2018-5-8 13:28 上傳
點(diǎn)擊文件名下載附件
|
|