PIC单片机的PWM与ADC的相互调用
1.前言
为提高对控制对象的控制精度的要求,闭环控制成为了一种普遍采用的方案。闭环控制是指:使用被控对象输出误差来修正控制对象的方法。
其常见的原理框图如图所示:

以常见的控制系统为例,其实现的过程一般为使用单片机ADC采样,进而修改单片机输出的PWM占空比,以实现对被控对象的控制。
在其他单片机中这一过程,往往需要软件编程来进行实现,然而dsPIC单片机可以凭借其中断实现硬件闭环。减少了软件的编写量,而且使闭环的可靠性有较大的提升。
其原理框图如:

本文将首先对PWM、ADC模块进行介绍,阐述相互调用的原理,并给出示范代码。
采用的单片机型号为dsPIC33FJ16GS502,编辑器为MPLAB X IDE V6.0,编译器为XC16 V2.00
2.PWM模块
2.1 总体介绍
在使用附属时钟的情况下,此款单片机的PWM模块的时钟输入频率可达到117.92MHz具有4×2路PWM输出,支持真正独立输出、冗余输出、中心对齐模式和推挽输出等多种PWM模式,并且可触发中断、ADC采样。其PWM模块功能强大,详情可参考其用户手册。
其时钟是经由附属时钟(ALCK)提供,详情也可看时钟简介的博客:
本文使用的PWM模式:完全独立的PWM输出。故仅介绍此种模式;
何为完全独立模式呢?
就是两路PWM的输出的周期,占空比均相互独立,不相互影响。可见下图:

2.2 PWM原理介绍
原理介绍网上有很多,可以参考:
https://zhuanlan.zhihu.com/p/379585884
其在单片机中的实现,可以参考
https://blog.csdn.net/weixin_48283961/article/details/122105151
死区相关知识,可以参考:
https://www.jianshu.com/p/61b0fdac2805
PWM触发ADC的原理也是较为容易理解的,见图:

