//★DC45V6_ATtiny13 CPU,与48相比,SFR有较大的差别 采样电阻30K!
//★内部RC震荡4.8MHz,CPU 8分频。定时器再8分频。
//把DWEN=1,RSTDSIBL=0两位同时设置(打钩)才能作为普通I/O口用!!!
//一旦“烧死”,程序不能再下载,须用高压编程器重新变成。
//BODLEVEL: VCC=4.3V;CKDIV8 √; SUT_CKSEL:int RS OSC 4.8MH 14CK+4sm
//主要思路:采样电容充电电压(R1/R2="STR"),达到额定电压的85%时,启动电磁铁(得电)。
//采样电磁铁工作电压(R3/R4="U50",并用5V1稳压管限幅),电源电压降到50%时,停止电磁铁(断电)。
//程序写入时,选择“Int…RC…6CK/14CK+0ms”,防止电磁铁“抖动”!
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//注:内部函数_delay_ms() 最高延时 262.144mS@1MHz 即 32.768ms@8MHz
#include <avr/sleep.h>
//时钟内部8M,经内部DIV8后系统时钟为1MHz★
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define NOP asm("nop")
//电压
uint U85=985; //85% (电磁铁未工作时的饱和电压4.48V) 380V参数(采样电阻17K7) (最佳300V~310V)
uint U50=245; //50% (采样电磁铁吸合后的工作)非线性电压 260mV (最佳200V~210V)
uint U30=145; //30% (采样电磁铁吸合后的工作后电压,对应电源电压30%)
//定义延时时间
#define T0_1MS 0xb5 //4.8/8/8=0.075MHz,1000*0.075=75,256-75=181=b5H(系统4.8MRC,CPU时钟8分频)
//延时时间
#define DL_CNT0 0 //0S
#define DL_CNT1 80 //1S 每10mS减一,加入零压保持电容后,断电响应时间变慢600mS
#define DL_CNT2 170 //2S
#define DL_CNT3 250 //3S
#define DL_CNT4 340 //4S
#define DL_CNT5 430 //5S
#define DL_CNT6 520 //6S
#define DL_CNT10 940 //10S
//管脚定义
#define adc_SA 1 //ADC3
//-----------位操作定义----
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define CH_ON cbi(PORTB,3) //低电平,充电。电容充电回路
#define CH_OFF sbi(PORTB,3) //高电平,关闭
#define DCT_ON sbi(PORTB,0) //低电平,电磁铁得电。电磁铁控制
#define DCT_OFF cbi(PORTB,0) //高电平,电磁铁失电
// 全局变量
uint ad_array[10]; //10次AD存储值 array
uchar tim_10cnt; //10ms计数器
uchar f_1ms; //1ms中断
uint delay_data=0; //设定的延时时间
uint dl_cnt; //延时计数器,10ms减1
uchar state=0; //状态计数器
uchar key_10ms; //键盘扫描,每10ms扫描一次
//**********************************************************************************
void timer0_init(void) //T0定时1ms
{
TCCR0A = 0x00; //T/C 控制寄存器A:COM0A1 COM0A0 COM0B1 COM0B0 – – WGM01 WGM00
TCCR0B = 0x00; //T/C 控制寄存器B:FOC0A FOC0B – – WGM02 CS02 CS01 CS00
TCNT0 = T0_1MS; //设定时间常数
TCCR0B = 0x02; //start timer--8分频--1M内部系统时钟--1ms中断一次
TIMSK0 = 0x02; //★T/C 中断屏蔽寄存器:– – – – OCIE0B OCIE0A TOIE0 –,溢出中断TOIE0
}
//**********************************************************************************
void adc_init(void)
{ //【ADCSRA 控制及状态寄存器】:ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0
ADCSRA=0x03 ; //时钟8分频 125KHz@1MHz system clock
ADCSRA &=~(1<<ADEN); //禁止ADC
ADMUX=0x01; //★VCC作为参考电压,第1路输入ADC1)
}
//**********************************************************************************
void WDT_off(void)
{
MCUSR &= ~(1<<WDRF); //清除MCUSR 寄存器中WDRF
WDTCR |= (1<<WDCE) | (1<<WDE); //在WDCE 与WDE 中写逻辑1 保持旧预分频器设置防止无意暂停
WDTCR = 0x00; //关闭WDT
}
//**********************************************************************************
void main_init(void) //DDRB PORTB
{
DDRB=0x09; //b0000_1001;PB4电容充电(初高)、PB0输出控制电磁铁(初低)
PORTB=0xfa; //b1111_1010;(★PB2为AD输入,无上拉电阻-高阻态)
PCMSK=0x00; //引脚变化屏蔽寄存器– – PCINT5 PCINT4 PCINT3 PCINT2 PCINT1 PCINT0(全禁用)
ACSR=0x80; //模拟比较器控制及状态寄存器ACD(关闭) ACBG ACO ACI ACIE – ACIS1 ACIS0
DIDR0=0x08; //数字输入禁用寄存器0(模拟比较器关)– – ADC0D ADC2D ADC3D ADC1D AIN1D AIN0D
ACSR=(1<<ACD); //模拟比较器(上电默认是打开的,需要手工关闭)
timer0_init();
adc_init();
WDT_off();
}
//**********************************************************************************
unsigned int read_adc(uchar adc_port) //查询方式读取ADC单端通道
{
uchar i; //ADMUX【多路复用选择寄存器】:– REFS0 ADLAR – – – MUX1 MUX0
ADCSRA |=(1<<ADEN); //ADEN=1,使能ADC ADMUX=(0x40|adc_port);
//★AD端口号及 “adc_port”参考电压,已给定
for(i=10;i>0;i--); //延时等待稳定
ADCSRA|=(1<<ADSC); //启动AD转换ADC
loop_until_bit_is_set(ADCSRA,ADIF); //ADIF=1时后,AD转换结束
ADCSRA|=(1<<ADIF); //写1清除标志位
ADCSRA &=~(1<<ADEN); //ADEN=0,禁止ADC
return ADC; //ADC=ADCH:ADCL
}
//**********************************************************************************
//取10个数maxmin取平均
unsigned int ad_lb(uint ad_tmp[])
{
ulong temp=ad_tmp[0];
uchar i=1;
uint max=ad_tmp[0],min=ad_tmp[0];
for(i=1;i<10;i++)
{
temp+= ad_tmp[i];
if(ad_tmp[i]>max)
{
max=ad_tmp[i];
}
else if(ad_tmp[i]<min)
{
min=ad_tmp[i];
}
}
temp=(temp-max-min)/8;
return (uint)temp;
}
//**********************************************************************************
SIGNAL(TIM0_OVF_vect) //T0溢出中断1ms
{
TCNT0 = T0_1MS;
f_1ms=1;
}
//**********************************************************************************
void vol_deal(uint volt_ad) //电压处理
{
switch(state)
{
case 0:
{ //断开态
if(volt_ad>U85) //>85%吸合 全导通
{
DCT_ON; //启动电磁铁得电
_delay_ms(100); //延时100mS
_delay_ms(100); //延时100mS
CH_ON; //电容开始充电
_delay_ms(100); //延时100mS
state=1;
_delay_ms(10); //延时100mS
}
break;
}
case 1:
{ //吸合态
if(volt_ad<U50) //电压低于50%,进入断电延时
{
if(delay_data==0)
{
DCT_OFF; //关闭电磁铁(断电)
CH_OFF; //关闭电容充电
_delay_ms(5);
state=0;
}
else
{
dl_cnt=delay_data;
state=2;
}
}
break;
}
case 2: //延时中……
{
if(volt_ad>U50) //停止延时,返回正常状态
{
state=1;
}
else if((--dl_cnt==0)) //零压延时
// else if((--dl_cnt==0)||(volt_ad<U30))
{
DCT_OFF; //关闭电磁铁(断电)
CH_OFF; //关闭电容充电
state=0; //延时完成
}
break;
}
default:
{
state=0;
break;
}
}
}
//**********************************************************************************
void vol_judgment(void)
{
uint ad_dat;
ad_array[tim_10cnt]=read_adc(adc_SA);
if(++tim_10cnt==10) //10ms处理一次 交流半周期波形(每个周期测10个点)
{
tim_10cnt=0;
key_10ms=1; //key_10ms=1;
ad_dat=ad_lb(ad_array);
vol_deal(ad_dat);
}
if(state==0)
{
ADMUX&=~(1<<REFS0); //★(切换到)VCC作为参考电压
}
else
{
ADMUX|=(1<<REFS0); //★(切换到)片内基准电压1.1V
}
}
//******************************************************************************
void key_scan(void)
{
uchar key_state;
key_state = PINB; //读引脚
key_state &=0x32; //得到按键状态
switch(key_state) //延时时间 (0S)(1S)(2S)(3S)(4S)(5S)(6S)(10S)
{
case 0x32:delay_data=DL_CNT0;break;
case 0x30:delay_data=DL_CNT1;break;
case 0x22:delay_data=DL_CNT2;break;
case 0x20:delay_data=DL_CNT3;break;
case 0x12:delay_data=DL_CNT4;break;
case 0x10:delay_data=DL_CNT5;break;
case 0x01:delay_data=DL_CNT6;break;
case 0x00:delay_data=DL_CNT10;break;
default:delay_data=DL_CNT0;break;
}
}
//**********************************************************************************
int main(void)
{
uchar temp=0;
main_init();
_delay_ms(100); //延时100mS
_delay_ms(100); //延时100mS
_delay_ms(100); //延时100mS,等待电容充电稳定
sei(); //使能全局中断
while(1)
{
if(f_1ms==1)
{
f_1ms=0;
vol_judgment(); //电压判断
}
if(key_10ms==1)
{
key_10ms=0;
key_scan(); //延时开关扫描
// delay_data=DL_CNT0; //瞬时实验
}
set_sleep_mode(SLEEP_MODE_IDLE); //设定空闲模式
sleep_mode( ); //0.52mA
}
}
求解程序的中文解释,最好把其中宏定义的数字选择原因说一下 |