This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] CCS/EK-TM4C123GXL:启用多个计时器会导致事件捕获时序不准确

Guru**** 1794070 points
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/572169/ccs-ek-tm4c123gxl-enabling-multiple-timers-is-causing-inaccuracy-in-event-capture-timing

器件型号:EK-TM4C123GXL

工具/软件:Code Composer Studio

您好!

我一直在从事一个程序、此程序需要读取 PWM 输入信号的占空比并生成一个适当的比例输出信号。 该程序使用定时器0 (分为两个半宽定时器)捕捉 PWM 信号的上升沿和下降沿、并使用定时器1定期更新比例信号。 在调试时、我发现当定时器1未启用时、程序会完美地读取 PWM 信号。 当定时器0和1都被使能时、上升/下降沿的捕捉时间不会按照它们在给定 PWM 信号中的时间进行线性排列。

我粘贴了以下代码。 我是否可以更改任何内容来解决此问题?

#include 
#include 
include "inc/tm4c123gh6m.h"
#include "inc/hw_gpio.h"
#include "inc/hw_types.h"
#include


"volatile /hw_memmap.h"#include "driverlib/pvert/intrabe.h"







#include "driverlib/driver.h"#driveript/driveript.md小时#include "driveript/driveript.id.h"#include "driverlib#driveript.trategot.h"#include "driveript/driveript.in.id.idr.idr.ide"#include "driver.ide"#driveript/drive.tr.ide"#include "drive.tr.ide"#def"driver.ide"#include "drive.ipt/drive"drive.md.ipt.in.ide"#include "drive.in.ide"#drive.tr.ide"#include "drive.ipt.in.ide"#drive.in.idr.ide"#include




//如索引 volatile
int32_t error = 0;
volatile uint32_t index = 0;//跟踪 gait 数据
中的点 volatile int32_t PIDsignal = 0;//更改 goalpwmhigh
volatile uint32_t proportional = 50的信号;//来自 PID
volatile uint32_t goalpwmhigh = 2048; //占空比值、4096
个易失性 uint32_t goalDuty = 50;//占空比%
易失性 float rawgoalpos = 0;

//此块用于 PWMREAD
静态易失性 uint32_t periodStartTime = 0;
静态易失性 uint32_t
volatile EndTimePrevious= 0;静态易失性 uint32_t pulseperiod= 0
;静态易失性 uint32_t volatile Endpulse脉 冲宽度= 0;静态易失性
静态易失性 uint32_t periodWidth = 1;
静态易失性浮点 dutyCycle = 0;
静态易失性 uint32_t 编码值= 0;

void timer1ISR (void)
{
TimerIntClear (Timer1_base、timer_TValue_timeout);
rawgoalpos = getKneedData (index);
goalpos =(浮
点

=(浮点=) 2.88 (浮点=(浮点=)) 2、浮点=(浮点=(浮点=(浮点=)))-0.5);信号(浮点=(浮点=(浮点=(浮点=))-0.5)-0.5);rg
goalpwmhigh = 2048 + PIDsignal;
if (goalpwmhigh > 3696)
{
goalpwmhigh = 3696;
}
否则、if (goalpwmhigh < 410)
{
goalpwmhigh = 410;
}
goalDuty =(float) 100 *((float) goalpwmhigh/(float) 4096);setalpulsepalpwmhigh =





(index
= 0);index = 0)+(index = 1000);如果 index = 1000、则+(index = 1000)

}

