我手头有两只pic16f883,不想报废,于是参考别人代码编写了2路A/D转换程序,采用Proteus仿真误差很大,明明是5V参考电压,结果显示8V多,不知哪里出问题了?时钟从1MHZ~20MHZ都是一样的结果,不知是Proteus仿真软件的bug还是代码有问题,请大侠帮忙// 名称: 数码管显示两路A/D转换结果
//-----------------------------------------------------------------
// 说明: 调节RV1和RV2时,两路模拟电压将显示在集成式数码管上.
//
//-----------------------------------------------------------------
#include <pic.h>
__CONFIG(0x2004); //?????? //配置字要在头文件后 PROTEUS仿真也要有 改为__CONFIG(0x2002); 也不行
//bit13=1禁止在线调试 bit12=0关系RB3数字口 bit11=0禁止故障保护时钟监视器 bit10 =0禁止内外时钟切换
//bit9/8=00禁止欠压复位 bit7=0使能RAM保护 bit6=0使能ROM bit5=0内部复位RB3为数字引脚
//bit4=0使能上电延时定时器 bit3=0禁止看门狗 bit2:0=100INTOSCO振荡,RA6/7为I/O口 手册14.1配置位
#define INT8U unsigned char
#define INT16U unsigned int
#define _XTAL_FREQ 4000000UL
//共阳数码管0~9的数字段码,最后一位为黑屏
const INT8U SEG_CODE[] =
{0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF};
//两路模拟转换结果显示缓冲,显示格式为:X.XX X.XX ,第4位和第8位不显示
volatile INT8U Display_Buffer[] = {0,0,0,10,0,0,0,10};
//1.108ms @1MHZ
void delay_xms(INT16U ms)
{
INT8U i;
while(ms--)
for(i = 0; i < 20; i++);
}
//-----------------------------------------------------------------
// 对通道Channel进行模数转换,转换结果分解存入显示缓冲
//-----------------------------------------------------------------
void ADC_Convert(INT8U Channel)
{
//设置ADCON0寄存器的通道选择位CHS[3..0]=Channel(0~13)
//选择通道后等待
CHS3 = Channel >> 3;
CHS2 = Channel >> 2;
CHS1 = Channel >> 1;
CHS0 = Channel >> 0;
//__delay_us(1); //选择通道后等待
delay_xms(10);
//开始转换--->等待,直到一次转换结束(ADGO还可替换成GO_DONE)
//GO_DONE = 1; while(GO_DONE);
//ADGO = 1; while(ADGO); //PIC16F877的写法
GODONE = 1;while(GODONE);
//读取转换结果,并转换为电压值
//参考电压5v,所以转换结果*500/1023.0,使结果在000~500间
int Result = ( int) ((ADRESL + (ADRESH << 8)) * 500.0 / 1023.0);
//AN0的结果放入数组0,1,2单元中,AN1的结果放入数组4,5,6单元中
if (0 == Channel) //通道0的在左面3个数码管显示
{
Display_Buffer[0] = Result / 100;
Display_Buffer[1] = Result / 10 % 10;
Display_Buffer[2] = Result % 10;
}
else if (1 == Channel) //通道1的在4、5、6数码管显示
{
Display_Buffer[4] = Result / 100;
Display_Buffer[5] = Result / 10 % 10;
Display_Buffer[6] = Result % 10;
}
}
//-----------------------------------------------------------------
// 主程序
//-----------------------------------------------------------------
void main()
{
//SCS= 1; //内部时钟,OSCCON配置 手册P64,
//0=时钟由配置字1的FOSC2:0决定,1=时钟由IRCF2:0决定
//IRCF2=1;IRCF1=1;IRCF0=0; //内部4MHZ,OSCCON配置 手册P64
//OSTS = 0; //器件依靠内部内部时钟运行,OSCCON配置 手册P64
//1=时钟靠时钟配置字1的FOSC2:0决定,手册P71
TRISB = TRISC = 0x00; //配置数码管输出端口
PORTB = PORTC = 0x00;
//以下配置用于TMR0定时器刷新数码管显示
PSA = 0; //前分频给TMR0
PS2 = 0; PS1 = PS0 = 1; //16分频(OPTION低3位为011)
TMR0 = (INT8U)(256 - _XTAL_FREQ / 4 / 16 * 0.002); //2ms定时
T0IF = 0; //清TMR0中断标志
T0CS = 0; //TMR0工作于定时器
T0IE = 1; //允许TMR0溢出中断
GIE = 1; //开全局中断
//PEIE = 1;
TRISA0 = 1; TRISA1 = 1; //AN0/AN1输入口
ANS0=1; ANS1=1; //AN0/AN1模拟输入
ADCS1 = 1; ADCS0 =0; //设置AD转换时钟为F_OSC/32
VCFG1=0;VCFG0=0; //以电源脚VDD\VSS为参考电压
//VRSS = 0;VROE =0; //VRCON寄存器的bit6/4 手册P98
ADFM = 1; //转换结果右对齐
ADON = 1; //打开A/D转换模块
//__delay_ms(1700);
delay_xms(3000); //等待AD模块稳定
while(1) //AN0,1通道开始持续A/D转换
{
ADC_Convert(0);delay_xms(10);//__delay_ms(5);
ADC_Convert(1);delay_xms(10);//__delay_ms(5);
}
}
//-----------------------------------------------------------------
// TMR0定时器溢出中断控制数码管刷新显示两路A/D转换结果
//-----------------------------------------------------------------
void interrupt TMR0_ISR(void )
{
static INT8U i = 0;
if (T0IF&&T0IE)
{
//PORTB = 0xff;
PORTC = 0x00; //暂时关闭位码
PORTB = SEG_CODE[Display_Buffer[i]]; //发送数字段码
PORTC = 1 << i; //发送数码管位码
if(i== 0 || i == 4) RB7 = 0; //点亮小数点
i = (i + 1) & 0x07; //下一位数字索引
TMR0 = (INT8U)(256 - _XTAL_FREQ / 4 / 16 * 0.002);//位间延时间隔2ms
T0IF = 0; //清TMR0中断标志
}
}
|
|