IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> TM4C123系列(六)————timer定时器(capture边沿计时实现输入捕获PWM频率和占空比) -> 正文阅读

[嵌入式]TM4C123系列(六)————timer定时器(capture边沿计时实现输入捕获PWM频率和占空比)

首先感谢我姐送来的耳机(血脉压制,被逼的),再顺便给我姐捞个男朋友(诚心)。

一.实验简介

通过定时器的capture模式中的边沿计时模式,实现输入捕获PWM的频率和占空比。

二.板载定时器介绍(capture-边沿计时)

定时器模块可以捕捉上升沿,下降沿,在边沿到来时记录计数值,用来测定脉冲间的时间间隔。加计时的计时范围是从0到用户的预设值,减计时的范围为从预设值减到0,预设值可以通过TimerLoadSet函数进行设置。但是在此模式中不需要设置,如果在不设置preload的情况下也没有启用预分频器,那么预设值将默认为是2^16=0xffff,如果启用了预分频器,那么预设值将变为2^24。

对于加计时来说,加到preload后将会重置为0重复之前的工作,减计时也是,减到0后会重置到preload然后重复之前工作。

每当边沿到来,定时器模块会产生中断并记录当前计时值。可以通过计时值计算频率,占空比。

注意输入捕获只能在定时器拆分的情况下使用。

三.引脚图

?使用PF2作为PWM输出引脚,使用PB6作为输入捕获的引脚。

四.所需函数

有关串口GPIOPWM还有timer中已经用过的函数不在提起,有问题的可以去看我之前的博客

1.GPIOPinTypeTimer(uint32_t ui32Port, uint8_t ui8Pins)

参数:ui32Port为GPIO基地址,ui8Pins为外设引脚

作用:分配定时器信号

2.TimerControlEvent(uint32_t ui32Base, uint32_t ui32Timer,uint32_t ui32Event)

参数:ui32Base为定时器基地址,ui32Timer为定时器中的模块,ui32Event为捕捉边沿

作用:设置输入捕获的捕捉边沿

3.TimerValueGet(uint32_t ui32Base, uint32_t ui32Timer)

参数:ui32Base为定时器基地址,ui32Timer为定时器中的模块

作用:获取特定引脚的计时值。

4.TimerIntEnable(uint32_t ui32Base, uint32_t ui32IntFlags)

参数:ui32Base为定时器基地址,ui32IntFlags为中断模式

//! - \b TIMER_TIMB_DMA - Timer B uDMA complete
//! - \b TIMER_TIMA_DMA - Timer A uDMA complete
//! - \b TIMER_CAPB_EVENT  - Capture B event interrupt
//! - \b TIMER_CAPB_MATCH  - Capture B match interrupt
//! - \b TIMER_TIMB_TIMEOUT  - Timer B timeout interrupt
//! - \b TIMER_RTC_MATCH  - RTC interrupt mask
//! - \b TIMER_CAPA_EVENT  - Capture A event interrupt
//! - \b TIMER_CAPA_MATCH  - Capture A match interrupt
//! - \b TIMER_TIMA_TIMEOUT  - Timer A timeout interrupt

?如果是普通定时器模式就设置为TIMOUT,如果是capture的边沿计数就是match,如果是边沿计时就是EVENT

作用:使能中断模式

五.代码及讲解