void timerARisingISR (void)
{
//
计算周期宽度
//

//清除中断源
TimerIntClear (TIMER0_BASE、TIMER_CAP_EVENT);

//在事件触发时间
周期检索时钟计数 StartTime =((TIMER0_BASE、TIMER_A)<< 16);

//如果发生了计时器溢出,则在
以下情况下计算周期宽度:(periodStartTime < periodStartTimePreVent){
periodWidth = periodStartTime +(65536 - PeriodStartTimePreVent);
}
//如果自最后一个事件以来没有计时器溢出
,则计算周期宽度:{
periodWidth = StartTimeStartTimePreVent;
}

//计算占空比
dutyCycle =(((periodwidth)((periodwidth))

编码值=(dutyCycle *1024);


UARTprintf ("rising\n");
UARTprintf ("periodStartTime:%u\n"、periodStartTime);
UARTprintf ("periodStartTimePrevent:%u\n"、periodStartTimePrevent);

//将当前周期开始时间标记为旧
的 periodStartTimePrevent = periodStartTime;
}

void timerBFallingISR (void)
{
//清除中断源
TimerIntEndClear (TIMER0_BASE、TIMERCAPB_EVENT);TimerB<16


)、TimereTimerIntTimerIntTimerTimereTimerB (timerTimerTimerTimerB >);(timerTimereTimerTimerTimerTimereTimerTimerTimerTimerTimerTimerB)

//如果16位计时器溢出,则在
(pulseEndTime < periodStartTime){
pulsewidth = pulseEnd+(65536 - periodStartTime);
}
//如果计时器没有溢出
,则相应地计算脉冲宽度,否则{
pulsewidth = pulseEndTime - startTime;
}

Uprintf ("Falling\n");
UARTprintf ("%rtpulseTime):%printseTime


int main (void)
{
//将时钟设置为40MHz
SysCtlClockSet (SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_16MHz|SYSCTAL_OSC_MAIN);

//启用 UART0 SysCtlSysCtlUSPELEnable
(SYSCL_UART0);

//
启用 SysCtlSysCtlSysPeriph_GPIOPTL (SYSC_GPIOPTL);//


启用 GPIOPTL 外设 和 GPIO 端口 B 和 F
SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF);

//等待 TIMER0模块就绪
while (!CCPt1_PPT7_GPIO6)
;








配置 GPIOPTMCTTimer_P0_PIN_CAPT0_GPIO7 (Timer_PPT0_GPIO7);//为 GPIO6)

//将 TimerA 配置为半宽单次触发定时器,将 TimerB 配置为//
半宽边沿捕获计数器。
TimerConfigure (TIMER0_BASE、(TIMER_CFG_SPLIT_PAIR | TIMER_CFG_A_CAP_TIME_UP | TIMER_CFG_B_CAP_TIME_UP);

// TIMER_CLOCK_SYSTEM:使用40MHz 系统时钟
// TIMER_CLOCK TIOSC:使用16MHz 精密内部振荡器作为计时信号
//似乎不是 TIMERC123GMCK_TIME_CLOCK 系统时钟选项
;TIMERC123GRTINSGC0 (TIMERCLOCK)

//为 timerA 和 timerB 设置预分频器值以确保溢出发生的速度比 PWM 周期慢
//计时器频率当前设置为10MHz
//出于某种原因,现在无法正常工作,计时器仍以40MHz 运行
//TimerPrescaleSet (TIMER0_BASE、TIMER_Both、4);

//将 TimerA 配置为标记上升沿的时间,将 TimerB 配置为标记下降沿的时间
TimerControlEvent (TIMER0_BASE、TIMER_A、TIMER_EVENT_POS_EDGE);
TimerControlEvent (TIMER0_BASE、TIMER_B、 Timer_EVENT_NEG_EDGE);

//清除两个中断
TimerIntClear (TIMER0_BASE、TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);

//寄存器计时器中断服务例程
// TIMERIntRegister (TIMER0_BASE、TIMER_A、* TIMERARisingISR);
// TIMER0_BASE、TIMER0_BASE (TIMER0寄存器) * timerBFallingISR);

//为两个计时器启用中断,A 检测上升沿,B 检测下降沿
TimerIntEnable (TIMER0_BASE,TIMER_CAPA_EVENT | TIMER_CAPB_EVENT);

//为 timerA 和 timerB
IntEnable (INT_TIMER0A)启用中断;
IntCtl(INT_CAMP_EVENT)


;Timer1 (TIMERB) Timer1 (TSYSRB_启用中断;Timer1)

//等待定时器模块1准备就绪
while (!SysCtlPeripheralReady (SYSCTL_Periph_Timer1)
){
//

配置一个全宽定时器,递减计数
TimerConfigure (Timer1_base、timer_CFG_PERIODICRAY);

//将定时器1设置为从系统时钟
TimerClockSet (Timer1_base、Timer100Hz)运行;//将 TimerBlockTimerSet

(TimerSet (Timer1_base
)、TimerTimer100Hz)设置为系统时钟源计时器1;TimerTimer100Hz

//注册定时器中断服务例程
TimerIntRegister (Timer1_base、timer_A、* timer1ISR);

//清除翻转中断,然后将其启用
TimerIntClear (Timer1_base、timer_TINA_timeout);
TimerIntEnable (Timer1_base、timer_TIMA_TIMEOUT);

IntEnable (TIMER_TIMER_TIMEOUT);

//为 UART
GPIOPinConfigure (GPIO_PA0_U0RX)、
GPIOPinConfigure (GPIO_PA1_U0TX)、
GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1)配置 GPIO 引脚;

//使用内部16MHz 振荡器作为 UART 时钟源。
UARTClockSourceSet (UART0_BASE、UART_CLOCK_PIOSC);

//初始化控制台 I/O 的 UART
UARTStdioConfig (0、921600、16000000);


GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_3);
GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_3、GPIO_PIN_3);

IntMasterEnable ();

//同步计时器 A 和计时器 B 以在相同的时钟周期启动
TimerSynchronize (TIMER0_BASE、TIMER0A_SYNC | TIMER_0B_SYNC);

//启动计时器
TimerTimerTimerEnable (TIMER1)
;

while (TIMER1和 NOT_BASE)


;}Timer1 (TIMER1 (while)
} 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好 Thomas

    我已将该帖子分配给相关的 SME、以帮助您解决问题。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

    第一步:从中断例程中删除所有 UARTPrintf 语句。 使用实数调试、断点、而不是 UARTPrintf。 切换 GPIO 引脚。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Thomas:
    您能不能说出预期的输入频率是多少? 在 Timer1禁用的情况下、您使用 timer0捕获了什么占空比? 与启用 Timer1相比、关闭多少?
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    你好。

    删除 UART print 语句解决了问题、谢谢。 我们正在读取的信号的频率约为1kHz。 我们测量了 ISR 的长度、发现 UART 语句导致它们超限我们的 PWM 周期。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    尊敬的 Thomas:
    很高兴您找到了根本原因。 这当然是论坛社区的一个好建议。 您正在尝试通过 UART 打印 ISR 内部的以下三个字符串、地址为921600。 这三个字符串大约为50个字符或400位。 每个位时间为1/921600秒。 对于400位、可能需要超过1KHz 的时间。

    UARTprintf ("rising\n");
    UARTprintf ("periodStartTime:%u\n"、periodStartTime);
    UARTprintf ("periodStartTimePrevent:%u\n"、periodStartTimePrevent");