找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5325|回复: 1
收起左侧

STM32F10X CAN+TJA1050中断 接受例程详解,测试无误

[复制链接]
ID:105323 发表于 2016-3-4 17:40 | 显示全部楼层 |阅读模式
硬件平台:stm32F10X内部CAN模块 + TJA1050 + JLink
软件平台:Keil 4

一、结果演示



二、接受程序例程
程序涉及的模块有:
USART:通用同步异步收发器,即串口,用于发送数据至上位机显示已接收到的数据;
RCC:复位及时钟控制模块,用于初始化STM32 外设时钟及设置CAN总线通信的波特率;
GPIO:通用输入输出口;
NVIC:中断服务程序;
CAN:STM32F10X自带的CAN通信模块,F1系列只有1个CAN,F4系列含有2个CAN,大容量的由2个,小容量的只有一个;
Delay:延时等待模块
Led:用led灯来指示是否正常发送,系统是否工作正常。
RCC
#include "Rcc.h"  
void RCC_Init(void)  
{      
     ErrorStatus HSEStartUpStatus;  //定义枚举类型错误状态变量         
     RCC_DeInit();//复位系统时钟设置         
     RCC_HSEConfig(RCC_HSE_ON); //打开外部高速时钟晶振,使能HSE  
    /*RCC_HSE_ON  开  
     _off 关  _bypass hse晶振被外部时钟旁路*/        
    HSEStartUpStatus = RCC_WaitForHSEStartUp();  
    /*RCC_WaitForHSEStartUp()返回一个ErrorStatus枚举值,  
    success好,error未好*/   
     if(HSEStartUpStatus == SUCCESS)//HES就绪  
     {         
         RCC_HCLKConfig(RCC_SYSCLK_Div1);  
         //AHB时钟(HCLK)=系统时钟   
         RCC_PCLK1Config(RCC_HCLK_Div2);  
         //设置低速AHB时钟(APB1)为HCLK的2分频   
         RCC_PCLK2Config(RCC_HCLK_Div1);  
         //设置高速AHB时钟(APB2)=HCLK时钟  
         FLASH_SetLatency(FLASH_Latency_2);  
         //设置FLASH延时周期数为2  
         //使能领取指缓存  
         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);  
         RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);  
         //设置PLL时钟源及倍频系数,为HSE的9倍频 8MHz * 9 = 72MHz  
         /*void RCC_PLLConfig(u32 RCC_PLLSource, u32 RCC_PLLMul)  
         RCC_PLLSource_HSI_Div2   pll输入时钟=hsi/2;  
         RCC_PLLSource_HSE_Div1   pll输入时钟 =hse  
         RCC_PLLSource_HSE_Div2   pll输入时钟=hse/2  
         RCC_PLLMul_2  ------_16       pll输入时钟*2---16  
         pll输出时钟不得超过72MHZ*/   
         RCC_PLLCmd(ENABLE);  
         //ENABLE  / DISABLE  
         while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);//等待PLL输出稳定  
         /*FlagStatus RCC_GetFlagStatus(u8 RCC_FLAG)  检查指定RCC标志位  
         返回SET OR RESET  
         RCC_FLAG_HSIRDY  HSI晶振就绪  
         RCC_FLAG_HSERDY  
         RCC_FLAG_PLLRDY  
         RCC_FLAG_LSERDY   
         RCC_FLAG_LSIRDY.......*/     
         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);  
         //设置PLL为系统时钟源  
         /*void RCC_SYSCLKConfig(u32 RCC_SYSCLKSource)  设置系统时钟  
         RCC_SYSCLKSource_HSI   
         RCC_SYSCLKSource_HSE   
         RCC_SYSCLKSource_PLLCLK  选HSI  HSE PLL 作为系统时钟*/                 while(RCC_GetSYSCLKSource() != 0x08);  
         //判断PLL是否是系统时钟  
         /*u8 RCC_GetSYSCLKSource(void)  返回用作系统时钟的时钟源  
         0x00:HSI   0x04:HSE 0x08:PLL */  
     }     
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |   
                                                    RCC_APB2Periph_AFIO , ENABLE);  
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);  
     //U2  U3 时钟在APB1  
     //打开GPIO时钟,复用功能,串口1的时钟                                      RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟        
     /*void RCC_APB2PeriphClockCmd(u32 RCC_APB2Periph, FunctionalState NewState)   
        enable 或 disable apb2 外设时钟  
     RCC_APB2Periph_AFIO  功能复用IO 时钟  
     RCC_APB2Periph_GPIOA/B/C/D/E   GPIOA/B/C/D/E 时钟  
     RCC_APB2Periph_ADC1/ADC2           ADC1/2 时钟  
     RCC_APB2Periph_TIM1   
     RCC_APB2Periph_SPI1  
     RCC_APB2Periph_USART1   
     RCC_APB2Periph_ALL         全部APB2外设时钟*/  
}  

