你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

刘洋【入门笔记】第31讲 STM8 CAN总线标识符过滤实验

[复制链接]
众想@刘洋 发布时间:2016-10-8 15:13
【剑齿虎】STM8开发板学习笔记
31讲   STM8 CAN总线标识符过滤实验
31.1 CAN控制器原理图   
图片1.png
31.1 CAN控制器接口
    CAN协议里,报文的标识符不代表节点的地址,而是跟报文的内容相关的。因此,发送者以广播的形式把报文发送给所有的接收者。节点在接收报文时,根据标识符(CAN ID)的值决定软件是否需要该报文;如果需要,就拷贝到SRAM里;如果不需要,报文就被丢弃且无需软件的干预。
31.2 实验目的   
通过对CAN过滤器的设置,屏蔽总线上其他无用的报文,只接收自己需要的报文。  标识符过滤模式
31.2.1  标识符过滤模式
每个过滤器组的位宽都可以独立配置,以满足应用程序的不同需求。根据位宽的不同,每个过滤器组可提供:
  ─  1 个 32 位过滤器,包括:STDID[10:0]/EXTID[28:18]、IDE、EXID[17:0]和 RTR 位;
  ─  2 个 16 位过滤器,包括:STDID[10:0]/EXTID[28:18]、IDE 和 RTR 位;
  ─  4 个 8 位过滤器,包括:STDID[10:3]/EXTID[28:21],其他位可以不用关心;
  ─  1 个 16 位过滤器和 2 个 8 位过滤器,具体的过滤器描述如上16位和8位过滤器描述。
FMLx位定义该寄存器组的低半组(CAN_FxR1-4寄存器)的模式,
FMHx位定义该寄存器组的高半组(CAN_FxR5-8寄存器)的模式。
31.2.2  32位过滤器组设置
FMHx=0 高位寄存器工作在屏蔽位模式。FMLx =0 低位寄存器工作在屏蔽位模式。
FMHx=1 高位寄存器工作在标识符列表模式。FMLx =1 低位寄存器工作在标识符列表模式。
FMLx和FMHx位必须拥有相同的值以确保4个屏蔽位/标识符过滤器位处于相同的模式。
图片2.png
31.2 32位过滤器图31.1 CAN控制器接接口
“STID”代表标准数据帧;
“EXID”代表扩展数据帧;
“RTR”如果为0代表数据帧,如果为1代表远程帧;
“IDE”如果为0代表标准帧,如果为1代表扩展帧;
STM8的CAN有1个FIFO,每组过滤器组必须关联这一个FIFO.且复位默认就关联到FIFO。所谓"关联",是指假如收到的报文从某个过滤器通过了,那么该报文会被存到该过滤器相连的FIFO。
31.3 程序文件设计   31.3.1  main.c文件中的程序
主程序就实现初始化和调用驱动程序,这样主程序控制思路清晰,流程简单。要想了解全面详实的程序,请大家参考光盘(网盘)中程序及程序注释。
/***********************************************************************
*   作    者: 刘洋 张殿东
*   版    本: V1.0
*   日    期: 2016-05-03   
*
*   IAR开发环境    版本 V2.20.1
*   ST库函数       版本 V2.2.0
***********************************************************************/
#include "pbdata.h"//引入自定义公共头文件
void BSP_Configuration(void);//硬件初始化函数声明
/***********************************************************************
*   函 数 名: main
*   功能说明: c程序入口
*   形    参:无
*   返 回 值: 错误代码(无需处理)
***********************************************************************/
int main(void)
{
  BSP_Configuration();//硬件驱动初始化函数
  
  while(1)//主程序循环,反复执行循环体里的语句
  {
    //LED_Demo1();//在主程序中调用LED_Demo1()函数
    //LED_Demo2();//在主程序中调用LED_Demo2()函数
    //UART1_Printf_Demo();
    //CAN_SendData_Demo2();
  }
}
/***********************************************************************
*   函 数 名: BSP_Configuration
*   功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
*   形    参:无
*   返 回 值: 无
***********************************************************************/
void BSP_Configuration(void)
{  
  CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);//时钟速度为内部16M,1分频,
  UART1_Congfiguration();//调用RS232串口1初始化函数
  LED_Init();//调用LED初始化函数
  CAN_Configuration();//调用CAN初始化函数
  rim();//打开总中断
}
/*断言函数:它的作用是在编程的过程中为程序提供参数检查*/
#ifdef USE_FULL_ASSERT
void assert_failed(u8* file,u32 line)
{
  while(1)
  {
  }
}
#endif
31.3.2  pbdata.c文件中的程序
#include "pbdata.h"   //引入自定义公共头文件
/***************************************************************************
*   函 数 名: delay_us
*   功能说明: 微秒延时程序,注意此函数的运行环境为(16M时钟速度)
*   形    参:nCount要延时的微秒数,输入nCount=1微妙
*   返 回 值: 无
***************************************************************************/
void delay_us(u16 nCount)   //16M 晶振时  延时 1个微妙
{
    nCount*=3;//等同于 nCount=nCount*3  相当于把nCount变量扩大3倍
    while(--nCount);//nCount变量数值先减一,再判断nCount的数值是否大于0,大于0循环减一,等于0退出循环。
}
/***************************************************************************
*   函 数 名: delay_ms
*   功能说明: 毫秒延时程序,注意此函数的运行环境为(16M时钟速度)
*   形    参:nCount要延时的毫秒数,输入nCount=1毫秒
*   返 回 值: 无
***************************************************************************/
void delay_ms(u16 nCount)  //16M 晶振时  延时 1个毫秒
{
    while(nCount--)//先判断while()循环体里的nCount数值是否大于0,大于0循环,减一执行循环体,等于0退出循环。
    {
        delay_us(1000);//调用微妙延时函数,输入1000等译演示1毫秒。
    }
}
/***************************************************************************
*   函 数 名: Get_decimal
*   功能说明: 获得数值小数部分
*   形    参:dt输入数据 deci小数位数,最多保留4位小数
*   返 回 值: 放大后的小数部分
***************************************************************************/
u16 Get_decimal(double dt,u8 deci)   //获得数值小数部分
{
    long x1=0;
    u16 x2=0,x3=0;
    if(deci>4) deci=4;
    if(deci<1) deci=1;
    x3=(u16)pow(10, deci);
    x1=(long)(dt*x3);
    x2=(u16)(x1%x3);
    return x2;
}
31.3.3  pbdata.h文件中的程序
#ifndef _PBDATA_H//宏定义,定义文件名称
#define _PBDATA_H
#include "stm8s.h"//引入STM8的头文件
#include <stdio.h>//需要引用这个头文件才能实现
#include "math.h"//需要引用这个头文件才能实现
#include "led.h"  //引用LED头文件
#include "uart1.h"//引用RS232头文件
#include "can.h"
void delay_us(u16 nCount); //微秒延时程序
void delay_ms(u16 nCount); //毫秒延时程序
u16 Get_decimal(double dt,u8 deci);   //获得数值小数部分
#endif //定义文件名称结束

