
#include <reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define ushort unsigned short
uchar TxBuf[32]
sbit re=P2^5 //液晶接口
sbit rw=P2^4
sbit rs=P2^3
sbit psb=P2^6
sbit rst=P2^7
sbit LED=P1^5//粉尘传感器控制接口
sbit ADCS=P2^0//AD0832接口
sbit ADCLK=P2^1
sbit ADDI=P2^2
sbit ADDO=P2^2
sbit SET=P3^3//按键接口
sbit ADD=P3^4
sbit DEC=P3^5
sbit BEEP=P3^6//蜂鸣器接口
uchar set_st
uchar tab[4]
uint DUST_SET=35//固体颗粒物的阀值
int x //计数器
//定义标志
uchar FlagStar=0
float DUST_Value
uint DUST
uchar num=0
uchar mm
uchar abc
uchar ADC_Get[10]={0}//定义AD采样腊袭知数组
uchar str[5]={0}
uchar code tab0[]="pm2.5:"
uchar code tab1[]="温度值:"
uchar code tab2[]="报警阀值:"
void delaym1s(uint z)
{
uint x,y
for(x=zx>0x--)
for(y=110y>0y--)
}
void DelayMs(uchar k)
{ uchar i
i=k
while(i--)
}
void wr_date(uchar date)//写数据
{
uint i
uchar a,p
delaym1s(10)
a=date
rs=1 //数据命令选择=1时读取数据
re=0 //串口时钟,未开
rw=1 //选择串口方式
for(i=0i<5i++) //开启字节
{
re=1
re=0
}
rw=0 // 写
re=1 //开启轮消时钟脉冲
re=0
rw=1 //选择数据
re=1
re=0
rw=0
re=1
re=0
for(p=0p<2p++)
{
for(i=0i<4i++)
{
a=a<<1 //左禅纳移目的是为了将溢出数据(即0或1)赋予std
rw=CY //单片机特殊功能寄存器,“CY”用于存放字符串溢出字符
re=1 //一开一锁将数据显示
re=0
}
rw=0
for(i=0i<4i++)
{
re=1
re=0
}
}
}
void wr_com(uchar com) //写命令
{
uchar a,p
uint i
delaym1s(10)
a=com
rs=1 //数据命令选择=1时读取数据
re=0 //串口时钟,未开
rw=1 //选择串口方式
for(i=0i<5i++) //开启字节
{
re=1
re=0
}
rw=0
re=1 //开启时钟脉冲
re=0
rw=0
re=1
re=0
rw=0
re=1
re=0
for(p=0p<2p++)
{
for(i=0i<4i++)
{
a=a<<1//左移目的是为了将溢出数据(即0或1)赋予std
rw=CY//单片机特殊功能寄存器,“CY”用于存放字符串溢出字符
re=1//一开一锁将数据显示
re=0
}
rw=0
for(i=0i<4i++)//延时一下为下一数据到来做准备
{
re=1
re=0
}
}
}
void write_lcd() //向液晶写入显示内容
{
uchar num
wr_com(0x80)
for(num=0num<7num++)
{
wr_date(tab0[num])
delaym1s(1)
}
wr_com(0x90)
for(num=0num<7num++)
{
wr_date(tab1[num])
delaym1s(1)
}
wr_com(0x88)
for(num=0num<10num++)
{
wr_date(tab2[num])
delaym1s(1)
}
// wr_com(0x98)
// for(num=0num<16num++)
// {
// wr_date(tab3[num])
// delay(1)
// }
}
void init_lcd()
{
rst=1
psb=0 //选串口
wr_com(0x30)//30---基本指令动作
wr_com(0x01)//清屏,地址指针指向00H
delaym1s(1)
wr_com(0x06)//光标的移动方向即读入或写入数据后指针加一
wr_com(0x0c)//开显示,关游标类似1602
return
}
void init()
{
init_lcd()
write_lcd()
}
/*******初始化定时器0***********/
void InitTimer(void)
{
TMOD=0x01
TH0=(65536-8881)/256//定时10ms
TL0=(65536-8881)%256
TR0=1
ET0=1
EA=1
}
/****************显示函数********************/
void disp(uint Data)//PM2,5值显示
{
uint Temp
Temp=Data%10000
TxBuf[0]=Temp/1000+0x30//千位
Temp%=1000
TxBuf[1]='.'
TxBuf[2]=Temp/100+0x30//百位
Temp%=100
TxBuf[3]=Temp/10+0x30//十位
TxBuf[4]=Temp%10+0x30//个位
wr_com(0x83)
wr_date(TxBuf[0])
wr_date(TxBuf[1])
wr_com(0x84)
wr_date(TxBuf[2])
wr_date(TxBuf[3])
wr_com(0x85)
wr_date(TxBuf[4])
wr_date('u')
wr_com(0x86)
wr_date('g')
wr_date('/')
wr_com(0x87)
wr_date('m')
wr_date('3')
}
/*********报警值显示**********/
void baojing()
{
wr_com(0x8d)
wr_date(TxBuf[12])
wr_date(TxBuf[13])
wr_com(0x8e)
wr_date(TxBuf[14])
wr_date(TxBuf[15])
}
// /******延时********/
// void Delay(uint num)
// {
// while(--num)
// }
//
/*******按键检测********/
void checkkey()
{
if(SET==0)
{
delaym1s(10)
do{}while(SET==0)
set_st++
if(set_st>1)set_st=0
}
if(set_st==0)
{
}
else if(set_st==1)
{
if(DEC==0)
{
delaym1s(10)
do{}while(DEC==0)
if(DUST_SET>0) DUST_SET--
if(DUST_SET==0) DUST_SET=0
}
if(ADD==0)
{
delaym1s(10)
do{}while(ADD==0)
DUST_SET++
if(DUST_SET>80) DUST_SET=80
}
}
TxBuf[12]=DUST_SET/100
TxBuf[13]='.'
TxBuf[14]=DUST_SET%100/10
TxBuf[15]=DUST_SET%100%10
}
///******报警子程序*******/
//void Alarm()
//{
// if(x>=10){beep_st=~beep_stx=0}
// if(DUST/10>DUST_SET&&beep_st==1) BEEP=1
// else BEEP=0
// if(DUST/10>0&&DUST/10<10){LED2=0LED3=1LED4=1}
// if(DUST/10>=10&&DUST/10<30){LED2=1LED3=0LED4=1}
// if(DUST/10>=30){LED2=1LED3=1LED4=0}
//}
/*******AD0832转换程序**********/
uchar AD0832(bit mode,bit channel) //AD转换,返回结果
{
uchar i,dat,ndat
ADCS=0// 拉低CS端
_nop_()
_nop_()
ADDI=1 //第一个下降沿为高电平
ADCLK=1 // 拉高CLK端
_nop_()
_nop_()
ADCLK=0// 拉低CLK端,形成下降沿1
_nop_()
_nop_()
ADDI=mode //低电平为差分模式,高电平为单通道模式。
ADCLK=1 // 拉高CLK端
_nop_()
_nop_()
ADCLK=0// 拉低CLK端,形成下降沿2
_nop_()
_nop_()
ADDI=channel //低电平为CH0,高电平为CH1
ADCLK=1 // 拉高CLK端
_nop_()
_nop_()
ADCLK=0// 拉低CLK端,形成下降沿3
ADDI=1// 控制命令结束(经试验必须)
dat=0
//下面开始读取转换后的数据,从最高位开始依次输出(D7~D0)
for(i=0i<8i++)
{
dat<<=1
ADCLK=1//拉高时钟端
_nop_()
_nop_()
ADCLK=0//拉低时钟端形成一次时钟脉冲
_nop_()
_nop_()
dat|=ADDO
}
ndat=0 //记录 D0
if(ADDO==1)
ndat|=0x80
//下面开始读取反序的数据从(D1到D7)
for(i=0i<7i++)
{
ndat>>=1
ADCLK=1//拉高时钟端
_nop_()
_nop_()
ADCLK=0//拉低时钟端形成一次时钟脉冲
_nop_()
_nop_()
if(ADDO==1)
ndat|=0x80
}
ADCS=1//拉高cs端,结束转换
ADCLK=0//拉低CLK端
ADDI=1//拉高数据段,回到初始状态
if(dat==ndat)
return(dat)
else
return 0
}
/**********定时器0中断服务程序***************/
void timer0(void) interrupt 1
{
uint j
x++
TH0=(65536-8881)/256//定时10us
TL0=(65536-8881)%256
LED=1
for(j=0j<30j++)//延时0.28ms
abc=AD0832(1,0) //开启ADC采集
FlagStar=1
for(j=0j<5j++)
TR0=0
EA=0
LED=0 //关闭传感器LED
}
/**************************************************************
中值滤波 算法:先进行排序,然后将数组的中间值作为当前值返回。
**************************************************************/
uchar Error_Correct(uchar *str,uchar num)
{
uchar i=0
uchar j=0
uchar Temp=0
//排序
for(i=0i<num-1i++)
{
for(j=i+1j<numj++)
{
if(str[i]<str[j])
{
Temp=str[i]
str[i]=str[j]
str[j]=Temp
}
}
}
//去除误差,取中间值
return str[num/2]
}
/*******主函数*********/
void main()
{
// uchar a
InitTimer() //初始化定时器
LED=1
DelayMs(255)//等待电源稳定,液晶复位完成
init()//12864 液晶初始化
// DS18B20_Init()//18B20 初始化,可不用初始化,因为18B20 出厂时默认是12 位精度
delaym1s(100)
while(1)
{
checkkey()//按键检测
baojing()//显示报警值
disp(DUST) //显示粉尘浓度值
if(set_st==0)
{
// write_com(0x0c)
if(FlagStar==1)
{
num++
ADC_Get[num]=abc
if(num>9)
{
num=0
DUST=Error_Correct(ADC_Get,10)//求取10次AD采样的值
DUST_Value=(DUST/256.0)*5000 //转化成电压值mv
DUST_Value=DUST_Value*0.17-0.1//固体悬浮颗粒浓度计算 Y=0.17*X-0.1 X--采样电压
// if(DUST_Value<0) DUST_Value=0
// if(DUST_Value>19600) DUST_Value=760 //限位
DUST=(uint)DUST_Value
}
TH0=(65536-8881)/256//定时10ms
TL0=(65536-8881)%256
TR0=1 //开启定时器0
EA=1
FlagStar=0
}
// Alarm() //报警检测
}
// write_com(0x80+0x4f)
// write_data('3')
// if(set_st==1) //报警值闪动
// {
// write_com(0xca)
// write_com(0x0d)
// delaym1s(150)
// }
}
}
1.你要把30H开始的8个字节加帆历起来,和放在字节变量可能溢出,所以你的代码把和放在R2R3拼起来的16位单元中;
每个字节先加到R3中,有进位则R2 加1
2.
第一次的SWAP A 和 RL A的作用是把刚才求和结果的高位字节中的bit0,1,2移位到bit5,6,7 ,相当于高位字节除以8的结果(8个字节相加,高位字节只有bit0,1,2可能非0)
第二次的SWAP A 和陪轿茄 RL A的作用是把刚才求和结果的低位字节中的bit76543移位到bit43210,配合后面的 ANL A,#1FH 去掉bit765后,也相当于除以8
3.
第二次的SWAP A 和 RL A 后,A的bit7 是原来的bit2移动过来的,
这里的四舍五入做的是:原bit2是1的话bit210就不小于4,除8结果就加一
做法是通过ADD A ,#80H如果现在的bit7也就是原芦察来的bit2为1就置位进位标志c, 在后面的 ADDC A , R3 那句把这个c加进去。
所以这个做法其实是三舍四入。
单片机一般的ADC是没有问题的,我觉得很有可能是下述原因之一慧祥颂:
1.是不是电平有跳动的不稳定,比如输入电平抖动(干扰导致),你只是肉眼没看出来而前郑已,所以认为它是稳定的。这个解决方法如果输入是稳定电压(直流),那就在电压之间加上个电容就完事了。
2.是不是输入电压的范围超了?如果是范宴槐围超了,加个分压电路,然后在单片机程序里面再按比例的增加就行了。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)