STM32 cubemx CAN

受信に使用される構造は次のとおりです。 CAN の概念:

        正式名称はコントローラー エリア ネットワークで、半二重の非同期通信です。

物理層:

        クローズドループ:バスの最大長は40m、最大速度は1Mbps、バスの両端に120Ωの抵抗があり、クローズドループであることが規定されています。

       オープンループ: 最大伝送距離は 1Km、最大速度は 125Kbps、各ラインは 2.2kΩ 抵抗で直列に接続する必要があり、オープンループ

CANプロトコルの基本機能

       基本的な機能は次のとおりです。

       マルチマスター制御: CAN バスがアイドル状態の場合、バス上のすべての端末がメッセージを送信でき、優先順位は識別子 (CAN ID) に従って決定されます。バス上にメッセージを送信する端末が 3 つ以上ある場合、それぞれの端末がメッセージを送信します。メッセージ CAN ID の各ビットが 1 つずつ比較され、調停されます。CAN ID 値が低いほど、メッセージの優先度が高くなります より速い速度とより長い距離: CAN プロトコルは最速で 1Mbps に達し (距離 40m 未満)、最も遠いものでは 10KM (レート 5Kbps 未満) の CAN フレームに到達できます。タイプ: CAN 通信には
       、データ フレーム、リモート コントロール フレーム、エラー フレーム、オーバーロード フレーム、インターバル フレームの 5 つのフレーム タイプが含まれます。このうち最も重要なものはデータ フレームで、通信ノードがデータを外部に送信するために使用します。データ フレームにはデータの内容を伝えるデータ セグメントがあり、1 フレームで 0 ~ 8 バイトのデータを送信でき、MSB が先頭になります。
上記の基本機能を簡単に理解すれば、すぐに CAN バスの設定を始めることができます。

       ドミナントレベルは「0」に対応し、リセシブレベルは「1」に対応します。リセッシブ レベル (1) 両方のラインの電圧は 2.5V、つまり電圧差は 0、ドミナント レベル (0) CAN_High と CAN_Low はそれぞれ 3.5V と 1.5V で、電圧差は 2V です。

       バス上では、ドミナントを出力しているノードが 1 つある限り、バスはドミナント レベルになり、すべてのノードがリセッシブ レベルの場合にのみ、バスはリセッシブ レベルになります。

CAN ネットワークは CAN コントローラと CAN トランシーバで構成されますが、STM32 には CAN コントローラのみが統合されています。

1. ハードウェアチップ使用: STM32F103Cx シリーズ

cubeMX 構成クロック

APB1には缶ペリフェラルが搭載されています。

 

一般的な通信は受信割り込みを開きます。ここでは CAN1 RX0 の割り込みを開きます。優先順位はNVICを通じて変更 できます。

CANボーレートとビット同期

ビットタイミングの内訳

 プリスケーラー: prescaler CAN 最小時間単位 Tq を決定します。

ここでは F103C8T6 を例に挙げます。APB1 クロックは 36Mhz、
ボーレートの計算方法: 36M/周波数分割係数/(BS1 + BS2 + 1) が
図に示すように設定され、ボーレートは 1000Kbps、36M / 4 / (4 + 4 + 1 ) =1M = 1000K

ボーレート計算式:

作業モードを構成します。

CANデータフレームフォーマット

 CANボーレート計算ツール

STM32 CAN Baud Rate CalculatorV1.0-STM32 CAN Baud Rate Calculator 公式ダウンロード_3DM ソフトウェア

STM32 CAN通信ボーレート計算機

 

 CANProプロトコル解析プラットフォームソフトウェアはCANalyst-II+の標準ソフトウェアです

CAN 基本関数 Function
Function
HAL_CAN_Start CAN 通信を開く
HAL_CAN_Stop CAN 通信を閉じる
HAL_CAN_RequestSleep CAN モジュールに現在の動作を完了させ、スリープ モードへの移行を試行する
HAL_CAN_WakeUp スリープ モードからウェイクアップする
HAL_CAN_IsSleepActive スリープ モードになっているかどうかを確認する
HAL_CAN_AddTxMessage Tx にメッセージを追加するHAL_CAN_GetTxMailboxesFreeLevelアイドル状態の
送信
メールボックスの数を問い合わせる HAL_CAN_IsTxMessagePending 指定
された Tx メールボックスで待機中の送信要求があるかどうかを確認する
HAL_CAN_GetRxMessage Rx FIFO から CAN フレームを受信する
HAL_CAN_GetRxFifoFillLevel 受信側の未読メールボックスの数を問い合わせるメールボックス