usart.c
#include "usart.h"
#include "uart.h"
#include "gpio.h"
#include "sysctl.h"
#include "pin_map.h"
#include "hw_memmap.h"
#include "uartstdio.h"
//配置串口,有问题的去看我之前博客
void USART_Config(void)
{
    SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOA);
	SysCtlPeripheralEnable( SYSCTL_PERIPH_UART0);
	GPIOPinConfigure( GPIO_PA0_U0RX);
	GPIOPinConfigure( GPIO_PA1_U0TX);
	GPIOPinTypeUART( GPIO_PORTA_BASE,  GPIO_PIN_0);
	GPIOPinTypeUART( GPIO_PORTA_BASE,  GPIO_PIN_1);
	UARTClockSourceSet( UART0_BASE,  UART_CLOCK_PIOSC);
	UARTStdioConfig( 0,  115200,
                             16000000);
}
usart.h
#ifndef __USART_H
#define __USART_H
void USART_Config(void);
#endif
pwm_out.c
#include "gpio.h"
#include "pin_map.h"
#include "pwm_out.h"
#include "sysctl.h"
#include "pwm.h"
#include "hw_memmap.h"
//配置PWM输出,有问题的看我之前博客
void PWM_OUT_Config(void)
{
    SysCtlPWMClockSet( SYSCTL_PWMDIV_4);
    SysCtlPeripheralEnable( SYSCTL_PERIPH_GPIOF);
	SysCtlPeripheralEnable( SYSCTL_PERIPH_PWM1);
	GPIOPinTypePWM( GPIO_PORTF_BASE,  GPIO_PIN_2);
	GPIOPinConfigure( GPIO_PF2_M1PWM6);
	PWMGenConfigure( PWM1_BASE,  PWM_GEN_3,
                             PWM_GEN_MODE_DOWN|PWM_GEN_MODE_NO_SYNC);
	PWMGenPeriodSet( PWM1_BASE,  PWM_GEN_3,
                             2000);
	PWMPulseWidthSet( PWM1_BASE,  PWM_OUT_6,
                              PWMGenPeriodGet(PWM1_BASE, PWM_GEN_3)*0.5 - 1);
	PWMOutputState( PWM1_BASE,  PWM_OUT_6_BIT,
                            true);
	PWMGenEnable( PWM1_BASE,  PWM_GEN_3);
}
pwm_out.h
#ifndef __PWM_OUT_H
#define __PWM_OUT_H
void PWM_OUT_Config(void);
#endif
pwm_in.c
#include "pwm_in.h"
#include "gpio.h"
#include "sysctl.h"
#include "hw_memmap.h"
#include "pin_map.h"
#include "hw_ints.h"
#include "uartstdio.h"
#include "timer.h"
_Bool flag=0;
uint32_t zhouqi=0;
uint32_t freq=0;
_Bool uart_flag=0;
_Bool led_flag=0;
 uint32_t capture_1=0,capture_2=0,capture_3=0;
 uint32_t timer_flag=0;
 uint32_t duty=0;
 uint32_t up_count=0,down_count=0;
void PWM_IN_IRQHandler(void);
void TIMER_WID_IRQHandler(void);
//配置输入捕获引脚
void PWM_IN_Config(void)
{
    //使能定时器与GPIO
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);
    //使能引脚复用
	GPIOPinConfigure(GPIO_PB6_T0CCP0);
    //分配引脚信号
	GPIOPinTypeTimer(GPIO_PORTB_BASE, GPIO_PIN_6);
    //设置引脚方向,注意虽然这是输入捕获,但是这是由外界的PWM信号控制,属于硬件控制,要设置为GPIO_DIR_MODE_HW
	GPIODirModeSet( GPIO_PORTB_BASE,  GPIO_PIN_6,
                            GPIO_DIR_MODE_HW);
    //设置为推挽上拉输入
	GPIOPadConfigSet( GPIO_PORTB_BASE,  GPIO_PIN_6,
                              GPIO_STRENGTH_2MA,  GPIO_PIN_TYPE_STD_WPU);
    //因为是输入捕获,只有在拆分模式下可以用输入捕获,所以将TIMER_CFG_SPLIT_PAIR与A周期计数进行或运算
	TimerConfigure( TIMER0_BASE,  TIMER_CFG_SPLIT_PAIR|TIMER_CFG_A_CAP_TIME_UP);
	//设置为上升沿触发
	TimerControlEvent( TIMER0_BASE,  TIMER_A,
                               TIMER_EVENT_POS_EDGE);
    //注册中断函数
	TimerIntRegister( TIMER0_BASE,  TIMER_A,
                             PWM_IN_IRQHandler);
    //设置中断优先级
	IntPrioritySet( INT_TIMER0A,
                            0);
    //使能定时器中断的计时中断
	TimerIntEnable( TIMER0_BASE,  TIMER_CAPA_EVENT);
    //使能中断
	IntEnable( INT_TIMER0A);
	IntMasterEnable();
	TimerEnable( TIMER0_BASE,  TIMER_A);
    /*设置装载值,在边沿计时模式下可以省略,会自己填入默认值。
    如果设置了预分频值,那么默认装载值就是2^24,如果没有预分频值,那么默认装载值就是2^16。
    相当于STM32中使用了oc——toggle模式,默认预装载值填写65535*/
    //TimerLoadSet(TIMER0_BASE, TIMER_A, Capture_LoadSet);
}
//输入捕获中断
void PWM_IN_IRQHandler(void)
{
    //读取中断状态
    uint32_t status=TimerIntStatus( TIMER0_BASE,  true);
    //清除中断标志位
	TimerIntClear( TIMER0_BASE,  status);
    //第一次进中断是由于检测到了上升沿,然后将计时值读取,并将边沿检测变为下降沿
	if(timer_flag==0)
	{
		TimerControlEvent( TIMER0_BASE,  TIMER_A,
                               TIMER_EVENT_NEG_EDGE);
		capture_1=TimerValueGet( TIMER0_BASE,  TIMER_A);
		timer_flag=1;
	}
    //第二次进中断是因为检测到了下降沿,然后将计时值读取,这时就已经获得了高电平数,
    //可以计算出占空比,并将边沿检测变为上升沿
	else if(timer_flag==1)
	{
		TimerControlEvent( TIMER0_BASE,  TIMER_A,
                               TIMER_EVENT_POS_EDGE);
		capture_2=TimerValueGet( TIMER0_BASE,  TIMER_A);
		timer_flag=2;
	}
    //第三次进中断时因为检测到了上升沿,至此,已经检测到了两个上升沿,也就可以得到周期值
	else if(timer_flag==2)
	{
	    timer_flag=0;
		capture_3=TimerValueGet( TIMER0_BASE,  TIMER_A);
        /* ____   ___ capture_1相当于检测到第一个上升沿记的数,
           |  |   |   capture_2相当于检测到第一个下降沿记的数
          _|  |___|   所以capture_2与capture_1之间即为高电平数
        capture_3相当于检测到第二个上升沿记的数,所以capture_3与capture_1之间为周期数*/
        /*  /|   /| 现在要求占空比和频率,因为设置的是定时器A周期性加计数,
           / |  / | 定时器A记的数先到最大然后再从0开始计数,现在通过求高电平和低电平时间来计算
          /  | /  | 如果capture_1与capture_2都在第一个计数周期的上升阶段,那1与2的差就是高电平
         /   |/   | 如果1与2分别落在两个周期的上升阶段,那高电平就要通过0xffff-capture_1+capture_2获得。
        如果capture_2与capture_3都在第一个计数周期的上升阶段,那2与3的差就是低电平,
        如果分别落在两个周期上升阶段,低电平就要通过0xffff-capture_2+capture_3来获得*/
		if(capture_2>capture_1)
		{
		    up_count=capture_2-capture_1;
		}
		else
		{
		    up_count=0xffff-capture_1+capture_2;
		}
		if(capture_3>capture_2)
		{
		    down_count=capture_3-capture_2;
		}
		else 
		{
		    down_count=0xffff-capture_2+capture_3;
		}
        //频率用主频除周期即可得到
		freq=SysCtlClockGet()/(up_count+down_count);
        //占空比为高电平占周期的比值即可得到
		duty=up_count*100/(up_count+down_count);
	}
}

