本帖最后由 wangjj19950516 于 2021-11-1 16:06 编辑
PWM模块的功能很强大,可以做输出比较,输入捕获,组合输出,正交解码等。一般用的最多的就是输出PWM波形和捕获外部PWM信号的频率占空比了。上次发了一篇帖子,介绍用一个PWM模块同时捕获多路信号的例子,https://bbs.21ic.com/icview-3173730-1-1.html。用于解决多路捕获资源不足的问题。
但有些应用,即需要输出PWM波形,又需要捕获外部信号,在资源不够分配的情况下,可以用同一个PWM模块的不同通道分别实现输出和输入,下面具体介绍使用配置。
硬件:AC7801开发板
PWM1-CH0(PB5)产生一路占空比可以调的PWM信号
PWM1-CH1(PB4)作为输入,捕获外部信号的频率和占空比
一、初始化配置
1.GPIO配置
void GPIO_Config(void)
{
GPIO_SetFunc(GPIOB, GPIO_PIN5, GPIO_FUN1); //PWM1-CH0
GPIO_SetFunc(GPIOB, GPIO_PIN4, GPIO_FUN1); //PWM1-CH1
}
2.PWM模块配置
PWM-CH0生成一个1KHZ频率的波形,模块时钟为24MHZ,2分频,所以最大计数值应为24000000/2/1000=12000;
由于一个PWM模块只有一个计数器,所以作为输入通道的捕获值也只能从0计到12000
//PWM模块初始化,CH0配置为输出,CH1配置为输入
void PWM_Capture_Output_Init(void)
{
PWM_DeInit(PWM1);//去初始化PWM0
PWM_SimplyConfigType SimplyConfig;
PWM_inputChConfigType inputChConfig[1];//输入通道配置
PWM_inputCaptureConfigType inputCapconfig;//输入捕获结构体
PWM_ConfigType config; //PWM模块结构体
//结构体数据清零
memset(&SimplyConfig, 0, sizeof(SimplyConfig));
memset(&inputChConfig, 0, sizeof(inputChConfig));
memset(&inputCapconfig, 0, sizeof(inputCapconfig));
memset(&config, 0, sizeof(config));
//输出配置,
SimplyConfig.allChCombineMode = PWM_INDEPENDENT_MODE; //独立模式
SimplyConfig.countMode = PWM_UP_COUNT; //向上计数
SimplyConfig.levelMode = PWM_HIGH_TRUE; // PWM_HIGH_TRUE;
SimplyConfig.clkSource = PWM_CLK_SOURCE_APB; // PWM_CLK_SOURCE_BUS;
SimplyConfig.chValue[0] = 2000;
PWM_SimplyInit(PWM1, &SimplyConfig);
//输入通道结构体配置,如果有多个输入通道,更改结构体数组,在后面添加相关配置即可。
inputChConfig[0].channel = PWM_CH_1; //信号捕获通道
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; //该通道输入捕获中断使能
//输入捕获配置
inputCapconfig.channelNum = 1;
inputCapconfig.channelConfig = inputChConfig;//输入通道配置变量地址赋值。
//PWM模块配置
config.mode = PWM_MODE_INPUT_CAPTURE;//PWM模块配置为输入捕获模式
config.initModeStruct = &inputCapconfig;//输入捕获配置变量赋值
config.clkSource = PWM_CLK_SOURCE_APB; //PWM时钟源配置
config.clkPsc = 1;//PWM时钟源分频
config.initValue = 0;//计数器初始寄存器值
config.maxValue = MAX_MOD; //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.中断回调函数
在中断函数中,计算CH1外部信号的频率和占空比,同时每次在溢出中断里修改CH0的占空比。
在计算捕获频率和占空比时,需要考虑数据溢出的情况,每次数据溢出后,判断之前的电平状态,如果之前是高电平,那么将高电平的溢出次数加1。当发生下降沿边沿捕获中断时,计算高电平时间需要用溢出次数*最大计数值(12000),再加上两次捕获值的差即可。
uint16_t Freq =0; //频率
uint16_t Duty =0; //占空比
void PWM_Capture_CallBack(void *device, uint32_t wpara, uint32_t lpara)
{
static uint16_t value=0;
static uint32_t high_time=0;
static uint32_t Low_time =0;
static uint16_t high_over_cnt =0;
static uint16_t low_over_cnt =0;
static uint8_t pinlevel =0;
uint16_t CountValue=0;
static uint16_t CountValue_Last =0;
if(value < MAX_MOD)
{
value++;
}
else
{
value =0;
}
if (wpara & PWM_INIT_CNTOF_Msk) //溢出中断
{
PWM_SetChannelCountValue(PWM1, PWM_CH_0, value) ;//修改PWM1-CH0占空比
if(pinlevel == 0) //根据之前的电平状态,判断该溢出时间加在那个状态,避免溢出中断时电平发生跳变,导致时间计算错误
{
low_over_cnt++;
}
else
{
high_over_cnt ++;
}
}
if (lpara & PWM_STR_CH1SF_Msk) //通道1中断
{
CountValue = PWM_GetChannelCountValue(PWM1, PWM_CH_1); //读取通道1的捕获数据
if(GPIO_GetPinLevel(GPIOB, GPIO_PIN4)== GPIO_LEVEL_LOW)//下降沿,读出高电平时间
{
high_time = (uint32_t)(high_over_cnt)*MAX_MOD + CountValue - CountValue_Last;
pinlevel = 0; //低电平状态
}
else//上升沿,读出低电平时间
{
Low_time = (uint32_t)low_over_cnt * MAX_MOD + CountValue - CountValue_Last;
pinlevel =1;
}
//频率和占空比计算
//PWM时钟24MHZ,2分频
Freq = 24000000/2/(Low_time + high_time);
Duty = (high_time)*100/(Low_time + high_time);
low_over_cnt =0;
high_over_cnt = 0;
CountValue_Last = CountValue;
}
}
二、测试结果
下图为测试结果,其中黄色波形为CH0生成的1KHZ频率的波形,绿色为外部输入信号,频率为152.7KZ,占空比为55%。在debug的watch窗口中可以看到,程序中计算得到的Freq为152,Duty为55,与实际相符。
三、附件
为了方便大家调试,这里把整个工程附上
pwm_捕获+输出.rar
(586.42 KB)
|