CAN編寫完分幀發送, 分幀接收,J1939位域型結構體心得


關於由多個不同的C文件構成的工程,我采用以下方法

以為400Hz數字電源程序為例

假設工程由以下文件組成

DC_Comm.c 主要完成串口通訊部分

DC_Config.c 主要完成時鍾,外設 中斷初始化

DC_Control.c 主要完成電源數字化SPWM控制,以及串口接收中斷的處理

DC_Memory.c 主要完成FM33256 的SPI時序的軟件實現。故障記錄與操作記錄的寫入與讀取操作。

DC_Timing.h 主要完成與CPLD配合的一些時序。

 

響應的在include 中我還用到了一些頭文件

DC_Comm.h 主要用來對DC_Comm.c中用到的數據類型進行聲明,以及函數進行聲明。這些函數都在DC_Comm.c中定義

DC_Control.h 主要用來對DC_Control.c中用到的數據類型進行聲明,以及函數進行聲明。這些函數在DC_Control.c 中定義

DC_Types.h 中宏定義了 一些Q格式常量 ,以及一些函數的聲明。

 

總之:假設在DC_Comm.c中 定義了函數SCIRXProcess ()

則在DC_Comm.h中聲明了 extern void SCIRXProcess ()

那么我在main.c 文件中調用 SCIRXProcess()的時候, 直接在main.c的前方將DC_Comm.h 包含進來就ok .

總結 就是 一個工程假設有A,B,C,main.c 4個文件組成, 假設在main.c 中定義了一些變量p,q,m 若A文件要使用p , 則需要在A文件的開頭 用extern 關鍵字進行聲明。

 

拋磚引玉:開始進入基於ican協議的CAN開發,該平台單片機采用STC89C52

該工程由兩個文件組成SJA.C 和ican.c

    

SJA1000.h 中 定義了寄存器的硬件地址

基本地址 #define SJA_BaseAdr 0X7F00 由外部電路的硬件地址決定 單片機的那一個引腳連接在SJA1000的CS引腳上

內部控制寄存器 #define REG_CONTROL SJA_BaseAdr+0x00

命令寄存器 #define REG_COMMAND SJA_BaseAdr+0x01

狀態此存器 #define REG_STATUS SJA_BaseAdr+0x02

…….

發送緩沖區寄存器

#define REG_TXBuffer1 SJA_BaseAdr+0x10 //發送緩沖區1

#define REG_TXBuffer2 SJA_BaseAdr+0x11 //

#define REG_TXBuffer3 SJA_BaseAdr+0x12 //

#define REG_TXBuffer4 SJA_BaseAdr+0x13 //

#define REG_TXBuffer5 SJA_BaseAdr+0x14 //

#define REG_TXBuffer6 SJA_BaseAdr+0x15 //

#define REG_TXBuffer7 SJA_BaseAdr+0x16 //

#define REG_TXBuffer8 SJA_BaseAdr+0x17 //

#define REG_TXBuffer9 SJA_BaseAdr+0x18 //

#define REG_TXBuffer10 SJA_BaseAdr+0x19 //

#define REG_TXBuffer11 SJA_BaseAdr+0x1A //

#define REG_TXBuffer12 SJA_BaseAdr+0x1B //

#define REG_TXBuffer13 SJA_BaseAdr+0x1C //發送緩沖區13

接收緩沖區寄存器

#define REG_RXBuffer1 SJA_BaseAdr+0x10 //接收緩沖區1

#define REG_RXBuffer2 SJA_BaseAdr+0x11 //

#define REG_RXBuffer3 SJA_BaseAdr+0x12 //

#define REG_RXBuffer4 SJA_BaseAdr+0x13 //

#define REG_RXBuffer5 SJA_BaseAdr+0x14 //

#define REG_RXBuffer6 SJA_BaseAdr+0x15 //

#define REG_RXBuffer7 SJA_BaseAdr+0x16 //

#define REG_RXBuffer8 SJA_BaseAdr+0x17 //

#define REG_RXBuffer9 SJA_BaseAdr+0x18 //

#define REG_RXBuffer10 SJA_BaseAdr+0x19 //

#define REG_RXBuffer11 SJA_BaseAdr+0x1A //

#define REG_RXBuffer12 SJA_BaseAdr+0x1B //

#define REG_RXBuffer13 SJA_BaseAdr+0x1C //接收緩沖區13

 

