酒精测试仪,实物制作完成后导入程序,液晶屏只亮灯,不显示,问了师兄说是时序问题,很苦恼,求解决
单片机源程序如下:
- //程序头函数
- #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;
- }*/
复制代码
|