stm32---CAN通信

2020-03-26来源: eefocus关键字:stm32  CAN通信  初始化

can.c


#include "can.h"

 

/*************************************************************

函数名:CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)

功能:CAN初始化

变量:

//tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq

//tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;

//tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq

//brp :波特率分频器.范围:1~1024;  tq=(brp)*tpclk1

//波特率=Fpclk1/((tbs1+tbs2+1)*brp);

//mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;

//Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack);

//则波特率为:36M/((8+9+1)*4)=500Kbps

//返回值:0,初始化OK;

//    其他,初始化失败;

**************************************************************/

void CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    CAN_InitTypeDef CAN_InitStructure;

    CAN_FilterInitTypeDef CAN_FilterStructure;

#if CAN_RX0_INT_ENABLE 

    NVIC_InitTypeDef        NVIC_InitStructure;

#endif

    //1*开启CAN时钟和对应引脚时钟

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1,ENABLE);

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

    

    //2*引脚初始化配置

    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);

    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_InitStructure.CAN_Prescaler = brp; //分频系数为brp+1

    CAN_InitStructure.CAN_Mode=mode; //模式设置

    CAN_InitStructure.CAN_BS1=tbs1; //Tbs1范围

    CAN_InitStructure.CAN_BS2=tbs2; //Tbs2范围

    CAN_InitStructure.CAN_SJW=tsjw; //重新同步跳跃宽度的

    CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理

    CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通过软件唤醒

    CAN_InitStructure.CAN_NART=ENABLE;  //使用报文自动传输

    CAN_InitStructure.CAN_RFLM=DISABLE;  //报文不锁定,新的覆盖旧的

    CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式

    CAN_InitStructure.CAN_TXFP=DISABLE;//优先级由报文标识符决定 

    CAN_Init(CAN1,&CAN_InitStructure);

    

    //4*过滤器初始化配置

    CAN_FilterStructure.CAN_FilterNumber =0; //过滤器0

    CAN_FilterStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //掩码模式,缺点是有误差,报表模式缺点是可识别ID少

    CAN_FilterStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32位

    CAN_FilterStructure.CAN_FilterIdHigh=0x0000; //32位ID

    CAN_FilterStructure.CAN_FilterIdLow = 0x0000;

    CAN_FilterStructure.CAN_FilterMaskIdHigh=0x0000; //32位掩码

    CAN_FilterStructure.CAN_FilterMaskIdLow=0x0000;

    CAN_FilterStructure.CAN_FilterFIFOAssignment=CAN_FilterFIFO0;//过滤器0关联到FIFO0(邮箱0)

    CAN_FilterStructure.CAN_FilterActivation=ENABLE;//激活过滤器0

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

 

    #if CAN_RX0_INT_ENABLE 

    CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);              //FIFO0消息挂号中断允许.            

 

    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;     // 主优先级为1

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;            // 次优先级为0

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);

    #endif

}

 

    #if CAN_RX0_INT_ENABLE  //使能RX0中断

    //中断服务函数                

    void USB_LP_CAN1_RX0_IRQHandler(void)

    {

        CanRxMsg RxMessage;

        int i=0;

        CAN_Receive(CAN1, 0, &RxMessage);

        for(i=0;i<8;i++)

        printf("rxbuf[%d]:%drn",i,RxMessage.Data[i]);

    }

    #endif

    

 

//can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)   

//len:数据长度(最大为8)                     

//msg:数据指针,最大为8个字节.

//返回值:0,成功;

//       其他,失败;

u8 CAN_Send_Msg(u8 *msg,u8 len)

