谁用过GP2Y1051AU0F 能否给一个51单片机的程序?

谁用过GP2Y1051AU0F 能否给一个51单片机的程序?,第1张

#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.是不是输入电压的范围超了?如果是范宴槐围超了,加个分压电路,然后在单片机程序里面再按比例的增加就行了。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/12561131.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2025-08-26
下一篇2025-08-26

发表评论

登录后才能评论

评论列表(0条)

    保存