[学习笔记] AC7801:一个PWM同时做输入捕获和输出PWM

[复制链接]
 楼主| wangjj19950516 发表于 2021-11-1 16:01 | 显示全部楼层 |阅读模式
本帖最后由 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配置
  1. void GPIO_Config(void)
  2. {
  3.          GPIO_SetFunc(GPIOB, GPIO_PIN5, GPIO_FUN1);   //PWM1-CH0
  4.          GPIO_SetFunc(GPIOB, GPIO_PIN4, GPIO_FUN1);   //PWM1-CH1
  5. }
2.PWM模块配置
   PWM-CH0生成一个1KHZ频率的波形,模块时钟为24MHZ,2分频,所以最大计数值应为24000000/2/1000=12000;
   由于一个PWM模块只有一个计数器,所以作为输入通道的捕获值也只能从0计到12000
  1. //PWM模块初始化,CH0配置为输出,CH1配置为输入
  2. void PWM_Capture_Output_Init(void)
  3. {
  4.     PWM_DeInit(PWM1);//去初始化PWM0  
  5.     PWM_SimplyConfigType SimplyConfig;
  6.     PWM_inputChConfigType inputChConfig[1];//输入通道配置
  7.     PWM_inputCaptureConfigType inputCapconfig;//输入捕获结构体
  8.     PWM_ConfigType config; //PWM模块结构体
  9.         
  10.           //结构体数据清零
  11.     memset(&SimplyConfig, 0, sizeof(SimplyConfig));
  12.     memset(&inputChConfig, 0, sizeof(inputChConfig));
  13.     memset(&inputCapconfig, 0, sizeof(inputCapconfig));
  14.     memset(&config, 0, sizeof(config));
  15.         
  16.           //输出配置,
  17.     SimplyConfig.allChCombineMode = PWM_INDEPENDENT_MODE; //独立模式
  18.     SimplyConfig.countMode = PWM_UP_COUNT;   //向上计数
  19.     SimplyConfig.levelMode = PWM_HIGH_TRUE;               // PWM_HIGH_TRUE;
  20.     SimplyConfig.clkSource = PWM_CLK_SOURCE_APB;          // PWM_CLK_SOURCE_BUS;
  21.     SimplyConfig.chValue[0] = 2000;
  22.     PWM_SimplyInit(PWM1, &SimplyConfig);
  23.    
  24.     //输入通道结构体配置,如果有多个输入通道,更改结构体数组,在后面添加相关配置即可。
  25.     inputChConfig[0].channel = PWM_CH_1; //信号捕获通道
  26.     inputChConfig[0].mode = PWM_INPUTCAP_SINGLE_EDGE; //输入单通道捕获模式
  27.     inputChConfig[0].detectType = PWM_BOTH_EDGE_DETECT;//上升沿和下降沿捕获
  28.         
  29.     inputChConfig[0].onceMode = PWM_INPUTCAP_CONTINUOUS;//连续捕获
  30.     inputChConfig[0].filterEn = DISABLE;//使能输入滤波,CH0-CH3才有该功能
  31.     inputChConfig[0].filterValue = 0; //filterValue值范围0-31,输入信号将被延迟filterValue*4个总线时钟
  32.     inputChConfig[0].eventPsc = PWM_EVENT_PSC_1; //输入事件与通道中断的对应关系。PWM_EVENT_PSC_1表示1次输入事件产生一次通道中断,PWM_EVENT_PSC_4表示4次输入事件产生一次通道中断。
  33.     inputChConfig[0].interruptEn = ENABLE; //该通道输入捕获中断使能
  34.                
  35.     //输入捕获配置
  36.     inputCapconfig.channelNum = 1;
  37.     inputCapconfig.channelConfig = inputChConfig;//输入通道配置变量地址赋值。
  38.    
  39.     //PWM模块配置
  40.     config.mode = PWM_MODE_INPUT_CAPTURE;//PWM模块配置为输入捕获模式
  41.     config.initModeStruct = &inputCapconfig;//输入捕获配置变量赋值
  42.     config.clkSource = PWM_CLK_SOURCE_APB; //PWM时钟源配置
  43.     config.clkPsc = 1;//PWM时钟源分频
  44.     config.initValue = 0;//计数器初始寄存器值
  45.     config.maxValue = MAX_MOD; //PWM计数器最大值,输出和输入捕获的最大计数值一致,
  46.     config.overflowInterrupEn = ENABLE;//计数器溢出中断使能位
  47.     config.cntOverflowFreq = 0;//CNTOF中断产生的频率与计数器频率的关系(0-127), 0表示每次计数器溢出都产生溢出中断,1表示间隔1次,2表示间隔2次,以此内推。
  48.     config.interruptEn = ENABLE; //PWM中断使能
  49.     config.callBack = PWM_Capture_CallBack; //PWM中断回调

  50.     PWM_Init(PWM1, &config); //配置初始化生效

  51.     NVIC_SetPriority(PWM1_IRQn, 0); //设置PWM模块中断的优先级
  52. }