STM32HAL ライブラリの学習 - CAN Notes_hal ライブラリ can_jdhfusk のブログ - CSDN ブログ

送信に使用される構造は次のとおりです。

typedef struct
{   uint32_t StdId; //標準 ID   uint32_t ExtId; //拡張 ID   uint32_t IDE; //メッセージが標準 ID を使用するか拡張 ID を使用するかを決定するために使用されます   uint32_t RTR; //メッセージがデータ フレームであるか、または拡張 ID を使用するかを決定するために使用されます。リモート コントロール Frame   uint32_t DLC; //データ長、値は 0 ~ 8   FunctionalState TransmitGlobalTime;  //最後のものはタイム トリガー モード用で、その後のデータの最後の 2 バイトにタイム スタンプが自動的に追加されますがオンになっています。現在使用されていません。DISABLE  } CAN_TxHeaderTypeDef;を選択してください。







StdId: 送信されるメッセージが標準 ID を使用する場合、このメンバーは標準 ID の値を記録します。 値
: 0x0 ~ 0x7FF

ExtId: 送信されるメッセージが拡張 ID を使用する場合、このメンバーは拡張 ID の値を記録します。
値: 0x0 ~ 0x1FFFFFFF

IDE: メッセージが標準 ID を使用するか拡張 ID
値を使用するかを決定するために使用されます: CAN_ID_STD または CAN_ID_EXT

RTR: メッセージがデータ フレームであるかリモート フレームであるかを判断するために使用されます。
値: CAN_RTR_DATA または CAN_RTR_REMOTE

DLC: データフレームのデータ長、単位バイトを記録するために使用されます (リモート制御フレームが送信される場合、このメンバーの内容は機能しません) 値:
0 ~ 8

TransmitGlobalTime: 現在使用されていません。DISABLE
の値を選択します: ENABLE または DISABLE

送信に使用する関数は次のとおりです。

HAL_StatusTypeDef HAL_CAN_AddTxMessage(CAN_HandleTypeDef *hcan, CAN_TxHeaderTypeDef *pHeader, uint8_t aData[], uint32_t *pTxMailbox);

CAN_TxHeaderTypeDef can_Tx;
uint8_t sendBuf[5] = {"hello"};
uint32_t box;

int main(void)
{
  	HAL_Init();
 	SystemClock_Config();
  	MX_GPIO_Init();
  	MX_CAN_Init();

    HAL_CAN_Start(&hcan1);
  
    can_Tx.StdId = 0x123;
    can_Tx.ExtId = 0;
    can_Tx.IDE = CAN_ID_STD;
    can_Tx.RTR = CAN_RTR_DATA;
    can_Tx.DLC = 5;
    can_Tx.TransmitGlobalTime = DISABLE;

  	while (1)
  	{
      	HAL_CAN_AddTxMessage(&hcan1, &can_Tx, sendBuf, &box);
      	HAL_Delay(100);
  	}
}

効果: 100ms ごとにメッセージを送信します。

 フィルター

 typedef struct
{   uint32_t FilterIdHigh; //CAN_FiR1 レジスタの上位 16 ビット   uint32_t FilterIdLow; //   CAN_FiR1 レジスタの上位 16 ビット uint32_t FilterMaskIdHigh; //CAN_FiR2 レジスタの上位 16 ビット uint32_t FilterMaskIdLow   ; //下位 16 ビット   uint32_t Fil of CAN_FiR2 register terFIFOAssignment; //フィルタを通過するメッセージは FIFO0 または   FIFO1 の uint32_t FilterBank に存在します; //この設定ではどのフィルタが使用されます。0 ~ 13 の単一の CAN 値を使用します   uint32_t FilterMode; //マスク モードまたはリスト モード   uint32_t FilterScale; //32 ビットまたは 16 ビット   uint32_t FilterActivation; //有効または無効   uint32_t SlaveStartFilterBank; //CAN1 と CAN2 を一緒に使用する場合、フィルターの数を CAN2 に割り当てます。 } CAN_FilterTypeDef;










メンバー:

FilterIdHigh: CAN_FiR1 レジスタの上位 16 ビットは、フィルタ コードを埋めるために使用されます。具体的なフォーマットは、16 ビット、32 ビット、マスクモード、リストモードに応じて決定する必要があります。
値: 0x0 ~ 0xFFFF

FilterIdLow: CAN_FiR1 レジスタの下位 16 ビット

FilterMaskIdHigh: CAN_FiR2 レジスタの上位 16 ビット

FilterMaskIdLow: CAN_FiR2 レジスタの下位 16 ビット

FilterFIFOAssignment: フィルタを通過したメッセージは FIFO0 または FIFO1 に保存されます。
値: CAN_FILTER_FIFO0 または CAN_FILTER_FIFO1

FilterBank: 今回設定したフィルター番号
値: シングル CAN の場合 0 ~ 13、デュアル CAN の場合 0 ~ 27

FilterMode : フィルター モード、マスク モード、またはリスト モード。
値: CAN_FILTERMODE_IDMASK または CAN_FILTERMODE_IDMASK

FilterScale: フィルター コード サイズ、16 ビットまたは 32 ビット。
値: CAN_FILTERSCALE_16BIT または CAN_FILTERSCALE_32BIT

FilterActivation : このフィルターを有効または無効にします。
値: CAN_FILTER_DISABLE または CAN_FILTER_ENABLE

SlaveStartFilterBank: CAN (CAN2) から割り当てられたフィルターの数。単一の CAN のみが使用される場合、このメンバーは無視できます。
値: 0 ~ 27

フィルター構造を入力し、次の関数を呼び出して有効にします。

HAL_StatusTypeDef HAL_CAN_ConfigFilter(CAN_HandleTypeDef *hcan, CAN_FilterTypeDef *sFilterConfig);

CAN_FilterTypeDef can_Filter = {0};

can_Filter.FilterIdHigh = 0;
can_Filter.FilterIdLow = 0;
can_Filter.FilterMaskIdHigh = 0;
can_Filter.FilterMaskIdLow = 0;
can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
can_Filter.FilterBank = 0;
can_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
can_Filter.FilterActivation = CAN_FILTER_ENABLE;

HAL_CAN_ConfigFilter(&hcan1, &can_Filter);

効果: CAN バス上のすべてのメッセージが受信され、FIFO0 に保存されます。

CAN_FilterTypeDef can_Filter = {0};

can_Filter.FilterIdHigh = 0;
can_Filter.FilterIdLow = 0;
can_Filter.FilterMaskIdHigh = 0;
can_Filter.FilterMaskIdLow = 2;
can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
can_Filter.FilterBank = 0;
can_Filter.FilterMode = CAN_FILTERMODE_IDLIST;
can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
can_Filter.FilterActivation = CAN_FILTER_ENABLE;

HAL_CAN_ConfigFilter(&hcan1, &can_Filter);

効果: 標準 ID が 0x0 のデータ フレームとリモート コントロール フレームのみを受信し、FIFO0 に格納します。

引き継ぐ

CAN 受信は通常、割り込みを使用して実現されます (DMA がなく、クエリ方式ではリアルタイムのパフォーマンスを保証することが難しいため)。そのため、最初に受信用のグローバル割り込みを CubeMX で有効にする必要があります。

FIFO0 のデータ受信用の RX0 割り込みと、FIFO1 のデータ受信用の RX1 割り込みの 2 つの割り込みがあることがわかりますが、ここでは FIFO0 のみを使用しているので、これだけを確認します。(ここで私自身の理解についても話します。1 つの FIFO には 3 つのメッセージしか保存できないため、2 つの FIFO では 6 つのメッセージを保存できます。フィルターを介して異なる ID を持つメッセージを異なる FIFO に入れることができます。たとえば、FIFO0 にキーと重要なメッセージを受信させることができます)メッセージを受信するには FIFO1 を使用し、重要度の低いメッセージを受信します。これら 2 つの割り込みは独立しているため、異なる割り込み優先順位を設定することもできます。)

グローバル割り込みをオンにするだけでは不十分です。割り込み要求を一時停止するには、CAN FIFO メッセージ (つまり、CAN ペリフェラルの割り込みイネーブル ビット) をオンにする必要もあります。

HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);

