//STC12C2052AD输出PWM波 ,同时检测电压显示,自动稳压 。
//74HC164串入并出显示数码管,一位一位显示,之后熄灭省电,根据我焊的板子确定的数码管值。
/************************************************/
//C编程技巧 :判断恒等于==把常量写前面
//注意:这里把常量写在前面是为了防止把“==”写成“=”,写成赋值后会报错,常量不能赋值
//注意:用于自加自减的变量要初始化。不然程序为他随机分配一个值,就乱了
/************************************************/
#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 control=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;
uint a=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_t1();
//显示测试
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
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(1000);
wei1=1;
SBUF=tab[xianshi[1]];
while(!TI);
TI=0;
wei2=0;
wei2=0;
delayms(1000);
wei2=1;
SBUF=tab[xianshi[2]];
while(!TI);
TI=0;
wei3=0;
wei3=0;
delayms(1000);
wei3=1;
SBUF=tab[xianshi[3]];
while(!TI);
TI=0;
wei4=0;
wei4=0;
delayms(1000);
wei4=1;
}
/*****************主程序***********************************************************/
void main()
{
//默认STC12是1T运行模式。时钟没有分频,为了兼容8051,定时器可以分频12.但是如果时钟也分频,就会影响他了。
AUXR=0x00;//定时器T0 T1,12分频。兼容8051
delayms(100);
IDLE_CLK=0x00;
PWM=1;
delayms(1000);//延时
InitADC();
control=0;
delayms(600);
ceshi();
delayms(600);
sound=0;
OK=1;
BAOJING=1;
START=0;
control=1;//初次开机要先加热一分钟以上。在这里等待一分钟
wei1=0;//开启显示 数码管,做指示用
for(a=0;a<53;a++)
{
delayms(300);
ADC(6);
sendchar();
}
wei1=1;
control=0;//关闭5V,成为1.5V低电平加热90S
wei2=0; //数码管位2亮做指示用
for(a=0;a<80;a++)
{
delayms(500);
}
wei2=1;//关闭数码管显示
a=0; //a清0,下面还要用
sound=0;
ADC(6);
control=0;
sound=0;
control=0;//关闭5V加热
run_t1();
while(1)
{
if(START)
{
delayms(20);
}
a++;
if(a==150)
{
a=0;
sendchar();
}
}
}
/******************************************************/
void run_t1()
{
cnt=0;
high=1;//首次启动加热5V高电平。标志位置1
low=0;//低电平1.5V加热标志
control=1;//首次启动定时开启5V
TMOD=0x11;
//注意:不能用负号的写法初始化。结果是错误的。并不是-50000到0次计数。
-(50000/256)是错误的
TH1=(65536-50000)/256; //虽然写的复杂,但是编译时会自动计算出结果,所以实际运行代码并没有多
TL1=(65536-50000)%256; //
TH0=(65536-1000)/256; //不用"-"号是错误的 (-(1000/256)是错误的,并不是65536减去1000的64536)
TL0=(65536-1000)%256; //这样才对
ET0=1;
ET1=1;
TR1=1;
EA=1;
}
//
void t0()interrupt 1
{
sound=!sound;
TH0=-(1000/256);
TL0=-(1000%256);
TR0=1;
}
//
void time1(void) interrupt 3//using **
{
cnt++;
//C编程技巧 :判断恒等于==把常量写前面
if((120==cnt)&&high) //注意:这里把常量写在前面是为了防止把“==”写成“=”,写成赋值后会报错,常量不能赋值
{
ADC(6);
}
if((600==cnt)&&high) //5V加热达到60S,这里加括号为了阅读方便。但是有时候要注意优先级。==比&就高得多
{
ADC(6);
}
if((1110==cnt)&&high) //5V加热达到60S,这里加括号为了阅读方便。但是有时候要注意优先级。==比&就高得多
{
control=0;//开启1.5V,即关闭5V
cnt=0;
high=0;//停止加热高5V后清标志位
low=1;
ADC(6);
}
if((180==cnt)&&low)//1.5V加热达到90S
{
ADC(6);
}
if((1000==cnt)&&low)//1.5V加热达到90S
{
ADC(6);
}
if((1680==cnt)&&low)//1.5V加热达到90S
{
control=1;//开启5V
cnt=0;
low=0;
high=1;//
ADC(6);
}
TH1=-(50000/256);
TL1=-(50000%256);
}
/************************************
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 最快速度
_nop_();_nop_();_nop_();_nop_();
ADC_CONTR = 0xe0; //1110,0000 清 ADC_FLAG, ADC_START 位和低 3 位
_nop_();_nop_();_nop_();_nop_();
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*4.99;//整形不能做除法,所以除号两边至少有一项是浮点型才可,先乘一个浮点数就会自动转成浮点型了
vol=voltage;
xianshi[0]=vol/1000;
xianshi[1]=vol%1000/100;
xianshi[2]=vol%100/10;
xianshi[3]=vol%10;
if(voltage<221.0)//危险浓度以下
{
OK=0;
BAOJING=1;//报警灯灭
START=1;
TR0=0;//声音控制脚灭
ET0=0;
}
if( voltage>221.0)//C0浓度过高
{
BAOJING=0;//报警灯亮
OK=1;
START=1;
ET0=1;
TR0=1;//声音报警
}
}
// 延时
void delayms(uint k)
{
uint data i,j;
for(i=0;i<k;i++)
{
for(j=0;j<600;j++)
{;}
}
}