SJA1000.h中聲明了若干函數 包括:

 

 

 

 

 

 

 

 

 

 

 

CAN總線發送數據的流程:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

發送數據還有一種寫法:

    if ((ReadSJAReg(REG_CAN_SR) & (TBS_BIT|TCS_BIT)) != (TBS_BIT|TCS_BIT))

     { status = 0;}    

 

查看SJA1000資料 有以下要點:

  1. SJA1000 的peilican模式的發送是單次發送

    (2)與發送有關的狀態寄存器的各位定義

符號

名稱

功能

SR.5

Ts

發送狀態

注3

1

發送 sja1000 在傳送信息

0

空閑 沒有要發送的信息

SR.3

Tcs

發送完畢狀態 注4

1

完畢 最近一次發送請求被成功處理

0

未完畢 當前發送請求未處理完畢

SR.2

Tbs

發送緩沖區狀態 注5

1

釋放:CPU可以向發送緩存器寫數據

0

鎖定:CPU不能訪問發送緩沖器,有信息正在等待

發送或者正在發送

 

注3:如果接收狀態位和發送狀態位 都是0 ,則CAN總線是空閑的。

注4:無論何時發送請求位被置為1,發送完畢位(Tcs)都會被置為0,發送完畢位會一直保持到消息被成功發送。

注5:如果CPU在發送緩沖器狀態為是0時(鎖定)試圖寫發送緩沖器,則寫入的字節被拒絕接收且會在無任何提示的情況下丟失。

 

     與485通訊比較,485發送出去的數據 若接收方沒有安裝,主機依然顯示發送成功,相比較CAN,CAN發送數據給另一個節點,則CAN節點在應答場會給主機CAN節點一個信號,表示主節點的CAN發送成功。

 

 

 

 

 

 

 

 

 

 

 

關於ican.c 中的應用

首先 我用結構體定義 iCANMSG 數據類型

在SJA.C 中定義了 icanmsg 數據類型的變量

 

iCANMSG message1 ;

iCANMSG * pcan ;

iCANMSG msg_readonly_s;

 

此外:對於ican協議我專門定義了指針 pcan 並用宏定義去進行處理,這樣很方便的與29位ID號所對應的標識符號對應上。

 

 

然后在ican.c中因為 用到了這些變量 全部在前面加上 extern

 

在main.c 里 我用

至於為什么要在main () 文件 的開頭 定義 msg_readonly_s

iCANMSG msg_readonly_s; //保存副本

 

是因為 如果出現如下情況 相當於是一個臨時變量,

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

關於使用位閾型結構體的總結:

ICAN協議:

遵循原則 第    條我認為不一定對,因為在ican下 我infoID定義8位

但是ican下 我的低3位 是沒有被定義的 undef

Ican 協議的格式定義如下:

幀結構信息

BIT7

BIT6

BIT5

BIT4

BIT3

BIT2

BIT1

BIT0

說明

FF

RTR

X

X

DLC.3

DLC.2

DLC.1

DLC.0

 

幀標識符信息

 

ID28

ID27

ID26

ID25

ID24

ID23

ID22

ID21

00

SRCMACID(資源節點編號)

 

ID20

ID19

ID18

ID17

ID16

ID15

ID14

ID13

00

DestMACID(目標節點編號)

 

ID12

ID11

ID10

ID9

ID8

ID7

ID6

ID5

ACK

FUNCID(功能碼)

SourceID(資源節點編號)

 

ID4

ID3

ID2

ID1

ID0

X

X

X

 

SourceID(資源節點編號)

未使用(忽略)

我定義的方法如下:

 

 

但是 我在應用j1939協議的時候

J1939協議 所定義的幀信息ID結構如下 (29位擴展)

ID28

ID27

ID26

ID25

ID24

ID23

ID22

ID21

優先級

保留位

數據頁

PDU格式

ID20

ID19

ID18

ID17

ID16

ID15

ID14

ID13

PDU格式

特定PDU

ID12

ID11

ID10

ID9

ID8

ID7

ID6

ID5

特定PDU

源地址

ID4

ID3

ID2

ID1

ID0

X

X

X

源地址

     

 

 

我的定義方法如下: 從低位到高位定義

 

 

 

 

 

 

 

 

      

 

 

 

 

 

 

 

 

 

 

 

 

 

 

假設 節點2 和節點3正在通訊,某一時刻節點1要設置節點3 。給節點3發數據,

