今天做一个AD采样DA还原程序的程序。用正选波输入DAC0输出。刚开始用 DAC0 = ADC0;直接将采样输出。结果输出波形隔一小段就有一个小跳变。开始以为是内部基准电压不稳定造成。遂换成外部基准电压,但是问题依旧。后经细致研究发现DAC0=ADC0的输出方式是先DAC0H=ADC0H,再DAC0L=ADC0L;这也问题就来了。因为C8051F在定义为sfr16 DAC0的时候就会先付高位值在付低位值。而C8051F是在付完高位值即更新DAC输出数据。所以就会造成高地位错位。但是将其改为 result = ADC0; //数据转存
DAC0L=result&0x00ff;
DAC0H=result/256;
这样子即下面代码中的红色位置即可保证16位数据正确输出,经测试输出正常。
//************************************************************
// AD采样DA还原程序
//
// (1)使用C8051F005芯片
// (2)内部晶振16MHZ ,外部参考电压2.425
// (2)单端输入ANIO,用定时器3启动AD转换
//*************************************************************
#include <C8051F000.h>
#include <stdio.h>
#include <intrins.h>
sfr16 TMR3RL = 0x92; //定时器 3 重载寄存器
sfr16 TMR3 = 0x94; //定时器 3 寄存器
sfr16 ADC0 = 0xbe; //ADC0寄存器
sfr16 ADC0GT = 0xc4; //ADC下限数据寄存器
sfr16 ADC0LT = 0xc6; //ADC上限数据寄存器
sfr16 DP = 0x82; // 数据指针
sfr16 RCAP2 = 0xca; // 定时器2捕捉寄存器
sfr16 T2 = 0xcc; // 定时器 2
sfr16 DAC0 = 0xd2; // DAC0 数据
#define SYSCLK 16000000 //系统时钟 频率
#define SAMPLE_RATE 50000
//#define VREF 2.425 //参考电压值
void ADC0_Init (void); //AD转换初始化设置函数
void Timer3_Init (int counts); //定时3初始化设置函数
void ADC0_ISR (void); //AD转换中断函数
void delay (int t); //延时程序
//void SYSCLK_Init (void); //系统时钟函数
void WDT_CLOSE(void); //关闭看门狗
int result; //数据存储
char flag; //标志
unsigned char k;
//***********************************************************
//关闭看门狗
//***********************************************************
void WDT_CLOSE(void)
{ EA="0";
WDTCN = 0xde;
WDTCN = 0xad;
EA="1";
}
//***********************************************************
//系统时钟设置
//晶振振荡方式,F>6.7MHz
//选用外部时钟
//允许时钟复位
//************************************************************
//void SYSCLK_Init (void)
//{ int i;
// OSCXCN = 0x67;
// for (i=0; i < 256; i++) ;
// while (!(OSCXCN & 0x80)) ; //等待外部准备
// OSCICN = 0x88;
// }
//***********************************************************
// 定时器3 初始化设置
// 1 系统时钟
//************************************************************
void Timer3_Init (int counts)
{
TMR3CN = 0x02; //计数器/定时器3使用系统时钟
TMR3RL =-counts;
TMR3 = 0xffff;
EIE2 &= ~0x01; //T3中断允许关(扩展中断允许, 允许定时器3中断)
TMR3CN |= 0x04; //定时器3开
}
//**********************************************************
//AD初始化设置
//AIN0 独立输入
//使用内部参考电压, PGA= 2,使用4系统时钟
//转换数据右对齐
//**********************************************************
void ADC0_Init (void)
{
ADC0CN = 0x44; //右对齐
//REF0CN = 0x03; //使用内部参考电压
REF0CN = 0x02; //使用外部参考电压
AMX0SL = 0x00; //AIN0 独立输入
AMX0CF = 0x00;
ADC0CF = 0x60; // 8系统时钟
ADC0CF|= 0x00; // PGA 增益 1
EIE2 |= 0x02; // ADC0转换结束中断开
}
//**********************************************
//AD转换程序
//**********************************************
void ADC0_ISR (void) interrupt 15
{
TMR3CN &=0x20; //关定时器3 清除标准位
ADCINT = 0x00; //清除中断标准位
//delay (10); //延时等待AD转换稳定
result = ADC0; //数据转存
DAC0L=result&0x00ff;
DAC0H=result/256;
// DAC0 = ADC0;
// _nop_();
TMR3CN |= 0x04; //定时器3开
flag = 1;
}
//***********************************************
//延时子程序
//***********************************************
void delay (int t)
{ int i,j;
for (i=0;i<t;i++)
for(j=0;j<10;j++) ;
}
//***********************************************
//端口设置
//***********************************************
//void Port_Init (void)
//{
// XBR2 = 0x40; // 若上拉使能
// PRT0CF |= 0xff; //P0口使能
//}
//******************************************
//MAIN
//******************************************
void main (void)
{
floAT voltage="0";
WDT_CLOSE(); //关闭看门狗
OSCICN = 0x97; //内部振荡器典型频率为16MHz
// SYSCLK_Init ( ); //系统时钟设置
//Port_Init (); //IO口输出使能设置
Timer3_Init (15);//SYSCLK/SAMPLE_RATE); //定时器3初始化设置
ADC0_Init (); //AD初始化
ADCEN = 1; //AD转换允许打开
DAC0CN = 0x80; // DAC0控制寄存器,DAC0使能;DAC0数据字的高4位在DAC0H[3:0],低字节在DAC0L中
EA = 1;
flag = 0;
while (1) //循环
{
while (flag == 1)
{ flag = 0;
//DAC0=result;
}
}
}
本文来源于大道无极 http://www.dadwj.cn/ , 原文地址:http://www.dadwj.cn/post/492.html
文章评论(0条评论)
登录后参与讨论