新手入门
积分 25
金钱 25
注册时间 2014-2-26
在线时间 0 小时
5 金钱
本人要做一个数控电源,用Atmega16,数模转换器用PCF8591,IIC通信,再加OP07运放放大,仿真的时候,按钮一按下数模的输出有点延迟,数码管要等十几秒才显示电压的值
麻烦看一下代码
# include <iom16v.h>
# include <AVR_HJ-2G.h>
# include <macros1.h.>
# define uint unsigned int
# define uchar unsigned char
# pragrma data: code
uchar SEG[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//不带小数点的数码管段选
# pragrma data: code
uchar SEG7[10]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd, 0x87, 0xff,0xef};//带小数点的数码管段选
uint adc_val=0, dis_val=0;//全局变量
uchar cnt=0,i=0,temp=0x00,cnt4=0;
void delay (uint i)//延时函数
{
uint j,k;
for (j=0; j<i;j++)
{
for (k=0; k<1141; k++)
;
}
}
void IO_Init ()//IO口初始化
{
DDRB=0xff;
PORTB=0x00;//PB口输出低电平,数码管的段选
DDRA=0xef;
PORTA=0x0f;//PA3-PA0设置为输出,PA4设置为输入 PA0-PA3数码管的位选
DDRD=0xff;
//PORTD|=BIT(2)|BIT(3);//PD2,3设置为带上拉电阻的输入 0000 1100
PORTD=0xff;
DDRC=0x00;
PORTC&=~BIT(2)&(~BIT(3));//PC2,PC3设置为带上拉电阻的输入,IIC通信
}
void Timer0_Init()//定时计数器0初始化
{
TCNT0=0x83;//1ms的定时初值1000 0011
TCCR0=0x03;//定时器0的计数预分频取64
TIMSK=0x01;//使能T/C0中断
SREG=0x80;
}
void Timer2_Init()
{
TCNT2=0x83;//1ms的定时初值1000 0011
TCCR2=0x03;//定时计数器2预分频取64
TIMSK|=BIT(6);//使能T/C2中断
}
void ADC_Init()//ADC模数转换器的寄存器的初始化
{
ADMUX=0x04;//0000 0100 使用外部参考源,ADCL,ADCH左对齐,PA4作为模拟输入通道
ADCSRA=0xe0;//1110 0011
}
/*void INT0_INT1 ()//中断寄存器的初始化
{
MCUCR=0x0a;//INT0和INT1中断触发方式,下降沿触发0000 1010
GICR=0xc0;//开启INT0和INT1的中断使能位
SREG=0x80;//开启全局中断
}*/
void Init_devices()
{
IO_Init();
Timer0_Init();
Timer2_Init();
ADC_Init();
//INT0_INT1();
}
uint ADC_Convert()
{
uint temp1,temp2;
//ADC_Init();
temp1=(uint)ADCL;
temp2=(uint)ADCH;
temp2=(temp2<<8)+temp1;//AD转换后的数字量所对应int型数,也就是整数
return (temp2);
}
uint conv (uint i)
{
long x;
uint y;
x=(10240*(long)i)/1023;
y=(uint)x;
return y;
}
/*I2C总线主机模式错误处理*/
void error(unsigned char type)
{
switch (type & 0xF8)
{
case 0x20: /*址址写失败*/
/*stop 停止*/
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); break;
case 0x30: /*数据写失败*/
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); break;
case 0x38: /*仲裁失败*/ break;
case 0x48: /*址址读失败*/
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); break;
}
}
/*I2C总线单字节写入*/
//这里是DA输出
unsigned char DA_write(unsigned char addr, unsigned char dd)
{
TWBR = 13; /*start 启动*/
// TWBR=(FOSC/baud-16)/2;
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if ((TWSR & 0xF8) != 0x08)
{
error(TWSR); return 0;
}
/*SLA_W 芯片地址0x90 1001 0000与芯片硬件有关*/
TWDR = 0x90; TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if ((TWSR & 0xF8) != 0x18)
{
error(TWSR);
return 0;
}
/*addr 操作地址 这里写控制字 0x40标示DA输出使能*/
TWDR = addr; TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if ((TWSR & 0xF8) != 0x28)
{
error(TWSR);
return 0;
}
/*dd 写入数据 写入需要显示的电压值 */
TWDR = dd;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
if ((TWSR & 0xF8) != 0x28)
{
error(TWSR);
return 0;
}
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
return 1;
}
void main ()
{
Init_devices();
while (1)
{
DA_write(0x40, temp);
if (cnt>5){
adc_val=ADC_Convert();
dis_val=conv(adc_val);
}
}
}
/*# pragma interrupt_handler int0:2 //INT0外部中断请求1的中断函数声明
int0 ()
{
temp++;
if (temp>=0x65)
{
temp=0x65;
}
}
# pragma interrupt_handler int1:3//INT1外部中断请求1的中断函数声明
int1 ()
{
temp--;
if ( temp>=0x65)
{
temp=0x00;
}
}*/
# pragma interrupt_handler Timer2:5
Timer2 ()
{
TCNT2=0x00;
cnt++;
PORTB=SEG[dis_val%10];//PB口先给第一位数码管的段选,给个位
PORTA&=~BIT(0);//给第一个数码管位选,让第一位数码管亮
delay(5);
PORTA|=BIT(0);
PORTB=SEG[dis_val/10%10];//再给PA口十位数的段选,给第二位数码管
PORTA&=~BIT(3);
delay(5);
PORTA|=BIT(3);
PORTB=SEG[dis_val/100%10];
PORTA&=~BIT(2);
delay(5);
PORTA|=BIT(2);
PORTB=SEG7[dis_val/1000%10];
PORTA&=~BIT(1);
delay(5);
PORTA|=BIT(1);
}
# pragma interrupt_handler Timer0: 10
Timer0 ()
{
uchar i;
//SREG=0x80;
TCNT0=0x83;
i=PIND;
delay(5);
cnt4++;
if (cnt4>5)
{
switch (i)
{
case 0xfb: //1111 1011
cnt4=0;
temp++;
if (temp>=0x65)
{
temp=0x65;
}
break;
case 0xf7: //1111 0111 1111 0111
cnt4=0;
temp--;
if ( temp>=0x65)
{
temp=0x00;
}
break;
default :
cnt4=0;;
}
}
}
我来回答