MCP2515的一段正确设置时钟的代码

直接上代码:

bool CMcp2515::SetupClock(double clk, double bps)
{
    bool result = false;
    if( clk > 0.0 && bps > 0.0 )
    {
        tagCanClock::List valid;

        // 遍历分频值
        for( int brp = 1; brp <= 64; ++ brp )
        {
            // 求名义比特时间,总时间量子
            double nbt = clk / (bps * brp );

            // 跳过不合适的参数
            if( nbt < 8.0  ) continue;
            if( nbt > 25.0 ) continue;
            
            // 获取整数值
            int nbt_int = static_cast<int>( std::round(nbt) );
            if( std::abs(nbt - nbt_int) > 0.1 ) continue;

            for( int prseg1 = 1; prseg1 <= 8; ++ prseg1 )  // 遍历可能的prseg1设置
            for( int phseg1 = 2; phseg1 <= 8; ++ phseg1 )  // 遍历可能的phseg1设置
            {
                // 计算对应的phseg2
                int phseg2 = nbt_int - 1 - prseg1 - phseg1;

                // 约束条件
                if( phseg2 < 2 ) continue;
                if( phseg2 > 8 ) continue;
                if( phseg1 < phseg2 ) continue;

                // 计算实际波特率
                double actual_bps = clk / ( brp * nbt_int );
                double error = std::abs(actual_bps - bps) / bps * 100.0;

                // 硬性约束条件,小于2%的误差
                if( error >= 2.0 ) continue;

                // 计算采样点
                double sample_point = ( 1.0 + prseg1 + phseg1 ) / nbt_int * 100.0;

                // 放入有效列表
                tagCanClock data;
                data.brp    = brp;
                data.prseg1 = prseg1;
                data.phseg1 = phseg1;
                data.phseg2 = phseg2;
                data.bps    = actual_bps;
                data.error  = error;
                data.sample = sample_point;

                valid.push_back( data );
            }
        }

        if( valid.empty() == false )
        {
            valid.sort();
            tagCanClock clock = valid.front();

            Serial.printf( "Total: %d\n", valid.size() );
            Serial.printf( "Can: brp:%d, prseg1: %d, phseg1:%d, phseg2: %d, bps: %f, error: %f, sample: %f\n", 
                clock.brp, clock.prseg1, clock.phseg1, clock.phseg2, clock.bps, clock.error, clock.sample );

            if( clock.brp    >= 1 && clock.brp    <= 64 &&
                clock.prseg1 >= 1 && clock.prseg1 <= 8 && 
                clock.phseg1 >= 2 && clock.phseg1 <= 8 && 
                clock.phseg2 >= 2 && clock.phseg2 <= 8 )
            {
                // 写入寄存器
                uint8_t sjw = min( clock.phseg1, clock.phseg2 );
                sjw = min( 4, sjw );

                uint8_t cnf1 = ( (sjw - 1) << 6 ) | ( (clock.brp - 1) & 0x3F );
                uint8_t cnf2 = 0x80 | ( ( (clock.phseg1 - 1) & 0x07 ) << 3 ) | ( (clock.prseg1 - 1) & 0x07 );
                uint8_t cnf3 = ( clock.phseg2 - 1 ) & 0x07;
            
                spi.WriteU08( CNF1, cnf1 );
                spi.WriteU08( CNF2, cnf2 );
                spi.WriteU08( CNF3, cnf3 );

                result = true;
            }
        }
    }
    return result;
}

tagCanClock的代码:

        struct tagCanClock
        {
            typedef list<tagCanClock> List;

            int brp;                // 分频
            int prseg1;             // 传播段 + 
            int phseg1;             // 相位缓冲段1(T)
            int phseg2;             // 相位缓冲段2
            double bps;             // 总线波特率
            double error;           // 误差率,必须小于2%
            double sample;          // 采样点,建议70%~90%之间

            inline tagCanClock(): 
            brp(0),prseg1(0),phseg1(0),phseg2(0),bps(0.0),error(0.0),sample(0.0)
            {
            }

            inline tagCanClock(const tagCanClock & value): 
            brp(value.brp),prseg1(value.prseg1),phseg1(value.phseg1),phseg2(value.phseg2),bps(value.bps),error(value.error),sample(value.sample)
            {
            }

            inline ~tagCanClock()
            {
            }

            inline tagCanClock & operator=(const tagCanClock & value)
            {
                brp     = value.brp;
                prseg1  = value.prseg1;
                phseg1  = value.phseg1;
                phseg2  = value.phseg2;
                bps     = value.bps;
                error   = value.error;
                sample  = value.sample;
                return( * this );
            }

            inline bool operator<(const tagCanClock & value) const
            {
                if( error <  value.error ) {
                    return true;
                }
                else
                if( error == value.error ) 
                {
                    if( sample > value.sample ) {
                        return true;
                    }
                }
                return false;
            }
        };

16Mhz晶振,500kbps的测试结果: 

can config mode.
Total: 26
Can: brp:2, prseg1: 5, phseg1:8, phseg2: 2, bps: 500000.000000, error: 0.000000, sample: 87.500000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值