直接上代码:
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: 26Can: brp:2, prseg1: 5, phseg1:8, phseg2: 2, bps: 500000.000000, error: 0.000000, sample: 87.500000