一、概述:
STC8H系列自带一组ADC转换器,传统的c51单片机需外挂AD芯片实现该功能,内置ADC不仅转换速度快,而且精度很高(12位),Stc8h系统最高可以达到每秒钟80万次的转换速度,相对来说已经是高效转换了。数据的转换结果有两种方式,一种是左对齐,另一种是右对齐,通过对内部寄存器的设置可以达到目的。
Stc8h系列单片机虽然内部只提供了一组ADC转换器,但同样可以实现多ADC转换功能,由于其内置了15个通道,理论上来说可能采用分时采集的方式,达到多ADC转换功能,同时内部提供1.19V基准电压,+VREF脚接MCUVCC,通过反推公式实现电源电压采集功能。
ADC的采集转换结果有两种方式可以实现,一种是通过查询标志位,另一种是中断方式,以下的实例,采集P10引脚的模拟电压值,当按下k1时采用查询方式通过串口2发送至PC接收,当按下K2时采用中断方式同样通中串口2将采集结果发送至PC接收。
二、知识链接:
1、ADC控制寄存器(ADC_CONTR):
其中ADC_POWER位置1时,使能ADC转换器电源。
ADC_START置1时,开始进入ADC转换
ADC_FLAG为ADC转换标志位,当ADC转换完成,硬件自动置1,必须软件方式清零后才能下一次采集。
ADC_CHS:采集通道转换,这里选择默认值0,为P10,而且P10必须为高阻状态。
2、ADC配置寄存器(ADCCFG):
其中RESFMT位,置1时,转换结果右对齐,置0时,转换结果左对齐,ADC_RES和ADC_RESL两个结果寄存器,左对齐则低4位置0,右对齐则高4位置0。下面的实例采用右对齐。
以上为转换时序图,读时序小结如下:
- 使能ADC_POWER=1。
- 开始转换ADC_START=1。
- 当ADC_FLAG=1时读数据,然后清零,准备下一次。
三、实验平台搭建:
1、MCU:STC-打狗棒系列核心实验板 V2.3
2、实验板平台:德飞莱LY-51s
3、硬件连接表:
电位器------>P10 模拟电压0-5V。
K1------>P20 查询方式采集ADC
K2------>P21 中断方式采集ADC
串口2----->PC 输出采集值
四、测试源代码:
#include <STC8H.h>
#include "intrins.h"
#include <stdio.h>
sbit Led1=P0^0;
sbit Led2=P0^1;
sbit Led3=P0^2;
sbit Led4=P0^3;
int Adc_value=0;
void Delay1ms(unsigned char x);//当主时钟频率为12M,1ms延时为基准
void init_IO();//初始化IO
void init_Uart2();//串口2初始化
void Uart2Send(char dat);//发送单字符
void init_ADC();//初始化ADC
int ADC_Start();//开始ADC转换
void ADC_StartIsr();//中断方式转换
void main()
{
int x=0;
P_SW2 |= 0x80; //扩展寄存器XFR访问使能
init_IO();
init_Uart2();
printf("STC8H ADC Test!");
init_ADC();
//ADC_Start();
while(1)
{
if(P20==0)//K0触发ADC
{
Delay1ms(20);
if(P20==0)
{
x=0;
x=ADC_Start();//开始转换
printf("ADC value=%d",x);
while(!P20);
}
}
if(P21==0)//K1触发ADC中断
{
Delay1ms(20);
if(P21==0)
{
ADC_StartIsr();
while(!P21);
}
}
}
}
void init_IO()
{
RSTCFG=0x50; //开启RST键进入ISP模式
P0M1 = 0x00; P0M0 = 0x00; //设置P0口为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置P0口为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置P1口为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置P3口为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置P4口为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置P5口为准双向口
}
void init_ADC()//初始化ADC
{
P1M1=0x01;P1M0=00;//配置P10为高阻模式
ADC_CONTR=0x00;
//ADCTIM=0x3f;
ADCCFG=0x20;//设置12位结果为右对齐
ADC_RES=0x00;
ADC_RESL=0x00;
ADC_CONTR|=0x80;//打开ADC_Power
EA=1;//开中总断
EADC=1;//开ADC中断
}
int ADC_Start()
{
int x=0;
ADC_CONTR|=0x40;//开启ADC_START
_nop_();
_nop_();
_nop_();
while(ADC_CONTR&0x20==0);
ADC_CONTR&=~0x20;//ADCFLAG=0;
x=ADC_RES*256; //高位值
x+=ADC_RESL; //低位值
return x;
}
void ADC_StartIsr()
{
ADC_CONTR&=~0x20;//ADCFLAG=0;
ADC_CONTR|=0x40;//开启ADC_START
}
void init_Uart2()//波特率11.0592
{
S2CON=0x10; //打开允许接收
T2L = 0xE8; //设置定时初始值
T2H = 0xFF; //设置定时初始值
AUXR|=0x04; //开启T2定时器1T工作模式
AUXR|=0x10; //开启T2定时器T2R=1
IE2|=0x01;//开启ES=1
P_SW2|=0x01;//串口2脚位切换,将串口2脚位切换到P46、P47,默认P10、P11
}
void Uart2Send(char dat)//u2发送单字符
{
S2BUF=dat;
while((S2CON & 2) == 0);
S2CON &= ~2; //Clear Tx flag
}
char putchar(char c)//重写printf
{
Uart2Send(c);
return c;
}
void Delay1ms(unsigned char x) //@12.000MHz
{
unsigned char i, j;
while(x--)
{
i = 16;
j = 147;
do
{
while (--j);
} while (--i);
}
}
void ADC_isr() interrupt 5 //中断方式
{
int Adc_value=0;
Led1=~Led1;
ADC_CONTR&=~0x20;//ADCFLAG=0;
Adc_value=ADC_RES*256; //高位值
Adc_value+=ADC_RESL; //低位值
ADC_RES=0x00;
ADC_RESL=0x00;
printf("ADC ISR value=%d",Adc_value); //打印输出
}