3.中断回调函数
  在中断函数中,计算CH1外部信号的频率和占空比,同时每次在溢出中断里修改CH0的占空比。
在计算捕获频率和占空比时,需要考虑数据溢出的情况,每次数据溢出后,判断之前的电平状态,如果之前是高电平,那么将高电平的溢出次数加1。当发生下降沿边沿捕获中断时,计算高电平时间需要用溢出次数*最大计数值(12000),再加上两次捕获值的差即可。
  1. uint16_t Freq =0;  //频率
  2. uint16_t Duty =0; //占空比
  3. void PWM_Capture_CallBack(void *device, uint32_t wpara, uint32_t lpara)
  4. {
  5.     static uint16_t value=0;
  6.     static uint32_t high_time=0;
  7.     static uint32_t Low_time =0;
  8.     static uint16_t high_over_cnt =0;
  9.     static uint16_t low_over_cnt =0;
  10.     static uint8_t pinlevel =0;
  11.     uint16_t  CountValue=0;
  12.     static uint16_t CountValue_Last =0;
  13.         
  14.     if(value < MAX_MOD)
  15.     {
  16.          value++;
  17.     }
  18.     else
  19.     {
  20.          value =0;
  21.     }
  22.     if (wpara & PWM_INIT_CNTOF_Msk)  //溢出中断
  23.     {
  24.          PWM_SetChannelCountValue(PWM1, PWM_CH_0, value) ;//修改PWM1-CH0占空比
  25.          if(pinlevel == 0)  //根据之前的电平状态,判断该溢出时间加在那个状态,避免溢出中断时电平发生跳变,导致时间计算错误
  26.          {
  27.               low_over_cnt++;
  28.          }
  29.          else
  30.          {
  31.               high_over_cnt ++;
  32.          }
  33.     }
  34.         
  35.     if (lpara & PWM_STR_CH1SF_Msk) //通道1中断
  36.     {
  37.          CountValue = PWM_GetChannelCountValue(PWM1, PWM_CH_1); //读取通道1的捕获数据
  38.                                 
  39.          if(GPIO_GetPinLevel(GPIOB, GPIO_PIN4)== GPIO_LEVEL_LOW)//下降沿,读出高电平时间
  40.          {
  41.               high_time = (uint32_t)(high_over_cnt)*MAX_MOD +  CountValue - CountValue_Last;
  42.               pinlevel = 0;  //低电平状态
  43.           }
  44.           else//上升沿,读出低电平时间
  45.           {
  46.                Low_time = (uint32_t)low_over_cnt * MAX_MOD + CountValue - CountValue_Last;
  47.                pinlevel =1;
  48.           }
  49.                                 
  50.          //频率和占空比计算
  51.          //PWM时钟24MHZ,2分频
  52.          Freq  = 24000000/2/(Low_time + high_time);
  53.          Duty = (high_time)*100/(Low_time + high_time);  
  54.          low_over_cnt =0;
  55.          high_over_cnt = 0;
  56.          CountValue_Last =  CountValue;
  57.      }
  58. }
二、测试结果
下图为测试结果,其中黄色波形为CH0生成的1KHZ频率的波形,绿色为外部输入信号,频率为152.7KZ,占空比为55%。在debug的watch窗口中可以看到,程序中计算得到的Freq为152,Duty为55,与实际相符。
dso_3.jpg
捕获.JPG

三、附件
    为了方便大家调试,这里把整个工程附上
pwm_捕获+输出.rar (586.42 KB, 下载次数: 50)


caigang13 发表于 2021-11-1 20:48 来自手机 | 显示全部楼层
下载看看,谢谢分享。
豌豆爹 发表于 2021-11-4 10:56 来自手机 | 显示全部楼层
下载看看,谢谢分享
您需要登录后才可以回帖 登录 | 注册

本版积分规则

24

主题

86

帖子

2

粉丝
快速回复 在线客服 返回列表 返回顶部