7 `" H0 e5 v. X) l. @$ p


% R1 Z0 c8 A8 w" X

   

! r* s" D- T+ m' z* U
图片3.png
收藏 1 评论7 发布时间:2016-10-8 15:13

举报

7个回答
众想@刘洋 回答时间:2016-10-8 15:14:29
31.3.4  can.c文件中的程序
3 ]5 N- O  x% o9 O0 ]8 _#include "pbdata.h"
( z* p$ ]/ ~4 T0 J/***************************************************************************
% x3 H; Z2 M$ D: t" _3 {2 d* v*   函 数 名: CAN_Configuration
3 S9 T) ^& n. ]$ [) h*   功能说明: CAN初始化9 m- b% O& v$ W2 d4 M/ x" _
*   形    参:无* N1 i; c+ H8 R1 }  a
*   返 回 值: 无
+ \$ |0 k6 \5 v8 p: ~5 o) J***************************************************************************/$ R' Y5 l" Q! x# {7 k
void CAN_Configuration(void)
. E5 {/ ], F- S' a* X& I7 o9 |{
; @  ^7 ^. K, I    //初始化CAN波特率为1M      CAN_Init(CAN_MasterCtrl_AllDisabled,CAN_Mode_Normal,CAN_SynJumpWidth_1TimeQuantum,CAN_BitSeg1_11TimeQuantum,CAN_BitSeg2_4TimeQuantum,1);
+ _3 u4 g5 G3 @  y) E    //配置CAN第0组过滤器为屏蔽模式。但是屏蔽位都设置为0,所以相当于没启动屏蔽功能。    //CAN_FilterInit(CAN_FilterNumber_0,ENABLE,CAN_FilterMode_IdMask,CAN_FilterScale_32Bit,0,0,0,0,0,0,0,0);    //CAN_FilterInit(CAN_FilterNumber_1,ENABLE,CAN_FilterMode_IdMask,CAN_FilterScale_32Bit,0x02,0x40,0,0,0xFF,0xF8,0,0);     屏蔽滤波//CAN_FilterInit(CAN_FilterNumber_2,ENABLE,CAN_FilterMode_IdMask,CAN_FilterScale_32Bit,0,0x08,0x24,0x68,0xFF,0xFF,0xFF,0xFE);   屏蔽滤波 CAN_FilterInit(CAN_FilterNumber_3,ENABLE,CAN_FilterMode_IdList,CAN_FilterScale_32Bit,0x02,0x40,0,0,0x03,0x40,0,0); // 所过滤的ID号是:Ox12和Ox1A  列表功能     CAN_FilterInit(CAN_FilterNumber_4,ENABLE,CAN_FilterMode_IdList,CAN_FilterScale_32Bit,0,0x08,0x24,0x68,0,0x08,0x34,0x68); //所过滤的ID号是:Ox1234和Ox1A34  列表功能
( u8 ?( `4 R* N1 Q7 V+ f    //使能CAN接收中断功能
3 X+ @! C7 \+ ^/ o/ r3 k    CAN_ITConfig(CAN_IT_FMP,ENABLE);: G9 B- W- p7 ]) C% S9 f9 N4 f
}
, t6 ^3 f5 @% w9 @8 A/***************************************************************************
$ Q# P3 `' z; k, u* I*   函 数 名: CAN_RecvData_Demo1" }1 i% f. I- I8 f5 e7 W3 }
*   功能说明: CAN数据转发实验例程
3 U. x: u* P9 @6 Q: X1 J; A7 y*   形    参:无
2 k) ^6 Y: N6 K" ]5 m8 }8 N4 T/ Q*   返 回 值: 无% _" p$ i! ]9 p& o# b( ~8 U7 u
***************************************************************************/
9 p! l- j7 C8 c7 {3 i; j. g" m$ Y1 ?* `! }void CAN_RecvData_Demo1(void)
% D& E, x* {- F! d9 A1 G5 j* g{  @' W- l& T$ l. O) r- I
    u32 id;% I. M9 X7 Z3 s2 t  K6 A, r
    CAN_Id_TypeDef ide;2 Q2 }2 `; J, U  v6 o
    CAN_RTR_TypeDef rtr;
. W: R& m& u* a0 ^    u8 data[8];0 y$ `, E7 F* G, z
    u8 dlc,i;: L: H2 G! L& W( l* ?1 `
    CAN_Receive();//读取缓存中的数据
( [6 G2 {" r0 j1 a2 D. S    id=CAN_GetReceivedId();//读取ID号; [( a) u4 M7 u0 ^& ^; A5 [
    ide=CAN_GetReceivedIDE();//读取帧类型(标准或扩展)! B3 Z8 S; H9 o) I% w1 B% T
    rtr=CAN_GetReceivedRTR();//读取帧类型(数据或远程)
' Z0 Q: c( P( n; @$ i    dlc=CAN_GetReceivedDLC();//读取接收到的数据字节数8 @# L0 G, D/ ?6 ^
   
8 |+ L3 p: T0 `0 Q. S    for(i=0;i<dlc;i++)! t, R& C- N$ C  W. {/ H: @
    {
# g( l! O: _) \. _4 \( X+ ]1 ]        data=CAN_GetReceivedData(i);//把接收到的数据送到自定义数组里   
; }9 m5 D1 j& e* B  R" q0 G, F    }$ G! i  a" y9 O6 o! B
    CAN_Transmit(id,ide,rtr,dlc,data);//把接收到的数据转发出去(包括ID号、帧类型和数据)
# u& `* e' W+ `1 i1 l! @}
, I9 T' u/ i/ H* c* _) C  f( ?/***************************************************************************
8 y- J  _# u( c+ N8 X*   函 数 名: CAN_SendData_Demo2$ g2 i8 c3 `9 n1 J6 u3 f
*   功能说明: CAN数据发送实验例程1 t& w, P& c2 ~6 v
*   形    参:无
  G9 E: o0 \: r0 ?. u+ ?*   返 回 值: 无
* T( \1 U- P# R- L3 v8 `# s% q***************************************************************************/- u2 R/ j! J% U0 h' A
void CAN_SendData_Demo2(void)
6 I4 B* N& o& X' r9 j{9 F. o! |  L+ P
    u8 data[8];//定义CAN发送数组% {: Q: j5 o( l+ r# ~2 p
    data[0]=0x11;5 e" ?! r2 z/ }# K/ f! n4 V
    data[1]=0x22;
* j6 v+ y! e* D; v! ^4 r    data[2]=0x33;
& [# Q# r  P) ], o0 ?) M5 q    data[3]=0x44;! J; n2 a1 c! l) u$ W2 d
    data[4]=0x55;
/ H9 X% `( N) j+ b1 N$ X    data[5]=0x66;) m) E( M4 m/ ~, x3 g, j
    data[6]=0x77;  x- e; ~' E* p  C% b  C
    data[7]=0x88;
5 [% \! E' e: {6 h7 e    //发送标准数据帧. g- ?4 H+ P) D8 i& ]2 R
    CAN_Transmit(0x12,CAN_Id_Standard,CAN_RTR_Data,8,data);
- A. C2 P/ {* z3 N4 H! ?, u2 k0 N  r    delay_ms(1000);//延时1秒钟
1 T' l! Z; A, {+ v5 G3 G    //发送扩展数据帧8 z# _, V  P  }& R8 a8 I
    CAN_Transmit(0x1234,CAN_Id_Extended,CAN_RTR_Data,8,data);
+ @8 D& [: B( ~7 C    delay_ms(1000);//延时1秒钟
& s6 v% p& ~' X" F; |3 N0 j) i    //发送标准远程帧) {; h/ ]0 B3 F# O$ `8 M, U
    CAN_Transmit(0x12,CAN_Id_Standard,CAN_RTR_Remote,0,data);- F1 M# Q) y- m& V4 Y9 W2 r
    delay_ms(1000);//延时1秒钟* T9 p( f0 d7 _0 `4 S- X
    //发送扩展远程帧( h- B2 ]2 {$ l
    CAN_Transmit(0x1234,CAN_Id_Extended,CAN_RTR_Remote,0,data);
4 J3 Q$ l4 a# s# F8 D    delay_ms(1000);//延时1秒钟" l: t8 b: T' W+ _, k7 d: h" x' i( [1 [
}
# H. d* E: r& m  n' j/***************************************************************************
/ J! s+ i9 c2 L/ o4 \: C3 i# d*   函 数 名: CAN_RecvData_Demo3
" C7 @& ^* Q3 I* F* c*   功能说明: 接收命令控制LED灯实验
* j# ?9 Q7 s2 Z4 e8 i! u  h$ I1 a*   形    参:无
1 W& g# o: R& J! W8 F1 E# ^*   返 回 值: 无8 T2 L' a8 x% [' G' j! B  l
***************************************************************************/2 O% H$ V3 g" P6 p
void CAN_RecvData_Demo3(void), e; q# I, ~. d5 P
{$ B: R4 c7 u- s1 w' W- D
    u32 id;* Z  ]2 c/ s& ]3 ?! q% @- t( B: N4 {
    CAN_Id_TypeDef ide;4 G" N( K3 w! t) \7 S& \' k
    CAN_RTR_TypeDef rtr;
, H* @# \6 S! d( C    u8 data[8];
$ ^" Z2 N! O, z, X2 b' S    u8 dlc,i;
  l& {- l6 }' P; X: d. `    CAN_Receive();//读取缓存中的数据) N8 B. n( s$ `0 U1 `# O
    id=CAN_GetReceivedId();//读取ID号
* b& w: M3 y2 {* m    ide=CAN_GetReceivedIDE();//读取帧类型(标准或扩展)
% [0 C2 }5 F6 x" K' V+ }4 @    rtr=CAN_GetReceivedRTR();//读取帧类型(数据或远程)% Y, P- U& [# r/ k' F1 {6 D" ?! e
    dlc=CAN_GetReceivedDLC();//读取接收到的数据字节数; e, Y& \/ K0 ?5 w
    for(i=0;i<dlc;i++)
& F8 `0 c( e- p' Y2 K& d    {
- G9 ~5 ?. R( V# @+ l        data=CAN_GetReceivedData(i);//把接收到的数据送到自定义数组里   
& D* ^& J) x/ _- ]% |    }
4 R' `. T3 g. p% l    if(ide==CAN_Id_Standard && rtr==CAN_RTR_Data)//标准数据帧
% K- `# P+ [* G' `    {1 g6 c6 ^' t" z: O$ S8 n) i) E9 L
        if(data[0]==0x01) LED1_L;//点亮LED1发光二极管( `, v( F  G7 j8 T4 U% s: C1 _
        if(data[1]==0x01) LED2_L;//点亮LED2发光二极管) |. e0 W6 `# p# b9 ?
        if(data[2]==0x01) LED3_L;//点亮LED3发光二极管
/ W; y9 L5 z0 _- @    }1 z% V" g8 s" t9 X8 y/ G
   
( t& B$ G! h' S: _    if(ide==CAN_Id_Extended && rtr==CAN_RTR_Data)//扩展数据帧. V7 \% {8 J9 _
    {  k& Y. R0 x3 ?& o$ f' ^2 l
        if(data[0]==0x02) LED1_H;//熄灭LED1发光二极管
/ v! ~1 i* V" l' f/ Y5 g        if(data[1]==0x02) LED2_H;//熄灭LED2发光二极管- e4 u: P$ ^0 K
        if(data[2]==0x02) LED3_H;//熄灭LED3发光二极管
5 x) X' y& T* T; [+ ^" s    }  k1 M" h/ R" A8 u, d+ L
    if(ide==CAN_Id_Standard && rtr==CAN_RTR_Remote)//标准远程帧
9 D- i; ~+ J8 P: z' q! I8 i    {$ ~3 O5 V+ i) G& E  e, ]
        for(i=0;i<8;i++)! n7 u, F6 o2 z
        {# C" S- N3 K2 Q" y
            data=i;/ q: X' U. }5 _
        }1 Q1 _3 ?% Z" e: k5 y2 u$ U% e$ r
        
3 C" J) }3 E8 I+ a$ q% r2 ]        CAN_Transmit(id,CAN_Id_Standard,CAN_RTR_Data,8,data);//发送标准数据帧
) G5 f( ]3 ^" Z" X4 h" U5 }    }' f* v: t- s8 y; o5 ~+ h8 D
    if(ide==CAN_Id_Extended && rtr==CAN_RTR_Remote)//扩展远程帧5 ?' Q/ R, S* L: i: j
    {( u( U' w4 a7 @- Y# X, j4 e
        for(i=8;i<=0x0F;i++)8 g) x" S9 ]. e: `, Y
        {
- h, Z1 V7 V5 N8 j8 m            data[i-8]=i;( }! d" f2 @+ b* W
        }
. b% r# V: Q. g0 n        CAN_Transmit(id,CAN_Id_Extended,CAN_RTR_Data,8,data);//发送扩展数据帧% q6 H8 }3 G/ c  J6 X4 ]3 _
    }
2 G" H- x5 T. H; _) j}$ A7 r- ~/ Q* y( _2 @: m, n
31.3.5  can.h文件中的程序! `" A/ i: S- ]1 B/ R( M
#ifndef _CAN_H  //宏定义,定义文件名称2 [  O4 \1 L4 c4 j5 S) E6 }
#define _CAN_H. Y% \* y: V7 ?  x" O
#include "stm8s.h"//引用STM8头文件! j# c. i4 |0 d) f# N" `8 x  T0 G
void CAN_Configuration(void);//CAN初始化函数
" h4 g1 v) H: r5 \/ n; z% Uvoid CAN_RecvData_Demo1(void);//CAN数据转发函数7 O2 o5 g) [) y
void CAN_SendData_Demo2(void);//CAN数据发送函数+ M; v, C' j, c( c* o$ _
void CAN_RecvData_Demo3(void);//接收命令控制LED灯实验
. f9 i+ Y0 C- ^) E& p#endif //定义文件名称结束
0 J& e, L) t7 @; q6 Q31.3.6  uart1.c文件中的程序  H, }$ I. X9 \# W( o! `% L7 S( U/ X
设计串口通讯软件是为了通过串口uart1能把CAN通讯数据输出到计算机上显示出来,能直观的看到通讯数据是否和设计一致。
3 f* R# h# q7 Q3 O$ L: z' Y……详细程序请参考程序例程。
1 }2 `' [9 C& D3 _% C/ y31.3.7  uart1.h文件中的程序; W1 C3 D7 N% D" T# b8 }$ a
……详细程序请参考程序例程。( G7 P' W) n6 o4 A4 D
31.3.8  led.h文件中的程序( t: B, Y  C1 c2 H; J" z6 a' t
……详细程序请参考程序例程
9 _' C3 M) C, ]31.3.9  led.h文件中的程序
8 U: S# Y' M; Q: g7 \……详细程序请参考程序例程  k" s* k8 q& z% \/ G  ]
31.4 实验过程
* u# {6 d3 ^. l   我们使用蓝精灵多功能监控软件来实现CAN通讯调试过程,打开串口后,在接收区会有两条提示信息,包括CAN控制器型号、通道等等;接着要设置波特率,波特率默认值是5KBPS,我们要设置为1MBPS。# l. l1 P6 j6 z- t7 \, @4 i
stary666 回答时间:2016-10-8 16:23:10
顶一下,,,,,,,,,
ynwscfsfi 回答时间:2016-10-8 19:50:46
感谢分享!
ynwscfsfi 回答时间:2016-10-8 19:51:12
感谢分享!
mark0668 回答时间:2016-10-9 15:28:56
感谢分享!支持
jczhao_2003 回答时间:2018-4-20 12:14:08
感谢分享!!!!!
ykkkkk 回答时间:2019-11-4 17:05:44
感谢分享!!!
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版