|
本帖最后由 浪迹天涯123 于 2017-12-26 20:21 编辑 * F0 a4 ^) k o # M R/ N/ r4 n" {$ K 简介:
总线电平=CAN_H的电压-CAN_L的电压 显性电平对应逻辑0=总线电平为2V左右 隐性电平对应逻辑0=总线电平为0V 9 N" f5 K4 R7 S4 Z: | S6 g 显性电平具有优先权,只要有一个单元输出显性电平,总线上即为显性电平。而隐形电平则具有包容的意味,只有所有的单元都输出隐性电平,总线上才为隐性电平(显性电平比隐性电平更强)。另外,在CAN总线的起止端都有一个120Ω的终端电阻,来做阻抗匹配,以减少回波反射。 帧种类介绍:[td]
注:其中,数据帧和遥控帧有标准格式和扩展格式两种格式。 STM32 CAN控制器简介:标准格式有11 个位的标识符(ID),扩展格式有29 个位的ID 。
3种模式: 工作模式:
测试模式:
调试模式(不常用) STM32 CAN筛选器位宽和模式配置:CAN的标识符不表示目的地址而是表示发送优先级,接收节点根据标识符的值,来决定是否接收对应消息。 ! H& F3 {" n1 B( ] 标识符屏蔽模式:过滤一组标识符 标识符列表模式:过滤一个标识符 例:设置筛选器组0工作在:1个32位筛选器-标识符屏蔽模式,然后设置CAN_F0R1=0XFFFF0000,CAN_F0R2=0XFF00FF00。其中存放到CAN_F0R1的值就是期望收到的ID,即(STID+EXTID+IDE+RTR)最好是:0XFFFF0000。而0XFF00FF00就是设置我们需要必须关心的ID,表示收到的映像,其位[31:24]和位[15:8]这16个位的必须和CAN_F0R1中对应的位一模一样,而另外的16个位则不关心,可以一样,也可以不一样,都认为是正确的ID,即收到的映像必须是0XFFxx00xx,才算是正确的(x表示不关心)。 波特率设置:寄存器: CAN主控制寄存器(CAN_MCR) 该寄存器的我们仅介绍下INRQ位,该位用来控制初始化请求。 " n$ w8 R3 `& X8 E, J+ a 设置INRQ=0,可使CAN从初始化模式进入正常工作模式。 设置INRQ=1,可使CAN从正常工作模式进入初始化模式。 CAN初始化时,先设置INRQ=1,进入初始化模式,进行初始化(尤其是CAN_BTR的设置,该寄存器,必须在CAN正常工作之前设置),之后再设置INRQ=0,进入正常工作模式。 CAN位时序寄存器(CAN_BTR)设置波特率 配置步骤:CAN接收FIFO寄存器(CAN_RF0R/CAN_RF1R) CAN发送邮箱标识符寄存器(CAN_TIxR)(x=0~2) % f2 r; K0 n& Z) I6 y' l( J CAN发送邮箱数据长度和时间戳寄存器 (CAN_TDTxR) (x=0~2) 低4位用于设置发送多少个字节,最多为8个字节 CAN发送邮箱数据寄存器(CAN_TDLxR/CAN_TDHxR) (x=0~2) G0 e& E( P# c- e" k) ] S, B! A/ O CAN接收FIFO邮箱标识符寄存器(CAN_RIxR)(x=0/1) CAN接收FIFO邮箱数据长度和时间戳寄存器(CAN_RDTxR) (x=0/1) - [3 b* {$ a/ F+ U/ I+ c CAN接收FIFO邮箱邮箱数据寄存器(CAN_RDLxR/CAN_RDHxR) (x=0/1) CAN筛选器模式寄存器(CAN_FM1R)(0标识符屏蔽,1标识符列表) CAN筛选器尺度寄存器(CAN_FS1R)(0双16位,1单32位) CAN筛选器FIFO关联寄存器(CAN_FFA1R)(0筛选器分到FIFO0,1筛选器分到FIFO1) CAN筛选器激活寄存器(CAN_FA1R)(0未激活,1激活) CAN筛选器组i寄存器x(CAN_FiRx)(i=0~27,x=1/2)(F103筛选器只有14个) ①配置相关引脚的 复用功能,使能CAN时钟。
②设置CAN工作模式及波特率等。
③设置滤波器。 CODE://can.c #include "can.h"* D M; A6 y$ y( E #include "led.h" #include "delay.h" #include "usart.h" ; M4 M2 z; m# _7 t& ? % B- }! Y# J R% q //CAN初始化 //tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq+ }( X( f2 h3 N5 g8 R/ @ //tbs2:时间段2的时间单元. 范围:CAN_BS2_1tq~CAN_BS2_8tq; //tbs1:时间段1的时间单元. 范围:CAN_BS1_1tq ~CAN_BS1_16tq //brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1 //波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);( P s; ^1 ^1 _6 n$ t //mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式; //Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);8 C/ E3 r* d" K- v# r //则波特率为:36M/((8+9+1)*4)=500Kbps! n8 U4 R( O. F& t* x$ l //返回值:0,初始化OK; // 其他,初始化失败; u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)) P) d6 o# h3 X8 E2 J { GPIO_InitTypeDef GPIO_InitStructure; CAN_InitTypeDef CAN_InitStructure; CAN_FilterInitTypeDef CAN_FilterInitStructure; #if CAN_RX0_INT_ENABLE NVIC_InitTypeDef NVIC_InitStructure;' q1 F3 M7 J! ?( v0 d' u. N #endif 8 I0 g/ N4 `% y6 i4 t- G4 ]7 } RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PORTA时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //使能CAN1时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;% J3 z' T- W, k4 M) w' p GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化IO //CAN单元设置) u [( {* o6 u) _$ p CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式 CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理 CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位) CAN_InitStructure.CAN_NART=ENABLE; //禁止报文自动传送 + V @8 M9 z/ o$ e+ N# r+ S CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的 CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定 3 f8 ~6 X9 F& J- V& _ CAN_InitStructure.CAN_Mode= mode; //模式设置: mode:0,普通模式;1,回环模式; 1 ]3 H8 V7 H' Q0 S$ b8 I //设置波特率2 T, ^! d2 h/ [* `# m CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq/ X1 O! n: M, H7 J CAN_InitStructure.CAN_BS1=tbs1; //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq4 ~3 y; x% r7 L) s CAN_InitStructure.CAN_BS2=tbs2; //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq CAN_InitStructure.CAN_Prescaler=brp; //分频系数(Fdiv)为brp+1 h! Z& o% A1 h3 w( K/ ~5 X CAN_Init(CAN1, &CAN_InitStructure); //初始化CAN1 " R- Q0 p# O7 \9 w J CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器0- A- w0 D! m/ M% ? CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //屏蔽位模式1 @4 {4 A" t* R& [; o CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位宽 CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //32位ID CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;$ ]2 I8 Y: O8 u( g7 u+ b/ B/ I CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK1 y' E6 Q: j+ _9 L z) W% d8 f CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;* P( M2 }( P% i o" ?" A CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0: b9 N. }" S& j3 u# t7 [9 ] CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0* D5 {2 r. ]+ E1 } CAN_FilterInit(&CAN_FilterInitStructure); //滤波器初始化- t! e1 d6 |/ p; a& X3 V 0 \8 L) d6 E$ Z4 H #if CAN_RX0_INT_ENABLE / B; i8 A! m, D CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //FIFO0消息挂号中断允许. ) N% Y0 i9 I* p8 P- i: ^ NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;2 J; c! }) r, @+ i NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;2 E% I( ?0 d) a1 Y2 |+ m& Q/ B5 C NVIC_Init(&NVIC_InitStructure); #endif return 0;3 F* A- a1 \& g, k } #if CAN_RX0_INT_ENABLE //使能RX0中断 //中断服务函数 ! s! d" `, P6 E" B m' ^% {/ x& z void USB_LP_CAN1_RX0_IRQHandler(void) { CanRxMsg RxMessage; int i=0; b/ f0 |( D! q) Y2 O: p, W CAN_Receive(CAN1, 0, &RxMessage); for(i=0;i<8;i++) printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data); }5 O: F+ ]( ~$ R6 Z* y0 C #endif //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧) //len:数据长度(最大为8) - E: C+ r/ g0 z. _" s //msg:数据指针,最大为8个字节.* q* v5 @1 j* H. u5 ^( } //返回值:0,成功;3 l6 ?0 y: ^; H7 V, I // 其他,失败;+ z5 z" n2 n+ M. `1 u u8 Can_Send_Msg(u8* msg,u8 len)5 h8 O4 Z4 {4 Z4 Y% o { / g* G/ \! K& z u8 mbox; u16 i=0;) W+ H5 e: E* i+ T2 W8 a CanTxMsg TxMessage;3 W* j* O* C! a0 g, G" [0 r/ e: F TxMessage.StdId=0x12; // 标准标识符 TxMessage.ExtId=0x12; // 设置扩展标示符 TxMessage.IDE=CAN_Id_Standard; // 标准帧 TxMessage.RTR=CAN_RTR_Data; // 数据帧 TxMessage.DLC=len; // 要发送的数据长度; b, Q0 ]+ A7 H for(i=0;i<len;i++) TxMessage.Data=msg; mbox= CAN_Transmit(CAN1, &TxMessage); i=0; while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++; //等待发送结束( B0 [; J4 ]6 z9 p$ l/ M if(i>=0XFFF)return 1;4 p0 V% P5 t2 |; Z# m# { return 0; # L8 u/ V; r8 Y2 q( k. c9 I: ?) F }: F: L6 i% j; \! U2 e2 j //can口接收数据查询 //buf:数据缓存区; 1 T' J. e+ {1 d& ^; W3 O/ `0 a //返回值:0,无数据被收到;, i* D1 f- r: K4 R/ W2 i# Y // 其他,接收的数据长度; u8 Can_Receive_Msg(u8 *buf)# V; u% A6 }' a, R { u32 i; CanRxMsg RxMessage;: Q* m0 a' x0 Y* {% c' P if( CAN_MessagePending(CAN1,CAN_FIFO0)==0)return 0; //没有接收到数据,直接退出 % A8 Z1 }0 |4 R5 z CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//读取数据 for(i=0;i<8;i++) buf=RxMessage.Data; 5 L' b' Q \2 U# l: d/ C$ u% U return RxMessage.DLC; 7 D; N; Z; {2 s( I' Q' a; f }' ^, W4 o6 H7 K3 ~& t # u# ~7 q) ]' T- d! N7 P main.c #include "led.h"# Z7 H7 g" X" {5 G2 A. s #include "delay.h" #include "key.h" P, `5 ~' j$ ` #include "sys.h" #include "lcd.h" #include "usart.h" #include "can.h" ( j8 k7 `" w. K* B& I E + c2 A) Y, h& U3 i" ` int main(void) { u8 key;+ L s% u9 b5 D# l v u8 i=0,t=0; u8 cnt=0;# e8 N; n+ ` X* z u8 canbuf[8];8 Y5 B/ |- g. M u8 res; u8 mode=CAN_Mode_LoopBack;//CAN工作模式;CAN_Mode_Normal(0):普通模式,CAN_Mode_LoopBack(1):环回模式 ! P( P$ z1 ] ~, F0 d delay_init(); //延时函数初始化 7 x( c. B6 V# ?3 y- c( N NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级5 r/ [0 m9 h. A6 z8 D8 E uart_init(115200); //串口初始化为115200 LED_Init(); //初始化与LED连接的硬件接口 LCD_Init(); //初始化LCD KEY_Init(); //按键初始化 - |6 C( i4 U% m' ~ CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);//CAN初始化环回模式,波特率500Kbps . g9 s' D. ~4 [1 O3 @! x8 M POINT_COLOR=RED;//设置字体为红色 LCD_ShowString(60,50,200,16,16,"WarShip STM32"); 4 V* _6 }& @9 { q LCD_ShowString(60,70,200,16,16,"CAN TEST"); : L6 |3 h- Y, a4 m- O2 o LCD_ShowString(60,90,200,16,16,"ATOM@ALIENTEK"); LCD_ShowString(60,110,200,16,16,"2015/1/15");0 S( U* F9 q, z" R! L LCD_ShowString(60,130,200,16,16,"LoopBack Mode"); & I# |; \ W: t4 D( w( ?2 I; M/ g LCD_ShowString(60,150,200,16,16,"KEY0:Send WK_UP:Mode");//显示提示信息 POINT_COLOR=BLUE;//设置字体为蓝色 r3 R) u: H, B5 }! A. h7 v LCD_ShowString(60,170,200,16,16,"Count:"); //显示当前计数值 LCD_ShowString(60,190,200,16,16,"Send Data:"); //提示发送的数据 7 q6 J6 C! Z5 P! m LCD_ShowString(60,250,200,16,16,"Receive Data:"); //提示接收到的数据 5 {" _4 R4 B4 \# _& t) t- j while(1) { key=KEY_Scan(0);, L' X- s1 i4 g% c if(key==KEY0_PRES)//KEY0按下,发送一次数据% @: I, U4 s0 `" v! C! a U4 w {0 e6 K2 r v6 ~( A, i* t for(i=0;i<8;i++) { canbuf=cnt+i;//填充发送缓冲区( V- M4 n9 L7 {& S3 Z* t, S Q if(i<4)LCD_ShowxNum(60+i*32,210,canbuf,3,16,0X80); //显示数据/ A' f7 @8 e# f$ G else LCD_ShowxNum(60+(i-4)*32,230,canbuf,3,16,0X80); //显示数据' y5 H) s* j/ q } res=Can_Send_Msg(canbuf,8);//发送8个字节 if(res)LCD_ShowString(60+80,190,200,16,16,"Failed"); //提示发送失败, J. `( F X1 `" i3 A else LCD_ShowString(60+80,190,200,16,16,"OK "); //提示发送成功 1 h* z* X# d5 `$ V. X. J3 q }else if(key==WKUP_PRES)//WK_UP按下,改变CAN的工作模式 { mode=!mode; CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);//CAN普通模式初始化, 波特率500Kbps POINT_COLOR=RED;//设置字体为红色 / C I/ t( R r& |* ]2 c; g+ N if(mode==0)//普通模式,需要2个开发板' \& `3 _+ M4 [' w- x* T7 K' [ { LCD_ShowString(60,130,200,16,16,"Nnormal Mode "); ) x; P4 @$ r1 | }else //回环模式,一个开发板就可以测试了. {3 } x6 ?* a/ s; i6 C LCD_ShowString(60,130,200,16,16,"LoopBack Mode"); } POINT_COLOR=BLUE;//设置字体为蓝色 6 \" S7 N, y+ y! S } key=Can_Receive_Msg(canbuf);* e) ~9 q$ u( z7 ]! E if(key)//接收到有数据 { LCD_Fill(60,270,130,310,WHITE);//清除之前的显示( y z2 C& g" r for(i=0;i<key;i++) { , o! O+ l/ h9 U if(i<4)LCD_ShowxNum(60+i*32,270,canbuf,3,16,0X80); //显示数据 else LCD_ShowxNum(60+(i-4)*32,290,canbuf,3,16,0X80); //显示数据9 O& m' F- a) n0 | } z/ B+ k, f' q, J p- S }5 C! ^% c6 j% F5 K! B% u# A t++; ( j \/ \# u6 g- T# L- i delay_ms(10); if(t==20) {! I# Z. B, ^ _% I9 v LED0=!LED0;//提示系统正在运行 t=0; cnt++; LCD_ShowxNum(60+48,170,cnt,3,16,0X80); //显示数据9 [" Z4 t3 n* J* B9 r1 D } # x% N% @5 p; ^( V$ r$ R' i/ k8 a } } |
谢谢楼主,收了 |
微信公众号
手机版