打印
[通用8051核FLASH系列]

PWM 和 ADC 模块实现 PWM 匹配中断触发 ADC 转换 的功能

[复制链接]
29|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xinpian101|  楼主 | 2025-2-27 10:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1. 代码功能概述
PWM 模块:配置 PWM0 和 PWM01 输出,设置周期和占空比,并通过 PWM 匹配中断触发 ADC 转换。
ADC 模块:配置 ADC 模块,使用外部通道 1(P11 引脚)采集模拟信号,并将转换结果存储在变量 gui_AdcValue 中。

中断服务函数:

PWM 中断:在 PWM 匹配时触发,翻转 P0_0 引脚状态。
ADC 中断:在 ADC 转换完成后触发,翻转 P0_1 引脚状态,并清除 ADC 中断标志。

系统初始化
WDTCCR = 0x00;  // 关闭看门狗
CLKCON = 0x02;  // 选择内部高频 RC 为系统时钟,Fosc = 32MHz
CLKDIV = 0x02;  // Fosc 2 分频得到 Fcpu,Fcpu = 16MHz
IO 配置初始化
P0M0 = 0x88;  // P00、P01 设置为推挽输出
P2M1 = P2M1 & 0xF0 | 0x08;  // P22 设置为推挽输出
P1M0 = P1M0 & 0xF0 | 0x08;  // P10 设置为推挽输出
PWM 配置初始化
PWM0_MAP = 0x12;  // PWM0 通道映射到 P22 口
PWM01_MAP = 0x08; // PWM01 通道映射到 P10 口

PWMCON0 = 0x04;   // 边沿对齐,12 位 PWM 计数
PWMCON1 = 0x30;   // PWM0 计数器匹配中断使能,不移相
PWMCON3 = 0x01;   // 独立模式
PWM0C = 0x80;     // 允许 PWM0 中断,PWM0 和 PWM01 高有效,Fosc 时钟 2 分频

PWM0PH = 0x03;    // 周期高 4 位
PWM0PL = 0xFF;    // 周期低 8 位
PWM0DH = 0x02;    // PWM0 高 4 位占空比
PWM0DL = 0x00;    // PWM0 低 8 位占空比
PWM0DTH = 0x02;   // PWM01 高 4 位占空比
PWM0DTL = 0x00;   // PWM01 低 8 位占空比

PWM0INTDIV = 0x10; // PWM0 匹配中断分频
PWMEN = 0x11;      // 使能 PWM0 和 PWM01 输出
PWM 周期和占空比计算:

周期 = 0x03FF / (Fosc / PWM 分频系数) = 1023 / (32MHz / 2) ≈ 63.93μs。
占空比 = 0x0200 / (Fosc / PWM 分频系数) = 512 / (32MHz / 2) ≈ 21.31μs,占空比为 33.3%。
PWM0_MAP 和 PWM01_MAP:将 PWM0 和 PWM01 输出映射到 P22 和 P10 引脚。
PWMCON0 和 PWMCON1:配置 PWM 的工作模式和中断使能。
PWMEN:使能 PWM0 和 PWM01 输出。

ADC 配置初始化
P1M0 = P1M0 & 0x0F | 0x30;  // P11 设置为模拟输入
ADCC0 = 0xC3;               // 启动 ADC 电源,内部参考电压 2V
Delay_2us(10);              // 延时 20us,确保 ADC 系统稳定
ADCC1 = 0x01;               // 选择外部通道 1(P11)
ADCC2 = 0x4B;               // 转换结果 12 位数据,数据右对齐,ADC 时钟 8 分频
ADCC3 = 0x0D;               // PWM0 匹配中断触发 ADC 转换

ADCDLYH = 0x00;
ADCDLYL = 0x01;

IP3 = 0x30;  // ADC 优先级为 3
EADC = 1;    // 打开 ADC 中断
EA = 1;      // 打开总中断
P1M0:配置 P11 为模拟输入模式,用于 ADC 采样。
ADCC0:启动 ADC 电源,选择内部参考电压 2V。
ADCC1:选择外部通道 1(P11)作为 ADC 输入。
ADCC2:配置 ADC 转换结果为 12 位,数据右对齐,ADC 时钟 8 分频。
ADCC3:配置 PWM0 匹配中断触发 ADC 转换。
EADC 和 EA:使能 ADC 中断和全局中断。