このようにして、CAN がフィルターを満たすメッセージを受信すると、割り込みがトリガーされ、この割り込みコールバック関数で受信メッセージを受信して​​処理できます。(FIFO0とFIFO1で使用する割り込み関数は独立しているため、ここでのコールバック関数も異なります。FIFO0かFIFO1かを確認してください。)

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &can_Rx, recvBuf);

	/*下面是你用来处理收到数据的代码,
	可以通过串口把内容发送出来,
	也可以用来控制某些外设*/
}

 受信に使用される構造は次のとおりです。

typedef struct
{
  uint32_t StdId;    
  uint32_t ExtId;    
  uint32_t IDE;      
  uint32_t RTR;      
  uint32_t DLC;      
  uint32_t Timestamp; 
  uint32_t FilterMatchIndex; 
} CAN_RxHeaderTypeDef;

これは送信構造とよく似ていますが、この構造は値を割り当てる必要がなく、受信関数の出力パラメーターとして使用されます。ここでは、送信構造体に存在しないメンバーのみを紹介します。

  1. Timestamp : タイムトリガーモードが有効な場合にのみ役立ち、タイムスタンプを記録します。
  2. FilterMatchIndex : このメッセージがどのフィルタを介して受信されるか

受信に使用する関数は次のとおりです。

