#include<stc15f2k60s2.h>
#include<stdio.h>
#include<intrins.h>
#include<string.h>
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
#include "modbus.h"
#include<AD.h>
#include"eeprom.h"
//串口2添加控制
#define S2RI 0x01 //S2CON.0
#define S2TI 0x02 //S2CON.1
#define S2RB8 0x04 //S2CON.2
#define S2TB8 0x08 //S2CON.3
//串口2切换io控制
#define S2_S0 0x01 //P_SW2.0
//串口1切换io控制
#define S1_S0 0x40 //P_SW1.6
#define S1_S1 0x80 //P_SW1.7
bit busy; //串口2用忙标识
//#define _debug 0
/*串口2**传感器*/
/*串口2接受数据长度*/
u8 Rec2_len=0;
u8 Uart2_Rec[9]={0};
/*串口1**max485*/
u8 Rec1_len=0;
u8 Rec_485buf[6];
u8 Send_485buf[11];
/****pm数据****/
u16 PM25_DATA=0;
u16 PM10_DATA=0;
u16 PM100_DATA=0;
/**485*********/
sbit b485Send = P2^0; //max485 发送接收控制 0接收 1发送
bit flag=0;
/*AD采集电压值===>换算为噪声分贝值*/
u16 noise=0;
/******空气质量传感器检测******/
sbit pin_a=P1^6;
sbit pin_b=P1^7;
u8 AQI=0; //空气质量等级:0-3 0最优
/*******本从机地址********/
extern u8 localAddr;
/*******定时*******/
u8 Caiji_Time=0;
/********传感器型号-程序版本信息*******/
u8 PRODUT_VER=255;
u8 CODE_VER=254;
/*
* 先进先出滤波算法
*/
#define FILTER_N 12
int filter_buf[FILTER_N + 1];
int Filter() {
int i;
int filter_sum = 0;
filter_buf[FILTER_N] = GetADCResult(2); //p12AD
for(i = 0; i < FILTER_N; i++) {
filter_buf[i] = filter_buf[i + 1]; // 所有数据左移,低位仍掉
filter_sum += filter_buf[i];
}
return (int)(filter_sum / FILTER_N);
}
/**********************************************************************
* 函数名: unsigned char FucCheckSum(unsigned char *i, unsigned char ln)
* 功能描述:求和校验(取发送、接收协议的1\2\3\4\5\6\7的和取反+1)
* 函数说明:将数组的元素1-倒数第二个元素相加后取反+1(元素个数必须大于2)
********************************************************************/
unsigned char FucCheckSum(unsigned char *i, unsigned char ln)
{
unsigned char j,tempq=0;
i+=1;
for(j=0;j<(ln-2);j++)
{
tempq+= *i;
i++;
}
tempq=(u8)((~tempq)+1);
return(tempq);
}
/************************************
延时子程序
延时时间(xms*1)ms
*************************************/
void delayms(u16 xms)
{
u16 x,y;
for(x=xms;x>0;x--)
for(y=550;y>0;y--);
}
//定时器0初始化
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
}
//串口1初始化 下载口 机复用到 p36、p37 485输出用
void Uart1Init(void) //9600bps@11.0592MHz
{
PCON &= 0x7F; //波特率不倍速
SCON = 0x50; //8位数据,可变波特率
AUXR |= 0x40; //定时器1时钟为Fosc,即1T
AUXR &= 0xFE; //串口1选择定时器1为波特率发生器
TMOD &= 0x0F; //清除定时器1模式位
TMOD |= 0x20; //设定定时器1为8位自动重装方式
TL1 = 0xDC; //设定定时初值
TH1 = 0xDC; //设定定时器重装值
ET1 = 0; //禁止定时器1中断
TR1 = 1; //启动定时器1
P_SW1 &= ~(S1_S0 | S1_S1); //S1_S0=1 S1_S1=0
P_SW1|=S1_S0; //设置串口1 在p36 p37
ES = 1; //使能串口中断
REN=1;//允许接收
}
//---串口1发送字节---//
void Uart1_SendData(u8 dat)
{
SBUF = dat; //Send data to UART buffer
while(!TI);
TI=0;
}
/*----------------------------
串口1发送字符串
----------------------------*/
void Uart1_SendString(char *s)
{
while (*s) //Check the end of the string
{
Uart1_SendData(*(s++)); //Send current char and increment string ptr
}
}
//串口2 初始化
void Uart2Init(void) //9600bps@11.0592MHz
{
S2CON = 0x50; //8位数据,可变波特率
AUXR |= 0x04; //定时器2时钟为Fosc,即1T
T2L = 0xE0; //设定定时初值
T2H = 0xFE; //设定定时初值
AUXR |= 0x10; //启动定时器2
IE2 = 0x01; //使能串口2中断
EA = 1;
//P_SW2 &= ~S2_S0; //S2_S0=0 (P1.0/RxD2, P1.1/TxD2)
}
//---串口2发送字节---//
void Uart2_SendData(u8 dat)
{
while(busy); //等待前面的数据发送完成
busy=1;
S2BUF = dat; //Send data to UART buffer
}
/*485发送函数*/
void Send_485_Data(u8 *buf,u8 len)
{
u8 i=0;
b485Send = 1; //置为发送状态
for(i=0;i<len;i++)
Uart1_SendData(buf[i]);
Rec1_len=0; //接收计数清零
b485Send = 0; //发送完后将485置于接收状态
}
/**pm传感器模式切换为查询模式**/
void Pm_Mode_Change()
{
u8 i=0;
u8 temp[9]={0};
temp[0]=0xff;temp[1]=0x01;temp[2]=0x78;temp[3]=0x41;temp[4]=0x00;
temp[5]=0x00;temp[6]=0x00;temp[7]=0x00;temp[8]=0x46;
for(i=0;i<9;i++)
Uart2_SendData(temp[i]); //切换为问答模式获取数据
}
/**读取传感器pm值**/
void Get_PmData()
{
u16 i=0,check=0; //pm数据校验
u8 temp[9]={0};
u8 tem[60]={0};
Rec2_len=0;
temp[0]=0xff;temp[1]=0x01;temp[2]=0x86;temp[3]=0x00;temp[4]=0x00;
temp[5]=0x00;temp[6]=0x00;temp[7]=0x00;temp[8]=0x79;
for(i=0;i<9;i++)
Uart2_SendData(temp[i]); //
i=0;
while(1)
{
delayms(300);
if(Rec2_len>0)
{
Rec2_len=0;
check=FucCheckSum(&Uart2_Rec,9);
sprintf(tem,"%d",check);
Uart1_SendString(tem);
check=(u8)check;
if(Uart2_Rec[8]==check)
{
// Uart1_SendString("Get DATA ok\r\n");
PM25_DATA=Uart2_Rec[2]*256+Uart2_Rec[3];
PM100_DATA=Uart2_Rec[4]*256+Uart2_Rec[5];
PM10_DATA=Uart2_Rec[6]*256+Uart2_Rec[7];
// sprintf((char*)tem,"pm2.5=%dug/m3 pm10=%dug/m3 pm1.0=%dug/m3 che:%d\r\n",PM25_DATA,PM100_DATA,PM10_DATA,check);
// Uart1_SendString(tem);
for(i=0;i<9;i++)
Uart2_Rec[i]=0;
break;
}
for(i=0;i<9;i++)
Uart2_Rec[i]=0;
} i++;
if(i>10)
{
// Uart1_SendString("no DATA\r\n");
break;
}
}
}
/**获取采集电压
噪声AD值最大为768 定义为噪声130dB
最小AD值为0,定义为噪声45dB 360 50db
AD采集到最大电压值为3.92V。
**/
void Get_Noise()
{
u16 ad_temp=0;
u8 temp1=0,temp2=0;
noise=Filter();
noise=10+noise/8;
if(noise>130)
noise=130;
}
void Write_Slave_Address(u8 address)
{
IapEraseSector(IAP_ADDRESS);
IapProgramByte(IAP_ADDRESS,address);
}
/*空气质量采集*/
void Air_Q()
{
if(pin_a==0&&pin_b==0)
{
AQI=0;
}
else if(pin_a==0&&pin_b==1)
{
AQI=1;
}
else if(pin_a==1&&pin_b==0)
{
AQI=2;
}
else
AQI=3;
}
/**主函数**/
void main(void)
{
u8 i=0;
u8 temp[20];
P1M0 = 0x00;
P1M1 = 0x00;
Uart1Init();
Uart2Init();
Timer0Init();
InitADC();
Pm_Mode_Change(); //设置pm传感器查询模式
b485Send=0; //默认设置485 接收模式
localAddr=IapReadByte(IAP_ADDRESS);
if(localAddr==255)//读取本从机地址为255 说明还未设置地址,默认设置为1
localAddr=1;
while(1)
{
#ifdef _debug
sprintf((char*)temp,"noise:%d dB\r\n",noise);
Send_485_Data(temp,strlen((char*)temp));
#endif
checkComm1Modbus();
if(Caiji_Time>1) //采集数据周期 1s
{
Caiji_Time=0;
Get_Noise(); //获取噪声
Get_PmData(); //获取pm传感器数据
Air_Q(); //获取空气质量
}
}
}
// UART1中断服务程序
void Uart1() interrupt 4
{
if(RI)
{
flag=1;
RI = 0;
Rec_485buf[Rec1_len] = SBUF;
Rec1_len++; //接收地址偏移寄存器加1
//Rec1_len &= 0x14; //最多一次只能接收21个字节
}
}
/*----------------------------
UART2 中断服务程序
-----------------------------*/
void Uart2() interrupt 8 using 1
{
if (S2CON & S2RI)
{
S2CON &= ~S2RI; //清除S2RI位
Uart2_Rec[Rec2_len] = S2BUF;
Rec2_len++;
}
if (S2CON & S2TI)
{
S2CON &= ~S2TI; //清除S2TI位
busy = 0; //清忙标志
}
}
// 定时器0中断服务函数
void timer0()interrupt 1 //1ms中断
{
static u16 num;
num++;
if(num>1000)
{
num=0;
Caiji_Time++;
}
}