OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3050|回复: 3

最近做PWM占空比改变实验,发现结果有点怪,所以求助一下各位

[复制链接]

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-10-30
在线时间
6 小时
发表于 2020-7-26 13:35:45 | 显示全部楼层 |阅读模式
1金钱
  1. 最近做PWM占空比改变实验,利用外部中段控制TIM14->ARR和TIM14-CRR1中的值,但是发现调试的时候现象很奇怪。
复制代码
定时器程序
void TIM14_PWM_Init(u32 arr,u32 psc)
{                                                          
        //此部分需手动修改IO口设置
       
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);          //TIM14时钟使能   
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);         //使能PORTA时钟       
       
        GPIO_PinAFConfig(GPIOA,GPIO_PinSource7,GPIO_AF_TIM14); //GPIOA7复用为定时器14
       
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;           //GPIOF7
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //速度100MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
        GPIO_Init(GPIOA,&GPIO_InitStructure);              //初始化PF9
          
        TIM_TimeBaseStructure.TIM_Prescaler=psc;  //定时器分频
        TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
        TIM_TimeBaseStructure.TIM_Period=arr;   //自动重装载值
        TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
       
        TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);//初始化定时器14
       
        //初始化TIM14 Channel1 PWM模式         
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性低
        TIM_OC1Init(TIM14, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM14OC1

        TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);  //使能TIM14在CCR1上的预装载寄存器

  TIM_ARRPreloadConfig(TIM14,ENABLE);//ARPE使能
       
        TIM_Cmd(TIM14, ENABLE);  //使能TIM14
}  
外部中断程序
  1. //extern u16 crr_sub;
  2. extern u16 arr;
  3. extern int crr;
  4. void My_EXTI_Init()
  5. {
  6.   NVIC_InitTypeDef NVIC_InitSource;        //NVIC中断优先级管理初始化
  7.         EXTI_InitTypeDef EXTI_InitSource;         //外部中断线初始化  注意F407的每个IO口都可以作为外部中断的输入
  8. //外部中断只能配置线0-线15  线16到线22已经链接好
  9.         //注意7组IO口要连接到16根中断线,同一个中断线只能同一时间映射到一个IO口上        
  10.        
  11.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG,ENABLE);            //使能中断线时钟
  12.         //设置映射关系
  13.   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA,EXTI_PinSource0);            //IO口与中断线映射函数  PA0映射到外部中断线0
  14.   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource4);            //IO口与中断线映射函数  PE4映射到外部中断线4
  15.   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource3);            //IO口与中断线映射函数  PE3映射到外部中断线3
  16.   SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE,EXTI_PinSource2);            //IO口与中断线映射函数  PE2映射到外部中断线2
  17.   //注意外部中断线5-9共用一条中断线,10-15公用一条中断线
  18.         //初始化中断线
  19.         EXTI_InitSource.EXTI_Line = EXTI_Line0 ;        //外部中断线
  20.         EXTI_InitSource.EXTI_LineCmd = ENABLE   ;        //状态
  21.   EXTI_InitSource.EXTI_Mode = EXTI_Mode_Interrupt;         //配置为事件或者中断
  22.         EXTI_InitSource.EXTI_Trigger = EXTI_Trigger_Rising ; //上升沿触发
  23.         EXTI_Init(&EXTI_InitSource);     //初始化
  24.        
  25.         EXTI_InitSource.EXTI_Line = EXTI_Line4|EXTI_Line3|EXTI_Line2 ;        //外部中断线 2 3 4
  26.         EXTI_InitSource.EXTI_LineCmd = ENABLE   ;        //状态
  27.   EXTI_InitSource.EXTI_Mode = EXTI_Mode_Interrupt;         //配置为事件或者中断
  28.         EXTI_InitSource.EXTI_Trigger = EXTI_Trigger_Falling ; //下降沿触发
  29.         EXTI_Init(&EXTI_InitSource);
  30.        
  31.         //配置优先级分组             注意!!!!中断线在顶层头文件里面 stm32xx.h
  32.         NVIC_InitSource.NVIC_IRQChannel = EXTI0_IRQn;            //PA0的外部中线初始化
  33.         NVIC_InitSource.NVIC_IRQChannelCmd = ENABLE;
  34.         NVIC_InitSource.NVIC_IRQChannelPreemptionPriority = 0x00;        //抢占优先级
  35.         NVIC_InitSource.NVIC_IRQChannelSubPriority = 0x00;             //响应优先级
  36.   NVIC_Init(&NVIC_InitSource);
  37.        
  38.         NVIC_InitSource.NVIC_IRQChannel = EXTI4_IRQn;               //PE4的外部中断线的
  39.         NVIC_InitSource.NVIC_IRQChannelCmd = ENABLE;
  40.         NVIC_InitSource.NVIC_IRQChannelPreemptionPriority = 0x01;           //抢占优先级为1
  41.         NVIC_InitSource.NVIC_IRQChannelSubPriority = 0x00;                     //响应优先级为0
  42.   NVIC_Init(&NVIC_InitSource);
  43.        
  44.         NVIC_InitSource.NVIC_IRQChannel = EXTI3_IRQn;         //PE3的外部中断线            
  45.         NVIC_InitSource.NVIC_IRQChannelCmd = ENABLE;           //
  46.         NVIC_InitSource.NVIC_IRQChannelPreemptionPriority = 0x02;        //抢占优先级2
  47.         NVIC_InitSource.NVIC_IRQChannelSubPriority = 0x00;              //响应优先级为0
  48.   NVIC_Init(&NVIC_InitSource);
  49.        
  50.         NVIC_InitSource.NVIC_IRQChannel = EXTI2_IRQn;              //PE2的外部中断线
  51.         NVIC_InitSource.NVIC_IRQChannelCmd = ENABLE;
  52.         NVIC_InitSource.NVIC_IRQChannelPreemptionPriority = 0x03;          //抢占优先级为3
  53.         NVIC_InitSource.NVIC_IRQChannelSubPriority = 0x00;                   //响应优先级为0
  54.   NVIC_Init(&NVIC_InitSource);
  55. }

  56. //处理函数在启动文件里定义
  57. //注意,判断外部中断和定时器中断的原理不同,外部中断要先延时消抖然后在判断,而定时器就不需要
  58. void EXTI0_IRQHandler()        //PA0--WK_UP的服务函数
  59. {
  60.         delay_ms(10);
  61.         if(WK_UP == 1)
  62.         {
  63.                 TIM_SetCompare1(TIM14,arr/2);           //占空比复位
  64.         }
  65.         EXTI_ClearITPendingBit(EXTI0_IRQn);
  66. }
  67. void EXTI4_IRQHandler()         //PE4--KEY0的服务函数
  68. {
  69.         delay_ms(10);         //去抖动然后再次检查
  70.         if(KEY0 == 0)
  71.         {
  72.     arr=arr*2;          //重装载寄存器的值变为2倍,则计时频率除2
  73.                 if(arr>4000)
  74.                         arr=250;          //最大频率为4KHz   计算公式为84M/(84*250)=4KHz
  75.                 crr=arr/2;            //令crr=arr/2,那么占空比就变为50%
  76.                 TIM14->ARR = arr-1;     //改变TIM14_ARR寄存器的值

  77.         }
  78.   EXTI_ClearITPendingBit(EXTI4_IRQn);
  79. }
  80. void EXTI3_IRQHandler()           //PE3--KEY1的服务函数
  81. {
  82.   delay_ms(10);       //去抖动然后再次检查
  83.         if(KEY1 == 0)
  84.         {
  85.                 crr=crr+arr/10;
  86.                 if(crr>arr*0.9)
  87.                         crr=arr/10;            //若超过90%,就变为10%
  88.                 TIM_SetCompare1(TIM14,crr); //TIM_改变CRRx寄存器的值

  89.         }
  90.   EXTI_ClearITPendingBit(EXTI3_IRQn);
  91. }
  92. void EXTI2_IRQHandler()               //PE2--KEY2的服务函数
  93. {
  94.         delay_ms(10);//去抖动然后再次检查
  95.         if(KEY2 == 0)
  96.         {
  97.                 crr=crr-arr/10;
  98.                 if(crr<arr/10)
  99.                         crr=0.9*arr;
  100.                 TIM_SetCompare1(TIM14,crr);//TIM_改变CRRx寄存器的值
  101.         }
  102.         EXTI_ClearITPendingBit(EXTI2_IRQn);
  103. }
