51單片機視力保護-實物+原理圖+程序
單片機源程序如下:
- #include <reg52.h> //調用單片機頭文件
- #define uchar unsigned char //無符號字符型 宏定義 變量范圍0~255
- #define uint unsigned int //無符號整型 宏定義 變量范圍0~65535
- #include <intrins.h>
- sbit CS=P1^4; //CS定義,連接ADC0832CS腳
- sbit SCL=P1^5; //SCL定義,連接ADC0832SCL腳
- sbit DO=P1^6; //DO定義,連接ADC0832DO腳
- //這三個引腳參考資料
- sbit rs=P1^0; //1602數據/命令選擇引腳 H:數據 L:命令
- sbit rw=P1^1; //1602讀寫引腳 H:數據寄存器 L:指令寄存器
- sbit e =P1^2; //1602使能引腳 下降沿觸發
- sbit c_send = P3^2; //超聲波發射
- sbit c_recive = P3^3; //超聲波接收
- uchar flag_hc_value; //超聲波中間變量
- long distance; //距離
- uint set_d; //距離
- bit flag_csb_juli; //超聲波超出量程
- uint flag_time0; //用來保存定時器0的時候的
- bit flag_200ms = 1 ;
- uchar guangxian; //光線的顯示變量
- uchar qiang_gx; //設置光線的強的變量
- uchar ruo_gx; //設置光線的弱的變量
- uchar value;
- uchar flag_alarm; //報警變量
- uchar miao = 0,fen = 0,shi;
- uchar s_miao = 55,s_fen = 44,s_shi=0;
- bit xuexi_start; //開始學習標志位
- uchar menu_1; //菜單設置變量
- uchar i;
- uchar flag_gx ; //光線報警
- uchar flag_juli ; //距離報警
- uchar flag_time = 0; //時間報警
- /***********************語音模塊控制IO口的定義************************/
- sbit VRST = P2^4;
- sbit VBUSY= P2^3;
- sbit VSDA = P2^2;
- sbit VCS = P2^1;
- sbit VSCL = P2^0;
-
- /***********************1ms延時函數*****************************/
- void delay_1ms(uint q)
- {
- uint i,j;
- for(i=0;i<q;i++)
- for(j=0;j<120;j++);
- }
- /********************************************************************
- * 名稱 : delay()
- * 功能 : 延時,延時時間大概為5US。
- * 輸入 : 無
- * 輸出 : 無
- ***********************************************************************/
- void delay_uint(uint q)
- {
- while(q--);
- }
- /********************************************************************
- * 名稱 : write_com(uchar com)
- * 功能 : 1602命令函數
- * 輸入 : 輸入的命令值
- * 輸出 : 無
- ***********************************************************************/
- void write_com(uchar com)
- {
- e=0;
- rs=0;
- rw=0;
- P0=com;
- delay_uint(3);
- e=1;
- delay_uint(25);
- e=0;
- }
- /********************************************************************
- * 名稱 : write_data(uchar dat)
- * 功能 : 1602寫數據函數
- * 輸入 : 需要寫入1602的數據
- * 輸出 : 無
- ***********************************************************************/
- void write_data(uchar dat)
- {
- e=0;
- rs=1;
- rw=0;
- P0=dat;
- delay_uint(3);
- e=1;
- delay_uint(25);
- e=0;
- }
- /***********************lcd1602上顯示兩位十進制數************************/
- void write_sfm2(uchar hang,uchar add,uchar date)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- write_data(0x30+date/10%10);
- write_data(0x30+date%10);
- }
- /***********************lcd1602上顯示超聲波距離************************/
- void write_sfm_csb(uchar hang,uchar add,uint date)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- write_data(0x30+date/100%10);
- write_data('.');
- write_data(0x30+date/10%10);
- write_data(0x30+date%10);
- }
- /********************************************************************
- * 名稱 : init_1602()
- * 功能 : 1602初始化,請參考1602的資料
- * 輸入 : 無
- * 輸出 : 無
- ***********************************************************************/
- void init_1602()
- {
- write_com(0x38); //
- write_com(0x0c);
- write_com(0x06);
- }
- /********************************************************************
- * 名稱 : write_string(uchar hang,uchar lie,uchar *p)
- * 功能 : 改變液晶中某位的值,如果要讓第一行,第五個字符開始顯示"ab cd ef" ,調用該函數如下
- write_string(1,5,"ab cd ef;")
- * 輸入 : 行,列,需要輸入1602的數據
- * 輸出 : 無
- ***********************************************************************/
- void write_string(uchar hang,uchar add,uchar *p)
- {
- if(hang==1)
- write_com(0x80+add);
- else
- write_com(0x80+0x40+add);
- while(1)
- {
- if(*p == '\0') break;
- write_data(*p);
- p++;
- }
- }
- uchar key_can;
- /********************獨立按鍵程序*****************/
- void key()
- {
- static uchar key_new;
- key_can = 20;
- if((P3 & 0xf0) != 0xf0)
- {
- delay_uint(50);
- if(((P3 & 0xf0) != 0xf0) && (key_new == 1))
- {
- key_new = 0;
- switch(P3 & 0xf0)
- {
- case 0xe0: key_can = 3; break; //左邊第1個
- case 0xb0: key_can = 2; break; //左邊第2個
- case 0x70: key_can = 1; break; //左邊第3個
- }
- }
- }
- else
- key_new = 1;
- }
- /***********讀數模轉換數據********************************************************/
- //請先了解ADC0832模數轉換的串行協議,再來讀本函數,主要是對應時序圖來理解,本函數是模擬0832的串行協議進行的
- unsigned char ad0832read(bit SGL,bit ODD)
- {
- unsigned char i=0,value=0,value1=0;
- SCL=0;
- DO=1;
- CS=0; //開始
- SCL=1; //第一個上升沿
- SCL=0;
- DO=ODD;
- SCL=1; //第二個上升沿
- SCL=0;
- DO=SGL;
- for(i=0;i<8;i++)
- {
- SCL=0; //開始從第四個下降沿接收數據
- value<<=1;
- SCL=1;
- if(DO)
- value++;
- }
- return value;
- }
- /*********************小延時函數*****************************/
- void delay()
- {
- _nop_(); //執行一條_nop_()指令就是1us
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
- /*********************超聲波測距程序*****************************/
- void send_wave()
- {
- c_send = 1; //10us的高電平觸發
- delay();
- c_send = 0;
- TH0 = 0; //給定時器0清零
- TL0 = 0;
- TR0=1;
- while(c_recive) //當c_recive為1計數并等待
- {
- flag_time0 = TH0 * 256 + TL0;
- if((flag_time0 > 40000)) //當超聲波超過測量范圍時,顯示3個888
- {
- TR0 = 0;
- flag_csb_juli = 2;
- distance = 888;
- break ;
- }
- else
- {
- flag_csb_juli = 1;
- }
- }
- if(flag_csb_juli == 1)
- {
- TR0=0; //關定時器0定時
- distance =flag_time0; //讀出定時器0的時間
- distance *= 0.017; // 0.017 = 340M / 2 = 170M = 0.017M 算出來是米
- if((distance > 500)) //距離 = 速度 * 時間
- {
- distance = 888; //如果大于3.8m就超出超聲波的量程
- }
- }
- }
- /*********************定時器0、定時器1初始化******************/
- void time_init()
- {
- EA = 1; //開總中斷
- TMOD = 0X11; //定時器0、定時器1工作方式1
- ET0 = 1; //開定時器0中斷
- TR0 = 1; //允許定時器0定時
- ET1 = 1; //開定時器1中斷
- TR1 = 1; //允許定時器1定時
- }
- /*******************按鍵執行函數******************/
- void key_with()
- {
- if(menu_1 == 0)
- {
- if(key_can == 2) //暫停學習
- {
- xuexi_start = ~xuexi_start;
- }
- if(key_can == 3)
- {
- xuexi_start = 1; //開始學習
- miao = 0;
- fen = 0;
- shi = 0;
- }
- }
- if(key_can == 1)
- {
- menu_1 ++;
- if(menu_1 == 1)
- {
- write_string(1,0,"1.xsb: m ");
- write_string(2,0,"2. : : ");
- write_sfm_csb(1,6,set_d);
- write_sfm2(2,3,s_shi); // 顯示
- write_sfm2(2,6,s_fen); // 顯示
- write_sfm2(2,9,s_miao); // 顯示
- write_com(0x80+0); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 == 2)
- {
- write_com(0x80+0x40+0); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 == 5)
- {
- write_string(1,0,"3.H-gx: % ");
- write_string(2,0,"4.L-gx: % ");
- write_sfm2(1,7,qiang_gx);
- write_sfm2(2,7,ruo_gx); //設置光線的參數
- write_com(0x80+6); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 >= 7)
- {
- menu_1 = 0;
- write_string(1,0," csb: m gx: ");
- write_string(2,0," : : ");
- write_com(0x0c); //關閉顯示
- }
- }
- if(menu_1 == 1) //設置超聲波參數
- {
- if(key_can == 2) //
- {
- set_d ++; //加超聲波距離報警數據
- if(set_d >= 200)
- set_d = 200;
- }
- if(key_can == 3) //
- {
- set_d --; //減超聲波距離報警數據
- if(set_d <= 10)
- set_d = 10;
- }
- write_sfm_csb(1,6,set_d); // 顯示設置的距離
- write_com(0x85); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 == 2) //設置時鐘參數
- {
- if(key_can == 2) //
- {
- s_shi ++; //加時鐘報警數據
- if(s_shi >= 24)
- s_shi = 0;
- }
- if(key_can == 3) //
- {
- if(s_shi <= 0)
- s_shi = 24;
- s_shi --; //減時鐘報警數據
- }
- write_sfm2(2,3,s_shi); // 顯示時
- write_sfm2(2,6,s_fen); // 顯示分
- write_sfm2(2,9,s_miao); // 顯示秒
- write_com(0x80+0x40+3); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 == 3) //設置分鐘參數
- {
- if(key_can == 2) //
- {
- s_fen ++; //加分鐘報警數據
- if(s_fen >= 60)
- s_fen = 0;
- }
- if(key_can == 3) //
- {
- if(s_fen <= 0)
- s_fen = 60;
- s_fen --; //減分鐘報警數據
- }
- write_sfm2(2,3,s_shi); // 顯示時
- write_sfm2(2,6,s_fen); // 顯示分
- write_sfm2(2,9,s_miao); // 顯示秒
- write_com(0x80+0x40+6); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 == 4) //設置秒鐘參數
- {
- if(key_can == 2) //
- {
- s_miao ++; //加秒鐘報警數據
- if(s_miao >= 60)
- s_miao = 0;
- }
- if(key_can == 3) //
- {
- if(s_miao <= 0)
- s_miao = 60;
- s_miao --; //減秒鐘報警數據
- }
- write_sfm2(2,3,s_shi); // 顯示時
- write_sfm2(2,6,s_fen); // 顯示分
- write_sfm2(2,9,s_miao); // 顯示秒
- write_com(0x80+0x40+9); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 == 5) //設置強光報警
- {
- if(key_can == 2) //
- {
- qiang_gx ++; //加強光報警數據
- if(qiang_gx >= 100)
- qiang_gx = 100;
- }
- if(key_can == 3) //
- {
- qiang_gx --; //減強光報警數據
- if(qiang_gx <= ruo_gx)
- qiang_gx = ruo_gx;
- }
- write_sfm2(1,7,qiang_gx);
- write_com(0x80+6); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- if(menu_1 == 6) //設置弱光報警
- {
- if(key_can == 2) //
- {
- ruo_gx ++; //加弱光報警數據
- if(ruo_gx >= qiang_gx)
- ruo_gx = qiang_gx;
- }
- if(key_can == 3) //
- {
- ruo_gx --; //減強光報警數據
- if(ruo_gx <= 1)
- ruo_gx = 1;
- }
- write_sfm2(2,7,ruo_gx);
- write_com(0x80+0x40+6); //將光標移動到
- write_com(0x0f); //顯示光標并且閃爍
- }
- }
- /***********************語音子程序************************/
- void Send_threelines(unsigned char addr)
- {
- unsigned char i;
- VRST=0;
- delay_1ms(5);
- VRST=1;
- delay_1ms(10); /* 復位拉高10ms*/
- VCS=0;
- delay_1ms(5); /* 片選拉低5ms */
- for(i=0;i<8;i++)
- {
- VSCL=1;
- if(addr&0x01 == 0x01)
- {
- VSDA=1;
- }
- else
- VSDA=0;
- addr<<=1;
- VSCL=0;
- }
- VCS=1;
- while(VBUSY == 0); //忙等待
- }
- /*********************報警函數***************************/
- void clock_beep()
- {
- if((guangxian >= qiang_gx) || (guangxian <= ruo_gx)) //光線報警
- {
- flag_gx = 1; //光線報警
- }else
- {
- flag_gx = 0;
- }
- if(xuexi_start == 1) //已經開始學習了
- {
- if(distance <= set_d) //距離報警
- {
- flag_juli = 1;
- Send_threelines(42) ; //距離太近,請坐直
- }else
- {
- flag_juli = 0;
- }
- if((shi == s_shi) && (fen == s_fen) && (miao == s_miao)) //時間報警
- {
- flag_time = 1;
- }
- }
- if(flag_time == 1) //時間提示報警
- {
- Send_threelines(41) ; //時間到了,休息一會兒
- }
- else
- {
- if(xuexi_start == 1) //已經開始學習了
- {
- if((flag_gx == 1) || (flag_juli == 1))
- {
- if(guangxian >= qiang_gx)
- Send_threelines(44) ; //光線太強
- if(guangxian <= ruo_gx)
- Send_threelines(43) ; //光線太暗
- }
- }
- }
- }
- /********************************************************************
- * 名稱 : Main()
- * 功能 : 主函數
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
程序.zip
(67.02 KB, 下載次數: 39)
2020-9-7 22:35 上傳
點擊文件名下載附件
元件清單.zip
(6.95 KB, 下載次數: 22)
2020-9-7 22:35 上傳
點擊文件名下載附件
原理圖.zip
(85.98 KB, 下載次數: 29)
2020-9-7 22:35 上傳
點擊文件名下載附件
|