单片机实验五:模拟接口实验

-
-
2025-11-28

一、实验目的

1、掌握A/D转换与单片机的接口方法;

2、掌握STC15系列单片机内部A/D转换器和实验板上的ADC与DAC编程方法;

3、掌握数据采集程序的设计方法;

二、实验内容

1、在PROTEUS软件仿真环境下,采用STC15系列单片机内部A/D转换器对电位器提供的模拟电压信号进行定时采样,结果送数码管模块显示;(仿真电路图如图5.1所示)

2、在PROTEUS软件仿真环境下,采用TLC5615做D/A转换器产生0-5V电压,输出电压在数码管显示,通过4个按键进行修改;(仿真电路图如图5.2所示)

3、在PROTEUS软件仿真环境下,用电位器产生0-5V电压,用MCP3201做A/D转换器读取电压,结果送数码管显示;(仿真电路图如图5.3所示)

三、实验线路

实验电路原理图如5.1图所示,所需元件为:STC15W4K32S4、7SEG-MPX4CC、MCP3201、TLC5615、POT-HG。

四、相关文件

任务一:片内 A/D 采集与显示

  • 功能:使用 STC15 内部 ADC (P1.7) 采集电位器电压,计算后在数码管显示(格式:X.XX V)。
  • 仿真图
  • main.c 代码
#define MAIN_Fosc 24000000L
#include "STC15Fxxxx.H"
#define ADC_RES ADC_RESH
// 注意:SEG4.H 中定义了 S1-S4 在 P3.2-P3.5,SEG 在 P0
#include "SEG4.H" 
#include "ADC.H"

// 变量定义
u16 adc_value = 0;
u16 voltage = 0; // 单位:0.01V

// 定时器0初始化 (1ms @ 24MHz) - 用于数码管刷新
void Timer0_Init(void)
{
    AUXR |= 0x80;   // 定时器时钟1T模式
    TMOD &= 0xF0;   // 设置定时器模式
    TL0 = 0x40;     // 设置定时初始值 (24MHz, 1ms)
    TH0 = 0xA2;     // 设置定时初始值
    TF0 = 0;        // 清除TF0标志
    TR0 = 1;        // 定时器0开始计时
    ET0 = 1;        // 开启定时器中断
    EA = 1;         // 开启总中断
}

// 定时器中断服务函数 - 刷新数码管
void Timer0_Routine(void) interrupt 1
{
    SEGDIS(); // 调用 SEG4.H 中的刷新函数
}

// 数据处理与显示缓冲更新
void Update_Display(u16 vol)
{
    // vol 范围 0 - 500 (对应 0.00V - 5.00V)
    u8 d0, d1, d2;
    
    d0 = vol / 100;         // 整数位 (个位)
    d1 = (vol % 100) / 10;  // 小数第一位
    d2 = vol % 10;          // 小数第二位
    
    DIS[0] = disptab[d0] | 0x80; // 个位 + 小数点
    DIS[1] = disptab[d1];
    DIS[2] = disptab[d2];
    DIS[3] = 0x00;               // 第四位关闭
}

void main()
{
    // 端口模式配置 (建议配置为推挽或准双向,此处沿用默认)
    P0M0 = 0x00; P0M1 = 0x00;
    P3M0 = 0x00; P3M1 = 0x00;
    
    // 初始化外设
    Timer0_Init();
    ADC_init(0x80); // 初始化ADC,参数0x80对应 P1.7 (ADC7) 通道 [cite: 12]

    while(1)
    {
        // 1. 获取ADC值 (10位精度 0-1023)
        // 传入参数7表示通道7 (P1.7)
        adc_value = ADC_Convert(7); 
        
        // 2. 转换为电压 (单位 0.01V)
        // 计算公式:Voltage = (ADC * 500) / 1024
        // 使用 long 强制转换防止乘法溢出
        voltage = ((unsigned long)adc_value * 500) / 1024;
        
        // 3. 更新显示
        Update_Display(voltage);
        
        delay_ms(100); // 延时,避免数字跳变过快
    }
}

任务二:TLC5615 D/A 输出与按键控制

  • 功能:通过按键调节数字量,驱动 TLC5615 输出 0-5V,并显示设定电压。
  • 硬件连接
    • CS: P1.4
    • CLK: P1.5
    • DIN: P1.6
    • 按键: K1-K4 (P2.0-P2.3)
  • 仿真图
  • main.c 代码