GPIO
#include "GPIO.h"  
void MYGPIO_Init(void)  
{  
     GPIO_InitTypeDef GPIO_InitStructure;  
    //GPIO_InitStructure初始化结构体为GPIO_InitTypeDef结构  
     GPIO_DeInit(GPIOA);  
     GPIO_StructInit(&GPIO_InitStructure);  
    //函数:指向结构GPIO_InitTypeDef的指针,待初始化  

    //CAN TX  : A12  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;  
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽  
    GPIO_Init(GPIOA, &GPIO_InitStructure);          //初始化IO  
    //CAN TX  : A11  
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   //上拉输入  
    GPIO_Init(GPIOA, &GPIO_InitStructure);          //初始化IO  

    // USART TX :A9  
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;   
    //GPIO_SPEED:GPIO_SPEED_10MHz/_2MHz/_50MHz   最高输出速率  
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  
    /*Mode,工作状态:GPIO_MODE_AIN  ----- 模拟输入  
                                                        _IN_FLOATING  ----- 浮空输入  
                                                        _IPD  ----- 上拉输出  
                                                        _IPU  ----- 上拉输入  
                                                        _OUT_OD  ----- 开漏输出  
                                                        _OUT_PP  ----- 推挽输出  
                                                        _AF_OD  ----- 复用开漏输出  
                                                        _AF_PP  ----- 复用推挽输出*/   
     GPIO_Init(GPIOA , &GPIO_InitStructure);  

     // USART RX :A10  
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;   
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;  
     //IO浮空输入  
     GPIO_Init(GPIOA, &GPIO_InitStructure);  
     //初始化  
}  

CAN
#include "can.h"  
#include "delay.h"  
#include "usart.h"  

