CAN协议是非常难的,但是在stm32中却是简单的,只需要我们配置寄存器即可,,,即使这样,我在学习的时候也遇到了许多困难

1.开时钟,不用说

2.设置GPIO口,,CAN_TX复用推挽输出,CAN_RX上拉或浮空输入

3.CAN初始化了,分三步

(1) 一般设置

  /*对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;            //优先级由报文的标识符决定

(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);        //确认退出初始化
    (3)滤波器设置、
    /* 设置过滤器组 */

    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.接收函数
void CAN_RX_Msg(u8 *ide, u32* id, u8* rtr, u8* len, u8 *data, u8 fifox)   (参数要用指针,开始我ide没用指针,在其他函数调用这个函数ide的值是不确定的)
{
    *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 txBuff[] ;
int main()
{
    u8 key,time = ;
    u8 i;
    u8 data = ;
    u8 reBuff[];
    Stm32_Clock_Init();    //系统时钟设置
    uart_init(,);    //串口初始化为115200
    delay_init();    //延时初始化
    LED_Init();    //初始化与LED连接的硬件接口
    LCD_Init();
    KEY_Init();
    LCD_ShowString(,,,,,"CAN回环模式实验");
    LCD_ShowString(,,,,,"KEY1:发送数据");
    CAN_Init(,,,,);
    )
    {
        key = KEY_Scan();     //查询按键
        if(key == KEY1)    //按键1发送数据
        {
            ; i < ; i++)
            txBuff[i] = data++;
            CAN_Send_Msg((u8*)txBuff, );
//        delay_ms(10);
            if(CAN_Receive_Msg(reBuff))
            {
                ; i < ; i++)
                {
                    printf ("CAN发送数据为:%d\r\n\r\n", reBuff[i]);
                    txBuff[i] = ;
//                LCD_ShowxNum(10 + i*10, 100,reBuff[i], 3, 16, 0x80);
                }
            }
        }

    time++;
    delay_ms();
    )
    {
        LED0 = !LED0 ;
        time = ;
    }
   }
}                                                
 
 
#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 -= ;
    ts1 -= ;
    ts2 -= ;
    brp -= ;

    /*开启CAN_TX与CAN_RX的时钟PB*/
    RCC->APB2ENR |=  << ;
    /*开启CAN时钟*/
    RCC->APB1ENR |=  << ;

    /*设置PB11上拉输入,PB12推挽输出*/
    GPIOB->CRH &= ~();
    GPIOB->CRH |= ;
    GPIOB->ODR |= <<;

    /*对CAN初始化*/
    CAN1->MCR |=  << ;          //软复位
    CAN1->MCR &= ~( << );
    CAN1->MCR |=  << ;           //设置初始化模式
     << ));   //等待确认初始化

    CAN1->MCR |=  << ;           //禁止时间触发模式
    CAN1->MCR |=  << ;           //禁止自动离线
    CAN1->MCR |=  << ;            //禁止自动唤醒
    CAN1->MCR |=  << ;            //报文只传送一次,禁止自动重传
    CAN1->MCR |=  << ;            //优先级由报文的标识符决定
    /* 设置CAN位时序*/
    CAN1->BTR &= 0x00000000;        //
    CAN1->BTR |= mode << ;        //正常模式或环回模式
    CAN1->BTR |= sjw << ;            //设置sjw
    CAN1->BTR |= ts2 << ;            //
    CAN1->BTR |= ts1 << ;            //
    CAN1->BTR |= brp << ;

    CAN1->MCR &= ~( << );            //退出初始化
     << );        //确认退出初始化

    /* 设置过滤器组 */

    CAN1->FMR |=  << ;            //过滤器组设置在初始化模式
    CAN1->FA1R &= ~( << );        //过滤器禁用
    CAN1->FM1R &= ~(<< );   //过滤器组工作在标识符屏蔽位模式
    CAN1->FS1R |= <<;         //过滤器组位宽为32位
    CAN1->FFA1R &= ~( << );  //关联到fifo0
    CAN1->sFilterRegister[].FR1 = 0X00000000;     //全都为0 ,什么数据都接受
    CAN1->sFilterRegister[].FR2 = 0X00000000;
    CAN1->FA1R |=  << ;        //激活过滤器
    CAN1->FMR &=  << ;         //退出滤波器初始化模式

