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.

[参考译文] RTOS/TM4C123GH6PM:QEI 多路复用

Guru**** 2608865 points
Other Parts Discussed in Thread: TM4C123GH6PM

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/755087/rtos-tm4c123gh6pm-qei-multiplexing

器件型号:TM4C123GH6PM

工具/软件:TI-RTOS

尊敬的所有人:

我使用的是 TM4C123GH6PM、CCSv8.1.0、TI-RTOS - 2.16.00.08

根据我的项目要求、我必须使用8个 QEI。 但 TM4C123GH6PM 能够提供2个 QEI。 是否可以将正常 GPIO 引脚设置为 QEI 以支持剩余6个 QEI。 如果不是、我如何解决这个问题。 请就此向我建议一个解决方案。

我尝试将4个电机的霍尔传感器多路复用为 QEI0、将其他4个电机的霍尔传感器多路复用为 QEI1。
但出于某种原因、我的多路复用器无法正常工作。

过去10天我一直在尝试解决这个问题,但我没有找到所需的解决方案。(现在我想我的方向是错误的)。
解决这一问题确实需要您的帮助。

提前感谢

此致、

Yashwanth Kumar Gandeti

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    //
    *版权所有(c) 2015,Texas Instruments Incorporated
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    *源代码的重新分发必须保留上述版权
    声明*、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须在
    
    *随发行提供的文档和/或其他材料中复制上述版权声明、本条件列表和以下免责声明。
    *
    ***未经
    
    事先书面许可、不得使用德州仪器公司的名称或*其贡献者的名称认可或推广从本软件衍生的产品*。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    //
    
    /*
    === pwmled.c ===
    //
    //* XDCtools 头文件*/
    #include 
    #include 
    #include //用于 Timestamp()调用
    #include //用于时钟调用
    #include 
    
    /* TivaWare 头文件*/
    #include 
    #include 
    #include "driverlib/sysctl.h"
    #include "inc/hw_memmap.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/QEI.h"
    
    /* BIOS 头文件*/
    #include 
    #include 
    #include 
    
    /* TI-RTOS 头文件*/
    #include 
    #include 
    
    
    
    /*示例/板头文件*/
    #include "Board.h"
    
    
    #define TASKSTACKSIZE 512
    
    Task_Structk0Struct;
    UINT8 tsk0Stack[TASKSTACKSIZE];
    Task_Handle 任务;
    Event_Handle myEvt;
    Semaphore_Structure_Structuresem0Struct, sem1Struct;
    semaphore_handle semHandle;
    Event_StructevStructStructStructStructStructStructStruct;
    
    volatile long enc_count = 0;
    long timeNew;
    long timeOld;
    long timeDelta;
    /*
    === pwmLEDFxn ===
    *任务会定期增加板载 LED 的 PWM 占空比。
    //
    void pwmLEDFxn (UArg0、UArg0 arg1)
    {
    PWM_Handle pwm1;
    PWM_Handle pwm2 =空;
    PWM_PARAMS 参数;
    uint32_t pwmPeriod = 50; //以微秒为单位的周期和占空比
    uint16_t Duty = 0;
    uint16_t dutyInc = 1;
    
    PWM_PARAMS_INIT (params);
    params.period = pwmPeriod;
    pwm1 = PWM_OPEN (Board_PWM0、params);
    if (pwm1 = NULL){
    System_abort ("Board_PWM0未打开");
    }
    
    if (Board_PWM1!= Board_PWM0){
    params.polarity = PWM_POL_ACTIVE_LOW;
    pwm2 = PWM_OPEN (Board_PWM1、params);
    if (pwm2 =NULL){
    System_abort ("Board_PWM1未打开");
    }
    }
    
    /*循环永远递增 PWM 占空比*/
    while (1){
    PWM_setDuty (pwm1、占空比);
    if (pwm2){
    PWM_setDuty (pwm2、Duty);
    }
    
    Duty =(Duty + dutyInc);
    if (Duty =pwmPeriod ||(!Duty)){
    dutyInc =- dutyInc;
    }
    
    Task_sleep ((UINT) arg0);
    }
    }
    
    void QEITaskFxn (UARg arg0、UARg arg1)
    {
    uint32_t qeVelocity1 = 0;
    uint32_t qePosition1 = 0;
    int32_t qeDirection1 = 0;
    
    uint32_t qeVelocity2 = 0;
    uint32_t qePosition2 = 0;
    int32_t qeDirection2 = 0;
    
    //禁用正交编码器。
    QEIDisable (QEI0_BASE);
    
    QEIConfigure (QEI0_BASE、(QEI_CONFIG_CAPTURE_A_B | QEI_CONFIG_NO_RESET | QEI_CONFIG_POSION_SWAP)、1000);
    
    //配置速度。
    QEIVelocityConfigure (QEI0_BASE、QEI_VELDIV_1、20000000);
    
    //注意:对于计算"ui32Period",TM4C123GH6PM 支持80 MHz 运行,因此我必须采用
    // ui32Period = 1/4 (80MHz)= 20000000
    
    //设置位置。
    QEIPositionSet (QEI0_BASE、0);
    
    //启用正交编码器速度。
    QEIVelocityEnable (QEI0_BASE);
    
    //启用正交编码器。
    QEIEnable (QEI0_BASE);
    
    //延迟一段时间...
    Task_sleep (1000);
    
    while (1)
    {
    发布了 UINT;
    布置= Event_pend (myEvt、Event_ID_none、Event_ID_00+Event_ID_01+Event_ID_02、BIOS_Wait_Forever);
    if (发布&& Event_ID_00)
    {//读取编码器位置。
    qePosition1 = QEIPositionGet (QEI0_BASE);
    System_printf ("\r\nqePosition1 ={%d}\r\n"、qePosition);
    system_flush();
    
    //读取编码器方向。
    qeDirection1 = QEIDirectionGet (QEI0_BASE);
    System_printf ("\r\nqeDirection1 ={%d}\r\n"、qeDirection);
    system_flush();
    
    //读取编码器速度。
    qeVelocity1 = QEIVelocityGet (QEI0_BASE);
    System_printf ("\r\nqeVelocity1 ={%d}** \r\n"、
    qeiVelocity);
    system_flush();
    }
    if (发布&& Event_ID_01)
    {//读取编码器位置。
    qePosition2 = QEIPositionGet (QEI0_BASE);
    System_printf ("\r\nqePosition2 ={%d}\r\n"、qePosition);
    system_flush();
    
    //读取编码器方向。
    qeDirection2=QEIDirectionGet (QEI0_BASE);
    System_printf ("\r\nqeDirection2 ={%d}\r\n"、qeDirection);
    system_flush();
    
    //读取编码器速度。
    qeVelocity2 = QEIVelocityGet (QEI0_BASE);
    System_printf ("\r\nqeVelocity2 ={%d}** \r\n"、
    qeiVelocity);
    system_flush();
    }
    
    
    Task_sleep (100);
    }
    
    }
    
    void encoder_isr0 (unsigned int index){
    GPIOPinWrite (GPIO_PORTD_BASE、GPIO_PIN_6、(GPIOPinRead (GPIO_PORTD_BASE、GPIO_PIN_2)& GPIO_PIN_2));
    GPIOPinWrite (GPIO_PORTD_BASE、GPIO_PIN_7、(GPIOPinRead (GPIO_PORTD_BASE、GPIO_PIN_3)& GPIO_PIN_3));
    EVENT_POST (myEvt、Event_ID_00);
    }
    void encoder_isr1 (unsigned int index){
    GPIOPinWrite (GPIO_PORTD_BASE、GPIO_PIN_6、(GPIOPinRead (GPIO_PORTB_BASE、GPIO_PIN_2)& GPIO_PIN_2));
    GPIOPinWrite (GPIO_PORTD_BASE、GPIO_PIN_7、(GPIOPinRead (GPIO_PORTB_BASE、GPIO_PIN_3)& GPIO_PIN_3));
    Semaphore_post (semHandle);
    }
    
    /*
    === main ====
    */
    int main (void)
    {
    Task_Params tskParams;
    Semaphore_Params semParams;
    
    /*呼叫板初始化功能。 *
    Board_initGeneral();
    Board_initGPIO();
    Board_initPWM();
    
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOD);
    SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
    
    //第一个电机的 QEI
    GPIOPinTypeGPIOInput (GPIO_PORTD_BASE、GPIO_PIN_2);
    GPIOPinTypeGPIOInput (GPIO_PORTD_BASE、GPIO_PIN_3);
    
    GPIO_setCallback (ENCODER_PHA0、ENCODER_ISR0);// ENCODER_PHA0 => GPIOTIVA_PD_2 | GPIO_CFG_IN_pu | GPIO_CFG_IN_INT_INT_ALTERY_FET_FETS_FEART_BRes
    GPIO_setCallback (ENCODER_PHB0、ENCODER_ISR0);// ENCODER_PHB0 => GPIOTIVA_PD_3 | GPIO_CFG_IN_pu | GPIO_CFG_IN_INT_INT_ALTER_REG_BY_ART_边沿
    
    //启用中断
    GPIO_enableInt (编码器_PHA0);
    GPIO_enableInt (编码器_PHB0);
    
    
    
    //第二个电机的 QEI
    GPIOPinTypeGPIOInput (GPIO_PORTB_BASE、GPIO_PIN_2);
    GPIOPinTypeGPIOInput (GPIO_PORTB_BASE、GPIO_PIN_3);
    
    GPIO_setCallback (ENCODER_PHA1、ENCODER_ISR1);// ENCODER_PHA1 => GPIOTIVA_PB_2 | GPIO_CFG_IN_pu | GPIO_CFG_IN_INT_INT_ALTER_REQ
    GPIO_setCallback (ENCODER_PHB1、ENCODER_ISR1);// ENCODER_PHB1 => GPIOTIVA_PB_3 | GPIO_CFG_IN_PU| GPIO_CFG_IN_INT_INT_INT_ALTER_REGPT_FET_ART_BYESS_PERANT
    
    //启用中断
    GPIO_enableInt (编码器_PHA1);
    GPIO_enableInt (编码器_PHB1);
    
    
    //启用 QEI 外设
    SysCtlPeripheralEnable (SYSCTL_Periph_QEI0);
    
    //将引脚设置为 PHA0和 PH0
    GPIOPinConfigure (GPIO_PD6_PHA0);
    GPIOPinConfigure (GPIO_PD7_PHB0);
    
    //设置 QEI 的 GPIO 引脚
    GPIOPinTypeQEI (GPIO_PORTD_BASE、(GPIO_PIN_6 | GPIO_PIN_7));
    
    
    /*构造 LED 任务线程*/
    Task_Params_init (&tskParams);
    tskParams.STACKSIZE = TASKSTACKSIZE;
    tskParams.stack =&tsk0Stack;
    tskParams.arg0 = 50;
    tskParams.priority = 1;
    Task_construct(&tsk0Struct,(Task_FuncPtr) pwmLEDFxn、&tskParams、NULL);
    
    event_construct(&evtStruct, NULL);
    
    /*获取事件实例句柄*/
    myEvt = Event_Handle (&evtStructStruct);
    
    Semaphore_Params_init (semParams);
    semParams.mode = Semaphore_Mode_binary;
    semParams.event = myEvt;
    semParams.EventID = Event_ID_01;
    Semaphore_construction (&sem0Struct, 0, semParams);
    
    semHandle = semaphore_handle (&sem0Structt);
    
    
    /*打开用户 LED */
    GPIO_WRITE (Board_LED0、Board_LED_ON);
    
    system_printf ("启动示例\n 系统提供程序设置为 SysMin。 "
    "停止目标以查看 ROV 中的任何 SysMin 内容。\n");
    
    /* SysMin 仅在您调用 flush 或 exit 时才会打印到控制台*/
    system_flush();
    
    SysCtlClockFreqSet (SYSCTL_XTAL_12MHz | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN、8000000);
    /*启动 BIOS */
    BIOS_start();
    
    返回(0);
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我忘记在帖子中附加代码。

    在上述代码中、我尝试对2个电机的 PhA 和 PhB 通道进行多路复用。
    明智的做法:
    1、电机1 PhA 被分配给 PD2、PhB 被分配给 PD3并配置为在两个边沿上产生中断。
    在 ENCODER_ISR0 ()中-将 PD2值写入 PD6 (QEI0 PhA 引脚)、将 PD3值写入 PD7 (QEI0 PhB 引脚)
    已过帐事件_ID_00。
    同样、ENCODER_ISR1()也发布了一个 Event_ID_01。
    5.QEITaskFxn 被设置为等待这些事件中的任何一个、并且基于到达事件将所需的值分配给变量(速度、方向、位置)。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好、Yashwanth、

    我还不知道您是如何添加多路复用器的。 当我提出这一建议时、我指的是由 MCU 控制的外部硬件、通过四个通道之一发送 QEI 信号。 它将是1个输入(QEI 信号)和4个输出、输出选择由2个 GPIO 选择引脚控制。

    然后、您的软件中将有一个逻辑电路、用于循环每个多路复用器输出一次一个、以控制每个电机。

    我没有看到这种逻辑已经落实到位、因此您尝试做的事情不起作用也不会让我感到意外。

    对于这个问题、我没有其他任何可做的事情、因为您的问题是特定于应用的、而不是与器件相关的、不过我希望我对多路复用器设置的解释证明是有价值的。