找回密码
 立即注册
查看: 118|回复: 3

STC32G/STC8H/AI8051U通用 PWM的高电平或者低电平中心位置触发中断以采样ADC例程

[复制链接]
已绑定手机
已实名认证

148

主题

4098

回帖

1万

积分

超级版主

积分
10912
发表于 5 天前 | 显示全部楼层 |阅读模式
截图202611021119492867.jpg

黄色线就是中断中取反的信号,粉色线是变动的占空比。
核心思想是通过中心对齐模式+启动前调整DIR方向,然后设置RCR为1,即可实现可控的固定中心触发

HSPWM_ADC_示例工程.zip (18.03 KB, 下载次数: 12)

黄色是ADC中断(P01),蓝色是下管的PWM(P25),红色是上管的PWM(P24)



  1. /* ============================================================
  2. * STC32G12K128  HSPWM + ADC 下管低电平中点触发 DEMO
  3. * ------------------------------------------------------------
  4. * 客户要求:
  5. *   - HSPWM 20 kHz,PWM_DTR=250,P2.4/P2.5 互补
  6. *   - ADC 在 P2.5(下管)低电平中心触发
  7. *   - ADC 中断翻转 P0.1,用于和 PWM 波形对比
  8. *
  9. * 关键:
  10. *   启动前预置 DIR,再进入 CMS=01,让其按 DIR 方向上下计数:
  11. *     1. 中央对齐模式 1:CMS=01;
  12. *     2. RCR=1:每两个半周期一次更新事件;
  13. *     3. 中心选择由 PWM_ADC_CENTER_LOW 宏决定:
  14. *        1 = P2.5 低电平中心(DIR=1)
  15. *        0 = P2.5 高电平中心(DIR=0)
  16. *     3. PWMA_CR2.MMS=010:更新事件作为 TRGO 触发 ADC;
  17. *     4. ADC_CONTR.ADC_EPWMT=1:ADC 由 PWM 硬件触发。
  18. *
  19. *   异步访问规则:
  20. *     - 一次异步写入只写一个完整值,不做读改写、与或非;
  21. *     - 先写 RCR;
  22. *     - 先在 CMS=00 下预置 DIR=1;
  23. *     - 保持 DIR=1 切入 CMS=01;
  24. *     - 最后 CEN=1;
  25. *     - 不写 EGR。
  26. *
  27. *   ADC 采样时间也缩短:
  28. *     ADCCFG=0x00(SPEED=0)
  29. *     ADCTIM=0x2A(CSSETUP=0, CSHOLD=1, SMPDUTY=10)
  30. *     约 1.8 us 转换,P0.1 翻转更贴近中点。
  31. *
  32. * 时钟:
  33. *   IRC 24M → PLL 144M → HSPWM 144M
  34. *   PWMA 计数时钟 72M,ARR=1800 → 20 kHz
  35. *   系统时钟 28.8M
  36. * ============================================================ */
  37. #include "STC32G.h"
  38. #include "intrins.h"
  39. typedef unsigned char  u8;
  40. typedef unsigned int   u16;
  41. typedef unsigned long  u32;
  42. #define FOSC          28800000UL
  43. #define PWM_ARR       1800
  44. #define PWM_DTR_VALUE 250
  45. #define DUTY_MIN10    220
  46. #define DUTY_MAX10    8100
  47. #define DUTY_STEP10   8
  48. /* ADC 触发中心选择:
  49. *   1 = P2.5 低电平中心(默认)
  50. *   0 = P2.5 高电平中心
  51. *
  52. * 只改这一个宏,重新编译即可切换中心。
  53. */
  54. #define PWM_ADC_CENTER_LOW   1
  55. #if PWM_ADC_CENTER_LOW
  56.   /* DIR=1,CMS=00 / CMS=01 / CEN=1 三种完整值 */
  57.   #define PWM_CR1_DIR_PRESET  0x90
  58.   #define PWM_CR1_DIR_CMS     0xB0
  59.   #define PWM_CR1_START       0xB1
  60. #else
  61.   /* DIR=0,CMS=00 / CMS=01 / CEN=1 三种完整值 */
  62.   #define PWM_CR1_DIR_PRESET  0x80
  63.   #define PWM_CR1_DIR_CMS     0xA0
  64.   #define PWM_CR1_START       0xA1
  65. #endif
  66. volatile u16 duty10 = DUTY_MIN10;
  67. volatile u8  duty_dir = 1;
  68. volatile u32 adc_beat = 0;
  69. volatile u32 tick_ms = 0;
  70. volatile u8  duty_tick = 0;     /* Timer0 只置标志,占空比在 main 中更新 */
  71. static void Duty_Update(void);
  72. static void Delay_ms(u16 ms)
  73. {
  74.     u16 i, j;
  75.     for (i = 0; i < ms; i++)
  76.         for (j = 0; j < (u16)(FOSC / 12000); j++);
  77. }
  78. static void WritePWMA(u8 addr, u8 dat)
  79. {
  80.     while (HSPWMA_ADR & 0x80);
  81.     HSPWMA_DAT = dat;
  82.     HSPWMA_ADR = addr & 0x7F;
  83.     while (HSPWMA_ADR & 0x80);   /* 等待本次异步写完成 */
  84. }
  85. static void System_Init(void)
  86. {
  87.     EAXFR = 1;
  88.     CLKSEL &= ~0x80;
  89.     CLKSEL |= 0x80;
  90.     USBCLK &= ~0x60;
  91.     USBCLK |= 0x20;
  92.     USBCLK |= 0x80;
  93.     Delay_ms(1);
  94.     HSCLKDIV = 0;
  95.     CLKSEL |= 0x40;
  96.     CLKDIV = 5;
  97.     CLKSEL &= 0xF0;
  98.     CLKSEL |= 0x04;
  99. }
  100. static void GPIO_Init(void)
  101. {
  102.     P2M1 &= ~0x30;
  103.     P2M0 |=  0x30;
  104.     P0M1 &= ~0x02;
  105.     P0M0 |=  0x02;
  106.     P01 = 0;
  107.     P1M1 |=  0x3B;
  108.     P1M0 &= ~0x3B;
  109. }
  110. static void PWM_Init(void)
  111. {
  112.     u16 cc;
  113.     HSPWMA_CFG = 0x07;          /* INTEN=1, ASYNCEN=1 */
  114.     PWMA_PS = 0x10;
  115.     WritePWMA((u8)&PWMA_CCER2, 0x00);
  116.     WritePWMA((u8)&PWMA_CCMR3, 0x68);
  117.     WritePWMA((u8)&PWMA_PSCRH, 0x00);
  118.     WritePWMA((u8)&PWMA_PSCRL, 0x01);
  119.     WritePWMA((u8)&PWMA_ARRH, (u8)(PWM_ARR >> 8));
  120.     WritePWMA((u8)&PWMA_ARRL, (u8)(PWM_ARR & 0xFF));
  121.     cc = (u16)(duty10 / 10);
  122.     WritePWMA((u8)&PWMA_CCR3H, (u8)(cc >> 8));
  123.     WritePWMA((u8)&PWMA_CCR3L, (u8)(cc & 0xFF));
  124.     WritePWMA((u8)&PWMA_DTR, PWM_DTR_VALUE);
  125.     /* 更新事件触发 ADC:MMS=010 */
  126.     WritePWMA((u8)&PWMA_CR2, 0x20);
  127.     WritePWMA((u8)&PWMA_ENO,  0x30);
  128.     WritePWMA((u8)&PWMA_CCER2, 0x05);
  129.     WritePWMA((u8)&PWMA_BKR, 0x80);
  130.     /* 先设置 RCR = 1 */
  131.     WritePWMA((u8)&PWMA_RCR, 1);
  132.     /* 启动前预置 DIR(此时还在 CMS=00) */
  133.     WritePWMA((u8)&PWMA_CR1, PWM_CR1_DIR_PRESET);
  134.     /* 保持 DIR,切入 CMS=01 */
  135.     WritePWMA((u8)&PWMA_CR1, PWM_CR1_DIR_CMS);
  136.     WritePWMA((u8)&PWMA_SR1, 0xFE);     /* 清 UIF */
  137.     /* 启动前写入 CNTR = 0,随后按 DIR=1 的方向开始上下计数 */
  138.     WritePWMA((u8)&PWMA_CNTRH, 0x00);
  139.     WritePWMA((u8)&PWMA_CNTRL, 0x00);
  140.     WritePWMA((u8)&PWMA_CR1, PWM_CR1_START);
  141. }
  142. static void ADC_Init(void)
  143. {
  144.     /* 缩短 ADC 转换时间:SPEED=0,SMPDUTY=10,约 1.8us */
  145.     ADCCFG = 0x00;
  146.     ADCTIM = 0x2A;
  147.     ADC_CONTR = 0x90;           /* ADC_POWER=1, ADC_EPWMT=1 */
  148.     ADC_CONTR = (ADC_CONTR & 0xF0) | 0x04; /* ADC 通道 4 */
  149.     ADC_CONTR &= ~0x20;         /* 清 ADC_FLAG */
  150.     EADC = 1;
  151. }
  152. static void Timer0_Init(void)
  153. {
  154.     TMOD &= 0xF0;
  155.     TMOD |= 0x00;
  156.     TM0PS = 0;
  157.     TL0 = (u8)((65536UL - FOSC / 12 / 1000) & 0xFF);
  158.     TH0 = (u8)(((65536UL - FOSC / 12 / 1000) >> 8) & 0xFF);
  159.     ET0 = 1;
  160.     TR0 = 1;
  161. }
  162. void main(void)
  163. {
  164.     EA = 0;
  165.     System_Init();
  166.     GPIO_Init();
  167.     PWM_Init();
  168.     ADC_Init();
  169.     Timer0_Init();
  170.     /* ADC 高优先级,Timer0 低优先级:避免 Timer0 阻塞 ADC 中断 */
  171.     PADC  = 1;  PADCH = 1;
  172.     PT0   = 0;  PT0H  = 0;
  173.     PPWMA = 0;  PPWMAH = 0;
  174.     EA = 1;
  175.     while (1)
  176.     {
  177.         if (duty_tick)
  178.         {
  179.             duty_tick--;
  180.             Duty_Update();
  181.         }
  182.     }
  183. }
  184. void Timer0_ISR(void) interrupt 1
  185. {
  186.     tick_ms++;
  187.     if (duty_tick < 255) duty_tick++;
  188. }
  189. /* 占空比更新放在 main 中,Timer0 中断只置标志。
  190. * 这样 Timer0 中断很短,不会用 HSPWM 异步写去阻塞 ADC 中断。
  191. */
  192. static void Duty_Update(void)
  193. {
  194.     u16 cc;
  195.     if (duty_dir)
  196.     {
  197.         duty10 += DUTY_STEP10;
  198.         if (duty10 >= DUTY_MAX10)
  199.         {
  200.             duty10 = DUTY_MAX10;
  201.             duty_dir = 0;
  202.         }
  203.     }
  204.     else
  205.     {
  206.         if (duty10 >= (DUTY_MIN10 + DUTY_STEP10))
  207.             duty10 -= DUTY_STEP10;
  208.         else
  209.         {
  210.             duty10 = DUTY_MIN10;
  211.             duty_dir = 1;
  212.         }
  213.     }
  214.     cc = (u16)(duty10 / 10);
  215.     WritePWMA((u8)&PWMA_CCR3H, (u8)(cc >> 8));
  216.     WritePWMA((u8)&PWMA_CCR3L, (u8)(cc & 0xFF));
  217. }
  218. void ADC_ISR(void) interrupt 5
  219. {
  220.     ADC_CONTR &= ~0x20;         /* 清 ADC_FLAG */
  221.     P01 = ~P01;                 /* 与 PWM 波形对比 */
  222.     adc_beat++;
  223. }