#if CAN_INT_ENABLE
    CAN1->IER |=  << ;   //FIFO0消息挂号中断使能
    MY_NVIC_Init(,,USB_LP_CAN1_RX0_IRQn,);
#endif

}

ide 0:标准帧  1:扩展帧id  标识idrtr  0:数据帧  1:远程帧len 数据长度*data 指向要发送数据的指针
u8 CAN_TX_Msg(u8 ide, u32 id, u8 rtr, u8 len, u8 *data)
{
    u8 mbox;
    <<) mbox = ;   //邮箱0为空
    <<) mbox = ;
    <<) mbox = ;
    else return 0xff;

    /*为标准id时*/
    )
    {
        id = id & 0x07ff;          //取11位
        id <<= ;
    }
    /*为扩展ID时*/
    )
    {
        id <<= ;
    }
    CAN1->sTxMailBox[mbox].TIR = ;
    CAN1->sTxMailBox[mbox].TIR |= ide << ;        //
    CAN1->sTxMailBox[mbox].TIR |= id ;             //
    CAN1->sTxMailBox[mbox].TIR &= ~(<<);         //
    CAN1->sTxMailBox[mbox].TDTR |= len&0xf;        //

    CAN1->sTxMailBox[mbox].TDLR =((u32)data[]) | ((u32)data[]<<) | ((u32)data[]<<) | ((u32)data[]<<);
    CAN1->sTxMailBox[mbox].TDHR =((u32)data[]) | ((u32)data[]<<) | ((u32)data[]<<) | ((u32)data[]<<);

    CAN1->sTxMailBox[mbox].TIR |=  << ;
    return     mbox ;
}

//判断发送是成功
//state = 7成功
u8 CAN_TX_Statt(u8 mbox)
{
    u8 state;
    switch(mbox)
    {
        :
            state |= (CAN1->TSR & <<) | (CAN1->TSR & <<) |((CAN1->TSR & <<)>>);
            break ;
        :
            state |= (CAN1->TSR & <<)>>;
            state |= (CAN1->TSR & <<)>>;
            state |= (CAN1->TSR & <<)>>;
            break ;
        :
            state |= (CAN1->TSR & <<)>>;
            state |= (CAN1->TSR & <<)>>;
            state |= (CAN1->TSR & <<)>>;
            break ;
        default :
            state = 0x05;
    }
    return state ;

}

//得到在FIFO0/FIFO1中接收到的报文个数.
//fifox:0/1.FIFO编号;
//返回值:FIFO0/FIFO1中的报文个数.
u8 CAN_Msg_Pend(u8 fifox)
{
    )return CAN1->RF0R&0x03;
    )return CAN1->RF1R&0x03;
    ;
}

参数同上
void CAN_RX_Msg(u8 *ide, u32* id, u8* rtr, u8* len, u8 *data, u8 fifox)
{
    *ide = (CAN1->sFIFOMailBox[fifox].RIR & <<)>>;
    )
    {
        *id = CAN1->sFIFOMailBox[fifox].RIR >> ;
    }
    else
    {
        *id = CAN1->sFIFOMailBox[fifox].RIR >> ;
    }
    *rtr = (CAN1->sFIFOMailBox[fifox].RIR & <<)>>;

    *len = CAN1->sFIFOMailBox[fifox].RDTR & 0x0f;

        //接收数据
    data[]=CAN1->sFIFOMailBox[fifox].RDLR&0XFF;
    data[]=(CAN1->sFIFOMailBox[fifox].RDLR>>)&0XFF;
    data[]=(CAN1->sFIFOMailBox[fifox].RDLR>>)&0XFF;
    data[]=(CAN1->sFIFOMailBox[fifox].RDLR>>)&0XFF;
    data[]=CAN1->sFIFOMailBox[fifox].RDHR&0XFF;
    data[]=(CAN1->sFIFOMailBox[fifox].RDHR>>)&0XFF;
    data[]=(CAN1->sFIFOMailBox[fifox].RDHR>>)&0XFF;
    data[]=(CAN1->sFIFOMailBox[fifox].RDHR>>)&0XFF;
      )CAN1->RF0R|=0X20;//释放FIFO0邮箱
    )CAN1->RF1R|=0X20;//释放FIFO1邮箱     

}

