標(biāo)題:
單片機(jī)酒精檢測(cè)程序Proteus仿真原理圖 24C02掉電保存
[打印本頁(yè)]
作者:
夢(mèng)不虛存
時(shí)間:
2022-5-8 14:26
標(biāo)題:
單片機(jī)酒精檢測(cè)程序Proteus仿真原理圖 24C02掉電保存
用可變電阻來(lái)模擬MQ-3酒精傳感器
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
51hei.gif
(99.77 KB, 下載次數(shù): 54)
下載附件
2022-5-8 15:35 上傳
單片機(jī)源程序如下:
#include<reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define nops4(); {_nop_();_nop_();_nop_();_nop_();}//4個(gè)空操作延時(shí)
#define add_write 0x90
#define add_rec 0x91
#define control_byte 0x03
#define u16 unsigned char
#define u8 unsigned int
#define lcd_data P0
sbit pe=P3^4;
sbit sda=P2^4; //IO口定義
sbit scl=P2^3;
sbit green=P2^5;
sbit red=P2^6;
sbit yellow=P2^7;
sbit k1=P3^5;
sbit k2=P3^6;
sbit k3=P3^7;
sbit SDA=P1^1;
sbit SCL=P1^0;
sbit RS = P2^0;
sbit RW = P2^1;
sbit E = P2^2;
sbit bf = P0^7;
bit flag=0,flag2=0;
unsigned int voldata1;
unsigned char i,j,k,m=0,tt=0;
unsigned int vol;
unsigned char num[]={"0,1,2,3,4,5,6,7,8,9"};
unsigned char character[]="alcohol:";
unsigned char character2[]="warn:";
unsigned char hdata=60,ldata=20;
extern voldate1;
unsigned char voldate;
void nop()
{
_nop_();
_nop_();
}
void delay(unsigned char i) //延時(shí)程序
{
for(j=i;j>0;j--)
for(k=125;k>0;k--);
}
void delay1s(void) //誤差 0us
{
unsigned char a,b,c;
for(c=167;c>0;c--)
for(b=171;b>0;b--)
for(a=16;a>0;a--);
_nop_(); //if Keil,require use intrins.h
}
void delay1ms(void) //誤差 0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=142;b>0;b--)
for(a=2;a>0;a--);
}
void delay10ms(void) //誤差 0us
{
unsigned char a,b,c;
for(c=1;c>0;c--)
for(b=38;b>0;b--)
for(a=130;a>0;a--);
}
void delay10us(void) //誤差 0us
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void delay100ms(void) //誤差 0us
{
unsigned char a,b,c;
for(c=19;c>0;c--)
for(b=20;b>0;b--)
for(a=130;a>0;a--);
}
void iic_start()
{
SCL = 1;
SDA = 1;
nops4();
SDA = 0;
nops4();
SCL = 0;
}
//IIC停止函數(shù)
void iic_stop()
{
SCL = 0;
SDA = 0;
nops4();
SCL = 1;
nops4();
SDA = 1;
nops4();
}
/*
* 函數(shù): void iic_sendACK(bit ack_back)
功能: 主機(jī)讀完數(shù)據(jù)后是否向從機(jī)發(fā)送應(yīng)答信號(hào)
*ck為1時(shí)發(fā)送應(yīng)答信號(hào)ACK, SDA拉低,繼續(xù)通信
*ck為0時(shí)不發(fā)送ACK,SDA置1,結(jié)束通信*/
void iic_sendACK(bit ack_back)
{
if(ack_back)
SDA = 0; //應(yīng)答,SDA拉低,繼續(xù)通信
else
SDA = 1; //非應(yīng)答,SDA置1,結(jié)束通信
nops4();
SCL = 1;
nops4();
SCL = 0;
nops4();
SDA = 1;
}
/*主機(jī)寫(xiě)字節(jié)后檢測(cè)讀取從機(jī)發(fā)送的應(yīng)答(寫(xiě)應(yīng)答)*/
bit iic_recACK()
{
unsigned char i=0;
SDA = 1; //先拉高SDA,等待檢測(cè)
nops4();
SCL = 1;
nops4();
while((1==SDA)&&(i<255)) i++; //SDA為1時(shí),循環(huán)檢測(cè)255次
if(SDA) //非應(yīng)答,拉低SCL,停止,返回1
{
SCL = 0;
iic_stop();
return 1;
}
else //應(yīng)答,拉低SCL,返回1
{
SCL = 0;
return 0;
}
}
/*主機(jī)發(fā)送1字節(jié)數(shù)據(jù)給從機(jī)*/
/*從最高位開(kāi)始發(fā)送*/
void iic_sendbyte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80) //判斷最高位,并賦予SDA
SDA = 1;
else
SDA = 0;
nops4();
SCL = 1; //SCL高電平,SDA數(shù)據(jù)穩(wěn)定,發(fā)送
nops4();
byt<<=1; //發(fā)送完成,字節(jié)左移
SCL = 0;
}
}
/*主機(jī)讀取1字節(jié)數(shù)據(jù)*/
/*從高位接收,存放在低位*/
unsigned char iic_recbyte()
{
unsigned char i,byt;
for(i=0;i<8;i++)
{
SCL = 1; //SCL高電平,SDA數(shù)據(jù)穩(wěn)定
nops4();
byt<<=1; //接收數(shù)據(jù)左移
if(SDA) //判斷接收數(shù)據(jù),并賦給byt,1則+1,0則保持0;
byt = byt|0x01;
SCL = 0; //拉低SCL,準(zhǔn)備接收下一位數(shù)據(jù)
nops4();
}
return byt; //讀取字節(jié)完畢,返回讀取值
}
unsigned char iic_readvoldata()
{
iic_start(); //起始
iic_sendbyte(add_write); //發(fā)送“寫(xiě)”地址
if(!iic_recACK()) //應(yīng)答判斷
{
iic_sendbyte(control_byte); //發(fā)送控制字
if(!iic_recACK()) //應(yīng)答判斷
{
iic_start(); //起始
iic_sendbyte(add_rec); //發(fā)送“讀”地址
if(!iic_recACK()) //應(yīng)答判斷
{
voldata1 = iic_recbyte(); //讀取A/D值
iic_sendbyte(0); //不發(fā)送應(yīng)答
iic_stop(); //停止
}
}
}
return voldata1; //返回A/D值
}
bit lcd_busytest() //忙碌檢測(cè)
{
bit result; //定義檢測(cè)結(jié)果變量
RS = 0; //從CGRAM或DDRAM讀取,RS=1,RW=1,E高電平有效
RW = 1;
E = 1;
nops4(); //空操作,給硬件反應(yīng)時(shí)間
result = bf; //讀取忙碌標(biāo)志
E = 0; //使能信號(hào)復(fù)位
return result; //返回忙碌標(biāo)志值,0空閑,1忙碌
}
void lcd_writecmd(unsigned char cmd)
{
while(lcd_busytest()==1); //忙碌檢測(cè)
RS = 0; //寫(xiě)指令RS=0,RW=0,E一個(gè)脈沖
RW = 0;
E = 0; //E先置零
nops4();
lcd_data = cmd; //將要寫(xiě)的數(shù)據(jù)給I/O口
nops4();
E = 1;
nops4();
E = 0; //E置1,再置零,執(zhí)行寫(xiě)操作有效
}
void lcd_writeadd(unsigned char add) //地址指令需要在原地址上+0x80
{
lcd_writecmd(add|0x80);
}
void lcd_writedata(unsigned char dat)
{
while(lcd_busytest()==1); //忙碌檢測(cè)
RS = 1;
RW = 0;
E = 0; //E先置零
nops4();
lcd_data = dat; //將要寫(xiě)的數(shù)據(jù)給I/O口
nops4();
E = 1;
nops4();
E = 0; //E置1,再置零,執(zhí)行寫(xiě)操作有效
}
void lcd_init()
{
delay1ms(); //延時(shí)15ms,首次寫(xiě)指令時(shí)應(yīng)給LCD一段較長(zhǎng)的反應(yīng)時(shí)間
lcd_writecmd(0x38); //指令6,顯示模式設(shè)置:16×2顯示,5×7點(diǎn)陣,8位數(shù)據(jù)接口
delay1ms();
lcd_writecmd(0x38);
delay1ms();
lcd_writecmd(0x38);
delay1ms();
lcd_writecmd(0x0f); //指令4顯示開(kāi)關(guān)控制,關(guān)閉顯示
delay1ms();
lcd_writecmd(0x01); //指令1,清顯示
delay1ms();
lcd_writecmd(0x06); //指令3,設(shè)置輸入模式,寫(xiě)入字符后,光標(biāo)右移、字符不動(dòng)
delay1ms();
}
/////////24C02讀寫(xiě)驅(qū)動(dòng)程序////////////////////
void delay1(unsigned char m)
{ unsigned int n;
for(n=0;n<m;n++);
}
void init() //24c02初始化子程序
{
scl=1;
nop();
sda=1;
nop();
}
void start() //啟動(dòng)I2C總線(xiàn)
{
sda=1;
nop();
scl=1;
nop();
sda=0;
nop();
scl=0;
nop();
}
void stop() //停止I2C總線(xiàn)
{
sda=0;
nop();
scl=1;
nop();
sda=1;
nop();
}
void writebyte(unsigned char j) //寫(xiě)一個(gè)字節(jié)
{
unsigned char i,temp;
temp=j;
for (i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
nop();
sda=CY; //temp左移時(shí),移出的值放入了CY中
nop();
scl=1; //待sda線(xiàn)上的數(shù)據(jù)穩(wěn)定后,將scl拉高
nop();
}
scl=0;
nop();
sda=1;
nop();
}
unsigned char readbyte() //讀一個(gè)字節(jié)
{
unsigned char i,j,k=0;
scl=0; nop(); sda=1;
for (i=0;i<8;i++)
{
nop(); scl=1; nop();
if(sda==1)
j=1;
else
j=0;
k=(k<<1)|j;
scl=0;
}
nop();
return(k);
}
void clock() //I2C總線(xiàn)時(shí)鐘
{
unsigned char i=0;
scl=1;
nop();
while((sda==1)&&(i<255))
i++;
scl=0;
nop();
}
////////從24c02的地址address中讀取一個(gè)字節(jié)數(shù)據(jù)/////
unsigned char read24c02(unsigned char address)
{
unsigned char i;
start();
writebyte(0xa0);
clock();
writebyte(address);
clock();
start();
writebyte(0xa1);
clock();
i=readbyte();
stop();
delay1(100);
return(i);
}
//////向24c02的address地址中寫(xiě)入一字節(jié)數(shù)據(jù)info/////
void write24c02(unsigned char address,unsigned char info)
{
start();
writebyte(0xa0);
clock();
writebyte(address);
clock();
writebyte(info);
clock();
stop();
delay1(5000); //這個(gè)延時(shí)一定要足夠長(zhǎng),否則會(huì)出錯(cuò)。因?yàn)?4c02在從sda上取得數(shù)據(jù)后,還需要一定時(shí)間的燒錄過(guò)程。
}
void keyscan() //按鍵掃描程序
{
if(k1==0)
{
delay1ms();
if(k1==0)
{
flag=!flag;
}
while(!k1);
}
if(flag==0)
{
if(k2==0)
{
delay1ms();
if(k2==0)
{
ldata++;
}
}
if(k3==0)
{
delay1ms();
if(k3==0)
{
if( ldata>0)
ldata--;
}
}
}
if(flag==1)
{
if(k2==0)
{
delay1ms();
if(k2==0)
{
hdata++;
}
}
if(k3==0)
{
delay1ms();
if(k3==0)
{
if( hdata>0)
hdata--;
}
}
}
}
void main()
{ TMOD=0x10; //定時(shí)器1定時(shí)模式,均16位計(jì)數(shù)模式
TH1=(65536-50000)/256; //約每50ms計(jì)數(shù)1次
TL1=(65536-50000)%256;
ET1=1; // 開(kāi)定時(shí)器1中斷
TR1=0; // 定時(shí)器1
EA=1; //開(kāi)總中斷
init(); //初始化24C02
lcd_init(); //初始化lcd
hdata=read24c02(1);
ldata=read24c02(0);
pe=0;
while(1)
{
voldate=iic_readvoldata();
//vol = voldate*5/0.255;
vol = voldate/2.7;
if(vol<=7)
vol=0;
lcd_writecmd(0x80);
for(i=0;i<8;i++)
{
lcd_writedata(character[i]);
}
lcd_writedata(vol/100%10+0x30); //顯示酒精濃度
lcd_writedata(vol/10%10+0x30);
lcd_writedata(vol%10+0x30);
lcd_writedata('m');
lcd_writedata('g');
lcd_writedata('/');
lcd_writedata('m');
lcd_writedata('L');
lcd_writecmd(0xc0);
for(i=0;i<5;i++)
{
lcd_writedata(character2[i]);
}
lcd_writedata(ldata/100%10+0x30); //顯示設(shè)定的低警示值
lcd_writedata(ldata/10%10+0x30);
lcd_writedata(ldata%10+0x30);
lcd_writedata('m');
lcd_writedata('g');
lcd_writedata(' ');
lcd_writedata(hdata/100%10+0x30); //顯示設(shè)定的高警示值
lcd_writedata(hdata/10%10+0x30);
lcd_writedata(hdata%10+0x30);
lcd_writedata('m');
lcd_writedata('g');
delay100ms();
keyscan();
if(vol<=ldata) //紅綠燈設(shè)定
red=1,green=0,yellow=1;
if(vol>ldata && vol<=hdata)
red=1,green=1,yellow=0;
if(vol>hdata)
red=0,green=1,yellow=1;
write24c02(0,ldata); //寫(xiě)數(shù)據(jù)到24c02
delay10ms();
write24c02(1,hdata);
if(vol>ldata && vol<hdata )
pe=1;
if(vol<ldata)
pe=0;
if(vol>hdata )
pe=1,TR1=1;
if(vol==hdata)
pe=0;
if(tt==1)
{
pe=0;
tt=0;
m=0;
TR1=0;
pe=1;
}
}
}
void timer1() interrupt 3
{
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
m++;
if(m==20)//1s
{ m=0;
tt++;
}
}
復(fù)制代碼
Keil5代碼與Proteus8.8仿真下載:
酒精檢測(cè)顯示.zip
(137.48 KB, 下載次數(shù): 79)
2022-5-8 14:12 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1