PWM 和 ADC 模块实现 PWM 匹配中断触发 ADC 转换 的功能
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--);
}
应用注意事项
ADC 时钟频率:建议 ADC 时钟频率不超过 2MHz,以保证转换精度。
内部参考电压:选择 2V 参考电压时,VDD 工作电压须高于 2.7V。
ADC 启动延时:使能 ADC 模块或切换通道后,建议延时 20μs 再启动转换。
PWM 触发 ADC:PWM 中点触发仅适用于中心对齐模式的 PWM 输出。 完整代码如下:
/**
* ************************************************************************************
* 上海芯圣电子股份有限公司
* 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应配置为1111,否则可能会造成内部通道
* 和外部通道同时打开的情况。
* 7、选择内部参考电压 2/3/4V时,相应的 ADC 时钟需要配置ADCTS 设置一次转换需要
* 的 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--);
}
页:
[1]