以上半边为例,当PTMRx与TRIGx中寄存器的值相等时,便会产生一个高电平触发,经过TRGSTRT延时(可设置),可TRGDIV分频(可设置),经过或门(可设置)后便会到达ADC触发其发生中断,对数据进行采样。
具体电平变化,如图所示
2.2 寄存器设置
搞懂PWM的原理后,便可以配置PIC的寄存器来时单片机输出PWM波形啦!
真正独立的PWM输出模式需要配置的寄存器很少,其名称和功能如下:
| 名称 | 功能 |
| PTCON | 周期更新设置,关断设置 |
| PTCON2 | 时钟分批 |
| PWMCON1 | PWM模块1功能设置 |
| PHASE1 | PWM1H周期寄存器 |
| SPHASE1 | PWM1L周期寄存器 |
| PDC1 | PWM1H占空比寄存器 |
| ALTDTR1 | PWM1L占空比寄存器 |
|
IOCON1 |
PWM1模块端口寄存器 |
|
TRIG1 |
PWM1H触发寄存器 |
|
STRIG1 |
PWM1L触发寄存器 |
|
TRGCON1 |
PWM1模块触发设置位 |
具体各个寄存器的作用,以及如何配置见代码及代码注释:
2.3 PWM代码
1 void PWM1_Init(void) 2 { 3 PTCONbits.EIPU = 0 ; // 周期边界处更新周期 4 PTCON2bits.PCLKDIV = 0b110 ; // PWM Divide is 64 5 6 PWMCON1bits.ITB = 1; // 使用独立时基模式 7 PWMCON1bits.MDCS = 0 ; // 使用PDC与SDC寄存器提供占空比信息 8 PWMCON1bits.DTC = 0 ; // 施加正死区 9 PWMCON1bits.IUE = 1 ; // 立即更新占空比 10 // PWMCON1bits.MTBS 11 // 周期 1ms 12 PHASE1 = 1843; 13 SPHASE1 = 1843; 14 // 占空比 MDC 15 PDC1 = 920; 16 SDC1 = 920; // 初始占空比50% 17 // 死区 18 DTR1 = (int)(0.05 * PDC1); 19 ALTDTR1 = (int)(0.05 * SDC1); // 10% 死区 20 //引脚模式 21 IOCON1bits.PENH = 1 ; // 使能PWM模块控制PWM1H引脚 22 IOCON1bits.PENL = 1 ; // 使能PWM模块控制PWM1L引脚 23 IOCON1bits.POLH = 0 ; 24 IOCON1bits.POLL = 0 ; // 高电平有效 25 IOCON1bits.PMOD = 0b11 ; // 真正独立PWM模式 26 //触发设置 27 TRIG1 = 64 ; 28 STRIG1 = 64 ; // 上升沿64个PWM周期后触发ADC中断 29 TRGCON1bits.TRGSTRT = 0; // 立即触发 30 TRGCON1bits.TRGDIV = 0; // 每次触发产生中断 31 TRGCON1bits.DTM = 1 ; // 或逻辑输出触发 32 33 PTCONbits.PTEN = 1 ; // enable PWM 34 }
按照上述配置后,便会产生周期为1ms,占空比为50%,死区为5%占空比的PWM信号。
3 ADC配置
3.1 简介
此款单片机的ADC模块为10位,对于一般的控制系统也是十分够用的。对于具有2个SAR(Successive Approximation Register)的模块,其采样速率达到的4Msps,并且其采样方案采用的为对采样,说人话就是一次对两个通道进行采样。对于电源控制方面来说,可以一次采样电压和电流,较为方便。
其时钟也是经由附属时钟(ALCK)提供,详情也可看时钟简介的博客:
3.2 原理简介
关于逐次逼近ADC的原理,网上有很多,故不再再次介绍。
不太明白的小伙伴可以去看一下这个视频:
3.2 寄存器介绍
搞明白ADC采样的原理后,就可以来配置寄存器啦。
ADC的寄存器也不是很多,详情见表格:
| 寄存器名 | 功能 |
| ADCON | ADC模块配置寄存器 |
| ADCFG | 端口配置寄存器 |
| ADCPC0 | 转换配置寄存器 |
| IPC27 | 中断优先级配置 |
| IFS6 | 中断标志 |
| IEC6 | 中断使能 |
具体各个寄存器的作用,以及如何配置见代码及代码注释:
1 void ADC_Init(void) 2 { 3 // 输入时钟设置 4 ADCONbits.SLOWCLK = 1; //使用附属PLL(ALCK)作为时钟源 5 ADCONbits.ADCS = 0b101; // ADC转换时钟6分频 6 // 模块配置 7 ADCONbits.ADSIDL = 0 ; // 空闲模式下继续工作 8 ADCONbits.SLOWCLK = 1 ; // Use ACLK as Clock Source 9 ADCONbits.FORM = 0 ; // 转换完成后数据格式为整数格式 10 ADCONbits.EIE = 1 ; // 提前中断模式,AN0采样完成后中断 11 // 转换设置 12 ADCONbits.ORDER = 0; 13 ADCONbits.SEQSAMP = 0; 14 ADCONbits.ASYNCSAMP = 0; //同步采样和并行转换 15 // AN0 AN1 端口配置 16 ADPCFGbits.PCFG0 = 0; //配置AN0 为模拟输入引脚 17 ADPCFGbits.PCFG1 = 0; //配置AN1 为模拟输入引脚 18 // ADC 转换对控制寄存器 19 ADCPC0bits.TRGSRC0 = 0b100; // PWM发生器1主触发0b100 20 ADCPC0bits.IRQEN0 = 1; //转换完成后产生中断 21 // ADC中断配置 22 IPC27bits.ADCP0IP = 0x01; // ADC转换优先级为 1 23 IFS6bits.ADCP0IF = 0; // 清除中断标志位 24 IEC6bits.ADCP0IE = 1; // 使能中断 25 //开启中断转换 26 ADCONbits.ADON = 1; // 开启ADC转换 27 }
比较重要的是第19行,将ADC转换触发设置为由PWM发生器1触发。
ADC初始化完成后,要读取ADC的转换值,需要在ADC的中断函数中,因此也可以在ADC中断服务函数中,来进行PWM的占空比调节;
ADC的中断服务函数如下:
1 void __attribute__((interrupt , no_auto_psv)) _ADCP0Interrupt (void) 2 { 3 PDC1 = ADCBUF0; 4 SDC1 = ADCBUF1; 5 // 死区 6 DTR1 = (int)(0.05 * PDC1); 7 ALTDTR1 = (int)(0.05 * SDC1); // 5% 死区 8 // clear ADC Pair 0 Interrupt flag 9 IFS6bits.ADCP0IF = 0 ; 10 }
至此ADC的配置就算完成了。
4 主函数
在各模块都已经完成的情况下,主函数的编写就十分的简单了,直接见代码:
int main() { System_Colck();//时钟设置 ALCK_Init(7); //附属时钟初始化 ADC_Init(); // ADC初始化 PWM1_Init(); // PWM 时钟初始化 while(1) {} }
至此便完成了--->””通过PWM触发ADC中断修改PWM参数的硬件闭环调用”“<--- ,在外电路合适的情况下,改变ADC引脚的电压值便可实现对PWM的占空比进行改变,具体表现为LED的亮度啦。

浙公网安备 33010602011771号