主要用于实现CAN2总线上的收发,无任何过滤,用于检验CAN信号,适合新手入门。
只要是在CAN2的信号线上都可以实现,不局限于开发板,本人移植到F103亲测成功!
can 头文件
#define CANx CAN2
#define CAN_CLK RCC_APB1Periph_CAN1 |RCC_APB1Periph_CAN2
#define CAN_RX_IRQ CAN2_RX0_IRQn
#define CAN_RX_IRQHandler CAN2_RX0_IRQHandler
#define CAN_RX_PIN GPIO_Pin_12
#define CAN_TX_PIN GPIO_Pin_13
#define CAN_TX_GPIO_PORT GPIOB
#define CAN_RX_GPIO_PORT GPIOB
#define CAN_TX_GPIO_CLK RCC_AHB1Periph_GPIOB
#define CAN_RX_GPIO_CLK RCC_AHB1Periph_GPIOB
#define CAN_AF_PORT GPIO_AF_CAN2
#define CAN_RX_SOURCE GPIO_PinSource12
#define CAN_TX_SOURCE GPIO_PinSource13
效果如图
可发任意信号,串口发送10位信号,前两位为id,其他位数据位,接受所有can信号
串口定义
串口参数 | 含义 |
---|---|
01 | ID高位 |
02 | ID低位 |
其他 | $1 |
CAN 头文件
#ifndef __CAN_H
#define __CAN_H
#include "stm32f4xx.h"
#include <stdio.h>
#define CANx CAN2
#define CAN_CLK RCC_APB1Periph_CAN1 |RCC_APB1Periph_CAN2
#define CAN_RX_IRQ CAN2_RX0_IRQn
#define CAN_RX_IRQHandler CAN2_RX0_IRQHandler
#define CAN_RX_PIN GPIO_Pin_12
#define CAN_TX_PIN GPIO_Pin_13
#define CAN_TX_GPIO_PORT GPIOB
#define CAN_RX_GPIO_PORT GPIOB
#define CAN_TX_GPIO_CLK RCC_AHB1Periph_GPIOB
#define CAN_RX_GPIO_CLK RCC_AHB1Periph_GPIOB
#define CAN_AF_PORT GPIO_AF_CAN2
#define CAN_RX_SOURCE GPIO_PinSource12
#define CAN_TX_SOURCE GPIO_PinSource13
/*debug*/
#define CAN_DEBUG_ON 1
#define CAN_DEBUG_ARRAY_ON 1
#define CAN_DEBUG_FUNC_ON 1
// Log define
#define CAN_INFO(fmt,arg...) printf("<<-CAN-INFO->> "fmt"\n",##arg)
#define CAN_ERROR(fmt,arg...) printf("<<-CAN-ERROR->> "fmt"\n",##arg)
#define CAN_DEBUG(fmt,arg...) do{\
if(CAN_DEBUG_ON)\
printf("<<-CAN-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
}while(0)
#define CAN_DEBUG_ARRAY(array, num) do{\
int32_t i;\
uint8_t* a = array;\
if(CAN_DEBUG_ARRAY_ON)\
{\
printf("CAN-data: ");\
for (i = 0; i < (num); i++)\
{\
printf("%02x ", (a)[i]);\
if ((i + 1 ) %10 == 0)\
{\
printf("\n");\
}\
}\
printf("\n");\
}\
}while(0)
#define CAN_DEBUG_FUNC() do{\
if(CAN_DEBUG_FUNC_ON)\
printf("<<-CAN-FUNC->> Func:%s@Line:%d\n",__func__,__LINE__);\
}while(0)
static void CAN_GPIO_Config(void);
static void CAN_NVIC_Config(void);
static void CAN_Mode_Config(void);
static void CAN_Filter_Config(void);
void CAN_Config(void);
void CAN_SetMsg(CanTxMsg *TxMessage);
void Init_RxMes(CanRxMsg *RxMessage);
#endif
CAN 主文件
/**
******************************************************************************
* @file bsp_can.c
* @author fire
* @version V1.0
* @date 2015-xx-xx
* @brief can驱动(回环模式)
******************************************************************************
* @attention
*
* 实验平台:野火 STM32 F407 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************************
*/
#include "can.h"
extern __IO uint32_t flag ; //用于标志是否接收到数据,在中断函数中赋值
extern CanRxMsg RxMessage; //接收缓冲区
u16 RxMessage_jishu=0;
#if 0
//初始化
CAN_Config();
//发送代码
CAN_SetMsg(&TxMessage);
CAN_Transmit(CANx, &TxMessage);
delay_ms(10);;//等待发送完毕,可使用CAN_TransmitStatus查看状态
printf("\r\n已使用CAN发送数据包!\r\n");
printf("\r\n发送的报文内容为:\r\n");
printf("\r\n 扩展ID号ExtId:0x%x \r\n",TxMessage.ExtId);
CAN_DEBUG_ARRAY(TxMessage.Data,8);
delay_ms(1000);
#endif
void CAN_RX_IRQHandler(void)
{
RxMessage_jishu++;
/*从邮箱中读出报文*/
CAN_Receive(CANx, CAN_FIFO0, &RxMessage);
printf(" %d-can 已接收-Stdid = %04x " ,RxMessage_jishu,RxMessage.StdId);
CAN_DEBUG_ARRAY(RxMessage.Data,8);
/* 比较ID是否为0x1314 */
// if((RxMessage.ExtId==0x1314) && (RxMessage.IDE==CAN_ID_EXT) && (RxMessage.DLC==8) )
// {
// flag = 1; //接收成功
// }
// else
// {
// flag = 0; //接收失败
// }
}
/*
* 函数名:CAN_GPIO_Config
* 描述 :CAN的GPIO 配置
* 输入 :无
* 输出 : 无
* 调用 :内部调用
*/
static void CAN_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIO clock */
RCC_AHB1PeriphClockCmd(CAN_TX_GPIO_CLK|CAN_RX_GPIO_CLK, ENABLE);
/* Connect CAN pins to AF9 */
GPIO_PinAFConfig(CAN_TX_GPIO_PORT, CAN_RX_SOURCE, CAN_AF_PORT);
GPIO_PinAFConfig(CAN_RX_GPIO_PORT, CAN_TX_SOURCE, CAN_AF_PORT);
/* Configure CAN TX pins */
GPIO_InitStructure.GPIO_Pin = CAN_TX_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(CAN_TX_GPIO_PORT, &GPIO_InitStructure);
/* Configure CAN RX pins */
GPIO_InitStructure.GPIO_Pin = CAN_RX_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_Init(CAN_RX_GPIO_PORT, &GPIO_InitStructure);
}
/*
* 函数名:CAN_NVIC_Config
* 描述 :CAN的NVIC 配置,第1优先级组,0,0优先级
* 输入 :无
* 输出 : 无
* 调用 :内部调用
*/
static void CAN_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/*中断设置*/
NVIC_InitStructure.NVIC_IRQChannel = CAN_RX_IRQ; //CAN RX0中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/*
* 函数名:CAN_Mode_Config
* 描述 :CAN的模式 配置
* 输入 :无
* 输出 : 无
* 调用 :内部调用
*/
static void CAN_Mode_Config(void)
{
CAN_InitTypeDef CAN_InitStructure;
/************************CAN通信参数设置**********************************/
/* Enable CAN clock */
RCC_APB1PeriphClockCmd(CAN_CLK, ENABLE);
/*CAN寄存器初始化*/
CAN_DeInit(CANx);
CAN_StructInit(&CAN_InitStructure);
/*CAN单元初始化*/
CAN_InitStructure.CAN_TTCM=DISABLE; //MCR-TTCM 关闭时间触发通信模式使能
CAN_InitStructure.CAN_ABOM=ENABLE; //MCR-ABOM 自动离线管理
CAN_InitStructure.CAN_AWUM=ENABLE; //MCR-AWUM 使用自动唤醒模式
CAN_InitStructure.CAN_NART=DISABLE; //MCR-NART 禁止报文自动重传 DISABLE-自动重传
CAN_InitStructure.CAN_RFLM=DISABLE; //MCR-RFLM 接收FIFO 锁定模式 DISABLE-溢出时新报文会覆盖原有报文
CAN_InitStructure.CAN_TXFP=DISABLE; //MCR-TXFP 发送FIFO优先级 DISABLE-优先级取决于报文标示符
CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; //正常工作模式
CAN_InitStructure.CAN_SJW=CAN_SJW_2tq; //BTR-SJW 重新同步跳跃宽度 2个时间单元
/* ss=1 bs1=4 bs2=2 位时间宽度为(1+4+2) 波特率即为时钟周期tq*(1+4+2) */
CAN_InitStructure.CAN_BS1=CAN_BS1_4tq; //BTR-TS1 时间段1 占用了4个时间单元
CAN_InitStructure.CAN_BS2=CAN_BS2_2tq; //BTR-TS1 时间段2 占用了2个时间单元
/* CAN Baudrate = 1 MBps (1MBps已为stm32的CAN最高速率) (CAN 时钟频率为 APB 1 = 42 MHz) */
CAN_InitStructure.CAN_Prescaler =12; BTR-BRP 波特率分频器 定义了时间单元的时间长度 42/(1+4+2)/6=1 Mbps
CAN_Init(CANx, &CAN_InitStructure);
}
/*
* 函数名:CAN_Filter_Config
* 描述 :CAN的过滤器 配置
* 输入 :无
* 输出 : 无
* 调用 :内部调用
*/
static void CAN_Filter_Config(void)
{
CAN_FilterInitTypeDef CAN_FilterInitStructure;
/*CAN筛选器初始化*/
CAN_FilterInitStructure.CAN_FilterNumber=14; //筛选器组14
CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask; //工作在掩码模式
CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //筛选器位宽为单个32位。
/* 使能筛选器,按照标志的内容进行比对筛选,扩展ID不是如下的就抛弃掉,是的话,会存入FIFO0。 */
CAN_FilterInitStructure.CAN_FilterIdHigh= 0; //要筛选的ID高位
CAN_FilterInitStructure.CAN_FilterIdLow= 0; //要筛选的ID低位
CAN_FilterInitStructure.CAN_FilterMaskIdHigh= 0; //筛选器高16位每位必须匹配
CAN_FilterInitStructure.CAN_FilterMaskIdLow= 0; //筛选器低16位每位必须匹配
CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0 ; //筛选器被关联到FIFO0
CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //使能筛选器
CAN_FilterInit(&CAN_FilterInitStructure);
/*CAN通信中断使能*/
CAN_ITConfig(CANx, CAN_IT_FMP0, ENABLE);
}
/*
* 函数名:CAN_Config
* 描述 :完整配置CAN的功能
* 输入 :无
* 输出 : 无
* 调用 :外部调用
*/
void CAN_Config(void)
{
CAN_GPIO_Config();
CAN_NVIC_Config();
CAN_Mode_Config();
CAN_Filter_Config();
}
/**
* @brief 初始化 Rx Message数据结构体
* @param RxMessage: 指向要初始化的数据结构体
* @retval None
*/
void Init_RxMes(CanRxMsg *RxMessage)
{
uint8_t ubCounter = 0;
/*把接收结构体清零*/
RxMessage->StdId = 0x00;
RxMessage->ExtId = 0x00;
RxMessage->IDE = CAN_ID_STD;
RxMessage->DLC = 0;
RxMessage->FMI = 0;
for (ubCounter = 0; ubCounter < 8; ubCounter++)
{
RxMessage->Data[ubCounter] = 0x00;
}
}
/*
* 函数名:CAN_SetMsg
* 描述 :CAN通信报文内容设置,设置一个数据内容为0-7的数据包
* 输入 :发送报文结构体
* 输出 : 无
* 调用 :外部调用
*/
void CAN_SetMsg(CanTxMsg *TxMessage)
{
// TxMessage->StdId=0x010f;
// TxMessage->ExtId=0x0f; //使用的扩展ID
TxMessage->IDE=CAN_ID_STD; //扩展模式
TxMessage->RTR=CAN_RTR_DATA; //发送的是数据
TxMessage->DLC=8; //数据长度为8字节
/*设置要发送的数据0-7*/
// for (ubCounter = 0; ubCounter < 8; ubCounter++)
// {
// TxMessage->Data[ubCounter] = ubCounter;
// }
}
/**************************END OF FILE************************************/
main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "can.h"
//ALIENTEK 探索者STM32F407开发板 实验27
//CAN通信实验-库函数版本
//技术支持:www.openedv.com
//淘宝店铺:http://eboard.taobao.com
//广州市星翼电子科技有限公司
//作者:正点原子 @ALIENTEK
__IO uint32_t flag = 0; //用于标志是否接收到数据,在中断函数中赋值
CanTxMsg TxMessage; //发送缓冲区
CanRxMsg RxMessage; //接收缓冲区
u16 usart_len;
int main(void)
{
u16 uart_jishu=0;
u8 t=0;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_Init(); //初始化LED
KEY_Init(); //按键初始化
CAN_Config();
printf("系统初始化完成!\n"); //显示当前计数值
printf("该系统只能在500k波特率、标准帧下进行!\n"); //显示当前计数值
printf("\n"); //显示当前计数值
while(1)
{
if(WK_UP==1)//KEY0按下,发送一次数据
{
CAN_SetMsg(&TxMessage);
CAN_Transmit(CANx, &TxMessage);
delay_ms(10);;//等待发送完毕,可使用CAN_TransmitStatus查看状态
printf("\r\n已使用CAN发送数据包!\r\n");
printf("\r\n发送的报文内容为:\r\n");
printf("\r\n 扩展ID号ExtId:0x%x \r\n",TxMessage.ExtId);
CAN_DEBUG_ARRAY(TxMessage.Data,8);
delay_ms(1000);
}
if(USART_RX_STA&0x8000)
{
uart_jishu++;
usart_len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf(" %d-can 已发送-StdId = %04x sen-data = ",uart_jishu,TxMessage.StdId);
TxMessage.StdId=USART_RX_BUF[0]<<8|USART_RX_BUF[1];
for(t=0;t<8;t++)
{
TxMessage.Data[t]=USART_RX_BUF[t+2];
printf("%02x ",USART_RX_BUF[t+2]);
}
CAN_SetMsg(&TxMessage);
CAN_Transmit(CANx, &TxMessage);
delay_ms(10);;//等待发送完毕,可使用CAN_TransmitStatus查看状态
printf("\r\n");//插入换行
USART_RX_STA=0;
}
t++;
delay_ms(5);
if(t==100)
{
LED0=!LED0;//提示系统正在运行
t=0;
}
}
}
附上代码链接
链接:https://pan.baidu.com/s/1PTQEcJziu7vZgcWV724yww
提取码:bk5v
–来自百度网盘超级会员V5的分享