复制代码



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-10-30
在线时间
6 小时
 楼主| 发表于 2020-7-26 13:39:45 | 显示全部楼层
main函数没有显示,操作失误。在这里
现象是:
1:占空比可以改变,但是按下KEY0,KEY2时while里面的等就常亮或者长灭,然后程序就不行了
2:频率改变时好时坏
3:KEY1好用,while里程序不会出现问题
4:占空比改变的同时,输出波形的幅值也随之增大而增大。

//u16 crr_sub=25;
u16 arr = 500;
int crr = 250;
int main(void)
{
  u8 fre;
        u8 duty_cycle;
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
        delay_init(168);  //初始化延时函数
        uart_init(115200);//初始化串口波特率为115200
        TIM14_PWM_Init(arr-1,84-1);        //84M/84=1Mhz的计数频率,重装载值500,所以PWM频率为 1M/500=2Khz.
  TIM_SetCompare1(TIM14,crr);           //初始占空比为50%       
  LED_Init();
        KEY_Init();
        My_EXTI_Init();
        LCD_Init();
        POINT_COLOR=RED;      //画笔颜色:红色
   while(1) //实现比较值从0-300递增,到300后从300-0递减,循环
        {
                fre = (char)1000000/arr;
                duty_cycle = (char)crr/arr;
                LCD_ShowString(30,110,200,16,16,"PWM_TEST");
                LCD_ShowString(30,140,200,16,16,"当前频率:");                //显示PWM当前频率
                LCD_ShowString(60,140,200,16,16,&fre);                //显示PWM当前频率                  
                LCD_ShowString(30,180,200,16,16,"当前占空比:");                //显示PWM当前频率          
                LCD_ShowString(90,180,200,16,16,&duty_cycle);                //显示PWM当前频率                 
                LCD_ShowString(100,90,200,12,12,"2019/11/19");                                                       
                printf("It is OK!!\r\n");
                delay_ms(100);
                LED1 =!LED1;       //指示灯反转表示程序运行
        }
}

回复

使用道具 举报

15

主题

1061

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
3623
金钱
3623
注册时间
2019-8-14
在线时间
1054 小时
发表于 2020-7-26 16:50:04 | 显示全部楼层
仿真看看,在按下key0或者是key2的时候,代码是卡在哪里的,此时波形的情况
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
33
金钱
33
注册时间
2019-10-30
在线时间
6 小时
 楼主| 发表于 2020-7-26 20:44:53 | 显示全部楼层
hou18 发表于 2020-7-26 16:50
仿真看看,在按下key0或者是key2的时候,代码是卡在哪里的,此时波形的情况

目前还不会调试,在学习了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-4-30 19:42

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表