#define MAIN_Fosc 24000000L
#include "STC15Fxxxx.H"
#include "SEG4.H"
#define ADC_RES ADC_RESH
// --- TLC5615 引脚定义 (必须在include TLC5615.H之前) ---
sbit CS  = P1^4;  // 根据仿真图 5-2 定义
sbit CLK = P1^5;
sbit DAT = P1^6;  // DIN
//sbit CY  = PSW^7; // TLC5615.H 中用到了 CY
#include "TLC5615.H"

// --- 按键定义 ---
#include "KEY.H"

// 变量定义
u16 dac_code = 0;   // 发送给DAC的数值 (0-1023)
u16 voltage = 0;    // 计算出的显示电压

void Timer0_Init(void) // 1ms
{
    AUXR |= 0x80; TMOD &= 0xF0; TL0 = 0x40; TH0 = 0xA2;
    TF0 = 0; TR0 = 1; ET0 = 1; EA = 1;
}

void Timer0_Routine(void) interrupt 1
{
    SEGDIS();
}

void Update_Display(u16 vol)
{
    u8 d0, d1, d2;
    d0 = vol / 100;
    d1 = (vol % 100) / 10;
    d2 = vol % 10;
    DIS[0] = disptab[d0] | 0x80;
    DIS[1] = disptab[d1];
    DIS[2] = disptab[d2];
    DIS[3] = 0x00; 
}

void main()
{
    u8 key_val;
    
    Timer0_Init();
    dac_code = 512; // 初始输出 2.5V (1024的一半)

    while(1)
    {
        key_val = GetKey();
        
        // 按键处理 
        if(key_val == 1) // K1: 增加
        {
            if(dac_code < 1023) dac_code += 10; // 步进10
            if(dac_code > 1023) dac_code = 1023;
        }
        if(key_val == 2) // K2: 减少
        {
            if(dac_code >= 10) dac_code -= 10;
            else dac_code = 0;
        }
        if(key_val == 3) dac_code = 1023; // K3: 最大 (5V)
        if(key_val == 4) dac_code = 0;    // K4: 最小 (0V)

        // 执行 DA 转换
        TLC5615(dac_code);

        // 计算理论电压显示
        voltage = ((unsigned long)dac_code * 500) / 1024;
        Update_Display(voltage);
        
        delay_ms(20); // 按键消抖延时
    }
}

任务三:MCP3201 外部 A/D 采集

  • 功能:使用 MCP3201 (12位 ADC) 采集外部电位器电压。
  • 硬件连接
    • CS: P1.4
    • CLK: P1.5
    • DOUT: P1.6 (注意:这里 MCU 是读取,所以 P1.6 是输入)
  • 仿真图
  • main.c 代码
#define MAIN_Fosc 24000000L
#include "STC15Fxxxx.H"
#include "SEG4.H"

// --- MCP3201 引脚定义 ---
// 根据仿真图 5-3 
sbit CS  = P1^4;
sbit CLK = P1^5;
sbit DAT = P1^6; // DOUT 接 MCU P1.6
#include "MCP3201.H"

u16 adc_res = 0;
u16 voltage = 0;

void Timer0_Init(void) // 1ms
{
    AUXR |= 0x80; TMOD &= 0xF0; TL0 = 0x40; TH0 = 0xA2;
    TF0 = 0; TR0 = 1; ET0 = 1; EA = 1;
}

void Timer0_Routine(void) interrupt 1
{
    SEGDIS();
}

void Update_Display(u16 vol)
{
    u8 d0, d1, d2;
    d0 = vol / 100;
    d1 = (vol % 100) / 10;
    d2 = vol % 10;
    DIS[0] = disptab[d0] | 0x80;
    DIS[1] = disptab[d1];
    DIS[2] = disptab[d2];
    DIS[3] = 0x00; 
}

void main()
{
    // 配置 IO 口
    // P1.6 (DAT) 必须配置为输入模式,或者准双向口并置1
    // MCP3201.H 中的时序是模拟SPI,直接操作IO
    
    Timer0_Init();

    while(1)
    {
        // 1. 读取 MCP3201 (12位精度 0-4095)
        adc_res = MCP3201();
        
        // 2. 计算电压
        // 12位ADC,基准电压5V
        // Voltage = (Data * 500) / 4096
        voltage = ((unsigned long)adc_res * 500) / 4096;
        
        // 3. 显示
        Update_Display(voltage);
        
        delay_ms(100);
    }
}

 

“您的支持是我持续分享的动力”

微信收款码
微信
支付宝收款码
支付宝

目录