節點1不用等到節點2和節點3不通訊了。節點1直接發送數據,節點1 的CAN硬件會自動控制給節點1發數據。不用人為控制,由CAN控制器的硬件來完成。

 

 

基於51單片機的CAN通訊試驗:

方法: 51單片機程序中不斷的往上位機(CANtest)發送數據 ,然后在某一任意時刻, 我用周立功的(CANtest)發送建立連接命令,看單片機是否可以正常響應。 並且記錄示波器的波形圖。

 

在CANTEST 上 點擊 發送消息幀 如下圖 第2個較短的時間間隔內的幀

該消息的ID號是 0x0023e4fe 數據場是 00 ee 0a

 

 

 

51單片機接收到消息以后,往上傳送消息 該消息的數據場 00 01 02 03 04

如下圖所示: 左側第一個較短的幀 就是 51單片機上傳的響應幀。數據場為00 01 02 03 04

響應場 的數據 (該數據我先不解析)

 

為了驗證我用kavaser 捕捉以下時間間隔 。

看兩個時間間隔

第一 就是上位機 發送建立連接命令 到收到51單片機 返回的響應幀的時間間隔

第二 就是51 單片機 返回響應幀 到 51單片機繼續往上位機傳送計數值的時間間隔

第三 測試 看一下 默認情況下 上位機不發送連接命令,51單片機上傳數據的時間間隔

 

第一個時間 我用示波器測試是: 約為200ms

第二個時間 我用示波器測試是: 約為1.5ms

第三個時間 我用示波器測試是: 約為12.4ms

 

我用kavaser 在 20190423 的 9點32 和 9點33 分左右的時候分別用cantest 發送建立連接命令 接收的時間間隔是 6041-4021=2021

2021*百分之一毫秒 約等於 200ms 與示波器測試一致

 

接下來 我用kavaser 的logging 功能測試

 

 

 

 

 

 

 

 

時刻 9點32 的數據

9點33時刻的數據

接下來 我的想法是 你新找一個51單片機 ,然后替換 周立功上位機的功能,進行連接命令的發送

試驗平台大家如下:

 

 

 

 

試驗平台照片

 

 

 

 

 

 

實際上 CAN 網絡是不分主機和從機的,不像485網絡。這里我設計的主機的功能就是:

按下:靠4個數碼管一側的按鍵, 按一下 數碼管的顯示增加1 然后並發送一幀

發送的消息幀 為 ID號 0x0023e4fe 數據場是00 ee 20 (16進制的20代表十進制32

計數 32次,認為握手時間是32秒,超過32秒可以認為連接斷開)

做這個事情的目的是:消息幀的發送我在用嵌入式編程的時候,用can_send_anylength()函數就可以搞定。這種情況使用於網絡中一直有數據通訊存在的情況。

 

 

 

 

 

 

 

試驗現象:

在時間10點24

我用主機(51單片機)的按鍵 發送消息幀 ID號0x0023e4fe 數據 00 ee 2 0

從機51單片機 在1秒以后 反饋給我響應幀 ID號0X3E034EE 數據是 00 01 02 03 04

在這個1秒的時間間隔內,CAN數據線上 還有一幀消息在傳遞 如下圖所示:

若在32秒內,主機再次發送連接命令,。從機將給主機反饋 已經在連接中的提示消息

該消息 的ID號是 0X3E02FFE 00 03

 

 

 

 

在時間:10:30:10:7323 我又用主機發送了 建立連接的消息

ID號是 0x023e4fe 00 ee 20

此時在10:30:10:8433 時刻 從機就給主機回復了消息幀 在這個時間間隔內,無其他幀在傳遞。 如下圖:

重要:與上面的那個中間有一幀的情況的截圖進行對比:可以知道:從機在接收到主機的連接,命令后,會判斷CAN線上是否空閑,如果當前有數據發送或接收 從機就等該數據發送完畢以后,在發送響應幀, 如果CAN線上空閑,則從機便可以直接發送給主機器響應幀。發送程序的時候 從機程序僅僅檢測 是不是上一幀數據是不是發送完成,並不檢測總線上空閑,這一塊是CAN控制器硬件自動完成的,我暫且先這么認為

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

在時間 10時30分 13秒 在32秒的計時時間內, 我再次發送建立連接命令,此時 從機

便會給我回復響應的消息幀 幀ID號 0x 3e02ffe 00 03 如下圖所示:

 

 

 

Word 源文件在百度網盤

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM