目錄
一、主要功能
二、使用步驟
三、硬件資源
四、軟件設計
五、實驗現象
一、主要功能
主要功能如下:
1、LCD12864顯示時間、日期、公交車車站、溫度等
2、按鍵設置時間,顯示公交車信息
3、串口播報相應站點信息
4、按鍵控制上行、下行、手動播報站
5、LED指示上行、下行信息
二、使用步驟
基于51單片機的公交報站系統,lcd屏幕顯示時間,溫度,站點信息等等,通過按鍵來控制對應信息報站。
三、硬件資源
1、51單片機核心模塊
2、按鍵模塊
3、溫度傳感器
4、蜂鳴器模塊
5、時鐘模塊
6、LCD12864顯示模塊
四、軟件設計
#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
#include "value.h"
#include <UART.h>
sbit x_key=P1^3;
sbit s_key=P1^4;
sbit bz_key=P1^5;
sbit gb_key=P1^6;
sbit x_LED=P2^6;
sbit s_LED=P2^7;
sbit key_zhantai=P3^7;
sbit key_gongjiao=P1^7;
uchar x_mode,s_mode;
uchar x_num,s_num;
bit flag_200ms = 1;
uchar flag_c_en;
bit flag_100ms;
sbit dq=P3^2;?? ? ?//18b20 IO口的定義
uint temperature ; ? ?//溫度變量
uint flag_zhantai ; ? ?//站臺顯示標志位
uint flag_gongjiao ; ? ?//公交顯示標志位
/************ 延時函數 ?*****************/
void delay_uint(uint z)
{
?while(z--);
}
/********************************************************************
* 名稱 : delay_1ms()
* 功能 : 延時1ms函數
* 輸入 : q
* 輸出 : 無
***********************************************************************/
void delay_1ms(uint q)
{?? ?
?uint i,j;
?for(i=0;i<q;i++)
?for(j=0;j<115;j++);
}
uchar dis_lcd[10];
#include "lcd12864bu.h"
/******************顯示時間函數***************************/
void dis_shijian()?? ?//顯示時間
{
?write_shu16(0,0*8,shi,0);
?write_shuzi(1,0*2,2*8,fuhao[1],0);?? ??? ?
?write_shu16(0,3*8,fen,0);?? ?
?write_shuzi(1,0*2,5*8,fuhao[1],0);?? ??? ?
?write_shu16(0,6*8,miao,0);
?write_yhanzi(2,0,5*16,qita[6]-1); ? //星期
?//write_shu16(0,14*8,week,0);
?if(week==0)
?{
? write_yhanzi(1,0,7*16,xingqi[0]);
?}
?if(week==1)
?{
? write_yhanzi(1,0,7*16,xingqi[1]); ?
?}
?if(week==2)
?{
? write_yhanzi(1,0,7*16,xingqi[2]); ??
?}
?if(week==3)
?{
? write_yhanzi(1,0,7*16,xingqi[3]); ??
?}
?if(week==4)
?{
? write_yhanzi(1,0,7*16,xingqi[4]); ??
?}
?if(week==5)
?{
? write_yhanzi(1,0,7*16,xingqi[5]); ??
?}
?if(week==6)
?{
? write_yhanzi(1,0,7*16,xingqi[6]); ??
?}
?write_shu16(1*2,0*8,0x20,0);
?write_shu16(1*2,2*8,nian,0);
?write_shuzi(1,1*2,4*8,fuhao[0],0);?? ?
?write_shu16(1*2,5*8,yue,0);
?write_shuzi(1,1*2,7*8,fuhao[0],0);?? ?
?write_shu16(1*2,8*8,ri,0);
?write_shu18b20(1*2,12*8,temperature,0);?? ?
?write_shuzi(1,1*2,14*8,dian,0);
}
/************初始化顯示*****************/
void init_12864_dis() //初始化顯示
{
?cs1=1; //左屏開顯示
?cs2=0;?? ??? ?
?dis_shijian();?? ?//顯示時間?? ?
}
/***********************18b20初始化函數*****************************/
void init_18b20()
{
?bit q;
?dq=1;?? ??? ??? ??? ?//把總線拿高
?delay_uint(1);?? ? ? ?//15us
?dq=0;?? ??? ??? ??? ?//給復位脈沖
?delay_uint(80);?? ??? ?//750us
?dq=1;?? ??? ??? ??? ?//把總線拿高 等待
?delay_uint(10);?? ??? ?//110us
?q=dq;?? ??? ??? ??? ?//讀取18b20初始化信號
?delay_uint(20);?? ??? ?//200us
?dq=1;?? ??? ??? ??? ?//把總線拿高 釋放總線
}
/*************寫18b20內的數據***************/
void write_18b20(uchar dat)
{
?uchar i;
?for(i=0;i<8;i++)
?{?? ??? ??? ??? ??? ? //寫數據是低位開始
? dq=0;?? ??? ??? ? //把總線拿低寫時間隙開始?
? dq=dat&0x01; //向18b20總線寫數據了
? delay_uint(5);?? ? // 60us
? dq=1;?? ??? ??? ? //釋放總線
? dat>>=1;
?}?? ?
}
/*************讀取18b20內的數據***************/
uchar read_18b20()
{
?uchar i,value;
?for(i=0;i<8;i++)
?{
? dq=0;?? ??? ??? ? //把總線拿低讀時間隙開始?
? value>>= 1;?? ? //讀數據是低位開始
? dq=1;?? ??? ??? ? //釋放總線
? if(dq==1)?? ??? ? //開始讀寫數據?
? value|=0x80;
? delay_uint(5);?? ? //60us?? ?讀一個時間隙最少要保持60us的時間
?}
?return value;?? ??? ? //返回數據
}
/*************讀取溫度的值 讀出來的是小數***************/
uint read_temp()
{
?uint value;
?uchar low;?? ??? ??? ? ? //在讀取溫度的時候如果中斷的太頻繁了,就應該把中斷給關了,否則會影響到18b20的時序
?init_18b20();?? ??? ? ? //初始化18b20
?write_18b20(0xcc);?? ? ? //跳過64位ROM
?write_18b20(0x44);?? ? ? //啟動一次溫度轉換命令
?delay_uint(50);?? ??? ? ? //500us
?init_18b20();?? ??? ? ? //初始化18b20?? ?
?write_18b20(0xcc);?? ? ? //跳過64位ROM
?write_18b20(0xbe);?? ? ? //發出讀取暫存器命令
?? ?
?EA=0;
?low=read_18b20();?? ? ? //讀溫度低字節
?value=read_18b20(); ?//讀溫度高字節
?EA =1;
?value<<=8;?? ??? ? ? //把溫度的高位左移8位
?value|=low;?? ??? ? ? //把讀出的溫度低位放到value的低八位中
?value*=0.625;?? ? ? ? ? //轉換到溫度值 小數
?return value;?? ??? ? ? //返回讀出的溫度 帶小數
}
/******************顯示時間函數***************************/
void dis_shijian_set()?? ?//顯示時間
{
?write_shu16(0*2,0*8,0x20,0);
?write_shu16(1*2,2*8,shi,0);
?write_shu16(1*2,6*8,fen,0);?? ?
?write_shu16(1*2,10*8,miao,0);
?write_shu16(0*2,2*8,nian,0);?? ?
?write_shu16(0*2,6*8,yue,0);?? ?
?write_shu16(0*2,10*8,ri,0);
?write_yhanzi(1,4,5*16,xingqi[week]);?? ??? ??? ?
}
/******************時間芯片顯示函數**********************/?? ? ??
void ds1302_dis()
{
?uchar miao_1;
?if(menu_1 == 0)
?{
? read_time();
? if(miao_1 != miao)
? {
? ?miao_1 = miao;
? ?dis_shijian();?? ?//顯示時間
? }
?}
}
/********************獨立按鍵程序*****************/
uchar key_can;?? ? //按鍵值
void key()?? ? //獨立按鍵程序
{
?static uchar key_new;
?key_can=20; ? ? ? ? ? ? ? ? ? //按鍵值還原
?P3|=0x78; ? ? ? ? ? ? ? ? ? ? //對應的按鍵IO口輸出為1
?if((P3&0x78)!=0x78)?? ??? ?//按鍵按下
?{
? delay_1ms(1);?? ? ? ? ?? ?//按鍵消抖動
? if(((P3&0x78)!=0x78)&&(key_new==1))
? {?? ??? ??? ??? ??? ??? ?//確認是按鍵按下
? ?key_new=0;
? ?switch(P3&0x78)
? ?{
?? ??? ?case 0x70:key_can=1;break;?? ? //得到按鍵值
?? ??? ?case 0x68:key_can=2;break;?? ? //得到按鍵值
?? ??? ?case 0x58:key_can=3;break;?? ? //得到按鍵值
?? ??? ?case 0x38:key_can=4;break;?? ? //得到按鍵值
? ?}
? }?? ??? ??? ?
?}
?else?
?key_new=1;?? ?
}
/**********************設置函數************************/
void key_with()
{
?if(key_can==4) ? //退出鍵
?{
? qingling();
? init_12864_dis(); //初始化顯示
? flag_200ms=1;
? menu_1=0;
?}
?if(key_can==1)?? ?//設置鍵
?{
? menu_1 ++;
? flag_200ms=1;
? if(menu_1==1)
? {
? ?x_num=0;
? ?s_num=0;
? ?x_mode=0;
? ?s_mode=0;
? ?qingling();
? ?init_12864_set1();
? }
? if(menu_1>7)
? menu_1 = 1;
?}
?if(menu_1!=0)
?{
? if(menu_1==1)?? ??? ? ?//設置年
? {
? ?if(key_can==2)?? ?//加
? ?set_ds1302time(1,&nian,0x99);?? ??? ?
? ?if(key_can==3)?? ?//減?? ? ?
? ?set_ds1302time(0,&nian,0x99);?? ?
? }
? if(menu_1==2)?? ??? ? ?//設置月
? {
? ?if(key_can==2)?? ?//加
? ?set_ds1302time(1,&yue,0x13);?? ??? ?
? ?if(key_can==3)?? ?//減?? ? ?
? ?set_ds1302time(0,&yue,0x13);?? ?
? }
? if(menu_1==3)?? ??? ? ?//設置日
? {
? ?if(key_can==2)?? ?//加
? ?set_ds1302time(1,&ri,0x32);?? ??? ?
? ?if(key_can==3)?? ?//減?? ? ?
? ?set_ds1302time(0,&ri,0x32);?? ?
? }
? if(menu_1==4)?? ??? ? ?//設置時
? {
? ?if(key_can==4)?? ?//加
? ?set_ds1302time(1,&shi,0x24);?? ??? ?
? ?if(key_can==3)?? ?//減?? ? ?
? ?set_ds1302time(0,&shi,0x24);?? ?
? }
? if(menu_1==5)?? ??? ? ?//設置分
? {
? ?if(key_can==2)?? ?//加
? ?set_ds1302time(1,&fen,0x60);?? ??? ?
? ?if(key_can==3)?? ?//減?? ? ?
? ?set_ds1302time(0,&fen,0x60);?? ?
? }
? if(menu_1==6)?? ??? ? ?//設置秒
? {
? ?if(key_can==2)?? ?//加
? ?set_ds1302time(1,&miao,0x60);?? ??? ?
? ?if(key_can==3)?? ?//減?? ? ?
? ?set_ds1302time(0,&miao,0x60);?? ?
? }
? if(menu_1==7)?? ??? ? ?//設置星期
? {
? ?if(key_can==2)?? ?//加
? ?set_ds1302time(1,&week,0x8);?? ??? ?
? ?if(key_can==3)?? ?//減?? ? ?
? ?set_ds1302time(0,&week,0x8);?? ?
? }
? dis_shijian_set();?? ?//顯示時間
? switch(menu_1)?? ? ? // 光標顯示
? {
? ?case 1:write_shu16(0*2,2*8,nian,1);break;
? ?case 2:write_shu16(0*2,6*8,yue,1);break;
? ?case 3:write_shu16(0*2,10*8,ri,1);break;
? ?case 4:write_shu16(1*2,2*8,shi,1);break;
? ?case 5:write_shu16(1*2,6*8,fen,1);break;
? ?case 6:write_shu16(1*2,10*8,miao,1);break;
? ?case 7:write_yhanzi(1,4,5*16,xingqi[week]);break;
? }
? write_time();?? ? ? //把時間寫進去
?}?? ??? ??? ?
}
/*********************定時器0、定時器1初始化******************/
void time0_init()?? ? ?
{?? ??? ??? ??? ??? ??
?EA=1;?? ? ?? ? ?//開總中斷
?TMOD=0X11;?? ? ?//定時器0、定時器1工作方式1
?ET0=1;?? ??? ? ?//開定時器0中斷?
?TR0=1;?? ??? ? ?//允許定時器0定時
}
void baozhan()
{
?? ?if(key_zhantai==0)
?{
? delay_1ms(20);
? if(key_zhantai==0)
? {
? ?qingling();
? ?x_mode=1;
? ?s_mode=0;
? ?x_num=0;
? ?s_num=0;
? ?x_LED=0;
? ?s_LED=0;
?? ??? ?
?? ?write_yhanzi(1,4,0*16,yihaozhan[0]); ? //一
? write_yhanzi(1,4,1*16,yihaozhan[1]); ? //號
? write_yhanzi(1,4,2*16,yihaozhan[2]); ? //站?
? write_yhanzi(1,4,4*16,erhaozhan[0]); ? //二
? write_yhanzi(1,4,5*16,erhaozhan[1]); ? //號
? write_yhanzi(1,4,6*16,erhaozhan[2]); ? //站
?? ?
?? ?write_yhanzi(1,6,0*16,sanhaozhan[0]); ? //三
? write_yhanzi(1,6,1*16,sanhaozhan[1]); ? //號
? write_yhanzi(1,6,2*16,sanhaozhan[2]); ? //站
? write_yhanzi(1,6,4*16,sinhaozhan[0]); ? //四
? write_yhanzi(1,6,5*16,sinhaozhan[1]); ? //號
? write_yhanzi(1,6,6*16,sinhaozhan[2]); ? //站
? }
? while(!key_zhantai);
?}
?if(x_key==0 || key_gongjiao==0)
?{
? delay_1ms(20);
? if(x_key==0 || key_gongjiao==0)
? {
? ?qingling();
? ?x_mode=1;
? ?s_mode=0;
? ?x_num=0;
? ?s_num=0;
? ?x_LED=0;
? ?s_LED=1;
? ?write_yhanzi(1,4,0*16,daoda[0]); ? //到
? ?write_yhanzi(1,4,1*16,daoda[1]); ? //達
? ?write_shuzi(1,2*2,4*8,fuhao[1],0);//:
? ?write_yhanzi(1,6,0*16,xiayizhan[0]); ? //下
? ?write_yhanzi(1,6,1*16,xiayizhan[1]); ? //站
? ?write_shuzi(1,3*2,4*8,fuhao[1],0); //:
? }
? while((!x_key) || (!key_gongjiao));
?}
?if(s_key==0 || key_gongjiao==0)
?{
? delay_1ms(20);
? if(s_key==0 || key_gongjiao==0)
? {
? ?qingling();
? ?x_mode=0;
? ?s_mode=1;
? ?x_num=0;
? ?s_num=0;
? ?x_LED=1;
? ?s_LED=0;
? ?write_yhanzi(1,4,0*16,daoda[0]); ? //到
? ?write_yhanzi(1,4,1*16,daoda[1]); ? //達
? ?write_shuzi(1,2*2,4*8,fuhao[1],0);//:
? ?write_yhanzi(1,6,0*16,xiayizhan[0]); ? //下
? ?write_yhanzi(1,6,1*16,xiayizhan[1]); ? //站
? ?write_shuzi(1,3*2,4*8,fuhao[1],0); //:
? }
? while((!s_key) || (!key_gongjiao));
?}
?if((bz_key==0)&&(x_mode==1))
?{
? delay(20);
? if((bz_key==0)&&(x_mode==1))
? {
?? ??? ?x_num++; ?
?? ? ?x_num%=6;
?? ??? ?}
?? ??? ? ?while(!bz_key);
? }
?if((bz_key==0)&&(s_mode==1))
?{
? delay(20);
?? ?if((bz_key==0)&&(s_mode==1))
? {
?? ??? ?s_num++; ?
?? ? ?s_num%=6;
? }
? while(!bz_key);
?}
?if(gb_key==0)
?{
? delay_1ms(20);
? if(gb_key==0)
? {
? ??? ?x_mode=0;
? ? s_mode=0;
? ? x_num=0;
? ? s_num=0;
?? ?x_LED=1;
? ? s_LED=1;
?? ?qingling();
? }
?}
}
void yuyin()
{
?/******************************下行報站顯示***********/
?if(x_num==1)
?{
?? ??
? write_yhanzi(1,4,3*16,yihaozhan[0]); ? //一
? write_yhanzi(1,4,4*16,yihaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,yihaozhan[2]); ? //站?
? write_yhanzi(1,6,3*16,erhaozhan[0]); ? //二
? write_yhanzi(1,6,4*16,erhaozhan[1]); ? //號
? write_yhanzi(1,6,5*16,erhaozhan[2]); ? //站
?? ? ?? ? delay(500);
?? ?
?}
?if(x_num==2)
?{
? write_yhanzi(1,4,3*16,erhaozhan[0]); ? //二
? write_yhanzi(1,4,4*16,erhaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,erhaozhan[2]); ? //站
? write_yhanzi(1,6,3*16,sanhaozhan[0]); ? //三
? write_yhanzi(1,6,4*16,sanhaozhan[1]); ? //號
? write_yhanzi(1,6,5*16,sanhaozhan[2]); ? //站
?}
?if(x_num==3)
?{
? write_yhanzi(1,4,3*16,sanhaozhan[0]); ? //三
? write_yhanzi(1,4,4*16,sanhaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,sanhaozhan[2]); ? //站
? write_yhanzi(1,6,3*16,sinhaozhan[0]); ? //四
? write_yhanzi(1,6,4*16,sinhaozhan[1]); ? //號
? write_yhanzi(1,6,5*16,sinhaozhan[2]); ? //站
?}
?if(x_num==4)
?{
? write_yhanzi(1,4,3*16,sinhaozhan[0]); ? //四
? write_yhanzi(1,4,4*16,sinhaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,sinhaozhan[2]); ? //站
? write_yhanzi(1,6,3*16,zhongdianzhan[0]); ? //終
? write_yhanzi(1,6,4*16,zhongdianzhan[1]); ? //點
? write_yhanzi(1,6,5*16,zhongdianzhan[2]); ? //站
?}
?if(x_num==5)
?{
? write_yhanzi(1,4,3*16,zhongdianzhan[0]); ? //終
? write_yhanzi(1,4,4*16,zhongdianzhan[1]); ? //點
? write_yhanzi(1,4,5*16,zhongdianzhan[2]); ? //站
? write_yhanzi(1,6,0*16,ganxiechengzuo[0]); ? //感
? write_yhanzi(1,6,1*16,ganxiechengzuo[1]); ? //謝
? write_yhanzi(1,6,2*16,ganxiechengzuo[2]); ? //乘
? write_yhanzi(1,6,3*16,ganxiechengzuo[3]); ? //坐
? write_yhanzi(1,6,4*16,ganxiechengzuo[4]); ? //本
? write_yhanzi(1,6,5*16,ganxiechengzuo[5]); ? //公
? write_yhanzi(1,6,6*16,ganxiechengzuo[6]); ? //車
??
?}
?/******************************上行報站顯示***********/
?if(s_num==1)
?{
?? ? ?write_yhanzi(1,6,0*16,xiayizhan[0]); ? //下
? ?write_yhanzi(1,6,1*16,xiayizhan[1]); ? //站
? ?write_shuzi(1,3*2,4*8,fuhao[1],0); //:
?? ??
? write_yhanzi(1,4,3*16,sinhaozhan[0]); ? //四
? write_yhanzi(1,4,4*16,sinhaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,sinhaozhan[2]); ? //站?
? write_yhanzi(1,6,3*16,sanhaozhan[0]); ? //三
? write_yhanzi(1,6,4*16,sanhaozhan[1]); ? //號
? write_yhanzi(1,6,5*16,sanhaozhan[2]); ? //站
?}
?if(s_num==2)
?{
? write_yhanzi(1,4,3*16,sanhaozhan[0]); ? //三
? write_yhanzi(1,4,4*16,sanhaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,sanhaozhan[2]); ? //站
? write_yhanzi(1,6,3*16,erhaozhan[0]); ? //二
? write_yhanzi(1,6,4*16,erhaozhan[1]); ? //號
? write_yhanzi(1,6,5*16,erhaozhan[2]); ? //站
?}
?if(s_num==3)
?{
? write_yhanzi(1,4,3*16,erhaozhan[0]); ? //二
? write_yhanzi(1,4,4*16,erhaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,erhaozhan[2]); ? //站
? write_yhanzi(1,6,3*16,yihaozhan[0]); ? //一
? write_yhanzi(1,6,4*16,yihaozhan[1]); ? //號
? write_yhanzi(1,6,5*16,yihaozhan[2]); ? //站?
?}
?if(s_num==4)
?{
? write_yhanzi(1,4,3*16,yihaozhan[0]); ? //一
? write_yhanzi(1,4,4*16,yihaozhan[1]); ? //號
? write_yhanzi(1,4,5*16,yihaozhan[2]); ? //站?
? write_yhanzi(1,6,3*16,zhongdianzhan[0]); ? //終
? write_yhanzi(1,6,4*16,zhongdianzhan[1]); ? //點
? write_yhanzi(1,6,5*16,zhongdianzhan[2]); ? //站
?}
?if(s_num==5)
?{
? write_yhanzi(1,4,3*16,zhongdianzhan[0]); ? //終
? write_yhanzi(1,4,4*16,zhongdianzhan[1]); ? //點
? write_yhanzi(1,4,5*16,zhongdianzhan[2]); ? //站
? write_yhanzi(1,6,0*16,ganxiechengzuo[0]); ? //感
? write_yhanzi(1,6,1*16,ganxiechengzuo[1]); ? //謝
? write_yhanzi(1,6,2*16,ganxiechengzuo[2]); ? //乘
? write_yhanzi(1,6,3*16,ganxiechengzuo[3]); ? //坐
? write_yhanzi(1,6,4*16,ganxiechengzuo[4]); ? //本
? write_yhanzi(1,6,5*16,ganxiechengzuo[5]); ? //公
? write_yhanzi(1,6,6*16,ganxiechengzuo[6]); ? //車
?}
}
void main()
{?
?x_key=1;
?s_key=1;
?bz_key=1;
?gb_key=1;
?x_LED=1;
?s_LED=1;
?P0=P1=P2=P3=0xff;?? ??? ?//單片機IO口初始化為1?? ?
?init_ds1302();
?delay_1ms(5);
?init_lcd();
?delay_1ms(5);?? ?
?Clr_Scr();
?time0_init();
?delay_1ms(5);
?init_12864_dis(); //初始化顯示
?delay_1ms(5);
?? ??? ? ?? ?uart_cfg();?? ?
?while(1)
?{
? baozhan(); ? ? ? ? ?//顯示上站和下站字頭
? yuyin(); ? ? ? ? ? ?//顯示上站和下站是哪一站
? key();?? ? ? ? ? ? ? ?//改變key_san的值,判斷K1-K4哪個鍵按下即設置時間的4個鍵哪個被按下
? if(key_can<10) ?
? {
? ?key_with();?? ? ? ? ?//根據key_san的值執行相應程序
? }
? if(flag_100ms==1)
? {?? ??
? ?flag_100ms=0;
? }
? if(flag_200ms==1) ? ?//200ms
? {
? ?flag_200ms=0;
? ?temperature=read_temp();?? ?//先讀出溫度的值
? ?ds1302_dis(); ? ?//時鐘顯示函數,同時顯示溫度函數也在里面
? }
?}
}
五、實驗現象
演示視頻: