STM32
直播中

卞轮辉

9年用户 1170经验值
私信 关注
[问答]

STM32F103ZE IO口外部中断计算PWM波形的占空比和频率遇到的疑问求解

大家好!
最近开始接触STM32F103ZE开发板,计划利用IO口外部中断的方法计算PWM波形的占空比和频率。出现了一些问题,还请大神们指点一二,万分感激!!!!
EXti初始化设置如下:
EXTI_InitTypeDef EXTI_InitStructure;
void EXTI1_Config_Rising(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // Ecirc; sup1; Auml; Uuml; cedil; acute; Oacute; Atilde; sup1; brvbar; Auml; Uuml; Ecirc;± Ouml; Oacute;

GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource1);
EXTI_InitStructure.EXTI_Line=EXTI_Line1;//PC1,EXTI1
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
#if 1
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//双边沿触发
#else
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿触发
#endif

EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init( EXTI_InitStructure);

首先,采用双边沿触发,进入中断之后判断引脚电平从而再次确定是哪种边沿触发。代码如下,但是一旦PWM波形的频率和占空比较低的话,此方法完全无效
TIMER_CNT Count[2]={0};//Count[0] is sample value, Count[1] is return value.
u16 TITimer=0;
void EXTI1_IRQHandler(void)
{
//using EXTI_Trigger_Rising_Falling as EXTI source.
if (EXTI_GetITStatus(EXTI_Line1) != RESET)
{
   if (PCin(PWM_PIN))//rising edge
   {
    TITimer++;
    if(TITimer==1)//with interrupt
    {
           TIM_SetCounter(TIM2,0);//set count=0, and start count timer.
    }
    else if(TITimer==3)
    {
          Count[0].Cnt[1]=TIM_GetCounter(TIM2);//周期时间
        Count[1]=Count[0];
          TITimer=0;
    }
   }
   else   //falling edge
   {
    if(TITimer==2)
    {
          Count[0].Cnt[0]=TIM_GetCounter(TIM2);//高电平持续时间
   }
   }
   EXTI_ClearITPendingBit(EXTI_Line1);
}
//占空比=Count[0].Cnt[0]/Count[0].Cnt[1]

如果采用单边沿触发的方法,在中断处理函数里面转换触发边沿,断点测试出来是触发边沿转换无效,所以,测得的周期是实际的2倍,也不能检测到另一种边沿。下面代码:
TIMER_CNT Count[2]={0};//Count[0] is sample value, Count[1] is return value.
u8 EXTI1_STA = 0;
void EXTI1_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line1) != RESET)
{
   if(EXTI1_STA == 0)//1st risng edge interrupt
   {
    TIM_SetCounter(TIM2,0);
    EXTI1_STA =0x40;
    EXTI1_Config_Falling();
   }
   else if(EXTI1_STA   0x40) //2ed falling edge,无法进入!!!!!!
  {
    Count[0].Cnt[0]=TIM_GetCounter(TIM2);
    EXTI1_STA =0x80;
    EXTI1_Config_Rising();
   }
   else if(EXTI1_STA   0xC0)//3rd rising edge
   {
    Count[0].Cnt[1]=TIM_GetCounter(TIM2);
    Count[1]=Count[0];
    EXTI1_STA=0;
   }
   //EXTI_Init( EXTI_InitStructure);
   EXTI_ClearITPendingBit(EXTI_Line1);
}


回帖(1)

石玉兰

2024-5-10 16:57:22
首先,您已经正确地进行了EXTI初始化设置。接下来,您需要配置外部中断的优先级、嵌套向量和中断服务例程。以下是一些建议:

1. 配置NVIC(嵌套向量中断控制器)以设置中断优先级和嵌套向量:

```c
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; // 选择EXTI1中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 中断优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 中断子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断
NVIC_Init(&NVIC_InitStructure);
```

2. 在您的中断服务例程中,编写代码以计算PWM波形的占空比和频率。您需要定义两个全局变量来存储PWM的周期和占空比:

```c
volatile uint32_t pwm_period = 0;
volatile uint32_t pwm_duty_cycle = 0;
```

3. 在EXTI1中断服务例程中,编写代码以更新这些变量。例如,您可以使用定时器中断来测量PWM波形的周期和高电平持续时间:

```c
void EXTI1_IRQHandler(void)
{
    if (EXTI_GetITStatus(EXTI_Line1) != RESET)
    {
        EXTI_ClearITPendingBit(EXTI_Line1);
        
        // 检查上升沿还是下降沿
        if (GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_1) == Bit_SET)
        {
            // 记录上升沿的时间戳
            uint32_t timestamp = ...; // 获取当前时间戳
            pwm_period = timestamp - pwm_duty_cycle;
            pwm_duty_cycle = timestamp;
        }
        else
        {
            // 记录下降沿的时间戳
            uint32_t timestamp = ...; // 获取当前时间戳
            pwm_duty_cycle = timestamp;
        }
    }
}
```

4. 根据测量到的周期和占空比,计算PWM波形的频率和占空比:

```c
float pwm_frequency = 1.0 / pwm_period;
float pwm_duty_cycle_percentage = (pwm_duty_cycle / pwm_period) * 100.0;
```


举报

更多回帖

发帖
×
20
完善资料,
赚取积分