ADC 中断服务函数:
void ADC_Rpr() interrupt ADC_VECTOR {
    if (ADCC0 & 0x20) {  // 检查 ADC 中断标志
        P0_1 = ~P0_1;    // 翻转 P0_1 引脚状态
        ADCC0 &= ~0x20;  // 清除 ADC 中断标志
    }
}
当 ADC 转换完成时,触发中断,翻转 P0_1 引脚状态,并清除中断标志。
PWM 中断服务函数:
void PWM_Rpt() interrupt PWM_VECTOR {
    if (PWMCON1 & 0x40) {  // 检查 PWM 中断标志
        PWMCON1 &= ~0x40;  // 清除 PWM 中断标志
        P0_0 = ~P0_0;      // 翻转 P0_0 引脚状态
    }
}
当 PWM 匹配时,触发中断,翻转 P0_0 引脚状态,并清除中断标志。
void Delay_2us(unsigned int fui_i) {
    while (fui_i--);
}



使用特权

评论回复
沙发
xinpian101|  楼主 | 2025-2-27 10:48 | 只看该作者
应用注意事项
ADC 时钟频率:建议 ADC 时钟频率不超过 2MHz,以保证转换精度。

内部参考电压:选择 2V 参考电压时,VDD 工作电压须高于 2.7V。

ADC 启动延时:使能 ADC 模块或切换通道后,建议延时 20μs 再启动转换。

PWM 触发 ADC:PWM 中点触发仅适用于中心对齐模式的 PWM 输出。

使用特权

评论回复
板凳
xinpian101|  楼主 | 2025-2-27 10:48 | 只看该作者
完整代码如下:
/**
*   ************************************************************************************
*                                                                上海芯圣电子股份有限公司
*                                                                    www.holychip.cn
*        ************************************************************************************
*        @Examle Version                V1.0.0.5
*        @Date                                2023.04.07
*        ************************************************************************************
*                                                                         模块性能介绍
*        1、HC89S105AC8提供10/12位ADC检测,拥有32路外部输入通道以及2路内部输入通道
*        2、参考电压可选择内部Vref(VDD、2V、3V、4V)以及外部Vref,转换后的数据可选择数
*           据位数和对齐方向
*        3、ADC 模拟看门狗功能,被 ADC 转换的模拟电压与高、低阈值比较寄存器的值比较
*        4、可由外部触发信号启动 ADC 转换,并带有触发延时计时器
*        5、提供 ADC 连续转换,并可设置连续转换的时间间隔
*        ************************************************************************************
*                                                                         应用注意事项
*        1、在掉电模式下,ADCEN强制为0,ADC失能。
*        2、为保证ADC转换精度,建议ADC转换时钟频率在2MHz及2MHz以下。
*        3、内部参考电压选择2V时,VDD工作电压须高于2.7V。内部参考电压选择3V/4V时,VDD工作电
*           压须高于内部参考电压0.5V以上。
*        4、使能ADC模块或者切换通道后,为保证精度建议延时20us再启动转换。
*        5、启动转换时,ADCIF需要先软件清0,ADCIF位为1时,置ADCST不能启动新的转换。在转换过
*           程中,若ADCST位软件清0将终止转换。
*        6、在进行内部通道选择时,外部通道选择XCHS[3:0]应配置为1111,否则可能会造成内部通道
*           和外部通道同时打开的情况。
*        7、选择内部参考电压 2/3/4V时,相应的 ADC 时钟需要配置ADCTS [2:0]设置一次转换需要
*           的 ADC_CLK 个数。如果选择 VDD 作参考电压,无论 ADC 时钟为多少,都可以选择 15 个
*           ADC_CLK。
*        8、PWM 中点触发仅适用于中心对齐模式的 PWM 输出。
*        9、当 ADCST 为 1 时(正在转换),外部触发信号不会影响 ADC 直到本次 ADC 转换结束即
*           ADCST 被硬件清 0。
*        ************************************************************************************
*                                                                         客户服务
*        感谢您使用我们的单片机,若发现错误或对函数的使用存在疑问。请添加上海芯圣电子官方QQ群
*        ****************************技术支持群:201030494***********************************
*   **************************************************************************************/
#define        ALLOCATE_EXTERN
#include "HC89S105AC8.h"

void Delay_2us(unsigned int fui_i);          //延时函数
unsigned int gui_AdcValue = 0;                                 //存放当前获取的ADC的值