{

    u16 i=0;

    u8 mbox;

    

    CanTxMsg TxMessage; 

    TxMessage.StdId=0x12; //标准ID,设置为扩展时自动变0

    TxMessage.ExtId=0x12; //扩展ID

    TxMessage.IDE=0; //决定是标准(1)还是扩展模式(0)

    TxMessage.RTR=0; //表明是数据帧(0)还是遥控帧(1),当是遥控帧时TxMessage.Data为0

    TxMessage.DLC=len; //数据长度(最大为8) 

    for(i=0;i

        TxMessage.Data[i] = msg[i];

    

    mbox = CAN_Transmit(CAN1,&TxMessage); //发送数据,返回所使用邮箱的号码,如果没有空邮箱返回 CAN_NO_MB

    i=0;

    while((CAN_TransmitStatus(CAN1,mbox)==CAN_TxStatus_Failed)&&(i<0xfff)) i++; //发送完退出,未发送完i自加到0xfff时强制退出

    if(i>=0xfff) return 1; //失败

    return 0; //成功

}

 

 

//can口接收数据查询

//buf:数据缓存区;     

//返回值:0,无数据被收到;

//       其他,接收的数据长度;

u8 CAN_Receive_Msg(u8 *buf)

{

    u32 i;

    CanRxMsg RxMessage; //结构体定义

    if(CAN_MessagePending(CAN1,CAN_FIFO0)==0) return 0; //邮箱为空

    CAN_Receive(CAN1,CAN_FIFO0,&RxMessage);

    for(i=0;i

        buf[i] = RxMessage.Data[i];

    return RxMessage.DLC;//返回接收的数据长度

}

can.h


#ifndef _can_H

#define _can_H

 

#include "system.h"

 

 

void CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode);

u8 CAN_Send_Msg(u8 *msg,u8 len);

u8 CAN_Receive_Msg(u8 *buf);

 

#endif

main.c


#include "system.h"

#include "SysTick.h"

#include "led.h"

#include "usart.h"

#include "can.h"

#include "key.h"

int main()

{

    u8 i,j,key;

    u8 mode=0; //默认是正常模式

    u8 res;

    u8 tbuf[8],char_buf[8];

    u8 rbuf[8];

    

    SysTick_Init(72);

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  //中断优先级分组 分2组

    LED_Init();

    USART1_Init(9600);

    KEY_Init();

    

    CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_Normal);

    

    while(1)

    {   

        key =KEY_Scan(0);

        if(key==KEY_UP) //切换模式

        {

            mode = !mode; //模式切换,正常模式0x00,环回模式0x01

            CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,mode);

            if(mode==0) 

                printf("Normal Modern");//正常模式

            else

                printf("LoopBack Modern");//环回模式

        }

        else if(key==KEY_DOWN)//发送接收数据

        {

            for(j=0;j<8;j++)

            {

                tbuf[j] = j;

                char_buf[j] = tbuf[j]+0x30;//加0x30变ASC码

            }

            res = CAN_Send_Msg(tbuf,8); //返回0成功

            if(res)

                printf("Send Failedrn");

            else

                printf("发送数据:%srn",char_buf);

        }

        res = CAN_Receive_Msg(rbuf); //返回0失败,非0为接收数据长度

        if(res) //res不为0就可进入

        {

            for(j=0;j

            {

                char_buf[j] = rbuf[j]+0x30; //加0x30变ASC码

            }

            printf("接收数据:%srn",char_buf);

        }

        i++;

[1] [2]
关键字:stm32  CAN通信  初始化 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic492637.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:stm32---SPI与外部FLASH
下一篇:stm32---RS485半双工通信

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm8l低功耗系列
最近干刚做了一个stm8的项目用的是L低功耗系列,其中遇到一个问题。外设寄存器的值怎么都写入不进去。用IAR仿真产看寄存器的值,不论写进去多少,都是初始值。后来把所有寄存器都写了一遍,发现有的能写进去,有的写不进去。比如GPIO的寄存器就能写进去。百思不得姐,偶然查看clock的库函数发现个函数是设置外设时钟的。这个系列,亦或者整个低功耗系列的每个外设是不是都需要在时钟寄存器中单独设置时钟。(以前所使用的芯片都是在外设寄存器中使能或者是禁使能)
发表于 2020-03-09
STM8L+BC26双低功耗,微安
现在在做一个项目需要用到STM8L和BC26。长时间断链后连接下服务器,并且发送一下当前状态,需要用到STM8L和BC26的低功耗。STM8L低功耗,这里用HALT模式,RTC规定时间唤醒。第一步需要关闭所有外设,把所有管脚为设置为输出,并且输出低,管脚根据具体环境设置,需要输出高电平的则输出高电平。在关闭外设的是后是需要先_DeInit,然后在关闭外设始终,有点需要特别主要,要把在进入halt模式的时候需要把所有的中断的标志位清空,否则使用RTC唤醒则会不起作用。第二步就设置低功耗的一些配置。第三步配置完成后进入低功耗。项目中需要用到外部高速始终和BC26通信,所以在进入和退出halt模式的时候需要重新初始化active模式下的
发表于 2020-03-09
stm8l151低功耗程序架构,调试心得
最近帮医院做了一款体温记录仪,整个硬件方案资源是:stm8L151 + NTC*2 + EEPROM + 锂电池充电保护电路 + 18mAh纽扣电池;软件逻辑是,每隔一分钟,采样两路温度并保存在EEP里;通过USB转TTL,上位机能够读取,展示温度曲线,最大最小平均值等简单的运算;整个方案很简单,但也走了不少弯路......单片机程序框架之伪代码:void main(void){    CLK_Config();    GPIO_Config();    ADC_Config();    USART_Config();   
发表于 2020-03-09
STM8s外部时钟晶振失效时钟安全系统CSS启动演示
使用的最小系统晶振是8m的。这里说下配置过程:时钟自动切换,开启切换中断在中断里面清除中断标志,使能CSS并开启CSS中断CSS中断发生,清除CSS中断标志,将HSI二分频,即16M/2=8M,与外部晶振相同,这样不会影响串口波特率窗口输出配置信息:用手触碰PA1、PA2引脚使外部晶振失效串口输出CSS中断
发表于 2020-03-09
STM8s外部时钟晶振失效时钟安全系统CSS启动演示
STM8S103之时钟设置
最大时钟(指的是system clock):外部晶振24MHz,内部高速RC16MHz三个时钟源:外部晶振、内部高速RC(上电默认) +内部低速RC几个时钟:master clock(即sytem clock),fcpu,外设时钟、AWU时钟调用库函数中CLK_ClockSwitchConfig,参考库函数clk_clockselection,但是分频还得进一步设置上电默认:内部高速RC,HSIDIV=/8,CPUDIV=/1,外部时钟全使能,查看相关寄存器的Reset value
发表于 2020-03-09
STM8S103之时钟设置
stm8 16M晶振下精确软件延时
void inerDelay_us(unsigned char n) {for(;n>0;n--) { asm("nop"); //在STM8里面,16M晶振,_nop_() 延时了 333nsasm("nop"); asm("nop"); asm("nop"); }}//---- 毫秒级延时程序----------------------- void Delayms(unsigned int time) { unsigned int i; 
发表于 2020-03-08
小广播
何立民专栏 单片机及嵌入式宝典

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

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