本帖最后由 wangjj19950516 于 2021-10-27 16:44 编辑
最近有较多客户提出需要捕获多路PWM信号,ATC芯片的PWDT是专门做捕获功能,但每个PWDT只能捕获一个通道,对于多通道的需求,资源不够用。PWM模块也可以做输入捕获功能,且PWM有多个通道。一般常规的使用都是用一个PWM模块做一路信号的捕获,难免有些浪费资源,这里向大家介绍一下PWM同时捕获多通道的做法。
一、PWM工作模式
AC7801的PWM模块包含很多功能,输出比较,输入捕获,双边沿捕获,组合输出模式,正交解码等。
可以看到,有输入捕获和双边沿输出捕获模式可以用来做外部信号的捕获。
1.输入捕获:单通道捕获,每个通道独立作为捕获通道,可设置捕获边沿。当通道输入出现选定的边沿时,PWM计数器的当前值会被捕获到PWM_CHnV寄存器中。同时,通道捕获中断标志位被置1,如果使能了通道中断,则可以产生中断。
如上图所示,设置上升沿捕获,当输入信号的上升沿来到时,把当前计数器的值2和8存入CHnV寄存器,相邻两次的数值差对应的时间即为波形的周期。
如果设置上升沿和下降沿都发生捕获,则可以分别得到高电平和低电平时间,从而可以计算波形的频率和占空比。
2.双边沿捕获:信号只能输入到通道CH0,CH2,CH4,但实际在芯片内部信号分两路走,CHn和CHn+1都有输入,可以设置CHn和CHn+1的捕获边沿。但不能同时使能CHn和CHn+1的中断,只能使能一个,即使设置的边沿不同,在一个周期内只能产生一个中断。
当输入信号出现CHn选择的边沿时,PWM计数器的当前值会存入CHnV寄存器,当出现CHn+1选择的边沿时,计数器的当前值会存入CHn+1V寄存器。
二、PWM多通道捕获
这里使用输入捕获(单通道)模式,捕获4路外部信号,每路信号都计算出频率和占空比。
使用PB5->PWM1_CH0,PB4->PWM1_CH1,PB8->PWM1_CH2,PC9->PWM1_CH6,这四个通道
1.首先配置GPIO功能,
void GPIO_PWM_Init(void)
{
GPIO_SetFunc(GPIOB, GPIO_PIN5, GPIO_FUN1);//PWM1_CH0
GPIO_SetFunc(GPIOB, GPIO_PIN4, GPIO_FUN1);//PWM1_CH1
GPIO_SetFunc(GPIOB, GPIO_PIN8, GPIO_FUN1);//PWM1_CH2
GPIO_SetFunc(GPIOC, GPIO_PIN9, GPIO_FUN1);//PWM1_CH6
}
2,配置PWM
void PWM_Capture_Init(void)
{
PWM_DeInit(PWM1); //去初始化PWM1
PWM_inputChConfigType inputChConfig[4]; //输入通道配置,总共4个通道
PWM_inputCaptureConfigType inputCapconfig; //输入捕获结构体
PWM_ConfigType config; //PWM模块结构体
//结构体数据清零
memset(&inputChConfig, 0, sizeof(inputChConfig));
memset(&inputCapconfig, 0, sizeof(inputCapconfig));
memset(&config, 0, sizeof(config));
//输入通道结构体配置,如果有多个输入通道,更改结构体数组,在后面添加相关配置即可。
/*
初始化PWM为捕获模式,捕获模式可以设上升/下降沿
*/
inputChConfig[0].channel = PWM_CH_0; //信号捕获通道
inputChConfig[0].mode = PWM_INPUTCAP_SINGLE_EDGE; //输入单通道捕获模式
inputChConfig[0].detectType = PWM_BOTH_EDGE_DETECT;//上升沿和下降沿捕获
inputChConfig[0].onceMode = PWM_INPUTCAP_CONTINUOUS;//连续捕获
inputChConfig[0].filterEn = DISABLE;//使能输入滤波,CH0-CH3才有该功能
inputChConfig[0].filterValue = 0; //filterValue值范围0-31,输入信号将被延迟filterValue*4个总线时钟
inputChConfig[0].eventPsc = PWM_EVENT_PSC_1; //输入事件与通道中断的对应关系。PWM_EVENT_PSC_1表示1次输入事件产生一次通道中断,PWM_EVENT_PSC_4表示4次输入事件产生一次通道中断。
inputChConfig[0].interruptEn = ENABLE; //该通道输入捕获中断使能
inputChConfig[1].channel = PWM_CH_1; //信号捕获通道
inputChConfig[1].mode = PWM_INPUTCAP_SINGLE_EDGE; //输入单通道捕获模式
inputChConfig[1].detectType = PWM_BOTH_EDGE_DETECT;//上升沿和下降沿捕获
inputChConfig[1].onceMode = PWM_INPUTCAP_CONTINUOUS;//连续捕获
inputChConfig[1].filterEn = DISABLE;//使能输入滤波,CH0-CH3才有该功能
inputChConfig[1].filterValue = 0; //filterValue值范围0-31,输入信号将被延迟filterValue*4个总线时钟
inputChConfig[1].eventPsc = PWM_EVENT_PSC_1; //输入事件与通道中断的对应关系。PWM_EVENT_PSC_1表示1次输入事件产生一次通道中断,PWM_EVENT_PSC_4表示4次输入事件产生一次通道中断。
inputChConfig[1].interruptEn = ENABLE; //输入捕获中断使能
inputChConfig[2].channel = PWM_CH_2; //信号捕获通道
inputChConfig[2].mode = PWM_INPUTCAP_SINGLE_EDGE; //输入单通道捕获模式
inputChConfig[2].detectType = PWM_BOTH_EDGE_DETECT;//上升沿和下降沿捕获
inputChConfig[2].onceMode = PWM_INPUTCAP_CONTINUOUS;//连续捕获
inputChConfig[2].filterEn = DISABLE;//使能输入滤波,CH0-CH3才有该功能
inputChConfig[2].filterValue = 0; //filterValue值范围0-31,输入信号将被延迟filterValue*4个总线时钟
inputChConfig[2].eventPsc = PWM_EVENT_PSC_1; //输入事件与通道中断的对应关系。PWM_EVENT_PSC_1表示1次输入事件产生一次通道中断,PWM_EVENT_PSC_4表示4次输入事件产生一次通道中断。
inputChConfig[2].interruptEn = ENABLE; //输入捕获中断使能
inputChConfig[3].channel = PWM_CH_6; //信号捕获通道
inputChConfig[3].mode = PWM_INPUTCAP_SINGLE_EDGE; //输入单通道捕获模式
inputChConfig[3].detectType = PWM_BOTH_EDGE_DETECT;//上升沿和下降沿捕获
inputChConfig[3].onceMode = PWM_INPUTCAP_CONTINUOUS;//连续捕获
inputChConfig[3].filterEn = DISABLE;//使能输入滤波,CH0-CH3才有该功能
inputChConfig[3].filterValue = 0; //filterValue值范围0-31,输入信号将被延迟filterValue*4个总线时钟
inputChConfig[3].eventPsc = PWM_EVENT_PSC_1; //输入事件与通道中断的对应关系。PWM_EVENT_PSC_1表示1次输入事件产生一次通道中断,PWM_EVENT_PSC_4表示4次输入事件产生一次通道中断。
inputChConfig[3].interruptEn = ENABLE; //输入捕获中断使能
//输入捕获配置
inputCapconfig.channelNum = 4; //输入捕获通道数目
inputCapconfig.channelConfig = inputChConfig;//输入通道配置变量地址赋值。
//PWM模块配置
config.mode = PWM_MODE_INPUT_CAPTURE;//PWM模块配置为输入捕获模式
config.initModeStruct = &inputCapconfig;//输入捕获配置变量赋值
config.clkSource = PWM_CLK_SOURCE_APB; //PWM时钟源配置
/*
设置捕获时钟频率:
可捕获的最小频率(前提是时钟源为PWM_CLK_SOURCE_APB):
min_clk = SYS_CLK/(PWM_CAPTURE_PRESCALER+1)/65536 = 24000000/2/65536 = 183HZ
*/
config.clkPsc = 1;//PWM时钟源分频,2分频
config.initValue = 0;//计数器初始寄存器值
config.maxValue = 65535; //PWM计数器最大值
config.overflowInterrupEn = ENABLE;//计数器溢出中断使能位
config.cntOverflowFreq = 0;//CNTOF中断产生的频率与计数器频率的关系(0-127), 0表示每次计数器溢出都产生溢出中断,1表示间隔1次,2表示间隔2次,以此内推。
config.interruptEn = ENABLE; //PWM中断使能
config.callBack = PWM_Capture_CallBack; //PWM中断回调
PWM_Init(PWM1, &config); //配置初始化生效
NVIC_SetPriority(PWM1_IRQn, 0); //设置PWM模块中断的优先级
}
3.中断处理函数PWM_CAPTURE_T PWM_Capture[4]; //定义结构体数组,分别存放4路信号的数据
void PWM_Capture_CallBack(void *device, uint32_t wpara, uint32_t lpara)
{
static uint8_t pwm_ch;
uint8_t gpio_edge =0; //边沿,1--上升沿 0--下降沿
uint16_t CountValue =0;
//PWM计数器溢出
if (wpara & PWM_INIT_CNTOF_Msk)
{
for(uint8_t index =0; index < 4;index++) //计算每个通道的电平溢出次数
{
if(PWM_Capture[index].pinlevel== 0) //根据之前的电平状态,判断该溢出时间加在那个状态,避免溢出中断时电平发生跳变,导致时间计算错误
{
PWM_Capture[index].low_over_cnt++;
}
else
{
PWM_Capture[index].high_over_cnt ++;
}
}
}
//通道中断
if(lpara !=0)
{
if (lpara & PWM_STR_CH0SF_Msk) //CH0中断
{
pwm_ch = 0;
if(GPIO_GetPinLevel(GPIOB, GPIO_PIN5)== GPIO_LEVEL_LOW)
{
gpio_edge = 0;
}
else
{
gpio_edge = 1;
}
CountValue = PWM_GetChannelCountValue(PWM1, PWM_CH_0); //读取通道0的捕获数据
}
else if(lpara & PWM_STR_CH1SF_Msk) //CH1中断
{
pwm_ch =1;
if(GPIO_GetPinLevel(GPIOB, GPIO_PIN4)== GPIO_LEVEL_LOW)
{
gpio_edge = 0;
}
else
{
gpio_edge = 1;
}
CountValue = PWM_GetChannelCountValue(PWM1, PWM_CH_1); //读取通道1的捕获数据
}
else if(lpara & PWM_STR_CH2SF_Msk) //CH2中断
{
pwm_ch =2;
if(GPIO_GetPinLevel(GPIOB, GPIO_PIN8)== GPIO_LEVEL_LOW)
{
gpio_edge = 0;
}
else
{
gpio_edge = 1;
}
CountValue = PWM_GetChannelCountValue(PWM1, PWM_CH_2); //读取通道2 的捕获数据
}
else if(lpara & PWM_STR_CH6SF_Msk) //CH6中断
{
pwm_ch =3;
if(GPIO_GetPinLevel(GPIOC, GPIO_PIN9)== GPIO_LEVEL_LOW)
{
gpio_edge = 0;
}
else
{
gpio_edge = 1;
}
CountValue = PWM_GetChannelCountValue(PWM1, PWM_CH_6); //读取通道6的捕获数据
}
else{}
PWM_Capture[pwm_ch].captureValue = CountValue;
if(gpio_edge==0) //下降沿,读出高电平时间
{
PWM_Capture[pwm_ch].high_time = (uint32_t)(PWM_Capture[pwm_ch].high_over_cnt)*65536 + PWM_Capture[pwm_ch].captureValue - PWM_Capture[pwm_ch].captureValue_last;
PWM_Capture[pwm_ch].pinlevel = 0;
}
else//上升沿,读出低电平时间
{
PWM_Capture[pwm_ch].Low_time = (uint32_t)PWM_Capture[pwm_ch].low_over_cnt * 65536 + PWM_Capture[pwm_ch].captureValue - PWM_Capture[pwm_ch].captureValue_last;
PWM_Capture[pwm_ch].pinlevel =1;
}
//频率和占空比计算
//PWM时钟24MHZ,2分频
PWM_Capture[pwm_ch].freq = 24000000/2/(PWM_Capture[pwm_ch].Low_time + PWM_Capture[pwm_ch].high_time);
PWM_Capture[pwm_ch].duty = (PWM_Capture[pwm_ch].high_time)*100/(PWM_Capture[pwm_ch].Low_time + PWM_Capture[pwm_ch].high_time);
PWM_Capture[pwm_ch].low_over_cnt =0;
PWM_Capture[pwm_ch].high_over_cnt = 0;
PWM_Capture[pwm_ch].captureValue_last = PWM_Capture[pwm_ch].captureValue;
}
}
三、附件
至此,便可以同时捕获4路信号,互不影响,实测每个通道都能正确计算出频率和占空比。
附件为测试工程,有需要可以参考
pwm_多通道捕获.rar
(20.87 KB)
|