打印
[其他]

HC32F4正交编码计数 HC32F4外部计数

[复制链接]
1883|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
qcliu|  楼主 | 2023-10-18 13:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
HC32F4不依赖中断的定时器外部计数模式,建议使用TIMA 的TRIG外部输入,以及正交编码计数模式,这两个都是外部计数,正交编码模式为正反向计数,计数器均为16位,测试使用 TIMA_3 电机编码器 正交编码器 TIMA_6_TRIG 外部计数器。


/*************************************************************************************************************************
* 函数                        :        void BSP_OuaEncoderInit(void)
* 功能                        :        正交编码计数器初始化(TIMA_3)
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-10-20
* 最后修改时间         :         2022-10-20
* 说明                        :        需要先初始化定时器
*************************************************************************************************************************/
void BSP_OuaEncoderInit(void)
{
        static IRQn_Type INT_IRQ_n = INTC_MALLOC_INVALID_IRQn;        //值允许0-31,超出的算无效值

        Encoder_BottomHardwareIoInit();                                //编码器IO初始化
        SYS_DeviceClockEnable(DEV_TIMERA_3, TRUE);        //使能timA_3时钟
       
        TMRA3->BCSTR = 0;                                                        //关闭定时器
        TMRA3->BCSTR = BIT1;        //溢出后继续,锯齿波模式,向上计数,定时器关闭
        TMRA3->ICONR = 0;                //关闭所有匹配中断
        TMRA3->ECONR = 0;                //事件输出关闭

        TMRA3->FCONR = 0;                //关闭滤波
        TMRA3->CNTER = 0x8000;        //计数器值
        TMRA3->PERAR = U16_MAX;        //周期基准值-计数器到这个值就溢出
        TMRA3->HCONR = 0;                //硬件触发事件选择寄存器
        TMRA3->HCUPR = BIT7;                //TIMA_<t>_CLKB端口为高电平时, TIMA_<t>_CLKA端口上采样到下降沿 条件匹配时,硬件递加有效
        TMRA3->HCDOR = BIT6;                //TIMA_<t>_CLKB端口为高电平时, TIMA_<t>_CLKA端口上采样到上升沿 条件匹配时,硬件递减有效
        //如果直接使用上溢出或者下溢出,可能存在竞争冲突,导致编码器值异常突变,此处使用2个比较寄存器,提前进行将编码器值复位,防止溢出
        TMRA3->CMPAR[0] = 3000;                        //下比较直,大概提前一圈;
        TMRA3->CMPAR[1] = 0xFFFF-3000;        //上比较值,大概提前一圈;
        TMRA3->ICONR = BIT0 | BIT1;                //使能2个比较中断

        if (INT_IRQ_n == INTC_MALLOC_INVALID_IRQn)                                                                                                                                                //无效,没有申请
        {
                INT_IRQ_n = INTC_MallocIRQn();                                                                              //获取空闲的中断服务号(只支持0-31),如果返回Int032_IRQn则为无效
        }
        if (INT_IRQ_n != INTC_MALLOC_INVALID_IRQn)                                                                                                                                                //申请成功了
        {
                INFO_S("TMRA3获取中断服务号:%d\r\n", INT_IRQ_n);
                INTC_RegisterIRQHandler(INT_IRQ_n, SYS_INT_TMRA3_CMP, TMRA3_CMP_IRQHandler);                                                                //注册中断服务程序
                INTC_IntEnable(INT_IRQ_n, TRUE);                                                                                                                                                        //中断线开关,只支持0-31中断线开关控制

                NVIC_ClearPendingIRQ(INT_IRQ_n);
                NVIC_SetPriority(INT_IRQ_n, 3);
                NVIC_EnableIRQ(INT_IRQ_n);
        }
        else
        {
                ERROR_S("TMRA3获取中断服务号失败\r\n");
        }

        TMRA3->BCSTR |= BIT0;                //启动定时器
}



/*************************************************************************************************************************
* 函数                        :        void BSP_OuaEncoderReset(void)
* 功能                        :        正交编码计数器复位
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-10-22
* 最后修改时间         :         2022-10-22
* 说明                        :       
*************************************************************************************************************************/
void BSP_OuaEncoderReset(void)
{
        TMRA3->BCSTR &= ~BIT0;                //定时器关闭
        TMRA3->CNTER = 0x8000;
        sg_EncoderOverCount = 0;
        TMRA3->BCSTR |= BIT0;                //启动定时器
}


