本帖最后由 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, 下载次数: 50)
|