酒精測試儀,實物制作完成后導入程序,液晶屏只亮燈,不顯示,問了師兄說是時序問題,很苦惱,求解決
$%@BJAUE8~30$~)AOQX)(]4.png (103.35 KB, 下載次數: 56)
下載附件
2022-1-13 23:02 上傳
單片機源程序如下:
- //程序頭函數
- #include <stc15.h>
- #include <intrins.h>
- #define uint unsigned int
- #define uchar unsigned char
- #define LCD1602 P0
- #define key_S 3 //宏定義按鍵短按(約15ms)
- #define key_L key_S*35 //宏定義按鍵長按(約500ms)
- #define key_I key_S*27 //宏定義長按連+/-間隔(約120ms)
- //宏定義ADC的操作命令
- #define ADC_POWER 0x80 //ADC power control dit (宏定義ADC電源控制位)1000 0000
- #define ADC_START 0x08 //ADC start control dit (宏定義ADC啟動控制位)0000 1000
- #define ADC_FLAG 0x10 //ADC complete flag (宏定義ADC完成標志位) 0001 0000
- #define ADC_SPEEDLL 0x00 //420 clocks (宏定義420時鐘)速度控制 0000 0000
- //宏定義ISP的操作命令
- #define CMD_IDLE 0 //空閑模式
- #define CMD_READ 1 //IAP字節讀命令
- #define CMD_PROGRAM 2 //IAP字節編程命令
- #define CMD_ERASE 3 //IAP扇區擦除命令
- #define ENABLE_IAP 0x82 //CPU的等待時間
- #define IAP_ADDRESS 0x0800 //保存地址
- //管腳聲明
- #define LCD1602 P0
- sbit LED_R= P2^2; //紅指示燈
- sbit LED_G= P2^0; //綠色指示燈
- sbit FENG = P2^5; //蜂鳴器
- sbit LCD_RS=P2^3; //液晶屏RS口
- sbit LCD_EN=P2^1; //液晶屏EN口
- sbit Key1=P2^6; //檢測/復位
- sbit Key2=P2^7; //設置
- sbit Key3=P3^6; //加
- sbit Key4=P3^7; //減
- //變量定義
- uchar table[] ="ALCOHOL: mg"; //第一行"酒精"
- uchar table1[]="WARNING H000 L00";//第二行"警告"
- uchar data dis_buf[]="000H000L000";
- bit flashing; //閃爍標志
- bit Rev_Stop; //啟動/停止標志
- bit preset; //預置標志
- uchar KeySec; //鍵值
- uchar set; //設置標志位
- uint TheH,TheL; //濃度高/濃度低參考值
- uint num,num1; //計數變量
- uchar ADCP,PH; //AD轉換值
- uchar WARNING; // 初始報警值
- uchar i;
- //函數聲明
- void Timer0Init(); //定時器0初始化聲明
- void Timer2Init(); //定時器2初始化聲明
- void Delay1ms(); //延時子程序聲明
- void key_scan(); //按鍵掃描聲明
- void ADC_Init(); //初始化ADC子程序聲明
- uchar Read(uchar CHA); //ADC轉換子程序聲明
- void detection();
- void IapIdle(); //關閉IAP/EEPROM
- void init_eeprom();
- uchar IapReadByte(uint addr); //讀取EEPROM數據
- void IapProgramByte(uint addr, uchar dat);//寫入EEPROM數據
- void IapEraseSector(uint addr); //擦除EEPROM數據
- void write_com(uchar com); //1602液晶屏寫指令程序
- void write_date(uchar date); //1602液晶屏寫數據程序
- void LCD_init(); //1602液晶屏初始化程序
- void display(); //顯示函數
- void alarm(); //報警函數
- void Buzzer_second();
- //主函數
- void main()
- {
- P0M0 = 0x00;
- P0M1 = 0x00;
- P1M1 = 0x01; //設置P1.0高阻ADC輸入
- P1M0 = 0x00; //設置P1.0高阻ADC輸入
- P2M0 = 0x00;
- P2M1 = 0x00;
- P3M0 = 0x00;
- P3M1 = 0x00;
- P4M0 = 0x00;
- P4M1 = 0x00;
- P5M0 = 0x00;
- P5M1 = 0x00;
- P6M0 = 0x00;
- P6M1 = 0x00;
- P7M0 = 0x00;
- P7M1 = 0x00;
- Timer0Init(); //定時器0初始化
- Timer2Init(); //定時器2初始化
- ADC_Init(); //初始化ADC
- LCD_init(); //初始化液晶屏
- init_eeprom(); //讀取eeprom初始數據
- while(1)//主循環
- {
- key_scan();//按鍵掃描
- if(num==0 && preset==1)//自動保存設置
- {
- IapEraseSector(IAP_ADDRESS);
- IapProgramByte(IAP_ADDRESS, TheH);
- IapProgramByte(IAP_ADDRESS+1, TheL);
- preset=0;
- KeySec=0;
- }
- detection();//檢測酒精濃度
- display();//刷新LCD
- // alarm();//報警函數
- // Buzzer_second();
- }
- }
- /*---------------------------------------------
- 定時器0初始化,時鐘12T、16位重載模式
- ----------------------------------------------*/
- void Timer0Init(void) //50毫秒@11.0592MHz
- {
- AUXR &= 0x7F; //定時器時鐘12T模式
- TMOD &= 0xF0; //設置定時器模式
- TL0 = 0x00; //設置定時初始值
- TH0 = 0x4C; //設置定時初始值
- TF0 = 0; //清除TF0標志
- TR0 = 1; //定時器0開始計時
- EA = 1; //開總中斷
- ET0 = 1;
- }
- /*---------------------------------------------
- 定時器2初始化,時鐘12T、16位重載模式
- ----------------------------------------------*/
- void Timer2Init() //250微秒@11.0592MHz
- {
- AUXR &= 0xFB; //定時器時鐘12T模式
- T2L = 0x1A; //設置定時初值
- T2H = 0xFF; //設置定時初值
- // AUXR |= 0x10; //定時器2開始計時
- IE2 |=0x04; //允許中斷
- }
- /*****************************
- 蜂鳴器間歇鳴響
- *****************************/
- /*
- void Buzzer_second()
- {
- if(flashing && WARNING>0) //計時周期1s
- {
- WARNING--; //蜂鳴器間歇鳴次數變量自-1
- AUXR |= 0x10; //定時器2開,蜂鳴器響一下
- }
- }*/
- /*-------------------------------------------
- 定時器2中斷服務程序 200微秒 驅動無源蜂鳴器
- --------------------------------------------*/
- void timer2() interrupt 12
- {
- static uint i=0; //中斷計數變量
- i++; //中斷計數變量count3自+1
- FENG=~FENG; //蜂鳴器端口取反
- if(i>=500) //0.1秒時間到500
- {
- i=0; //計數清0
- FENG=1; //蜂鳴器端口清0
- AUXR &= 0xef; //定時器2關閉
- }
- }
- void time0_int(void) interrupt 1 //定時器中斷0
- {
- static int count=0;
- if(++count>=20)
- {
- count=0;
- flashing=~flashing;
- }
- if(num>0)num--;
- if(num1>0)num1--;
- //加入報警時長代碼
- }
- void write_com(uchar com)//1602液晶屏寫指令程序
- {
- LCD_EN=0; //初始設置LCD_EN低電平
- LCD_RS=0; //允許寫指令
- P0=com; //傳遞指令
- Delay1ms(); //延時1ms
- LCD_EN=1; //使能寫入
- Delay1ms(); //延時1ms
- LCD_EN=0; //低跳變執行
- }
- void write_date(uchar date)//1602液晶屏寫數據程序
- {
- // LCD_EN=0; //初始設置LCD_EN低電平
- LCD_RS=1; //允許寫數據
- P0 =date; //傳遞數據
- Delay1ms(); //延時1ms
- LCD_EN=1; //使能寫入
- Delay1ms(); //延時1ms
- LCD_EN=0; //低跳變執行
- }
- void LCD_init()//1602液晶屏初始化程序
- {
- uchar i;
- LCD_EN=0; //初始設置LCD_EN低電平
- write_com(0x38);//設置16*2顯示,5*7點陣,8位數據接口
- write_com(0x01);//顯示清零,數據指針清零
- // write_com(0x0f);//設置開顯示,顯示光標,光標閃爍
- // write_com(0x0e);//設置開顯示,顯示光標,光標不閃
- write_com(0x0c);//設置開顯示,不顯光標
- write_com(0x06);//設置寫一個字符后地址指針加1
- // write_com(0x07);//設置寫一個字符后整屏左移
- write_com(0x80+1);//顯示固定字符
- for(i=0;i<13;i++)
- write_date(table[i]);
- write_com(0xc0);
- for(i=0;i<16;i++)
- write_date(table1[i]);
- }
- /*-----------------------------------------------------------------------------
- InitADC 初始化ADC
- -----------------------------------------------------------------------------*/
- void ADC_Init()
- {
- P1ASF=0x01; //設置P1的0通道端口作為模擬輸入
- ADC_RES=0; //清除ADC_RES存儲器以前的結果
- // ADC_RESL=0;
- ADC_CONTR=ADC_POWER|ADC_SPEEDLL;//ADC 開啟電源、轉換速度 1000 0000
- Delay1ms(); //上電延時1ms
- }
- /*----------------------------------------------------------------------------
- Get ADC Result(獲取ADC結果)
- ----------------------------------------------------------------------------*/
- uchar Read(uchar CHA) //獲取ADC結果
- {
- ADC_CONTR=ADC_POWER|ADC_SPEEDLL|CHA|ADC_START;//啟動轉換1000 1000
- _nop_(); //延時確保正確讀到ADC_CONTR寄存器的值
- _nop_();
- _nop_();
- _nop_();
- while(!(ADC_CONTR & ADC_FLAG)); //等待ADC轉換完成標志置位 1001 1000
- ADC_CONTR &=~ADC_FLAG; //關閉ADC
- // return (ADC_RES<<2)|ADC_RESL; //返回10位ADC結果
- return ADC_RES; //返回8位ADC結果
- }
- void key_scan()//按鍵掃描
- {
- static uint time=0;
- if(!Key1||!Key2)
- {
- time++;
- if(time>key_L)//長按有效
- time=key_I;//連+/-間隔
- if(time==key_S)//短按消抖
- {
- if(!Key1)
- {
- Rev_Stop=~Rev_Stop;
- if(Rev_Stop) num1=100;
- PH=0;
- AUXR |= 0x10;//蜂鳴器提示音"滴"
- }
- if(!Key2)
- {
- KeySec++;
- if(KeySec>3) KeySec=0;
- AUXR |= 0x10;//蜂鳴器提示音"滴"
- }
- }
- if(time==key_S||time==key_L)//短按消抖或長按連+/-
- {
- if(!Key3 && KeySec>1)
- {
- preset=1;
- switch(KeySec)
- {
- case 1: if(TheH<255)TheH++; break;
- case 2: if(TheL<TheH-1)TheL++; break;
- }
- AUXR |= 0x10;//蜂鳴器提示音"滴"
- num=100;//自復位變量賦值(5秒)
- }
- if(!Key4 && KeySec>1)
- {
- preset=1;
- switch(KeySec)
- {
- case 1: if(TheH>TheL+1)TheH--; break;
- case 2: if(TheL>0)TheL--; break;
- }
- AUXR |= 0x10;//蜂鳴器提示音"滴"
- num=100;//自復位變量賦值(5秒)
- }
- }
- }
- else time=0;
- }
- void detection()
- {
- uchar Pt;
- if(Rev_Stop)
- {
- Pt=Read(0);
- // ADCP=Pt + - * / ;//按實際要求換算PH值
- // if(PH<ADCP)//保留最大值
- // PH=ADCP;
- dis_buf[0]=Pt/100%10+'0';
- dis_buf[1]=Pt/10%10+'0';
- dis_buf[2]=Pt%10+'0';
- // dis_buf[3]='H';
- dis_buf[4]=TheH/100%10+'0';
- dis_buf[5]=TheH/10%10+'0';
- dis_buf[6]=TheH%10+'0';
- // dis_buf[7]='L';
- dis_buf[8]=TheL/100%10+'0';
- dis_buf[9]=TheL/10%10+'0';
- dis_buf[10]=TheL%10+'0';
- }
- /* else //清空緩存
- {
- dis_buf[0]=' ';
- dis_buf[1]=' ';
- dis_buf[2]=' ';
- dis_buf[3]=' ';
- dis_buf[4]=' ';
- dis_buf[5]=' ';
- }*/
- }
- /*-------------------------------
- 1ms延時子程序(11.0592MHz 1T)
- -------------------------------*/
- void Delay1ms() //@11.0592MHz
- {
- unsigned char i, j;
- _nop_();
- _nop_();
- _nop_();
- i = 11;
- j = 190;
- do
- {
- while (--j);
- } while (--i);
- }
- /*----------------------------
- 關閉IAP功能
- ----------------------------*/
- void IapIdle()
- {
- IAP_CONTR = 0; //關閉IAP功能
- IAP_CMD = 0; //清除命令寄存器
- IAP_TRIG = 0; //清除觸發寄存器
- IAP_ADDRH = 0x80; //將地址設置到非IAP區域
- IAP_ADDRL = 0;
- }
- /*----------------------------
- 從ISP/IAP/EEPROM區域讀取一字節
- ----------------------------*/
- uchar IapReadByte(uint addr)
- {
- uchar dat; //數據緩沖區
- IAP_CONTR = ENABLE_IAP; //使能IAP
- IAP_CMD = CMD_READ; //設置IAP命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_(); //等待ISP/IAP/EEPROM操作完成
- dat = IAP_DATA; //讀ISP/IAP/EEPROM數據
- IapIdle(); //關閉IAP功能
- return dat; //返回
- }
- /*-------------------------------
- 寫一字節數據到ISP/IAP/EEPROM區域
- --------------------------------*/
- void IapProgramByte(uint addr, uchar dat)
- {
- IAP_CONTR = ENABLE_IAP; //使能IAP
- IAP_CMD = CMD_PROGRAM; //設置IAP命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_DATA = dat; //寫ISP/IAP/EEPROM數據
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_(); //等待ISP/IAP/EEPROM操作完成
- IapIdle(); //關閉IAP功能
- }
- /*----------------------------
- ISP/IAP/EEPROM扇區擦除
- ----------------------------*/
- void IapEraseSector(uint addr)
- {
- IAP_CONTR = ENABLE_IAP; //使能IAP
- IAP_CMD = CMD_ERASE; //設置IAP命令
- IAP_ADDRL = addr; //設置IAP低地址
- IAP_ADDRH = addr >> 8; //設置IAP高地址
- IAP_TRIG = 0x5a; //寫觸發命令(0x5a)
- IAP_TRIG = 0xa5; //寫觸發命令(0xa5)
- _nop_(); //等待ISP/IAP/EEPROM操作完成
- IapIdle(); //關閉IAP功能
- }
- void init_eeprom()
- {
- TheH=IapReadByte(IAP_ADDRESS);
- TheL=IapReadByte(IAP_ADDRESS+1);
- if((TheL<1||TheL>=TheH)||(TheH>254||TheH<=TheL))//首次上電初始化數據
- {
- TheL=20;
- TheH=80;
- IapEraseSector(IAP_ADDRESS);
- IapProgramByte(IAP_ADDRESS, TheH);
- IapProgramByte(IAP_ADDRESS+1, TheL);
- }
- }
- void display()
- {
- uchar i;
- write_com(0x80+9);//顯示第一行數字
- for(i=0;i<3;i++)
- write_date(dis_buf[i]);
- write_com(0xc0+8);//顯示第二行數字
- for(i=0;i<9;i++)
- write_date(dis_buf[i+3]);
- }
- /*
- void alarm()
- {
- if(PH<TheL)
- {
- LED_R= 1; //紅指示燈
- LED_G= 1; //綠色指示燈
- }
- if(PH>=TheL && PH<TheH)
- {
- LED_R= 1; //紅指示燈
- LED_G= 0; //綠色指示燈
- }
- if(PH>=TheH)
- {
- LED_R= 0; //紅指示燈
- LED_G= 1; //綠色指示燈
- }
- WARNING=25;
- }*/
復制代碼
|