前言

  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。

关注公众号"小败日记",搬砖过程遇到的问题,大家一起探讨,资源共享

重学STM32---(十)之CAN通信(二)的更多相关文章

  1. 重学STM32---(十) ——CAN通信(二)

    CAN协议是非常难的,但是在stm32中却是简单的,只需要我们配置寄存器即可,,,即使这样,我在学习的时候也遇到了许多困难 1.开时钟,不用说 2.设置GPIO口,,CAN_TX复用推挽输出,CAN_ ...

  2. 重学STM32---(九) ——CAN通信(一)

    一.CAN简介 1.CAN是什么? CAN 是 Controller Area Network的缩写(以下称为 CAN),是 ISO 国际标准化的串行通信协议. 2.CAN特点 (1)  多主控制 ( ...

  3. 重学c#系列——c#运行原理(二)

    前言 c# 是怎么运行的呢?是否和java一样运行在像jvm的虚拟机上呢?其实差不多,但是更广泛. c# 运行环境不仅c#可以运行,符合.net framework 开发规范的都可以运行. c# 程序 ...

  4. 重学c#系列——datetime 和 datetimeoffset[二十一]

    前言 简单介绍一下datetime和 datetimeoffset. 正文 了解一个国家的文化,就要了解一个国家的历史. 要了解datetimeoffset,那么很有必要了解一下datetime. 表 ...

  5. 从头开始学JavaScript (十二)——Array类型

    原文:从头开始学JavaScript (十二)--Array类型 一.数组的创建 注:ECMAscript数组的每一项都可以保存任何类型的数据 1.1Array构造函数 var colors = ne ...

  6. MINA、Netty、Twisted一起学(十二):HTTPS

    由于HTTPS协议是由HTTP协议加上SSL/TLS协议组合而成,在阅读本文前可以先阅读一下HTTP服务器和SSL/TLS两篇博文,本文中的代码也是由这两篇博文中的代码组合而成. HTTPS介绍 上一 ...

  7. [老老实实学WCF] 第十篇 消息通信模式(下) 双工

    老老实实学WCF 第十篇 消息通信模式(下) 双工 在前一篇的学习中,我们了解了单向和请求/应答这两种消息通信模式.我们知道可以通过配置操作协定的IsOneWay属性来改变模式.在这一篇中我们来研究双 ...

  8. 12天,这本《重学Java设计模式》PDF书籍下载量9k,新增粉丝1400人,Github上全球推荐榜!

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言

  9. 重学 Java 设计模式:实战适配器模式

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 擦屁屁纸80%的面积都是保护手的! 工作到3年左右很大一部分程序员都想提升自己的技术 ...

随机推荐

  1. Jenkins教程(七)实现 GitLab 提交/合并代码触发构建

    楔子 最近公司推行统一构建平台(基于 Jenkins + Kubernetes 插件创建 slave),原来部门自建的 Jenkins 不让用了. 迁移上统一构建平台的最大阻力是前端模块发布的问题: ...

  2. Jmeter系列(29)- 性能指标(2) | 并发数

    并发数 概念 同时承载正常使用系统功能的用户数量:系统能够同时处理请求的数目. 通过问题详解 问题:网站的并发数,究竟指的同时提交请求的用户数目,还是用户同时提交的请求的数目? 答案:根据这句描述&q ...

  3. phpspider PHP 爬虫

    * 通过composer下载 composer require owner888/phpspider // composer.json { "require": { "o ...

  4. Appium WebView控件定位

    背景 移动应用可以粗分为三种:原生应用(native app), 网页应用(web app,或HTML5 app),以及它们的混血儿--混合模式移动应用(hybrid app). 什么是Hybrid ...

  5. 常用的jquery 中一些js

    目录: 1.验证用户登录信息 2. 获取下拉框所选中的元素 3.  动态获取 id 和对应文本框的值  4. table 中 tr  的隐藏 5 . 更换图片  6. ajax  进行提交 7. 判断 ...

  6. PHP审计之class_exists与任意实例化漏洞

    PHP审计之class_exists与任意实例化漏洞 前言 发现PHP的一些漏洞函数挺有意思,跟着七月火师傅的文章来学习. class_exists函数 函数说明 class_exists:(PHP ...

  7. 生日礼物网页Javascript版本与锚点版本

    <style> #dv1{ width:60px; height:36px; margin:0 auto; background-color:orange; display:none; } ...

  8. 2020.12.14--Codeforces Round #104 (Div.2)补题

    C - Lucky Conversion CodeForces - 146C Petya loves lucky numbers very much. Everybody knows that luc ...

  9. Bloom Filter算法

    Bloom Filter算法详解 什么是布隆过滤器 布隆过滤器(Bloom Filter)是 1970 年由布隆提出的.它实际上是一个很长的二进制向量和一系列随机映射函数 (下面详细说),实际上你也可 ...

  10. 【高热FAQ】关于智慧康养物联网加速器 ,你想知道的都在这

    摘要:从软硬件解决方案.设备接入到资源扶持,一文梳理智慧康养物联网加速器中ISV最关心的问题. 本文分享自华为云社区<[高热FAQ]关于智慧康养物联网加速器 ,你想知道的都在这>,作者:技 ...