/*************************************************************************************************************************
* 函数                        :        int BSP_GetOuaEncoderCount(void)
* 功能                        :        获取正交编码器值
* 参数                        :        无
* 返回                        :        编码器值
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-10-22
* 最后修改时间         :         2022-10-22
* 说明                        :        可能存在竞争冲突,就是溢出的瞬间调用此值,但是可能性很低
*************************************************************************************************************************/
int BSP_GetOuaEncoderCount(void)
{
        OS_CRITICAL_SR_VAL;
        int temp;
        int count;

        OS_EnterCriticalSection();        //进入临界区
        temp = TMRA3->CNTER;
        count = sg_EncoderOverCount;
        OS_LeaveCriticalSection();        //退出临界区

        temp -= 0x8000;
        count += temp;

        return count;
}

/*************************************************************************************************************************
* 函数                        :        void BSP_OuaEncoderPowerDown(void)
* 功能                        :        正交编码计数器掉电
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2023-01-04
* 最后修改时间         :         2023-01-04
* 说明                        :        进入低功耗前,关闭定时器,降低功耗
*************************************************************************************************************************/
void BSP_OuaEncoderPowerDown(void)
{
        TMRA3->BCSTR &= ~BIT0;                                                //关闭定时器
        SYS_DeviceClockEnable(DEV_TIMERA_3, FALSE);        //关闭timA_3时钟
}

/*************************************************************************************************************************
* 函数                        :        void BSP_OuaEncoderPowerUp(void)
* 功能                        :        正交编码计数器上电(需要先初始化)
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2023-01-04
* 最后修改时间         :         2023-01-04
* 说明                        :       
*************************************************************************************************************************/
void BSP_OuaEncoderPowerUp(void)
{
        SYS_DeviceClockEnable(DEV_TIMERA_3, TRUE);        //开启timA_3时钟
        TMRA3->BCSTR |= BIT0;                                                //开启定时器
       
}



//下面是外部计数

//TIMA6上溢出中断
static u32 sg_TIMA6_OverCount = 0;                                        //TIMA6计数器溢出计数器
static void TMRA6_OVER_IRQHandler(void)
{
        int temp;

        if (TMRA6->BCSTR & BIT14)                                                 //上溢出
        {
                sg_TIMA6_OverCount += 65536;
                INFO_S("TIMA6上溢出%d\r\n", sg_TIMA6_OverCount);
        }
       

        TMRA6->BCSTR &= ~BIT14;                                                 //清除状态标识
}


/*************************************************************************************************************************
* 函数                        :        void BSP_RotationInit(void)
* 功能                        :        转动计数器初始化
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-12-30
* 最后修改时间         :         2022-12-30
* 说明                        :        PB15 TIMA6_TRIG FUN5 同步计数模式
*                                        注意:CPU在STOP模式下,HCLK会被关闭,导致TRIG计数失效
*************************************************************************************************************************/
void BSP_RotationInit(void)
{
        static IRQn_Type INT_IRQ_n = INTC_MALLOC_INVALID_IRQn;        //值允许0-31,超出的算无效值
        u32 PCLK1_Speed;
        u32 TimeClockDir;

        SYS_DeviceClockEnable(DEV_TIMERA_6, TRUE);        //使能TIMERA_6时钟

        TMRA6->CNTER = 0;                                                        //计数器复位
        TMRA6->BCSTR = BIT12 | (10 << 4) | BIT1;        //定时器关闭,开启上溢出复位,锯齿波模式,向上计数
        TMRA6->FCONR = (3 << 1) | BIT0;                                //TRIG输入滤波使能,使用PCLK/64 作为滤波基准时钟
        TMRA6->HCUPR = BIT9;                                                //TRIG端口采集到下降沿,硬件递增有效

        HallRotation_IoInit();                                                //IO初始化


        if (INT_IRQ_n == INTC_MALLOC_INVALID_IRQn)                                                                                                                                                //无效,没有申请
        {
                INT_IRQ_n = INTC_MallocIRQn();                                                                              //获取空闲的中断服务号(只支持0-31),如果返回Int032_IRQn则为无效
        }
        if (INT_IRQ_n != INTC_MALLOC_INVALID_IRQn)                                                                                                                                                //申请成功了
        {
                INFO_S("TMRA6获取中断服务号:%d\r\n", INT_IRQ_n);
                INTC_RegisterIRQHandler(INT_IRQ_n, SYS_INT_TMRA6_OVF, TMRA6_OVER_IRQHandler);                                                                //注册中断服务程序
                INTC_IntEnable(INT_IRQ_n, TRUE);                                                                                                                                                        //中断线开关,只支持0-31中断线开关控制

                NVIC_ClearPendingIRQ(INT_IRQ_n);
                NVIC_SetPriority(INT_IRQ_n, 4);
                NVIC_EnableIRQ(INT_IRQ_n);
        }
        else
        {
                ERROR_S("TMRA6获取中断服务号失败\r\n");
        }


        TMRA6->BCSTR |= BIT0;                                                //计数器启动
}