void Timer_Wid_Config(void)
{
    //使能32/64bit定时器
    SysCtlPeripheralEnable(SYSCTL_PERIPH_WTIMER0);
    //使能复用
	TimerConfigure(WTIMER0_BASE,TIMER_CFG_PERIODIC_UP);
    //设置预装载值,使1s进一次中断
	TimerLoadSet64( WTIMER0_BASE,  SysCtlClockGet()/1000-1);
	//使能定时器A超时中断
	TimerIntEnable( WTIMER0_BASE,  TIMER_TIMA_TIMEOUT);
    //注册中断函数
	TimerIntRegister( WTIMER0_BASE,  TIMER_A,
                             TIMER_WID_IRQHandler);
    //设置优先级
	IntPrioritySet( INT_WTIMER0A,  1);
    //设置中断
	IntEnable( INT_WTIMER0A);
	IntMasterEnable();
	TimerEnable( WTIMER0_BASE,  TIMER_A);
}
void TIMER_WID_IRQHandler(void)
{
    static uint32_t time_count=0;
	
    uint32_t status=TimerIntStatus( WTIMER0_BASE,  true);
	TimerIntClear( WTIMER0_BASE,  status);
	
	time_count++;
    //1s打印一次,但是不知道为什么用UARTprintf打印一次就不打印了,我还在改进,但是输入捕获那块是没问题的
	if(time_count==1000)
	{
	    time_count=0;
		UARTprintf("duty:%d", duty);
        UARTprintf("freq:%d", freq);
	}
}
pwm_in.h
#ifndef __PWM_IN_H
#define __PWM_IN_H
#include <stdint.h>
extern _Bool uart_flag;
extern uint32_t zhouqi;
extern uint32_t freq;
extern _Bool led_flag;
void PWM_IN_Config(void);
void PWM_IN_IRQHandler(void);
void Timer_Wid_Config(void);
void TIMER_WID_IRQHandler(void);
#endif
main.c
#include "tm4c123gh6pm.h"
#include <stdint.h>
#include <stdbool.h>
#include "inc/hw_sysctl.h"
#include "inc/hw_gpio.h"
#include "inc/hw_memmap.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "pwm_in.h"
#include "pwm_out.h"
#include "usart.h"
#include "uartstdio.h"
void main(void)
{
	SysCtlClockSet( SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|SYSCTL_OSC_MAIN);
	PWM_OUT_Config();
	PWM_IN_Config();
    USART_Config();
	Timer_Wid_Config();
	while(1)
	{

	}
}

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-07-17 16:39:38  更:2022-07-17 16:43:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 23:11:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码