[通用8051核FLASH系列] PWM 和 ADC 模块实现 PWM 匹配中断触发 ADC 转换 的功能

[复制链接]
 楼主| 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 中断标志。

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

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

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

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

  7. ADCDLYH = 0x00;
  8. ADCDLYL = 0x01;

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


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



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

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

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

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

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

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

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

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

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

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

  78.         PWM0DH = 0x02;        //PWM0高4位占空比
  79.         PWM0DL = 0x00;        //PWM0低8位占空比
  80.        
  81.         PWM0DTH = 0x02; //PWM01高4位占空比
  82.         PWM0DTL = 0x00; //PWM01低8位占空比
  83.    
  84.         PWM0INTDIV = 0x10; // PWM0匹配中断分频
  85.         PWMEN = 0x11;           //使能PWM0和PWM01输出
  86.        
  87. /************************** ADC配置初始化 ************************************************/       
  88.     P1M0 = P1M0 & 0x0F | 0x30;  //P11设置为模拟输入
  89.         ADCC0 = 0xC3;                            //启动ADC电源,内部参考电压 2V
  90.         Delay_2us(10);              //延时20us,确保ADC系统稳定
  91.         ADCC1 = 0x01;                            //选择外部通道1
  92.         ADCC2 = 0x4B;               //转换结果12位数据,数据右对齐,ADC时钟8分频
  93.         ADCC3 = 0x0D;               //PWM0 匹配中断
  94.    
  95.         ADCDLYH = 0x00;
  96.         ADCDLYL = 0x01;
  97.        
  98.         IP3 = 0x30;             //ADC优先级为3
  99.        
  100.         EADC = 1;        //打开ADC中断
  101.         EA = 1;          //打开总中断
  102.         while (1);
  103.        
  104. }
  105. /***************************************************************************************
  106.   * @说明          ADC中断服务函数
  107.   *        @参数         无
  108.   * @返回值 无
  109.   * @注                  无
  110. ***************************************************************************************/

  111. void ADC_Rpr() interrupt ADC_VECTOR
  112. {
  113.         if (ADCC0 & 0X20)
  114.         {
  115.                 P0_1 = ~P0_1;
  116.                 ADCC0 &= ~0x20; //清ADCIF标志
  117.         }
  118. }
  119. /***************************************************************************************
  120.   * @说明          PWM中断服务函数
  121.   *        @参数         无
  122.   * @返回值 无
  123.   * @注                  无
  124. ***************************************************************************************/
  125. void PWM_Rpt() interrupt PWM_VECTOR
  126. {
  127.         if (PWMCON1 & 0x40)
  128.         {
  129.                 PWMCON1 &= ~0x40;
  130.                 P0_0 = ~P0_0;
  131.         }
  132. }
  133. /************************************************************************************
  134.   * @说明          延时函数
  135.   * @参数          fui_i : 延时时间
  136.   * @返回值 无
  137.   * @注         Fcpu = 16MHz,fui_i = 1时,延时时间约为2us
  138. ***********************************************************************************/
  139. void Delay_2us(unsigned int fui_i)
  140. {
  141.         while (fui_i--);
  142. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

125

主题

1624

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部

125

主题

1624

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部