//波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);  
//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;  
u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)  
{   
    CAN_InitTypeDef         CAN_InitStructure;  
    CAN_FilterInitTypeDef   CAN_FilterInitStructure;  
NVIC_InitTypeDef        NVIC_InitStructure;  

CAN_DeInit(CAN1);//重置can1为复位状态  
    //f10x的库函数文件里面居然定义了两个CAN!  
    CAN_StructInit(&CAN_InitStructure);//复位重置所有的成员变量  
    CAN_InitStructure.CAN_TTCM=DISABLE;   
    //enable or disable 时间触发通讯模式  
    //非时间触发通信模式   
    CAN_InitStructure.CAN_ABOM=DISABLE;      
    //enable or disable 自动离线管理  
    //软件自动离线管理     
    CAN_InitStructure.CAN_AWUM=DISABLE;      
    //enable or disable 自动唤醒模式  
    //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)  

    CAN_InitStructure.CAN_NART=ENABLE;            
    //enable or disable 非自动重传  
    //禁止报文自动传送   

    CAN_InitStructure.CAN_RFLM=DISABLE;           
    //enable or disable 接收FIFO 锁定模式  
    //报文不锁定,新的覆盖旧的   
    CAN_InitStructure.CAN_TXFP=DISABLE;           
    //enable or disable 发送FIFO 优先级  
    //优先级由报文标识符决定   
    CAN_InitStructure.CAN_Mode= mode;           
    /*CAN_Mode_Normal  CAN硬件工作在正常模式  
        CAN_Mode_silent  CAN硬件工作在静默模式  
        CAN_Mode_LoopBack 环回模式  
        CAN_Mode_Silent_LoopBack  静默环回模式*/  
    //模式设置: mode:0,普通模式;1,回环模式;   
    //设置波特率  
    CAN_InitStructure.CAN_SJW=tsjw;               
    /*重新同步跳跃宽度(Tsjw),每位中可以延长或缩短多少个时间单位的上限  
    为tsjw+1个时间单位   
    CAN_SJW_1tq  重新同步跳跃宽度为 1 个时间单位  
    CAN_SJW_2tq   
    CAN_SJW_3tq   
    CAN_SJW_4tq*/  
    CAN_InitStructure.CAN_BS1=tbs1;               
    /*时间段 1 的时间单位数目  为1--16个时间单位*/  
    //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq  
    CAN_InitStructure.CAN_BS2=tbs2;               
    /*时间段 2 的时间单位数目  为1--8个时间单位*/  
    //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq  
    CAN_InitStructure.CAN_Prescaler=brp;         
    /*设定一个时间单位的长度,范围是1---1024,实际会减一,这是什么鬼???*/   
    //分频系数(Fdiv)为 brp+1 因为实际会减一,所以这里有加一???  
    CAN_Init(CAN1, &CAN_InitStructure);         //初始化CAN1   

    //can 过滤器设置  
    CAN_FilterInitStructure.CAN_FilterNumber=0;   
    //指定待初始化的过滤器,范围是1---13  
    //过滤器0  
    CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;     
    /*CAN_FilterMode_IdMask   标识符屏蔽位模式  
        CAN_FilterMode_IdList   标识符列表模式*/  
    //屏蔽位模式  
    CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;   
    /*过滤器位宽   
    CAN_FilterScale_Two16bit  2 个 16 位过滤器  
    CAN_FilterScale_One32bit  1 个 32 位过滤器  
    因为版本吧 CAN_FilterScale_One32bit 已变为 CAN_FilterScale_32bit*/  
    //32位宽   
    CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;      
    /*设定过滤器标识符,范围是0x0000---0xFFFF  
    32 位位宽时为其高段位,16 位位宽时为第一个*/  
    //32位ID  
    CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;  
    /*设定过滤器标识符,范围是0x0000---0xFFFF  
    32 位位宽时为其低段位,16 位位宽时为第二个*/  

    CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;  
    /*设定过滤器屏蔽标识符或者过滤器标识符,范围是0x0000---0xFFFF  
    32 位位宽时为其高段位,16 位位宽时为第一个*/  
    //32位MASK  
    CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;  
    /*设定过滤器屏蔽标识符或者过滤器标识符,范围是0x0000---0xFFFF  
    32 位位宽时为其低段位,16 位位宽时为第二个*/  

    CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;  
    //设定了过滤器指向的FIFO : 0或1  
    /*CAN_FilterFIFO0  过滤器 FIFO 指向 过滤器x  
      CAN_FilterFIFO1       过滤器 FIF1 指向 过滤器x  */  
    //过滤器0关联到FIFO0  
    CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;  
    //激活过滤器0   enable or disable  

    CAN_FilterInit(&CAN_FilterInitStructure);           //滤波器初始化  

CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);               
    /*enable or disable can中断  
    CAN_IT_FMP0   FIFO0消息挂号中断允许.        */   

    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;  
    //USB 低优先级 or CAN 接收 0 中断  
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;      
    // 主优先级为1  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;              
    // 次优先级为0  
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  
    NVIC_Init(&NVIC_InitStructure);   

return 0; //配置成功返回 0   
}  

//如果是开启了,就有中断服务函数                 
void USB_LP_CAN1_RX0_IRQHandler(void)  
{  
  CanRxMsg RxMessage;  
    int i=0;  
    can_ack = 1;  
  CAN_Receive(CAN1, 0, &RxMessage);  
    for(i=0;i<8;i++)  
    can_rx[ i ]=RxMessage.Data[ i ];  
}  

Led

[html] view plain copy 在CODE上查看代码片派生到我的代码片
#include "led.h"  

//初始化PB12和13为输出口.并使能这两个口的时钟           

void LED_Init(void)  
{   
GPIO_InitTypeDef  GPIO_InitStructure;   
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);   //使能PB端口时钟   
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;               
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        //推挽输出  
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       //IO口速度为50MHz  
GPIO_Init(GPIOB, &GPIO_InitStructure);             //根据设定参数初始化GPIOB  
GPIO_SetBits(GPIOB,GPIO_Pin_12|GPIO_Pin_13);  
}  
回复

使用道具 举报

ID:486587 发表于 2019-6-17 02:44 | 显示全部楼层
谢谢楼主
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表