HAL_StatusTypeDef HAL_CAN_GetRxMessage(CAN_HandleTypeDef *hcan, uint32_t RxFifo, CAN_RxHeaderTypeDef *pHeader, uint8_t aData[]);

パラメータ:

  1. *hcan : 缶のハンドル。CubeMX によって自動的に定義されます。
  2. RxFifo : 受信FIFO番号を取得します。パラメータ: CAN_RX_FIFO0 または CAN_RX_FIFO1
  3. pHeader : 受信構造体、ここでは出力パラメータとして
  4. aData[] : 配列を出力パラメータとして受け取ります。

例:

#include <stdio.h>

CAN_RxHeaderTypeDef can_Rx;
uint8_t recvBuf[8];

uint8_t uartBuf[64];

int main(void)
{
  	HAL_Init();
 	SystemClock_Config();
  	MX_GPIO_Init();
  	MX_CAN_Init();
    MX_USART1_UART_Init()

    CAN_FilterTypeDef can_Filter = {0};
    
    can_Filter.FilterIdHigh = 0;
    can_Filter.FilterIdLow = 0;
    can_Filter.FilterMaskIdHigh = 0;
    can_Filter.FilterMaskIdLow = 0;
    can_Filter.FilterFIFOAssignment = CAN_FILTER_FIFO0;
    can_Filter.FilterBank = 0;
    can_Filter.FilterMode = CAN_FILTERMODE_IDMASK;
    can_Filter.FilterScale = CAN_FILTERSCALE_32BIT;
    can_Filter.FilterActivation = CAN_FILTER_ENABLE;
    HAL_CAN_ConfigFilter(&hcan1, &can_Filter);
    
    HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);
    
    HAL_CAN_Start(&hcan1);

  	while (1)
  	{

  	}
}

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    uint16_t len = 0;
    
    HAL_CAN_GetRxMessage(&hcan1, CAN_RX_FIFO0, &can_Rx, recvBuf);

    if(can_Rx.IDE == CAN_ID_STD)
    {
        len += sprintf((char *)&uartBuf[len], "标准ID:%#X; ", can_Rx.StdId);
    }
    else if(can_Rx.IDE == CAN_ID_EXT)
    {
        len += sprintf((char *)&uartBuf[len], "扩展ID:%#X; ", can_Rx.ExtId);
    }
    
    if(can_Rx.RTR == CAN_RTR_DATA)
    {
        len += sprintf((char *)&uartBuf[len], "数据帧; 数据为:");
        
        for(int i = 0; i < can_Rx.DLC; i ++)
        {
            len += sprintf((char *)&uartBuf[len], "%X ", recvBuf[i]);
        }
        
        len += sprintf((char *)&uartBuf[len], "\r\n");
        HAL_UART_Transmit(&huart1, uartBuf, len, 100);        
    }
    else if(can_Rx.RTR == CAN_RTR_REMOTE)
    {
        len += sprintf((char *)&uartBuf[len], "遥控帧\r\n");
        HAL_UART_Transmit(&huart1, uartBuf, len, 100);        
    }    
}

効果: CAN バス上のすべてのデータを受信し、シリアル ポート経由で内容を印刷します。

 

STM32 CAN初期化の詳細説明

CANとはController Area Network(CAN)の略称で、車載電子製品の研究開発・生産で有名なドイツのBOSCH社によって開発され、最終的に国際規格(ISO11898)となりました。世界で最も広く使用されているフィールドバスの 1 つです。北米と西ヨーロッパでは、CAN バス プロトコルが車載コンピュータ制御システムおよび組み込み産業用制御 LAN の標準バスとなっており、CAN を基礎プロトコルとして大型トラックや重機車両向けに設計された J1939 プロトコルがあります。近年ではその高い信頼性と優れたエラー検出能力が評価され、厳しい周囲温度、強い電磁波、大きな振動が存在する車載コンピュータ制御システムや産業環境などで広く使用されています。
元のリンク: https://blog.csdn.net/qq_20017379/article/details/125902421

u8 CAN1_Mode_Init(u8 tsjw, u8 tbs2,u8 tbs1, u16 brp, u8 mode)
{

    /* gpio结构体 */
    GPIO_InitTypeDef GPIO_InitStructure;

    /* can 初始化结构体 */
    CAN_InitTypeDef        CAN_InitStructure;

    /* can过滤器结构体 */
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;

    /* 使能时钟 */
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);                                    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    /* 初始化gpio
        设置引脚
        复用模式
        推挽
        速率100
        上拉
    */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11| GPIO_Pin_12;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* 复用pa11 pa12为can功能 */
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);

    /* 初始化can结构体 */
    /*事件触发消息传输机制
    在TTCAN模式下,CAN硬件的内部定时器被激活,并且被用于产生发送与接收邮箱的)时间戳
    为了使can满足,适合实时性和可靠性要求特别高或有安全性要求的场合
    路上各节点取得同步后, 消息只能根据调度表在规定的时间隙传输, 避免了消息传输的冲突、仲裁,消息传 
 输时延短, 且可预知
    */
    CAN_InitStructure.CAN_TTCM=DISABLE;

    /* 软件自动离线管理
    ENABLE:一旦硬件检测到128 次11位连续的隐性位,则自动退出离线状态
    将ABOM设1后,一旦检测到条件会自动恢复的,不需要人工干预
    如果ABOM位为’1’,bxCAN进入离线状态后,就自动开启恢复过程。
    如果ABOM位为’0’,软件必须先请求bxCAN进入然后再退出初始化模式,随后恢复过程才被开启
    */
    CAN_InitStructure.CAN_ABOM=DISABLE;

    /* 睡眠模式禁用
    软件通过对CAN_MCR寄存器的SLEEP位置’1’,来请求进入这一模式。在该模式下,bxCAN的时钟停止了,但软件仍然可以访问邮箱寄存器。
    当bxCAN处于睡眠模式,软件必须对CAN_MCR寄存器的INRQ位置’1’并且同时对SLEEP位清’0’,才能进入初始化模式。
    有2种方式可以唤醒(退出睡眠模式)bxCAN:通过软件对SLEEP位清’1’,或硬件检测到CAN总线的活动。
    如果CAN_MCR寄存器的AWUM位为’1’,一旦检测到CAN总线的活动,硬件就自动对SLEEP位清’0’来唤醒bxCAN。如果CAN_MCR寄存器的AWUM位为’0’,软件必须在唤醒中断里对SLEEP位清’0’才能退出睡眠状态。

    注: 如果唤醒中断被允许(CAN_IER寄存器的WKUIE位为’1’),那么一旦检测到CAN总线活动就会产生唤醒中断,而不管硬件是否会自动唤醒bxCAN。
    在对SLEEP位清’0’后,睡眠模式的退出必须与CAN总线同步,当硬件对SLAK位清’0’时,就确认了睡眠模式的退出。
    */
    CAN_InitStructure.CAN_AWUM=DISABLE;

    /* 自动重传使能
    该模式主要用于满足CAN标准中,时间触发通信选项的需求。通过对CAN_MCR寄存器的NART位置’1’,来让硬件工作在该模式。
    在该模式下,发送操作只会执行一次。如果发送操作失败了,不管是由于仲裁丢失或出错,硬件都不会再自动发送该报文。
    */
    CAN_InitStructure.CAN_NART=ENABLE;

    /*
    报文不锁定,新报文覆盖旧报文
    */
    CAN_InitStructure.CAN_RFLM=DISABLE;

    /* 优先级由报文标识符决定
    本成员用于选择CAN报文发送优先级判定方法
    用于选择CAN报文发送优先级判定方法
    */
    CAN_InitStructure.CAN_TXFP=DISABLE;

    /*
        #define CAN_Mode_Normal   正常模式
        #define CAN_Mode_LoopBack 回环模式 自己发,自己收
        回环模式下,它自己的输出端的所有内容都直接传输到自己的输入端,输出端的内容同时也会被传输到总线上,
        即也可使用总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。使用回环模式可以进行自检。
        #define CAN_Mode_Silent   静默模式
        静默模式下,它自己的输出端的逻辑 0 数据会直接传输到它自己的输入端,逻辑1
        可以被发送到总线,所以它不能向总线发送显性位(逻辑 0),只能发送隐性位(逻辑 1)。
        输入端可以从总线接收内容。由于它只可发送的隐性位不会强制影响总线的状态,
        所以把它称为静默模式。这种模式一般用于监测,它可以用于分析总线上的流量,但又不会因为发送显性位而影响总线
        #define CAN_Mode_Silent_LoopBack    静默回环模式
        回环静默模式是以上两种模式的结合,自己的输出端的所有内容都直接传输到自己的输入端,并且不会向总线发送显性位影响总线,
        不能通过总线监测它的发送内容。输入端只接收自己发送端的内容,不接收来自总线上的内容。
        这种方式可以在“热自检”时使用,即自我检查的时候,不会干扰总线
    */
    CAN_InitStructure.CAN_Mode= mode;

    /*
        重新同步跳跃宽度(SJW) 。定义了在每位中可以延长或缩短多少个时间单元的上限。其值可以编程为1到4个时间单元
    */
    CAN_InitStructure.CAN_SJW=tsjw;

    /*
        时间段1(BS1):定义采样点的位置。其值可以编程为1到16个时间单元,但也可以被自动延长,
        以补偿因为网络中不同节点的频率差异所造成的相位的正向漂移。
    */
    CAN_InitStructure.CAN_BS1=tbs1;

    /*
        时间段2(BS2):定义发送点的位置。其值可以编程为1到8个时间单元,但也可以被自动缩短以补偿相位的负向漂移。
    */
    CAN_InitStructure.CAN_BS2=tbs2;

    /*
        分频率
    */
    CAN_InitStructure.CAN_Prescaler=brp;

    /* 初始化结构体 */
    CAN_Init(CAN1, &CAN_InitStructure);

    /* 初始化过滤器 */
    /*
      选择过滤器0~13 for one can register
    */
    CAN_FilterInitStructure.CAN_FilterNumber = 0;

    /*
        屏蔽位模式和标识符列表模式
        #define CAN_FilterMode_IdMask       ((uint8_t)0x00)  
        #define CAN_FilterMode_IdList       ((uint8_t)0x01)
    */
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;

    /*  过滤器的位数
        #define CAN_FilterScale_16bit       ((uint8_t)0x00)
        #define CAN_FilterScale_32bit       ((uint8_t)0x01)
    */
    CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;

    /*
        32位ID 高位
    */
    CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;32??ID

    /*
        32位ID 低位
    */
    CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;

    /* 屏蔽位高字节 */
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;

    /* 屏蔽位低字节 */
    CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;

    /* 设定接收FIFO */
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;

    /* 激活过滤组 */
    CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;

    /* 初始化过滤器 */
    CAN_FilterInit(&CAN_FilterInitStructure);

    /* 配置can中断*/
    NVIC_InitTypeDef  NVIC_InitStructure;
    CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);
    NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    return 0;
}  

おすすめ

転載: blog.csdn.net/m0_37777700/article/details/132277458