这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 【STCAi8051U】Ai8051U的ADC处理程序示例4(多次采集,取平均值

共4条 1/1 1 跳转至

【STCAi8051U】Ai8051U的ADC处理程序示例4(多次采集,取平均值)

专家
2025-08-16 14:19:34     打赏

Ai8051U的ADC功能中,包含了一个可以多次转换自动处理为平均值的功能,需要设置《ADC 扩展配置寄存器(ADCEXCFG)》,可以选择的次数:

图片1.png

下面我们就以中断例程为基础,略作修改,设置8次方式工作。

在启动转换处理之前,设置这个参数:

ADCEXCFG = (ADCEXCFG & 0x0F) | 0x06;


整体代码如下:


//测试工作频率为 11.0592MHz
// 测试使用Timer2作为串口1的波特率发生器
// 串口1:P3.6(RXD),P3.7(TXD)
#include "Ai8051U.H" 
#include "intrins.h"
#include "stdio.h"
typedef unsigned char   u8;     //  8 bits 
typedef unsigned int    u16;    // 16 bits 
typedef unsigned long   u32;    // 32 bits 
#define FOSC 11059200UL //定义为无符号长整型,避免计算溢出
#define BRT (65536 - (FOSC / 115200+2) / 4)   //加 2 操作是为了让 Keil 编译器,自动实现四舍五入运算
bit busy1;
char wptr1;
char rptr1;
char buffer1[64];
// 初始化定时器2
void Timer2Init(void) {
    T2L = BRT;
    T2H = BRT >> 8;
    S1BRT = 1;  // S1BRT:串口 1 波特率发生器选择位, 0:选择定时器 1 作为波特率发生器, 1:选择定时器 2 作为波特率发生器(默认值)
    T2x12 = 1;
    T2R = 1;    
}
// 串口1
//---------------------------------------------------------------
// 串口1的中断处理
void Uart1Isr() interrupt 4 {
    if (TI) {
        TI = 0;
        busy1 = 0;
    }
    if (RI) {
        RI = 0;
        buffer1[wptr1++] = SBUF;
        wptr1 &= 0x0f;
    }
}
// 初始化串口1
void Uart1Init() {
    SCON = 0x50;  //
    wptr1 = 0x00;
    rptr1 = 0x00;
    busy1 = 0;
    
    P_SW1 |= 0x40;   // 选择P3.6,P3.7,因为擎天柱开发板上不提供P3.0,P3.1引脚
}
// 向串口1输出一个字符
void Uart1Send(char dat) {
    while (busy1);
    busy1 = 1;
    SBUF = dat;
}
// 向串口1输出一个字符串
void Uart1SendStr(char *p) {
    while (*p) {
        Uart1Send(*p++);
    }
}
// 初始化ADC
void AdcInit(void) {
    // 设置ADC, P1.0:高阻输入
    P1M0 = 0x00; //设置 P1.0 为 ADC 口
    P1M1 = 0x01;
    ADCTIM = 0x3f; //设置 通道选择时间、保持时间、采样时间
    ADCCFG = 0x2f; //设置 ADC 时钟为系统时钟/2/16/16; 转换结果右对齐
    ADC_POWER = 1; //使能 ADC 模块
    
}
// 延时
void delay_ms(u16 ms) {
    u16 i;
    do {
        i = FOSC/3000;
        while(--i);
    } while(--ms);
}
//========================================================================
// 函数: u16 Get_ADC12bitResult(u8 channel))//channel = 0~15
// 描述: 查询法读一次ADC结果.
// 参数: channel: 选择要转换的ADC, 0~15.
// 返回: 12位ADC结果.
// 版本: V1.0, 2016-4-28
//========================================================================
u16Get_ADC12bitResult(u8 channel) {
    
ADC_RES = 0;
ADC_RESL = 0;
    ADC_CONTR = (ADC_CONTR & 0xf0) | channel; //设置ADC转换通道
    
    ADC_START = 1;   // 启动ADC转换
    
    _nop_();
    _nop_();
    _nop_();
    while (!ADC_FLAG); //查询 ADC 完成标志
    ADC_FLAG = 0;
    
    return (((u16)ADC_RES << 8) | ADC_RESL);
}
/***********************************
查询方式做一次ADC, chn为通道号, chn=0~7对应P1.0~P1.7, chn=8~14对应P0.0~P0.6, chn=15对应BandGap电压.
***********************************/
u16 ADC_convert(u8 chn) {
u16val;
Get_ADC12bitResult(chn);//参数i=0~15,查询方式做一次ADC, 切换通道后第一次转换结果丢弃. 避免采样电容的残存电压影响.
    Get_ADC12bitResult(chn);//参数i=0~15,查询方式做一次ADC, 切换通道后第二次转换结果丢弃. 避免采样电容的残存电压影响.
    val = Get_ADC12bitResult(chn);
    return val;
}
u16 adc_val = 0;
bit adc_ok_flag = 0;
void ADC_Isr() interrupt 5  {
    ADC_FLAG = 0; //清中断标志
    adc_val = ((u16)ADC_RES << 8) | ADC_RESL;
    
    adc_ok_flag = 1;     // ADC完成标志
    
    ADC_START = 1; //继续 AD 转换
}
void main() {
    unsigned int val = 0;               // ADC转换值
    float v1=0.0;                // 电压值
    unsigned char str[32]={0};
    
    EAXFR = 1; //允许访问扩展的特殊寄存器,XFR
    //(32 位模式请使用这句,注释下一句)
    // P_SW2 |= 0x80; //允许访问扩展的特殊寄存器,XFR
    //(8 位模式请使用这句,注释上一句)
    WTST = 0; //设置取程序代码等待时间,
    //赋值为 0 表示不等待,程序以最快速度运行
    CKCON = 0; //设置访问片内的 xdata 速度,
    
    //赋值为 0 表示用最快速度访问,不增加额外的等待时间
    P0M0 = 0x00;    P0M1 = 0x00;
    P1M0 = 0x00;    P1M1 = 0x00;
    P2M0 = 0x00;    P2M1 = 0x00;
    P3M0 = 0x00;    P3M1 = 0x00;
    P4M0 = 0x00;    P4M1 = 0x00;
    P5M0 = 0x00;    P5M1 = 0x00;
    
    Timer2Init();
    
    Uart1Init();
 
    AdcInit();
    
    delay_ms(10);
    
    ES = 1;
    EADC = 1; //使能 ADC 中断
    
    EA = 1;
    
    Uart1SendStr("Start Test !\r\n");
    
    ADC_CONTR = (ADC_CONTR & 0xf0);        // 设置ADC转换通道为第0通道,P1.0
    //ADC_CONTR = (ADC_CONTR & 0xf0) | 15; //设置ADC转换通道为第15通道,1.19V
    
    ADCEXCFG = (ADCEXCFG & 0x0F) | 0x06;
    
    ADC_START = 1; //继续 AD 转换
    
    while (1) {
        if (adc_ok_flag) {
            val = adc_val;
            sprintf(str, "ADC Val = %d ", val);
            Uart1SendStr(str);
            
            v1 = (float)5 * val / 4096;
            sprintf(str, ", Input Vol = %f \r\n", v1);
            Uart1SendStr(str);
            delay_ms(500);        
        }
    }
}



测量效果:

图片2.png

可以看到,一致性确实变得更好了。





关键词: 菜鸟学单片机     Ai8051U     ADC示例    

专家
2025-08-16 16:06:08     打赏
2楼

感谢分享


专家
2025-08-16 16:09:41     打赏
3楼

感谢分享


专家
2025-08-16 16:22:23     打赏
4楼

感谢分享


共4条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]