/*************************************************************************************************************************
* 函数                        :        void BSP_RotationPowerDown(void)
* 功能                        :        转动计数器掉电(降低功耗)
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-01-04
* 最后修改时间         :         2022-01-04
* 说明                        :       
*************************************************************************************************************************/
void BSP_RotationPowerDown(void)
{
        TMRA6->BCSTR &= ~BIT0;                                                //关闭计数器
        SYS_DeviceClockEnable(DEV_TIMERA_6, FALSE);        //关闭TIMERA_6时钟
}

/*************************************************************************************************************************
* 函数                        :        void BSP_RotationPowerUp(void)
* 功能                        :        转动计数器上电(需要先初始化)
* 参数                        :        无
* 返回                        :        无
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-01-04
* 最后修改时间         :         2022-01-04
* 说明                        :       
*************************************************************************************************************************/
void BSP_RotationPowerUp(void)
{
        SYS_DeviceClockEnable(DEV_TIMERA_6, TRUE);        //使能TIMERA_6时钟
        TMRA6->BCSTR |= BIT0;                                                //计数器启动
}

/*************************************************************************************************************************
* 函数                        :        u32 BSP_GetRotationCount(void)
* 功能                        :        获取转动计数器值(1圈增加4次)
* 参数                        :        无
* 返回                        :        转动计数器值
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-12-30
* 最后修改时间         :         2022-12-30
* 说明                        :        需要初始化TIMA6
*************************************************************************************************************************/
u32 BSP_GetRotationCount(void)
{
        u32 count = sg_TIMA6_OverCount + TMRA6->CNTER;

        return count;
}


/*************************************************************************************************************************
* 函数                        :        u32 BSP_ClearRotationCount(void)
* 功能                        :        转动计数器值
* 参数                        :        无
* 返回                        :        转动计数器值
* 依赖                        :        底层宏定义
* 作者                        :        cp1300@139.com
* 时间                        :        2022-12-30
* 最后修改时间         :         2022-12-30
* 说明                        :        需要初始化TIMA6
*************************************************************************************************************************/
void BSP_ClearRotationCount(void)
{
        TMRA6->BCSTR &= ~BIT0;                                                //计数器关闭
        TMRA6->CNTER = 0;                                                        //计数器值复位
        sg_TIMA6_OverCount  = 0;                                        //溢出计数值清零
        TMRA6->BCSTR |= BIT0;                                                //计数器启动
}


————————————————
版权声明:本文为CSDN博主「cp1300」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/cp1300/article/details/128968531

使用特权

评论回复
沙发
guijial511| | 2023-10-19 08:39 | 只看该作者
编码器输出一般都支持正交编码功能

使用特权

评论回复
板凳
tpgf| | 2023-11-2 16:26 | 只看该作者
当我们采集三相电机的数据的时候 如何确定是正传 还是反转呢

使用特权

评论回复
地板
coshi| | 2023-11-2 16:54 | 只看该作者
我们怎么区分编码器的信号的方向性呢

使用特权

评论回复
5
wiba| | 2023-11-2 17:24 | 只看该作者
正交编码是一种典型编码形式,具有良好的抗噪性能,能有效消除脉冲边缘振荡造成的干扰,在测速时能有效提高准确性

使用特权

评论回复
6
kxsi| | 2023-11-2 17:45 | 只看该作者
编码器的输出信号路数跟本身的型号有关系

使用特权

评论回复
7
drer| | 2023-11-2 18:11 | 只看该作者
这种计数方式可以使用双边沿触发方式吗

使用特权

评论回复
8
qcliu|  楼主 | 2023-11-2 18:36 | 只看该作者
正交编码器会输出多少路信号呢

使用特权

评论回复
9
feifeifeichang| | 2024-4-24 14:45 | 只看该作者
好,感谢分享

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

62

主题

3315

帖子

4

粉丝