CAN通信については、色々なところにまとめられているので、それをご参考に。
参考URL:https://www.keyence.co.jp/ss/products/recorder/lab/candata/mechanism.jsp
さて、この通信規格でSTマイクロのCPUを使って通信したい。機器側はCANポートの後段にCANドライバー(今回はTJA1044BTを使用)をつなげ、その信号をケーブルを通して通信相手と接続する。今回の通信相手はPYLONTECH社のリチウムイオンバッテリRT12100G31。通信はCAN通信上でModbus-RTUプロトコルを通す、となっている。要は物理I/FはCAN、通信規格はCAN、中に流すデータ列はModbus-RTUを使う、ということ。
今回使用するマイコンはSTM32L431CBT6となっている。PA11をCAN1_RX、PB9をCAN1_TXに設定(ポート選定はユーザーの自由度があり、他も選択できる)。クロックは内部80MHz、通信用クロックをAPB1 Prescalerを1/2にして40MHzに設定した(別に、80MHzでもいい)。
参考URL:https://hsdev.co.jp/stm32-can/

40MHzをプリスケーラ―で4分周し10MHzに落とす。次の2つのパラメータは15Timesと4Timesにしている。参考URLで示すように、サンプリングポイントが80%になるよう、かつ250kbpsを実現できるよう、設定した。そのため、参考URLの表に合うよう、Time Quantumを100.0nsにしている(だから80MHzの源クロックを通信では40MHzにして、更に4分周している)。ここが違うと、パラメータを自分で計算しないといけない。面倒なんで、ここに合わせた。設定はこれだけ。この設定が終わった後はソフトを作りこむ。
CubeMXで上記設定をすると、ソフトが自動で作られる。作られる関数はMX_CAN1_Init。

上記にCubeMxで設定したパラメータが反映されている。
ユーザーが作るのは、受信割込み関数void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)の中身と、CANの初期化、送信だけとなる。今回は対象が一つしかないので、ともかく全部受信。そこで、CANの初期化は簡単にした。受信対象を細かく設定するのはやっていないので、やる方は上記参考URLを見てチャレンジして欲しい。以下ですべて受信となっている。

送信関数は以下のように作った。

ここで使用するTxHeaderだが、

このように設定している。詳細は割愛するが、IDが合っていないと当然通信できない。対象となるバッテリの仕様書によると、

最初、ちょっと間違ってしまった。CAN IDのLSB側、Bit[4:0]が示すのは、D4,D3,D2,D1,D0列のこと。つまり、5ビット。しかし、上に示すように、仕様書にはなぜか4ビットしか載っていない。自分、4ビットと思い込んでデータ作っていたので動かない。よく見たら、最後にHex.となっているのだが、ここが29ビットデータ列になっていた。これそのまま使えばよかったのだが、間違って1ビット少ない、28ビットデータをセットし、動かない、動かないとわめいていた。それで、StdIDは必要なのか?わからないけど、このデータ列でStdIDを抽出し、それも一応設定した。
では、仕様書に書かれている、接続バッテリ数を読み出してみよう。

読み出し命令(読み出し命令送信関数)は以下。

上の仕様書に示すように、Slave Addressを0xff、Function Codeを0x03、レジスタアドレスを0x1000、読み出し数を0x0001にして呼び出した。これで、何台のバッテリが繋がっているか、読み出せるようになった。
上記で読んだのは、レジスタアドレス(要はコマンド)0x1000。

これを模して続けて読んだのは0x1002。コマンドはCAN_TX(0xff, 0x03, 0x1002, 0x0001)。なお、レジスタアドレス0x1001は使わない(17台以上は繋がらないんだが)。1002を発行すると、つながっているバッテリのIDが読み出せる。16ビットのデータで1が立っているところが繋がっているバッテリで、例えばLSBとMSBだけが立っていた場合、Battery1とBattery16が繋がっているよ、ということになる。
最終的に読みたかったのはSoC(0x2108)とSoH(0x2112)。

で、Slave Addressは?今度は読み出したバッテリIDを使用する。0x1002で読んだ時のBattery IDを設定し読み出せば取り出せる。読み出しコマンドは、SoC=CAN_TX(バッテリID, 0x03, 0x2108, 0x0001)、SoH=CAN_TX(バッテリID, 0x03, 0x2112, 0x0001)となる。これで、欲しいものは読み出せた。