//
u8 CAN_Send_Msg(u8* data, u8 len)
{
    u8 mbox;
    u16 i = ;
    mbox = CAN_TX_Msg(,,len,data);
    ) && (i < 0xfff)) i++;
    ;
}

//返回0 接收失败
u8 CAN_Receive_Msg(u8* data)
{
    u32 id;
    u8 ide = ,rtr = ,len = ;
    ));
    CAN_RX_Msg(&ide,&id,&rtr,&len,data,);
     || rtr!=) ;
    else return len;
}

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

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

    目录 前言 程序编写 主代码 测试 前言   CAN协议是非常难的,但是在stm32中却是简单的,只需要我们配置寄存器即可,,,即使这样,我在学习的时候也遇到了许多困难 程序编写 1.开时钟,不用说 ...

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

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

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

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

  4. 第十六届“二十一世纪的计算”学术研讨会 牛津大学肿瘤成像学教授Michael Brady主题演讲

    Computing and Healthcare 牛津大学肿瘤成像学教授Michael Brady主题演讲" title="第十六届"二十一世纪的计算"学术研讨 ...

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

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

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

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

  7. 重学 Java 设计模式:实战外观模式「基于SpringBoot开发门面模式中间件,统一控制接口白名单场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 你感受到的容易,一定有人为你承担不容易 这句话更像是描述生活的,许许多多的磕磕绊绊总 ...

  8. 重学 Java 设计模式:实战享元模式「基于Redis秒杀,提供活动与库存信息查询场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 程序员‍‍的上下文是什么? 很多时候一大部分编程开发的人员都只是关注于功能的实现,只 ...

  9. Java集合类简单总结(重学)

    java集合类简介(重学) 一.Collection(集合).Map接口两者应该是平行关系吧. 1.Map介绍 Map是以键值(key-value)对来存放的,2个值.通过key来找到value(例: ...

随机推荐

  1. c++实现之 -- 汉语词语的简单处理

    好了,我们现在已经会怎样读入了,然后就是研究一下如何存储等一些细节上的的问题了. 首先,比较函数是不能传入char*的地址的,但是可以接受一个string类. 然而,如果是两个比较长的string类, ...

  2. Could not find artifact com.sun:tools:jar:1.5.0

    问题: Failed to execute goal on project petroleum: Could not resolve dependencies for project petroleu ...

  3. AFNetworking框架使用

    本文是由 iOS Tutorial 小组成员 Scott Sherwood撰写,他是一个基于位置动态加载(Dynamically Loaded)的软件公司(专业的混合定位)的共同创办人. 网络 — 你 ...

  4. ssh localhost “Permission denied (publickey)

    再次遇到 SSH Server And "Permission denied (publickey) 用这个关键词搜索才找到howtogeek上答案: sshd : Authenticati ...

  5. hdu 4611 Balls Rearrangement

    http://acm.hdu.edu.cn/showproblem.php?pid=4611 从A中向B中移动和从B中向A中移动的效果是一样的,我们假设从B中向A中移动 而且A>B 我们先求出所 ...

  6. Redis系列-存储篇list主要操作函数小结

    在总结list之前,先要弄明白几个跟list相关的概念: 列表:一个从左到右的队列,个人理解更类似于一个栈,常规模式下,先进列表的元素,后出. 表头元素:列表最左端第一个元素. 表尾元素:列表最右端的 ...

  7. (DFS)hdoj1312-Red and Black

    题目链接 非常简单的DFS,初学DFS做这道题很合适.需要注意的是题目中输入的行和列顺序是颠倒的. #include<cstdio> #include<cstring> usi ...

  8. Python 条件判断 循环

    age = 20 if age >= 18: print('your age is', age) print('adult') 根据Python的缩进规则,如果if语句判断是True,就把缩进的 ...

  9. CIO谈:基于K2 BPM平台怎么做报销?

    即时!可视!可控!高效! 面对报销系统四大业务目标,有一个对策——用K2! 演讲人:沈明 大鹏天然气CIO 查看完章分享内容请关注K2官方微信

  10. 【干货来了】2014年K2房地产IT分享峰会

    2014年K2房地产IT分享峰会已圆满落幕,嘉宾们纷纷出招,分享干货,现场妙语连珠不断,高潮迭起. 主题:流程驱动的地产业务管控平台 嘉宾:王寿欣(卓越地产战略与运营管理部 副总经理) 卓越地产应用K ...