复制代码






回复

使用道具 举报 送花

83

主题

8317

回帖

1万

积分

超级版主

积分
17930
发表于 5 天前 | 显示全部楼层
应该自动触发ADC转换,ADC中断再触发下一个通道转换,占空比不能到100%,一般要90%以下。对于测量2相电流的可以,而对于单电阻采样,则比较麻烦。

点评

这个是有客户用于电源DCDC的采样,需求在低侧MOS管的低电平中间位置触发ADC 由于没有现成的例子,便写了一个给客户,顺便发出来给大家参考用 例子是PLL+HSPWM+互补死区下的采样点设置参考  详情 回复 发表于 5 天前
回复

使用道具 举报 送花

已绑定手机
已实名认证

148

主题

4098

回帖

1万

积分

超级版主

积分
10912
 楼主| 发表于 5 天前 | 显示全部楼层
梁*** 发表于 2026-11-2 12:04
应该自动触发ADC转换,ADC中断再触发下一个通道转换,占空比不能到100%,一般要90%以下。对于测量2相电流的 ...

这个是有客户用于电源DCDC的采样,需求在低侧MOS管的低电平中间位置触发ADC
由于没有现成的例子,便写了一个给客户,顺便发出来给大家参考用
例子是PLL+HSPWM+互补死区下的采样点设置参考

点评

我以为是FOC驱动  详情 回复 发表于 5 天前
回复

使用道具 举报 送花

83

主题

8317

回帖

1万

积分

超级版主

积分
17930
发表于 5 天前 | 显示全部楼层
王*** 发表于 2026-11-2 13:23
这个是有客户用于电源DCDC的采样,需求在低侧MOS管的低电平中间位置触发ADC
由于没有现成的例子,便写了 ...

我以为是FOC驱动
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-7 10:39 , Processed in 0.078886 second(s), 60 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表