历史上的今天

今天是:2024年09月02日(星期一)

正在发生

2018年09月02日 | STM32--CAN简单接收和发送

发布者:平和的心情 来源: eefocus关键字:STM32  CAN  接收和发送 手机看文章 扫描二维码
随时随地手机看文章

前面对CAN原理进行了讲解,这里我用一个简单的例子来说明CAN的使用。我使用的STM32芯片是STM32F103ZE,几个基本的配置是:

1.配置CAN时钟

 /* CAN Periph clock enable */
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);

2.CAN管脚配置,这里使用的PB11,PB12管脚:

/* Configure CAN pin: RX */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
  
 /* Configure CAN pin: TX */
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 GPIO_Init(GPIOA, &GPIO_InitStructure);  

3.中断配置,这里打开CAN的接收和发送中断:

/* CAN RX interrupt */
NVIC_InitStructure.NVIC_IRQChannel=USB_LP_CAN_RX0_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);     
    
 /* CAN TX interrupt */
 NVIC_InitStructure.NVIC_IRQChannel=USB_HP_CAN_TX_IRQChannel; 
 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 NVIC_Init(&NVIC_InitStructure);   

这里需要注意的是CAN的发送中断,发送中断是发送邮箱中数据发送完毕后产生的发送完毕邮箱空中断--这和USART发送中断不同。详细点说CAN发送中断是指CAN的三个发送邮箱中的其中一个由满到发送数据完毕后空才产生的中断,当原来发送邮箱本来就是空的则不会产生发送中断。

4.CAN初始化配置:

void CAN_Ini(void)
{
  CAN_InitTypeDef        CAN_InitStructure;
  CAN_FilterInitTypeDef  CAN_FilterInitStructure;
  /* CAN register init */
  CAN_DeInit();
  CAN_StructInit(&CAN_InitStructure);

  /* CAN cell init */
  CAN_InitStructure.CAN_TTCM=DISABLE;  //禁止时间触发通信模式
  CAN_InitStructure.CAN_ABOM=DISABLE;  //软件对CAN_MCR寄存器的INRQ位进行置1随后清0后,一旦硬件检测
                                       //到128次11位连续的隐性位,就退出离线状态。
  CAN_InitStructure.CAN_AWUM=DISABLE;  //睡眠模式通过清除CAN_MCR寄存器的SLEEP位,由软件唤醒
  CAN_InitStructure.CAN_NART=DISABLE;   //CAN报文只被发送1次,不管发送的结果如何(成功、出错或仲裁丢失)
  CAN_InitStructure.CAN_RFLM=DISABLE;  //在接收溢出时FIFO未被锁定,当接收FIFO的报文未被读出,下一个收到的报文会覆盖原有的报文
  CAN_InitStructure.CAN_TXFP=ENABLE;  //用来使能或者失能发送FIFO优先级,由发送的请求顺序决定
 CAN_InitStructure.CAN_Mode=CAN_Mode_Normal;//CAN硬件工作在正常模式

 switch(CAN_BPP)
 {
    //总体配置保持,tBS1>=tBS2,tBS2>=1个CAN时钟周期,tBS2>=2tSJW
  case 100000:
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;   //重新同步跳跃宽度
  CAN_InitStructure.CAN_BS1=CAN_BS1_10tq;  //设定时间段1的时间单位数目
  CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;   //设定时间段2的时间单位数目
  CAN_InitStructure.CAN_Prescaler=20;         //一个时间单位的长度//(pclk1/((4+8+8)*9)) = 36Mhz/18/20 = 100Kbits
  break;
  case 50000:
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
  CAN_InitStructure.CAN_BS1=CAN_BS1_10tq;
  CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
  CAN_InitStructure.CAN_Prescaler=40;    //(pclk1/((4+8+8)*9)) = 36Mhz/18/40 = 50Kbits
  break;

  case 20000:
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
  CAN_InitStructure.CAN_BS1=CAN_BS1_10tq;
  CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
  CAN_InitStructure.CAN_Prescaler=100;    //(pclk1/((4+8+8)*9)) = 36Mhz/18/100 = 20Kbits
  break;
  case 250000:
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;
  CAN_InitStructure.CAN_BS1=CAN_BS1_8tq;
  CAN_InitStructure.CAN_BS2=CAN_BS2_7tq;
  CAN_InitStructure.CAN_Prescaler=9;    //(pclk1/((1+8+7)*9)) = 36Mhz/16/9 = 250Kbits
  break;

  case 500000:
  CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;    //重新同步跳跃宽度1个时间单位
  CAN_InitStructure.CAN_BS1=CAN_BS1_6tq;    //时间段1为6个时间单位
  CAN_InitStructure.CAN_BS2=CAN_BS2_5tq;    //时间段2为5个时间单位
  CAN_InitStructure.CAN_Prescaler=6;        //(pclk1/((1+6+5)*6)) = 36Mhz/12/6 = 500Kbits设定了一个时间单位的长度9
  break;
  default:
  break;

 }

  CAN_Init(&CAN_InitStructure);

  /* CAN filter init */
  CAN_FilterInitStructure.CAN_FilterNumber=0;     //指定了待初始化的过滤器0
  CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;      //指定了过滤器将被初始化到的模式为标识符屏蔽位模式
  CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;  //给出了过滤器位宽1个32位过滤器
  CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;                  //用来设定过滤器标识符(32位位宽时为其高段位,16位位宽时为第一个)
  CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;                  //用来设定过滤器标识符(32位位宽时为其低段位,16位位宽时为第二个
  CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;              //用来设定过滤器屏蔽标识符或者过滤器标识符(32位位宽时为其高段位,16位位宽时为第一个
  CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;              //用来设定过滤器屏蔽标识符或者过滤器标识符(32位位宽时为其低段位,16位位宽时为第二个
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_IT_FMP0;  //设定了指向过滤器的FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;              //使能过滤器
  CAN_FilterInit(&CAN_FilterInitStructure);

  /* CAN FIFO0 message pending interrupt enable */ 
  CAN_ClearITPendingBit(CAN_IT_FF0);
  CAN_ClearITPendingBit(CAN_IT_FOV0);
  CAN_ClearITPendingBit(CAN_IT_FF1);
  CAN_ClearITPendingBit(CAN_IT_FOV1);
  CAN_ClearITPendingBit(CAN_IT_RQCP0);
  CAN_ClearITPendingBit(CAN_IT_RQCP1);
  CAN_ClearITPendingBit(CAN_IT_RQCP2);
  CAN_ITConfig(CAN_IT_FMP0, ENABLE);  //使能接收中断
    //CAN_ITConfig(CAN_IT_TME, ENABLE); //TransmitMailbox empty,发送中断在CAN_Transmit()后才能打开,用来判断发送完毕发送下一个数据

}

5.实现CAN的发送中断和接收中断,这里我们只用了一个发送邮箱进行发送--简单方便:

