目录
前言程序编写主代码测试
CAN协议是非常难的,但是在stm32中却是简单的,只需要我们配置寄存器即可,,,即使这样,我在学习的时候也遇到了许多困难
1、开时钟,不用说
2、设置GPIO口,,CAN_TX复用推挽输出,CAN_RX上拉或浮空输入
3、CAN初始化了,分三步
一般设置 /*对CAN初始化*/ CAN1->MCR |= 1 << 15; //软复位 CAN1->MCR &= ~(1 << 1); //退出睡眠模式 (郁闷,忘退出睡眠模式了,折腾了半天) CAN1->MCR |= 1 << 0; //设置初始化模式 必须 while(!(CAN1->MSR & 1 << 0)); //等待确认初始化 CAN1->MCR |= 0 << 7; //禁止时间触发模式 CAN1->MCR |= 0 << 6; //禁止自动离线 CAN1->MCR |= 0 << 5; //禁止自动唤醒 CAN1->MCR |= 1 << 4; //报文只传送一次,禁止自动重传 CAN1->MCR |= 0 << 2; //优先级由报文的标识符决定 时序设置(时序也在初始化模式中) /* 设置CAN位时序*/ CAN1->BTR &= 0x00000000; // CAN1->BTR |= mode << 30; //正常模式(0)或环回模式(1)可见CAN_BTR寄存器 CAN1->BTR |= sjw << 24; //设置sjw CAN1->BTR |= ts2 << 20; // CAN1->BTR |= ts1 << 16; // CAN1->BTR |= brp << 0; CAN1->MCR &= ~(1 << 0); //退出初始化 while(CAN1->MSR & 1 << 0); //确认退出初始化 滤波器设置 /* 设置过滤器组 */ CAN1->FMR |= 1 << 0; //过滤器组设置在初始化模式(记得必须设置初始化模式) CAN1->FA1R &= ~(1 << 0); //过滤器禁用 CAN1->FM1R &= ~(1<< 0); //过滤器组工作在标识符屏蔽位模式 CAN1->FS1R |= 1<<0; //过滤器组位宽为32位 CAN1->FFA1R &= ~(1 << 0); //关联到fifo0 CAN1->sFilterRegister[0].FR1 = 0X00000000; //全都为0 ,什么数据都接受 CAN1->sFilterRegister[0].FR2 = 0X00000000; CAN1->FA1R |= 1 << 0; //激活过滤器 //退出滤波器初始化模式 (记得要退出,否则发送成功却接受不到,不要问我为什么这么清楚。。。) CAN1->FMR &= 0 << 0;4、发送消息函数和得到发送状态函数 见下写程序 u8 CAN_TX_Msg(u8 ide, u32 id, u8 rtr, u8 len, u8 *data) u8 CAN_TX_Statt(u8 mbox)
5、接收函数
// 参数要用指针,开始我ide没用指针,在其他函数调用这个函数ide的值是不确定的 void CAN_RX_Msg(u8 *ide, u32* id, u8* rtr, u8* len, u8 *data, u8 fifox) { *ide = (CAN1->sFIFOMailBox[fifox].RIR & 1<<2)>>2; if(*ide == 0) { *id = CAN1->sFIFOMailBox[fifox].RIR >> 21; } else { *id = CAN1->sFIFOMailBox[fifox].RIR >> 3; } *rtr = (CAN1->sFIFOMailBox[fifox].RIR & 1<<1)>>1; *len = CAN1->sFIFOMailBox[fifox].RDTR & 0x0f; //接收数据 data[0]=CAN1->sFIFOMailBox[fifox].RDLR&0XFF; data[1]=(CAN1->sFIFOMailBox[fifox].RDLR>>8)&0XFF; data[2]=(CAN1->sFIFOMailBox[fifox].RDLR>>16)&0XFF; data[3]=(CAN1->sFIFOMailBox[fifox].RDLR>>24)&0XFF; data[4]=CAN1->sFIFOMailBox[fifox].RDHR&0XFF; data[5]=(CAN1->sFIFOMailBox[fifox].RDHR>>8)&0XFF; data[6]=(CAN1->sFIFOMailBox[fifox].RDHR>>16)&0XFF; data[7]=(CAN1->sFIFOMailBox[fifox].RDHR>>24)&0XFF; if(fifox==0)CAN1->RF0R|=0X20;//释放FIFO0邮箱 else if(fifox==1)CAN1->RF1R|=0X20;//释放FIFO1邮箱 }
只有一块开发板,只能测试回环模式
main.c
主函数 u8 txBuff[8] ; int main() { u8 key,time = 0; u8 i; u8 data = 0; u8 reBuff[8]; Stm32_Clock_Init(9); //系统时钟设置 uart_init(72,115200); //串口初始化为115200 delay_init(72); //延时初始化 LED_Init(); //初始化与LED连接的硬件接口 LCD_Init(); KEY_Init(); LCD_ShowString(10,10,100,16,16,"CAN回环模式实验"); LCD_ShowString(10,30,100,16,16,"KEY1:发送数据"); CAN_Init(1,8,9,4,1); while(1) { key = KEY_Scan(); //查询按键 if(key == KEY1) //按键1发送数据 { for(i = 0; i < 8; i++) txBuff[i] = data++; CAN_Send_Msg((u8*)txBuff, 8); // delay_ms(10); if(CAN_Receive_Msg(reBuff)) { for(i = 0; i < 8; i++) { printf ("CAN发送数据为:%d\r\n\r\n", reBuff[i]); txBuff[i] = 0; // LCD_ShowxNum(10 + i*10, 100,reBuff[i], 3, 16, 0x80); } } } time++; delay_ms(100); if(time>10) { LED0 = !LED0 ; time = 0; } } }can.c
#include "can.h" //#include "stm32f10x.h" #include "sys.h" #define CAN_INT_ENABLE 0 void CAN_Init(u8 sjw, u8 ts2, u8 ts1,u16 brp, u8 mode) { sjw -= 1; ts1 -= 1; ts2 -= 1; brp -= 1; /*开启CAN_TX与CAN_RX的时钟PB*/ RCC->APB2ENR |= 1 << 3; /*开启CAN时钟*/ RCC->APB1ENR |= 1 << 25; /*设置PB11上拉输入,PB12推挽输出*/ GPIOB->CRH &= ~(0xff << 12); GPIOB->CRH |= 0xB3 << 12; GPIOB->ODR |= 1<<11; /*对CAN初始化*/ CAN1->MCR |= 1 << 15; //软复位 CAN1->MCR &= ~(1 << 1); CAN1->MCR |= 1 << 0; //设置初始化模式 while(!(CAN1->MSR & 1 << 0)); //等待确认初始化 CAN1->MCR |= 0 << 7; //禁止时间触发模式 CAN1->MCR |= 0 << 6; //禁止自动离线 CAN1->MCR |= 0 << 5; //禁止自动唤醒 CAN1->MCR |= 1 << 4; //报文只传送一次,禁止自动重传 CAN1->MCR |= 0 << 2; //优先级由报文的标识符决定 /* 设置CAN位时序*/ CAN1->BTR &= 0x00000000; // CAN1->BTR |= mode << 30; //正常模式或环回模式 CAN1->BTR |= sjw << 24; //设置sjw CAN1->BTR |= ts2 << 20; // CAN1->BTR |= ts1 << 16; // CAN1->BTR |= brp << 0; CAN1->MCR &= ~(1 << 0); //退出初始化 while(CAN1->MSR & 1 << 0); //确认退出初始化 /* 设置过滤器组 */ CAN1->FMR |= 1 << 0; //过滤器组设置在初始化模式 CAN1->FA1R &= ~(1 << 0); //过滤器禁用 CAN1->FM1R &= ~(1<< 0); //过滤器组工作在标识符屏蔽位模式 CAN1->FS1R |= 1<<0; //过滤器组位宽为32位 CAN1->FFA1R &= ~(1 << 0); //关联到fifo0 CAN1->sFilterRegister[0].FR1 = 0X00000000; //全都为0 ,什么数据都接受 CAN1->sFilterRegister[0].FR2 = 0X00000000; CAN1->FA1R |= 1 << 0; //激活过滤器 CAN1->FMR &= 0 << 0; //退出滤波器初始化模式 #if CAN_INT_ENABLE CAN1->IER |= 1 << 1; //FIFO0消息挂号中断使能 MY_NVIC_Init(2,2,USB_LP_CAN1_RX0_IRQn,2); #endif } // ide 0:标准帧 1:扩展帧 // id 标识id // rtr 0:数据帧 1:远程帧 // len 数据长度 // *data 指向要发送数据的指针 u8 CAN_TX_Msg(u8 ide, u32 id, u8 rtr, u8 len, u8 *data) { u8 mbox; if(CAN1->TSR & 1<<26) mbox = 0; //邮箱0为空 if(CAN1->TSR & 1<<27) mbox = 1; if(CAN1->TSR & 1<<28) mbox = 2; else return 0xff; /*为标准id时*/ if(ide == 0) { id = id & 0x07ff; //取11位 id <<= 21; } /*为扩展ID时*/ if(ide == 1) { id <<= 3; } CAN1->sTxMailBox[mbox].TIR = 0; CAN1->sTxMailBox[mbox].TIR |= ide << 2; // CAN1->sTxMailBox[mbox].TIR |= id ; // CAN1->sTxMailBox[mbox].TIR &= ~(1<<1); // CAN1->sTxMailBox[mbox].TDTR |= len&0xf; // CAN1->sTxMailBox[mbox].TDLR =((u32)data[0]) | ((u32)data[1]<<8) | ((u32)data[2]<<16) | ((u32)data[3]<<24); CAN1->sTxMailBox[mbox].TDHR =((u32)data[4]) | ((u32)data[5]<<8) | ((u32)data[6]<<16) | ((u32)data[7]<<24); CAN1->sTxMailBox[mbox].TIR |= 1 << 0; return mbox ; } //判断发送是成功 //state = 7成功 u8 CAN_TX_Statt(u8 mbox) { u8 state; switch(mbox) { case 0: state |= (CAN1->TSR & 1<<0) | (CAN1->TSR & 1<<1) |((CAN1->TSR & 1<<26)>>24); break ; case 1: state |= (CAN1->TSR & 1<<8)>>8; state |= (CAN1->TSR & 1<<9)>>9; state |= (CAN1->TSR & 1<<27)>>25; break ; case 2: state |= (CAN1->TSR & 1<<16)>>16; state |= (CAN1->TSR & 1<<17)>>17; state |= (CAN1->TSR & 1<<28)>>26; break ; default : state = 0x05; } return state ; } //得到在FIFO0/FIFO1中接收到的报文个数. //fifox:0/1.FIFO编号; //返回值:FIFO0/FIFO1中的报文个数. u8 CAN_Msg_Pend(u8 fifox) { if(fifox==0)return CAN1->RF0R&0x03; else if(fifox==1)return CAN1->RF1R&0x03; else return 0; } // 参数同上 void CAN_RX_Msg(u8 *ide, u32* id, u8* rtr, u8* len, u8 *data, u8 fifox) { *ide = (CAN1->sFIFOMailBox[fifox].RIR & 1<<2)>>2; if(*ide == 0) { *id = CAN1->sFIFOMailBox[fifox].RIR >> 21; } else { *id = CAN1->sFIFOMailBox[fifox].RIR >> 3; } *rtr = (CAN1->sFIFOMailBox[fifox].RIR & 1<<1)>>1; *len = CAN1->sFIFOMailBox[fifox].RDTR & 0x0f; //接收数据 data[0]=CAN1->sFIFOMailBox[fifox].RDLR&0XFF; data[1]=(CAN1->sFIFOMailBox[fifox].RDLR>>8)&0XFF; data[2]=(CAN1->sFIFOMailBox[fifox].RDLR>>16)&0XFF; data[3]=(CAN1->sFIFOMailBox[fifox].RDLR>>24)&0XFF; data[4]=CAN1->sFIFOMailBox[fifox].RDHR&0XFF; data[5]=(CAN1->sFIFOMailBox[fifox].RDHR>>8)&0XFF; data[6]=(CAN1->sFIFOMailBox[fifox].RDHR>>16)&0XFF; data[7]=(CAN1->sFIFOMailBox[fifox].RDHR>>24)&0XFF; if(fifox==0)CAN1->RF0R|=0X20;//释放FIFO0邮箱 else if(fifox==1)CAN1->RF1R|=0X20;//释放FIFO1邮箱 } // u8 CAN_Send_Msg(u8* data, u8 len) { u8 mbox; u16 i = 0; mbox = CAN_TX_Msg(0,0X12,0,len,data); while((CAN_TX_Statt(mbox) != 7) && (i < 0xfff)) i++; return 0; } //返回0 接收失败 u8 CAN_Receive_Msg(u8* data) { u32 id; u8 ide = 0,rtr = 0,len = 0; while(!CAN_Msg_Pend(0)); CAN_RX_Msg(&ide,&id,&rtr,&len,data,0); if( id!=0x12 || ide!=0 || rtr!=0) return 0; else return len; }
已在本地测试OK。
关注公众号"小败日记",搬砖过程遇到的问题,大家一起探讨,资源共享