//STC12C2052AD输出PWM波 ,同时检测电压显示,自动稳压 。
//74HC164串入并出显示数码管,一位一位显示,之后熄灭省电,根据我焊的板子确定的数码管值。
#include <stc12c2052ad.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define AD_SPEED 0x60 //0110,0000 1 1 270个时钟周期转换一次,
//少占鱼制作 河北正定欢迎您 长沙航空职业技术学院 2010 年QQ:411656434
//京畿之地 魅力河北 河北欢迎您
//注意:74HC164是先发Qh 位最后发Qa位的。共阳数码管代码要反过来写。
//74HC164的Qa----Qh对应数码管a----dp各段。
uchar code tab[16]={0x02,0x9f,0x25,0x0d,0x99,
// 0 1 2 3 4
0x49, 0x41, 0x1f,0x01,0x09, 0x11,
// 5 6 7 8 9 A
0xc1,0x63,0x85,0x61,0x71}; //共y阳数码管
// b c d e f
uchar xianshi[4]={0x11,0xd7,0x25,0x45};
sbit OK=P1^1; //浓度正常指示灯
sbit BAOJING=P1^2; //报警指示灯
sbit sound=P1^0; //声音报警
sbit PWM=P3^7;
sbit contrl=P1^7; //加热控制端
sbit wei1=P3^3;
sbit wei2=P3^4;
sbit wei3=P3^2;
sbit wei4=P3^5;
bit high=1; //定义高5V加热传感器标志
bit low=0; //定义低1.5V加热传感器标志
bit START =0;
uint cnt=0;
uchar timeL=0x90;
uchar timeH=0x90;
/****************************************************************/
void pwm();
void delayms(uint);
void ADC(uchar port);
void InitADC();
//void baohu();
void ceshi();
void sendchar();
float voltage=0.0;
uint vol=0;
void run_t0();
//显示测试
void ceshi()
{
uchar i;
TI=0;
OK=0;
BAOJING=0;
sound=1;
wei1=0;
wei2=0;
wei3=0;
wei4=0;
for(i=0;i<16;i++)
{
SBUF=tab[i];
while(!TI);
TI=0;
delayms(850);
}
wei4=1;
wei3=1;
wei2=1;
delayms(1600);
wei1=1;
}
void sendchar()
{
TI=0;
SBUF=tab[xianshi[0]];
while(!TI);
TI=0;
wei1=0;
wei1=0;
delayms(1200);
wei1=1;
SBUF=tab[xianshi[1]];
while(!TI);
TI=0;
wei2=0;
wei2=0;
delayms(1200);
wei2=1;
SBUF=tab[xianshi[2]];
while(!TI);
TI=0;
wei3=0;
wei3=0;
delayms(1200);
wei3=1;
SBUF=tab[xianshi[3]];
while(!TI);
TI=0;
wei4=0;
wei4=0;
delayms(1200);
wei4=1;
}
/*****************主程序***********************************************************/
void main()
{
uint a=0;
PWM=1;
pwm();
delayms(1000);//延时
InitADC();
contrl=0;
delayms(600);
ceshi();
delayms(600);
sound=0;
OK=1;
BAOJING=1;
START=0;
contrl=1;//初次开机要先加热一分钟以上。在这里等待一分钟
wei1=0;//开启显示 数码管,做指示用
for(a=0;a<53;a++)
{
delayms(1000);
ADC(6);
sendchar();
}
wei1=1;
contrl=0;//关闭5V,成为1.5V低电平加热90S
wei2=0;
for(a=0;a<80;a++)
{
delayms(1000);
}
wei2=1;
a=0;
while(1)
{
ADC(6);
contrl=0;
run_t0();
if(START)
{
delayms(5);
}
a++;
if(a==6235)
{
a=0;
sendchar();
}
}
}
//
void run_t0()
{
cnt=0;
high=1;//首次启动加热5V高电平。标志位置1
low=0;//低电平1.5V加热标志
TMOD=0x01;
TH0=-(50000/256);
TL0=-(50000%256);
ET0=1;
EA=1;
contrl=1;//首次启动定时开启5V
TR0=1;
}
//
void time0() interrupt 1//using **
{
cnt++;
TR0=0;
if((cnt==120)&&high) //5V加热达到60S,这里加括号为了阅读方便。但是有时候要注意优先级。==比&就高得多
{
TR0=0;
TH0=-(50000/256);
TL0=-(50000%256);
ADC(6);
}
if((cnt==600)&&high) //5V加热达到60S,这里加括号为了阅读方便。但是有时候要注意优先级。==比&就高得多
{
TR0=0;
TH0=-(50000/256);
TL0=-(50000%256);
ADC(6);
}
if((cnt==1200)&&high) //5V加热达到60S,这里加括号为了阅读方便。但是有时候要注意优先级。==比&就高得多
{
TR0=0;
contrl=0;//开启1.5V,即关闭5V
cnt=0;
high=0;//停止加热高5V后清标志位
low=1;
TH0=-(50000/256);
TL0=-(50000%256);
ADC(6);
}
if((cnt==180)&&low)//1.5V加热达到90S
{
TH0=-(50000/256);
TL0=-(50000%256);
ADC(6);
}
if((cnt==1000)&&low)//1.5V加热达到90S
{
TH0=-(50000/256);
TL0=-(50000%256);
ADC(6);
}
if((cnt==1800)&&low)//1.5V加热达到90S
{
contrl=1;//开启5V
cnt=0;
low=0;
high=1;//
TH0=-(50000/256);
TL0=-(50000%256);
ADC(6);
}
TR0=1;
}
//
void pwm()
{
CR=0;
START=0;
//PCA模块工作于PWM模式 C程序
CMOD = 0x02; //用定时器0溢出做PCA脉冲
CL = 0x00; //PCA定时器低8位 地址:E9H
CH = 0x00; //PCA高8位 地址 F9H
CCON=0x00;
CCAP0L = timeL; //PWM模式时他俩用来控制占空比
CCAP0H = timeH; //0xff-0xc0=0x3f 64/256=25% 占空比(溢出)
CCAPM0 = 0x42; //0100,0010 Setup PCA module 0 in PWM mode
// ECOM0=1使能比较 PWM0=1 使能CEX0脚用作脉宽调节输出
/*********************
PCA 模块工作模式设置 (CCAPMn 寄存器 n= 0-3四种)
7 6 5 4 3 2 1 0
- ECOMn CAPPn CAPNn MATn TOGn PWMn ECCFn
选项: 0x00 无此操作
0x20 16位捕捉模式,由 CEXn上升沿触发
0x10 16位捕捉模式,由CEXn下降沿触发
0x30 16位捕捉模式,由CEXn的跳变触发
0x48 16位软件定时器
0x4c 16位高速输出
0x42 8位PWM输出
每个PCA模块另外还对应两个寄存器:CCAPnH和CCAPnL 。 捕获或者比较时,它们用来
保存16位计数值,当工作于PWM模式时,用来控制占空比
*******************************/
CR=1; //Start PCA Timer.
}
//AD转换初始化 ----打开ADC电源,设置AD口开漏状态
void InitADC()
{
ADC_CONTR|=0x80;
delayms(12);
//这两个寄存器用来设置 P1口四种状态,每一位对应一个P1引脚 ,按状态组合操作
/*****************
P1M0 和P1M1 寄存器位 7 6 5 4 3 2 1 0
P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0
同理P3M0 P3M0 也是。因为STC12C2052AD只有两个P口,所以只有这俩组 STC12C5410AD还多P2M0 P1M0 有三组
P1M0 P1M1 高
0 0 普通I0口 (准双向) P1寄存器位 7 6 5 4 3 2 1 0
0 1 强推挽输出 (20MA电流 )尽量少用 P1.7 P1.6 P1.5 P1.4 P1.3 P1.2 P1.1 P1.0
1 0 仅做输入 A/D转换时可用此模式
1 1 开漏 ,A/D转换时可用此模式
例如:
要设置P1.1为 AD 输入口
则 P1M0=0X02 ;
P1M1=0X02; 开漏即可
当不用AD时,最好 关闭ADC电源 ,恢复为IO口状态
********************************/
P1M0=0x40;//这两个寄存器用来设置 P1口四种状态,每一位对应一个P1引脚 ,按状态组合操作
P1M1=0x40;//P1.6位AD输入端
delayms(12);
}
// AD转换程序
void ADC(uchar port)
{
uint V0;
ADC_DATA = 0; //清除结果
ADC_CONTR = 0x60; //转换速度设置 0x60 最快速度
ADC_CONTR = 0xe0; //1110,0000 清 ADC_FLAG, ADC_START 位和低 3 位
ADC_CONTR |= port; //选择 A/D 当前通道 P1.6
// delayms(1); //使输入电压达到稳定
ADC_CONTR |= 0x08; //0000,1000 令 ADCS = 1, 启动A/D转换,
while(!(ADC_CONTR & 0x10)); //!的优先级比&高太多了
//养成经常加括号的习惯 ,没坏处 。也不浪费速度
/***************
这里while 不能改成while(ADC_CONTR & 0x10==0) ;就错误了,因为优先级 ==比&高 ,所以要加括号
while( (ADC_CONTR & 0x10) ==0) 或者非一下 while(!(ADC_CONTR & 0x10)); //!的优先级比&高太多了
while()
******************************/
ADC_CONTR &= 0xE7; //1111,0111 清 ADC_FLAG 位, 关闭A/D转换,
V0= ADC_DATA; //返回 A/D
voltage=V0*100.0/256.0*5.0;//注意每一步计算要考虑是否超了左边变量的范围,如果5.0放前面就有可能溢出
xianshi[0]=vol/1000;
xianshi[1]=vol%1000/100;
xianshi[2]=vol%100/10;
xianshi[3]=vol%10;
if(voltage<399.0)//危险浓度以下
{
OK=0;
BAOJING=1;//报警灯灭
START=1;
sound=0;//声音控制脚灭
}
if( voltage>399.0)//C0浓度过高
{
BAOJING=0;//报警灯亮
OK=1;
START=1;
sound=1;//声音报警
}
}
// 延时
void delayms(uint k)
{
uint data i,j;
for(i=0;i<k;i++)
{
for(j=0;j<200;j++)
{;}
}
}