void USB_LP_CAN_RX0_IRQHandler(void)  //接收中断
{
  CanRxMsg RxMessage;
  U8 i=0;
  U8 targetid=0;

  //如果是标准帧
    CAN_Receive(CAN_FIFO0, &RxMessage);
    if(RxMessage.IDE==CAN_ID_STD)//只收标准帧数据
    {
        if((RxMessage.StdId&0x1F)==PCL_ID+bmqnum)   //接收到ID是取后5位是自己的ID
        {
            //每个完整的数据,以|开头,下面是ID
            while(!QIn(&Qlinecanrx,'|')){}
            targetid=(RxMessage.StdId>>6)&0x1F;
            while(!QIn(&Qlinecanrx,targetid)){}
            for(i=0;i            {
                while(!QIn(&Qlinecanrx,RxMessage.Data[i])){}
            }
        }

    }
  CAN_ITConfig(CAN_IT_FMP0, ENABLE); //中断退出
}
void USB_HP_CAN_TX_IRQHandler(void)
{
    CAN_ClearITPendingBit(CAN_IT_RQCP0);
    CAN_ClearITPendingBit(CAN_IT_RQCP1);
    CAN_ClearITPendingBit(CAN_IT_RQCP2);
    CAN_ITConfig(CAN_IT_TME, DISABLE);
    CANSendStr();   //时刻查询是否可以给上位发送数据
}

void CANSendStr()
{
    CanTxMsg TxMessage;
    TxMessage.StdId=PCL_ID+bmqnum;  //用来设定标准标识符,0x08+2=0x0A
    TxMessage.ExtId=0;              //用来设定扩展标识符
  TxMessage.RTR=CAN_RTR_DATA;     //用来设定待传输消息的帧类型,它可以设置为数据帧或者远程帧,使用数据帧
  TxMessage.IDE=CAN_ID_STD;       //用来设定消息标识符的类型,使用标准标识符
  TxMessage.DLC = 8;              //用来设定待传输消息的帧长度,它的取值范围是0到0x8
    //20160822----zhang
    TxMessage.RTR=CAN_RTR_DATA;    //数据帧
    //20160822----zhang
    TxMessage.Data[0]='~';
    TxMessage.Data[1]='0';
    TxMessage.Data[2]='1';
    TxMessage.Data[3]='2';
    TxMessage.Data[4]='3';
    TxMessage.Data[5]='4';
    TxMessage.Data[6]='5';
    TxMessage.Data[7]='6';             
    CAN_Transmit(&TxMessage);
    CAN_ITConfig(CAN_IT_TME, ENABLE); //TransmitMailbox empty,发送中断在CAN_Transmit()后才能打开,用来判断发送完毕发送下一个数据 
}

6.使用中先使用CANSendStr()发送一条数据,则发送完毕后进入发送空中断,则之后会循环发送数据

参考文章:

http://www.openedv.com/thread-38867-1-1.html

http://www.stmcu.org/module/forum/thread-565605-1-1.html

http://www.cnblogs.com/chris-cp/p/3961508.html

http://www.openedv.com/thread-51889-1-1.html


关键字:STM32  CAN  接收和发送 引用地址:STM32--CAN简单接收和发送

上一篇:STM32的CAN总线学习总结
下一篇:STM32之CAN通信

推荐阅读

CAN协议特点1.多主控制 所有单元都可以发送消息,根据标识符(Identifier简称ID)决定优先级。仲裁获胜(被判定为优先级最高)的单元可继续发送消息,仲裁失利的单元则立刻停止发送而进行接收工作2.系统的柔软性 与总线相连的单元没有类似于“地址”的信息。因此在总线上增加单元时,连接在总线上的其它单元的软硬件及应用层都不需要改变3.通信速度较快,...
hspeed 4000device = STM32F429ZIeraseloadbin BOOT.bin 0x8000000loadbin 正式版本.bin 0x08004000loadbin 工厂测试.bin 0x08020000savebin 工厂生产.bin 0x08000000 0x00080000rx 3qcexit一直在用这个脚本烧写程序,但是,细细一看有点懵。里面 h,rx 3,qc 等的含义不太清楚。接下来详细总结一下,Jlink都还有哪些常用的命令。一、查看...
对于希望学习 ARM 汇编的同学而言, 购买 ARM 开发板进行板上实测无疑是一个有效的方法,不过购买 ARM 开发板需要一笔费用,而且每次测试都需要连接开发板,比较麻烦。这里介绍一个 ARM 模拟器——SkyEye,通过 SkyEye 我们可以直接在一台 PC 上完成 ARM 汇编程序的开发和调试了,摆脱了 ARM 开发板的限制,真是不错!下面介绍如何使用:1、...
硬件:STM8单片机(很裸,就一个单片机加俩电容)ST-Link V2仿真器PL2103 USB转TTL小板声明部分uart.h#ifndef __UART_H__#define __UART_H__//#include “stm8s.h”#include “define.h”//Fcpu=8M时波特率设置#define UART_RATE_1200 (uint16)6666 //0x1a0a#define UART_RATE_2400 (uint16)3333 //0xd05#define UART_RATE_4800 (...

史海拾趣

小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved