|
硬件設(shè)計(jì):AT89S52單片機(jī)通過(guò)MAX232實(shí)現(xiàn)電平轉(zhuǎn)換與串口連接。由于電能表采用RS485通信,因此串口與電能表之間必須使用RS232/RS485轉(zhuǎn)換器UT-2216進(jìn)行連接。 軟件設(shè)計(jì):實(shí)時(shí)時(shí)間的顯示和通信程序設(shè)計(jì)。要實(shí)現(xiàn)實(shí)時(shí)顯示就需要對(duì)DS1302時(shí)鐘芯片和液晶LCD1602進(jìn)行編程,將DS1302的數(shù)據(jù)讀出來(lái)顯示在LCD1602第一行上,LCD1602也要顯示電能表數(shù)據(jù)。通信方式為主從站方式通信,單片機(jī)為主站,主站需要發(fā)送讀數(shù)據(jù)命令幀和接收電能表應(yīng)答回復(fù)的數(shù)據(jù),因此,就需要設(shè)計(jì)單片機(jī)發(fā)送命令和接收數(shù)據(jù)的程序。將接收到的數(shù)據(jù)儲(chǔ)存在單片機(jī)存儲(chǔ)器中,在程序中將其存于數(shù)組中。最后把數(shù)組中的數(shù)據(jù)取出來(lái)寫(xiě)入液晶LCD1602中,顯示在液晶上。
IMG_20130510_103257.jpg (114.66 KB, 下載次數(shù): 119)
下載附件
2017-1-19 20:40 上傳
IMG_20130510_103730.jpg (83.45 KB, 下載次數(shù): 130)
下載附件
2017-1-19 20:40 上傳
DSCN2973.jpg (147.75 KB, 下載次數(shù): 149)
下載附件
2017-1-19 20:40 上傳
源代碼如下:
- # include<reg52.h>
- # include<intrins.h> //包含_nop_()函數(shù)定義的頭文件
- # define uchar unsigned char
- # define uint unsigned int
- sbit SCLK=P1^0; //位定義1302芯片的接口,時(shí)鐘輸出端口定義在P1.0引腳
- sbit DATA=P1^1; //位定義1302芯片的接口,數(shù)據(jù)輸出端定義在P1.1引腳
- sbit RST=P1^2; //位定義1302芯片的接口,復(fù)位端口定義在P1.2引腳
- sbit RS=P2^0; //寄存器選擇位,將RS位定義為P2.0引腳
- sbit RW=P2^1; //讀寫(xiě)選擇位,將RW位定義為P2.1引腳
- sbit E=P2^2; //使能信號(hào)位,將E位定義為P2.2引腳
- sbit BF=P0^7; //忙碌標(biāo)志位,,將BF位定義為P0.7引腳
- uchar RecNum=0;
- uint cs;//存放校驗(yàn)碼
- uchar con;//存放控制碼
- uchar add[6];
- uchar idata rdata[6];
- uchar code string[ ]= {"Welcome to use"};
- uchar code string1[ ]= {"kWh"};
- uchar code digit[10]={"0123456789"}; //定義字符數(shù)組顯示數(shù)字
- unsigned char code key_code[]={ 0xee,0xde,0xbe,0x7e,0xed,0xdd,0xbd,0x7d,0xeb,0xdb,0xbb,0x7b,0xe7,0xd7,0xb7,0x77}; //鍵盤編碼
- uchar add1[6]={0x53,0x50,0x00,0x00,0x00,0x00};// 存放1#電能表地址碼,(地址碼已經(jīng)確定,通過(guò)電能表測(cè)試軟件確定)
- uchar add2[6];// 存放2#電能表地址碼
- uchar tdata[2]={0x10,0x90};// 存放要發(fā)送的數(shù)據(jù)
- uchar tdata1[2]={0x20,0x90};
- uchar tdata2[2]={0x10,0x94};
- uchar tdata3[2]={0x20,0x94};
- /***************************特殊字符定義************************/
- # define PRECURSOR_CHAR 0xfe;//定義前導(dǎo)字符
- # define START_CHAR 0x68;//定義幀起始符
- # define END_CHAR 0x16;//定義幀結(jié)束符
- /***************************接收狀態(tài)定義************************/
- # define RS_WAIT 0;//等待狀態(tài)
- # define RS_AWAKEN 1;//喚醒狀態(tài)
- # define RS_ADD 2;//接收地址域狀態(tài)
- # define RS_HEADER 3;//接收幀頭狀態(tài)
- # define RS_CON 4;//接收控制碼狀態(tài)
- # define RS_DATALEN 5;//接收數(shù)據(jù)域長(zhǎng)度狀態(tài)
- # define RS_DATA 6;//接收數(shù)據(jù)域狀態(tài)
- # define RS_CHECK 7;//接收校驗(yàn)碼狀態(tài)
- # define RS_END 8;//接收結(jié)束符狀態(tài)
- /********************************延時(shí)若干毫秒 ****************************/
- void delaynms(uchar n)
- {
- uchar i,j;
- while(n--)
- {
- for(i=0;i<10;i++)
- for(j=0;j<33;j++);
- }
- }[/color][/size][/align][size=3][color=#000000][font=宋體][align=left]
- /*****************************延時(shí)若干微秒******************************/
- void delaynus(uchar n)
- {
- uchar i;
- for(i=0;i<n;i++);
- }
-
- /************矩陣鍵盤程序***********************/[/align][align=left]uchar keyscan()
- {
- uchar scan1,scan2,keycode;[/align][align=left] P1=0xf0;
- scan1=P1;
- if((scan1&0xf0)!=0xf0) //判鍵是否按下
- {
- delaynms(20); //延時(shí)20ms
- scan1=P1;
- if((scan1&0xf0)!=0xf0) //二次判鍵是否按下
- {
- P1=0x0f; //線反轉(zhuǎn)法的核心
- scan2=P1;
- keycode=scan1|scan2; //組合成鍵編碼
- }
-
- return(keycode);
- }
-
- }
- /**********************判斷液晶模塊的忙碌狀態(tài)***********************/
- bit BusyTest(void)
- {
- bit result;
- RS=0; //根據(jù)規(guī)定,RS為低電平,RW為高電平時(shí),可以讀狀態(tài)
- RW=1;
- E=1; //E=1,才允許讀寫(xiě)
- _nop_(); //空操作
- _nop_();
- _nop_();
- _nop_(); //空操作四個(gè)機(jī)器周期,給硬件反應(yīng)時(shí)間
- result=BF; //將忙碌標(biāo)志電平賦給result
- E=0; //將E恢復(fù)低電平
- return result;
- }
- /********************將模式設(shè)置指令或顯示地址寫(xiě)入液晶模塊************************/
- void WriteInstruction (uchar dictate)
- {
- while(BusyTest()==1); //如果忙就等待
- RS=0; //根據(jù)規(guī)定,RS和R/W同時(shí)為低電平時(shí),可以寫(xiě)入指令
- RW=0;
- E=0; //E置低電平(根據(jù)表8-6,寫(xiě)指令時(shí),E為高脈沖,
- // 就是讓E從0到1發(fā)生正跳變,所以應(yīng)先置"0"
- _nop_();
- _nop_(); //空操作兩個(gè)機(jī)器周期,給硬件反應(yīng)時(shí)間
- P0=dictate; //將數(shù)據(jù)送入P0口,即寫(xiě)入指令或地址
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個(gè)機(jī)器周期,給硬件反應(yīng)時(shí)間
- E=1; //E置高電平
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個(gè)機(jī)器周期,給硬件反應(yīng)時(shí)間
- E=0; //當(dāng)E由高電平跳變成低電平時(shí),液晶模塊開(kāi)始執(zhí)行命令
- }
- /*****************指定字符顯示的實(shí)際地址*********************/
- void WriteAddress(uchar x)
- {
- WriteInstruction(x|0x80); //顯示位置的確定方法規(guī)定為"80H+地址碼x"
- }
- /*********************將數(shù)據(jù)(字符的標(biāo)準(zhǔn)ASCII碼)寫(xiě)入液晶模塊**************************/
- void WriteData(uchar y)
- {
- while(BusyTest()==1);
- RS=1; //RS為高電平,RW為低電平時(shí),可以寫(xiě)入數(shù)據(jù)
- RW=0;
- E=0; //E置低電平(根據(jù)表8-6,寫(xiě)指令時(shí),E為高脈沖,
- // 就是讓E從0到1發(fā)生正跳變,所以應(yīng)先置"0"
- P0=y; //將數(shù)據(jù)送入P0口,即將數(shù)據(jù)寫(xiě)入液晶模塊
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個(gè)機(jī)器周期,給硬件反應(yīng)時(shí)間
- E=1; //E置高電平
- _nop_();
- _nop_();
- _nop_();
- _nop_(); //空操作四個(gè)機(jī)器周期,給硬件反應(yīng)時(shí)間
- E=0; //當(dāng)E由高電平跳變成低電平時(shí),液晶模塊開(kāi)始執(zhí)行命令
- }[/align][align=left]/*********************向1302寫(xiě)一個(gè)字節(jié)數(shù)據(jù)******************************/
- void Write1302(uchar dat)
- {
- uchar i;
- SCLK=0; //拉低SCLK,為脈沖上升沿寫(xiě)入數(shù)據(jù)做好準(zhǔn)備
- delaynus(2); //稍微等待,使硬件做好準(zhǔn)備
- for(i=0;i<8;i++) //連續(xù)寫(xiě)8個(gè)二進(jìn)制位數(shù)據(jù)
- {
- DATA=dat&0x01; //取出dat的第0位數(shù)據(jù)寫(xiě)入1302 低位在前,高位在后
- delaynus(2); //稍微等待,使硬件做好準(zhǔn)備
- SCLK=1; //上升沿寫(xiě)入數(shù)據(jù)
- delaynus(2); //稍微等待,使硬件做好準(zhǔn)備
- SCLK=0; //重新拉低SCLK,形成脈沖
- dat>>=1; //將dat的各數(shù)據(jù)位右移1位,準(zhǔn)備寫(xiě)入下一個(gè)數(shù)據(jù)位
- }
- }
- /********************根據(jù)命令字,向1302寫(xiě)一個(gè)字節(jié)數(shù)據(jù) Cmd,儲(chǔ)存命令字;dat,儲(chǔ)存待寫(xiě)的數(shù)據(jù)***************/
- void WriteSet1302(uchar Cmd,uchar dat)
- {
- RST=0; //禁止數(shù)據(jù)傳遞
- SCLK=0; //確保寫(xiě)數(shù)居前SCLK被拉低
- RST=1; //啟動(dòng)數(shù)據(jù)傳輸
- delaynus(2); //稍微等待,使硬件做好準(zhǔn)備
- Write1302(Cmd); //寫(xiě)入命令字
- Write1302(dat); //寫(xiě)數(shù)據(jù)
- SCLK=1; //將時(shí)鐘電平置于高電平狀態(tài)
- RST=0; //禁止數(shù)據(jù)傳遞
- }
- /************************從1302讀一個(gè)字節(jié)數(shù)據(jù)***************************/
- uchar Read1302(void)
- {
- uchar i,dat;
- delaynus(2); //稍微等待,使硬件做好準(zhǔn)備
- for(i=0;i<8;i++) //連續(xù)讀8個(gè)二進(jìn)制位數(shù)據(jù)
- { dat>>=1;
- if(DATA==1) //如果讀出的數(shù)據(jù)是1
- dat|=0x80; //將1取出,寫(xiě)在dat的最高位
- SCLK=1; //將SCLK置于高電平,為下降沿讀出
- delaynus(2); //稍微等待
- SCLK=0; //拉低SCLK,形成脈沖下降沿
- delaynus(2); //稍微等待
- }
- return dat; //將讀出的數(shù)據(jù)返回
- }
- /*****************從1302讀取一個(gè)字節(jié)數(shù)據(jù)**********************/
- uchar ReadSet1302(uchar Cmd)
- {
- uchar dat;
- RST=0; //拉低RST
- SCLK=0; //確保寫(xiě)數(shù)居前SCLK被拉低
- RST=1; //啟動(dòng)數(shù)據(jù)傳輸
- Write1302(Cmd); //寫(xiě)入命令字
- dat=Read1302(); //讀出數(shù)據(jù)
- SCLK=1; //將時(shí)鐘電平置于已知狀態(tài)
- RST=0; //禁止數(shù)據(jù)傳遞
- return dat; //將讀出的數(shù)據(jù)返回
- }
- /************************顯示秒***********************/
- void DisplaySecond(uchar x)
- {
- uchar i,j; //j,k分別儲(chǔ)存十位和個(gè)位
- i=x/10;//取十位
- j=x%10;//取個(gè)位
- WriteAddress(0x0e); //寫(xiě)顯示地址,將在第1行第15列開(kāi)始顯示
- WriteData(digit[i]); //將百位數(shù)字的字符常量寫(xiě)入LCD
- WriteData(digit[j]); //將十位數(shù)字的字符常量寫(xiě)入LCD
- delaynms(50); //延時(shí)1ms給硬件一點(diǎn)反應(yīng)時(shí)間
- }[/i][/align][align=left][i]/*************************顯示分鐘*********************/
- void DisplayMinute(uchar x)
- {
- unsigned char i,j; //j,k十位和個(gè)位
- i=x/10;//取十位
- j=x%10;//取個(gè)位
- WriteAddress(0x0b); //寫(xiě)顯示地址,將在第1行第12列開(kāi)始顯示
- WriteData(digit[i]); //將百位數(shù)字的字符常量寫(xiě)入LCD
- WriteData(digit[j]); //將十位數(shù)字的字符常量寫(xiě)入LCD
- delaynms(50); //延時(shí)1ms給硬件一點(diǎn)反應(yīng)時(shí)間
- }
- /*************************顯示小時(shí)********************/
- void DisplayHour(uchar x)
- {
- uchar i,j; //j,k十位和個(gè)位
- i=x/10;//取十位
- j=x%10;//取個(gè)位
- WriteAddress(0x08); //寫(xiě)顯示地址,將在第1行第9列開(kāi)始顯示
- WriteData(digit[i]); //將百位數(shù)字的字符常量寫(xiě)入LCD
- WriteData(digit[j]); //將十位數(shù)字的字符常量寫(xiě)入LCD
- delaynms(50); //延時(shí)1ms給硬件一點(diǎn)反應(yīng)時(shí)間
- }
- /*******************顯示日*********************/
- void DisplayDay(uchar x)
- {
- uchar i,j; //j,k十位和個(gè)位
- i=x/10;//取十位
- j=x%10;//取個(gè)位
- WriteAddress(0x06); //寫(xiě)顯示地址,將在第1行第7列開(kāi)始顯示
- WriteData(digit[i]); //將十位數(shù)字的字符常量寫(xiě)入LCD
- WriteData(digit[j]); //將個(gè)位數(shù)字的字符常量寫(xiě)入LCD
- delaynms(50); //延時(shí)1ms給硬件一點(diǎn)反應(yīng)時(shí)間
- }
- /************************顯示月**************/
- void DisplayMonth(uchar x)
- {
- uchar i,j; //j,k分別儲(chǔ)存十位和個(gè)位
- i=x/10;//取十位
- j=x%10;//取個(gè)位
- WriteAddress(0x03); //寫(xiě)顯示地址,將在第1行第4列開(kāi)始顯示
- WriteData(digit[i]); //將十位位數(shù)字的字符常量寫(xiě)入LCD
- WriteData(digit[j]); //將個(gè)位數(shù)字的字符常量寫(xiě)入LCD
- delaynms(50); //延時(shí)1ms給硬件一點(diǎn)反應(yīng)時(shí)間
- }
- /*************************顯示年**************/
- void DisplayYear(uchar x)
- {
- uchar i,j; //j,k分別儲(chǔ)存十位和個(gè)位
- i=x/10;//取十位
- j=x%10;//取個(gè)位
- WriteAddress(0x00); //寫(xiě)顯示地址,將在第1行第1列開(kāi)始顯示
- WriteData(digit[i]); //將十位位數(shù)字的字符常量寫(xiě)入LCD
- WriteData(digit[j]); //將個(gè)位數(shù)字的字符常量寫(xiě)入LCD
- delaynms(50); //延時(shí)1ms給硬件一點(diǎn)反應(yīng)時(shí)間
- }[/i][/i][/i][/i][/i][/i][/align][align=left][i][i][i] /********************時(shí)間顯示********************/
- void display_time(void)
- {
-
- uchar second,minute,hour,day,month,year; //分別儲(chǔ)存秒、分、小時(shí),日,月,年
- uchar ReadValue; //儲(chǔ)存從1302讀取的數(shù)據(jù)
- WriteAddress(0x02); //寫(xiě)年月分隔符的顯示地址, 顯示在第1行第3列
- WriteData('-'); //將字符常量寫(xiě)入LCD
- WriteAddress(0x05); //寫(xiě)月日分隔符的顯示地址, 顯示在第1行第12列
- WriteData('-'); //將字符常量寫(xiě)入LCD
- WriteAddress(0x0a); //寫(xiě)小時(shí)與分鐘分隔符的顯示地址, 顯示在第1行第6列
- WriteData(':'); //將字符常量寫(xiě)入LCD
- WriteAddress(0x0d); //寫(xiě)分鐘與秒分隔符的顯示地址, 顯示在第1行第14列
- WriteData(':'); //將字符常量寫(xiě)入LCD
- ReadValue = ReadSet1302(0x81); //從秒寄存器讀數(shù)據(jù)
- second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//將讀出數(shù)據(jù)轉(zhuǎn)化
- DisplaySecond(second); //顯示秒
- ReadValue = ReadSet1302(0x83); //從分寄存器讀
- minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
- DisplayMinute(minute); //顯示分
- ReadValue = ReadSet1302(0x85); //從分寄存器讀
- hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
- DisplayHour(hour); //顯示小時(shí)
- ReadValue = ReadSet1302(0x87); //從分寄存器讀
- day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
- DisplayDay(day); //顯示日
- ReadValue = ReadSet1302(0x89); //從分寄存器讀
- month=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
- DisplayMonth(month); //顯示月
- ReadValue = ReadSet1302(0x8d); //從分寄存器讀
- year=((ReadValue&0xf0)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
- DisplayYear(year); //顯示年[/i][/i][/i][/align][align=left][i][i][i]
- }
- /*****************數(shù)據(jù)解析*********************/
- void message_proc()
- {
- uchar mm,m,n,i;[/i][/i][/i][/align][align=left][i][i][i] WriteAddress(0x42); // 設(shè)置顯示位置
- for(i=5;i>=3;i--)
- {
- mm=((rdata[i]&0x70)>>4)*10 + (rdata[i]&0x0F);
- m=mm/10;
- n=mm%10;
- WriteData(digit[m]);
- WriteData(digit[n]);
- delaynms(100);
- }
- WriteData('.');
- delaynms(100);
- mm=((rdata[2]&0x70)>>4)*10 + (rdata[2]&0x0f);//將BCD碼轉(zhuǎn)化成字符
- m=mm/10; //取十位
- n=mm%10; //取個(gè)位
- WriteData(digit[m]);
- WriteData(digit[n]); //顯示在LCD1602上
- delaynms(100);
- for(i=0;i<3;i++)
- WriteData(string1[i]);
- delaynms(100);
- }
- /***************************1302初始化********************/
- void Init_DS1302(void)
- {[/i][/i][/i][/i][/i][/i][/align][align=left][i][i][i] /*--------------------這是每次都初始化的語(yǔ)句-----------------*/
-
- /*
-
- WriteSet1302(0x8E,0x00); //根據(jù)寫(xiě)狀態(tài)寄存器命令字,寫(xiě)入不保護(hù)指令
- WriteSet1302(0x80,((20/10)<<4|(20%10))); //根據(jù)寫(xiě)秒寄存器命令字,寫(xiě)入秒的初始值[/i][/i][/i][/align][align=left][i][i][i] WriteSet1302(0x82,((28/10)<<4|(28%10))); //根據(jù)寫(xiě)分寄存器命令字,寫(xiě)入分的初始值[/i][/i][/i][/align][align=left][i][i][i] WriteSet1302(0x84,((10/10)<<4|(10%10))); //根據(jù)寫(xiě)小時(shí)寄存器命令字,寫(xiě)入小時(shí)的初始值[/i][/i][/i][/align][align=left][i][i][i] WriteSet1302(0x86,((10/10)<<4|(10%10))); //根據(jù)寫(xiě)日寄存器命令字,寫(xiě)入日的初始值[/i][/i][/i][/align][align=left][i][i][i] WriteSet1302(0x88,((5/10)<<4|(5%10))); //根據(jù)寫(xiě)月寄存器命令字,寫(xiě)入月的初始值[/i][/i][/i][/align][align=left][i][i][i] WriteSet1302(0x8c,((13/10)<<4|(13%10))); //根據(jù)寫(xiě)年寄存器命令字,寫(xiě)入年的初始值[/i][/i][/i][/align][align=left][i][i][i] WriteSet1302(0x90,0xa5); //打開(kāi)充電功能 選擇2K電阻充電方式[/i][/i][/i][/align][align=left][i][i][i] WriteSet1302(0x8E,0x80); //根據(jù)寫(xiě)狀態(tài)寄存器命令字,寫(xiě)入保護(hù)指令
- */
- uchar flag;
-
- flag= ReadSet1302(0x81);
- if(flag&0x80)
- { //判斷時(shí)鐘芯片是否關(guān)閉
- WriteSet1302(0x8E,0x00); //根據(jù)寫(xiě)狀態(tài)寄存器命令字,寫(xiě)入不保護(hù)指令
- WriteSet1302(0x80,((10/10)<<4|(10%10))); //根據(jù)寫(xiě)秒寄存器命令字,寫(xiě)入秒的初始值
- WriteSet1302(0x82,((28/10)<<4|(28%10))); //根據(jù)寫(xiě)分寄存器命令字,寫(xiě)入分的初始值
- WriteSet1302(0x84,((10/10)<<4|(10%10))); //根據(jù)寫(xiě)小時(shí)寄存器命令字,寫(xiě)入小時(shí)的初始值
- WriteSet1302(0x86,((10/10)<<4|(10%10))); //根據(jù)寫(xiě)日寄存器命令字,寫(xiě)入日的初始值
- WriteSet1302(0x88,((5/10)<<4|(5%10))); //根據(jù)寫(xiě)月寄存器命令字,寫(xiě)入月的初始值
- WriteSet1302(0x8c,((13/10)<<4|(13%10))); //根據(jù)寫(xiě)年寄存器命令字,寫(xiě)入年的初始值
- WriteSet1302(0x90,0xa5); //打開(kāi)充電功能 選擇2K電阻充電方式
- WriteSet1302(0x8E,0x80); //根據(jù)寫(xiě)狀態(tài)寄存器命令字,寫(xiě)入保護(hù)指令
- }
-
-
- //如果不想每次都初始化時(shí)間,也就是掉電后還想讓時(shí)鐘繼續(xù)走時(shí)的話 就用上面的語(yǔ)句 [/i][/i][/i][/align][align=left][i][i][i] }
- /***************串口初始化*********************/
- void initial_serial(void)
- {[/i][/i][/i][/align][align=left][i][i][i] TMOD=0x20; // 定時(shí)器1工作于8位自動(dòng)重載模式(工作方式2), 用于產(chǎn)生波特率
- TH1=TL1=0xe8; // 波特率為1200bps
- TF1=0; // 計(jì)數(shù)未滿
- TR1=1; //啟動(dòng)定時(shí)器1
- SCON=0xd0; // 設(shè)定串行口工作方式3(11位異步收發(fā)方式) ,允許接收數(shù)據(jù)
- PCON=0x00; //波特率不加倍 //波特率不加倍(SMOD=0)
- ES=1; //開(kāi)串行口中斷
- EA=1; //開(kāi)總中斷[/i][/i][/i][/align][align=left][i][i][i]}
- /*************************LCD初始化**************************/
- void LcdInitiate(void)
- {
- delaynms(15); //延時(shí)15ms,首次寫(xiě)指令時(shí)應(yīng)給LCD一段較長(zhǎng)的反應(yīng)時(shí)間
- WriteInstruction(0x38); //顯示模式設(shè)置:16×2顯示,5×7點(diǎn)陣,8位數(shù)據(jù)接口
- delaynms(5); //延時(shí)5ms ,給硬件一點(diǎn)反應(yīng)時(shí)間
- WriteInstruction(0x38);
- delaynms(5); //延時(shí)5ms ,給硬件一點(diǎn)反應(yīng)時(shí)間
- WriteInstruction(0x38); //連續(xù)三次,確保初始化成功
- delaynms(5); //延時(shí)5ms ,給硬件一點(diǎn)反應(yīng)時(shí)間
- WriteInstruction(0x0c); //顯示模式設(shè)置:顯示開(kāi),無(wú)光標(biāo),光標(biāo)不閃爍
- delaynms(5); //延時(shí)5ms ,給硬件一點(diǎn)反應(yīng)時(shí)間
- WriteInstruction(0x06); //顯示模式設(shè)置:光標(biāo)右移,字符不移
- delaynms(5); //延時(shí)5ms ,給硬件一點(diǎn)反應(yīng)時(shí)間
- WriteInstruction(0x01); //清屏幕指令,將以前的顯示內(nèi)容清除
- delaynms(5); //延時(shí)5ms ,給硬件一點(diǎn)反應(yīng)時(shí)間[/i][/i][/i][/align][align=left][i][i][i] }
- /***************單片機(jī)(主站)發(fā)送函數(shù)********************/
- void send(uchar * add,uchar con1,uchar DataLen1,uchar *tdata)
- {
- uchar sh,j,m,ecc=0; //定義變量
- TI=0;// 發(fā)送中斷標(biāo)志復(fù)位
- sh=START_CHAR;//發(fā)送幀起始符0x68;
- ACC=sh;
- TB8=P;
- SBUF=sh;
- ecc=ecc+sh;//計(jì)算校驗(yàn)和 (校驗(yàn)和指從幀起始符到檢驗(yàn)碼之前所有各字節(jié)二進(jìn)制和)
- while(!TI);
- TI=0;
- for(j=0;j<6;j++)
- {
- sh=*(add+j);//發(fā)送地址
- ACC=sh;
- TB8=P;
- SBUF=sh;
- ecc=ecc+sh;//再一次計(jì)算校驗(yàn)和
- while(!TI);
- TI=0;
- }
- sh=START_CHAR;//發(fā)送幀起始符0x68;
- ACC=sh;
- TB8=P;
- SBUF=sh;
- ecc=ecc+sh;//計(jì)算校驗(yàn)和 (校驗(yàn)和指從幀起始符到檢驗(yàn)碼之前所有各字節(jié)二進(jìn)制和)
- while(!TI);
- TI=0;
- sh=con1;//發(fā)送控制碼
- ACC=sh;
- TB8=P;
- SBUF=sh;
- ecc=ecc+sh;//計(jì)算校驗(yàn)和
- while(!TI);
- TI=0;
- sh=DataLen1; //發(fā)送數(shù)據(jù)長(zhǎng)度
- ACC=sh;
- TB8=P;
- SBUF=sh;
- ecc=ecc+sh;//計(jì)算校驗(yàn)和
- while(!TI);
- TI=0;
- for(m=0;m<DataLen1;m++)
- {
- sh=(*(tdata+m)+0x33);// 發(fā)送數(shù)據(jù)標(biāo)識(shí)DI0 DI1,傳輸時(shí)發(fā)送方按字節(jié)進(jìn)行加33H 處理
- ACC=sh;
- TB8=P;
- SBUF=sh;
- ecc=ecc+sh;//計(jì)算校驗(yàn)和
- while(!TI);
- TI=0;
- }
- sh=ecc;
- ACC=sh;
- TB8=P;
- SBUF=sh;
- while(!TI);
- TI=0;
- ecc=0;//校驗(yàn)和清0
- sh=END_CHAR; //發(fā)送幀結(jié)束符0x16
- ACC=sh;
- TB8=P;
- SBUF=sh;
- while(!TI);
- TI=0;
- [/i][/i][/i][/align][align=left][i][i][i]}
-
- /********************主函數(shù)********************/
- void main(void)
- {
- uchar tt,i;
- LcdInitiate(); //液晶初始化
- initial_serial(); //串口初始化
- Init_DS1302(); //DS1302初始化
- WriteAddress(0x01); // 設(shè)置顯示位置為第一行的第1個(gè)字
- i = 0;
- while(string[i] != '\0') //'\0'是數(shù)組結(jié)束標(biāo)志
- {
- WriteData(string[i]);
- i++;
- delaynms(20);
-
- }
-
- WriteAddress(0x42); // 設(shè)置顯示位置為第二行的第5個(gè)字
- for(i=0;i<12;i++)
- WriteData('-'); //顯示在LCD1602上
- while(1)
- {
- P1=0xf0;
- if((P1&0xf0)!=0xf0)
- {
- tt=keyscan();
- switch (tt)
- {
- case 0xe7: send(&add1,0x01,0x02,&tdata);display_time();break;//發(fā)送讀正向有功總電能命令幀
- case 0xd7: send(&add1,0x01,0x02,&tdata1);display_time();break; //讀反向有功總電能
- case 0xb7: send(&add1,0x01,0x02,&tdata2);display_time();break; //讀上月正向有功總電能
- case 0x77: send(&add1,0x01,0x02,&tdata3);display_time();break; //讀上月反向有功總電能
- }
- }
- message_proc();
- [/i][/i][/i][/i][/i][/align][align=left][i][i][i] }
-
- }[/i][/i][/i][/align][/font][/color][/size][align=left][size=3][color=#000000][font=宋體][i][i][i]/********************單片機(jī)(主站接收)串行口中斷函數(shù)********************/
- void serial() interrupt 4
- {
- uchar ch;//存放當(dāng)前接收的字符
- static uchar ecc,flag=0;
- static uchar AddCount;//地址域計(jì)數(shù)器
- static uchar DataCount;//數(shù)據(jù)域計(jì)數(shù)器
- static uchar DataLen;//數(shù)據(jù)域長(zhǎng)度
- static uchar RecState=RS_WAIT;//串口初始接收狀態(tài)為等待
- if(RI) //接收中斷
- {
- RI=0;//中斷標(biāo)志復(fù)位
- ch=SBUF;// 將接收的字符存入ch
- ACC=ch;
- if(RB8==P) //判斷偶校驗(yàn)
- {
- if(flag==1)
- ecc=ecc+ch;//計(jì)算校驗(yàn)和
- }
- else
- RecState=RS_WAIT;//如果偶校驗(yàn)錯(cuò)誤,返回等待狀態(tài)
- if(RecNum!=0) return;//如果主程序正在處理接收緩沖區(qū)內(nèi)容,返回
- switch(RecState) //根據(jù)當(dāng)前狀態(tài)和接收字節(jié)判斷接收狀態(tài)
- {
- case 0://等待狀態(tài)
- if(ch==0xfe) //前導(dǎo)字符
- {
- RecState++;
- flag=1;//從下一個(gè)狀態(tài)開(kāi)始計(jì)算校驗(yàn)和
-
- }
- break;
- case 1: //喚醒狀態(tài)
- if(ch==0x68) //如果接收幀起始符68H
- {
- RecState++; //進(jìn)入接收地址域狀態(tài)
- AddCount=0;
- }
- else
- {
- flag=0;
- ecc=0;
- RecState=RS_WAIT;//返回等待狀態(tài)
- }
- break;
- case 2: //接收地址域狀態(tài)
- *(add+AddCount)=ch;
- AddCount++;
- if(AddCount==6)//如果接受完地址域6個(gè)字節(jié)
- {
- AddCount=0;// 地址域計(jì)數(shù)器復(fù)位
- RecState++;
- }
- break;
- case 3: //接收幀頭狀態(tài)
- if(ch==0x68)
- RecState++;
- break;
- case 4: //接收控制碼狀態(tài)
- con=ch;//保存控制碼
- RecState++;
- break;
- case 5: //接收數(shù)據(jù)域長(zhǎng)度狀態(tài)
- DataLen=ch;//取出數(shù)據(jù)域長(zhǎng)度
- if(DataLen==0)
- RecState=RecState+2;//如果數(shù)據(jù)域長(zhǎng)度為0,直接進(jìn)入校驗(yàn)和狀態(tài)
- else
- {
- RecState++;
- DataCount=0; //賦初值
- }
- break;
- case 6: //接收數(shù)據(jù)狀態(tài)
- *(rdata+DataCount)=ch-0x33; //保存數(shù)據(jù)在rdata[10]數(shù)組中
- DataCount++;
- if(DataCount==DataLen) //接收完DataLen個(gè)數(shù)據(jù)
- {
- RecState++;
- DataCount=0;//數(shù)據(jù)域計(jì)數(shù)器復(fù)位,準(zhǔn)備接收下一幀數(shù)據(jù)
- flag=0; //下一個(gè)狀態(tài)停止計(jì)算檢驗(yàn)和
- }
- break;
- case 7:
- cs=ch;//保存校驗(yàn)和
- ecc=ecc^cs;
- if(ecc==0)//校驗(yàn)和正確
- {
- RecState++;
- ecc=0;
- }
- else
- RecState=RS_WAIT; //如果校驗(yàn)和錯(cuò)誤,返回等待狀態(tài)
- break;
- case 8: //接收結(jié)束符
- if(ch==0x16) //如果接收幀結(jié)束符,表明這一幀接收正確
- {
- RecNum=DataLen;//取出字節(jié)數(shù)
- DataLen=0;
-
- }
- RecState=RS_WAIT;// 返回等待狀態(tài)
- break;
- }
- }
- }
復(fù)制代碼
|
評(píng)分
-
查看全部評(píng)分
|