/***************************************************************************************
  * @实现效果        PWM匹配中断触发ADC
  * @操作方法   P11端口接1V电压,P01,P00翻转
***************************************************************************************/
void main(void)
{
/************************************系统初始化****************************************/
        WDTCCR = 0x00;                           //关闭看门狗
                                                           //本例程为方便测试关闭看门狗,实际使用中,建议客户打开看门狗,详见WDT复位例程
        CLKCON = 0x02;                           //选择内部高频RC为系统时钟,Fosc=32MHz
        CLKDIV = 0x02;                           //Fosc 2分频得到Fcpu,Fcpu=16MHz
                                 
/**********************************IO配置初始化**************************************/
        P0M0 = 0x88;   //P00、P01设置为推挽输出       

/**********************************PWM 配置初始化**************************************/
        P2M1 = P2M1 & 0xF0 | 0x08; //P22设置为推挽输出
        P1M0 = P1M0 & 0xF0 | 0x08; //P10设置为推挽输出

        PWM0_MAP = 0x12;  //PWM0通道映射P22口
        PWM01_MAP = 0x08; //PWM01通道映射P10口

        PWMCON0 = 0X04;     //边沿对齐,12位PWM计数
        PWMCON1 = 0X30;     //PWM0 计数器匹配中断使能,不移相
        PWMCON3 = 0x01;     //独立模式
        PWM0C = 0x80;       //允许 PWM0 中断 PWM0 PWM01高有效,Fosc时钟2分频

        //独立模式下,PWM0和PWM01共用一个周期寄存器
        //PWM0的占空比调节使用                        PWM0组的占空比寄存器
        //PWM01的占空比调节使用                        PWM0组的死区寄存器

        //周期计算         = 0x03ff / (Fosc / PWM分频系数)               
        //                        = 0x03ff / (32000000 / 2)
        //                         = 1023   /16000000
        //                        = 63.93us                                  

        PWM0PH = 0x03; //周期高4位
        PWM0PL = 0xFF; //周期低8位

        //占空比计算= 0x0200 / (Fosc / PWM分频系数)               
        //                        = 0x0200 / (32000000 / 2)
        //                         = 341          / 16000000
        //                        = 21.31us                   占空比为 21.31/63.93 = 33.3%

        PWM0DH = 0x02;        //PWM0高4位占空比
        PWM0DL = 0x00;        //PWM0低8位占空比
       
        PWM0DTH = 0x02; //PWM01高4位占空比
        PWM0DTL = 0x00; //PWM01低8位占空比
   
        PWM0INTDIV = 0x10; // PWM0匹配中断分频
        PWMEN = 0x11;           //使能PWM0和PWM01输出
       
/************************** ADC配置初始化 ************************************************/       
    P1M0 = P1M0 & 0x0F | 0x30;  //P11设置为模拟输入
        ADCC0 = 0xC3;                            //启动ADC电源,内部参考电压 2V
        Delay_2us(10);              //延时20us,确保ADC系统稳定
        ADCC1 = 0x01;                            //选择外部通道1
        ADCC2 = 0x4B;               //转换结果12位数据,数据右对齐,ADC时钟8分频
        ADCC3 = 0x0D;               //PWM0 匹配中断
   
        ADCDLYH = 0x00;
        ADCDLYL = 0x01;
       
        IP3 = 0x30;             //ADC优先级为3
       
        EADC = 1;        //打开ADC中断
        EA = 1;          //打开总中断
        while (1);
       
}
/***************************************************************************************
  * @说明          ADC中断服务函数
  *        @参数         无
  * @返回值 无
  * @注                  无
***************************************************************************************/

void ADC_Rpr() interrupt ADC_VECTOR
{
        if (ADCC0 & 0X20)
        {
                P0_1 = ~P0_1;
                ADCC0 &= ~0x20; //清ADCIF标志
        }
}
/***************************************************************************************
  * @说明          PWM中断服务函数
  *        @参数         无
  * @返回值 无
  * @注                  无
***************************************************************************************/
void PWM_Rpt() interrupt PWM_VECTOR
{
        if (PWMCON1 & 0x40)
        {
                PWMCON1 &= ~0x40;
                P0_0 = ~P0_0;
        }
}
/************************************************************************************
  * @说明          延时函数
  * @参数          fui_i : 延时时间
  * @返回值 无
  * @注         Fcpu = 16MHz,fui_i = 1时,延时时间约为2us
***********************************************************************************/
void Delay_2us(unsigned int fui_i)
{
        while (fui_i--);
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

120

主题

1522

帖子

1

粉丝